Skip to content

Commit

Permalink
wip: include transpose and columns_to_anodes options
Browse files Browse the repository at this point in the history
  • Loading branch information
patricksurry committed Dec 25, 2024
1 parent 111040f commit fdb38cc
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 18 deletions.
19 changes: 17 additions & 2 deletions shared-bindings/keypad_demux/DemuxKeyMatrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
//| self,
//| row_addr_pins: Sequence[microcontroller.Pin],
//| column_pins: Sequence[microcontroller.Pin],
//| columns_to_anodes: bool = True,
//| transpose: bool = False,
//| interval: float = 0.020,
//| max_events: int = 64,
//| debounce_threshold: int = 1,
Expand All @@ -51,7 +53,18 @@
//| An `keypad.EventQueue` is created when this object is created and is available in the `events` attribute.
//|
//| :param Sequence[microcontroller.Pin] row_addr_pins: The pins attached to the rows demultiplexer.
//| If your columns are multiplexed, set ``transpose`` to ``True``.
//| :param Sequence[microcontroller.Pin] column_pins: The pins attached to the columns.
//| :param bool columns_to_anodes: Default ``True``.
//| If the matrix uses diodes, the diode anodes are typically connected to the column pins
//| with the cathodes connected to the row pins. This implies an inverting multiplexer that drives
//| the selected row pin low. If your diodes are reversed, with a non-inverting multiplexer
//| that drives the selected row high, set ``columns_to_anodes`` to ``False``.
//| If ``transpose`` is ``True`` the sense of columns and rows are reversed here.
//| :param bool transpose: Default ``False``.
//| If your matrix is multiplexed on columns rather than rows, set ``transpose`` to ``True``.
//| This swaps the meaning of ``row_addr_pins`` to ``column_addr_pins``;
//| ``column_pins`` to ``row_pins``; and ``columns_to_anodes`` to ``rows_to_anodes``.
//| :param float interval: Scan keys no more often than ``interval`` to allow for debouncing.
//| ``interval`` is in float seconds. The default is 0.020 (20 msecs).
//| :param int max_events: maximum size of `events` `keypad.EventQueue`:
Expand All @@ -67,10 +80,12 @@

static mp_obj_t keypad_demux_demuxkeymatrix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
keypad_demux_demuxkeymatrix_obj_t *self = mp_obj_malloc(keypad_demux_demuxkeymatrix_obj_t, &keypad_demux_demuxkeymatrix_type);
enum { ARG_row_addr_pins, ARG_column_pins, ARG_interval, ARG_max_events, ARG_debounce_threshold };
enum { ARG_row_addr_pins, ARG_column_pins, ARG_columns_to_anodes, ARG_transpose, ARG_interval, ARG_max_events, ARG_debounce_threshold };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_row_addr_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_column_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_columns_to_anodes, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
{ MP_QSTR_transpose, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
{ MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
{ MP_QSTR_debounce_threshold, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
Expand Down Expand Up @@ -107,7 +122,7 @@ static mp_obj_t keypad_demux_demuxkeymatrix_make_new(const mp_obj_type_t *type,
column_pins_array[column] = pin;
}

common_hal_keypad_demux_demuxkeymatrix_construct(self, num_row_addr_pins, row_addr_pins_array, num_column_pins, column_pins_array, interval, max_events, debounce_threshold);
common_hal_keypad_demux_demuxkeymatrix_construct(self, num_row_addr_pins, row_addr_pins_array, num_column_pins, column_pins_array, args[ARG_columns_to_anodes].u_bool, args[ARG_transpose].u_bool, interval, max_events, debounce_threshold);
return MP_OBJ_FROM_PTR(self);
}

Expand Down
2 changes: 1 addition & 1 deletion shared-bindings/keypad_demux/DemuxKeyMatrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

extern const mp_obj_type_t keypad_demux_demuxkeymatrix_type;

void common_hal_keypad_demux_demuxkeymatrix_construct(keypad_demux_demuxkeymatrix_obj_t *self, mp_uint_t num_row_addr_pins, const mcu_pin_obj_t *row_addr_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], mp_float_t interval, size_t max_events, uint8_t debounce_threshold);
void common_hal_keypad_demux_demuxkeymatrix_construct(keypad_demux_demuxkeymatrix_obj_t *self, mp_uint_t num_row_addr_pins, const mcu_pin_obj_t *row_addr_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, bool transpose, mp_float_t interval, size_t max_events, uint8_t debounce_threshold);

void common_hal_keypad_demux_demuxkeymatrix_deinit(keypad_demux_demuxkeymatrix_obj_t *self);

Expand Down
10 changes: 8 additions & 2 deletions shared-bindings/keypad_demux/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@

//| """Support for scanning key matrices that use a demultiplexer
//|
//| The `keypad_demux` module provides native support to scan sets of keys or buttons,
//| connected in a row-and-column matrix.
//| The `keypad_demux` module provides native support to scan a matrix of keys or buttons
//| where either the row or column axis is controlled by a demultiplexer or decoder IC
//| such as the 74LS138 or 74LS238. In this arrangement a binary input value
//| determines which column (or row) to select, thereby reducing the number of input pins.
//| For example the input 101 would select line 5 in the matrix.
//| Set ``columns_to_anodes`` to ``False`` with a non-inverting demultiplexer
//| which drives the selected line high.
//| Set ``transpose`` to ``True`` if columns are multiplexed rather than rows.
//|
//| .. jinja
//| """
Expand Down
39 changes: 26 additions & 13 deletions shared-module/keypad_demux/DemuxKeyMatrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,15 @@ static keypad_scanner_funcs_t keymatrix_funcs = {
};

static mp_uint_t row_column_to_key_number(keypad_demux_demuxkeymatrix_obj_t *self, mp_uint_t row, mp_uint_t column) {
return row * self->column_digitalinouts->len + column;
// return the key index in the user's coordinate system
return row * common_hal_keypad_demux_demuxkeymatrix_get_column_count(self) + column;
}

void common_hal_keypad_demux_demuxkeymatrix_construct(keypad_demux_demuxkeymatrix_obj_t *self, mp_uint_t num_row_addr_pins, const mcu_pin_obj_t *row_addr_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], mp_float_t interval, size_t max_events, uint8_t debounce_threshold) {
void common_hal_keypad_demux_demuxkeymatrix_construct(keypad_demux_demuxkeymatrix_obj_t *self, mp_uint_t num_row_addr_pins, const mcu_pin_obj_t *row_addr_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, bool transpose, mp_float_t interval, size_t max_events, uint8_t debounce_threshold) {

// the multiplexed pins are outputs so we can set the address for the target row
// the sense of the address pins themselves doesn't change with columns_to_anodes
// but the value output on the selected row line will be !columns_to_anodes
mp_obj_t row_addr_dios[num_row_addr_pins];
for (size_t row = 0; row < num_row_addr_pins; row++) {
digitalio_digitalinout_obj_t *dio =
Expand All @@ -42,17 +46,20 @@ void common_hal_keypad_demux_demuxkeymatrix_construct(keypad_demux_demuxkeymatri
}
self->row_addr_digitalinouts = mp_obj_new_tuple(num_row_addr_pins, row_addr_dios);

// the column pins are always inputs, with default state based on columns_to_anodes
mp_obj_t column_dios[num_column_pins];
for (size_t column = 0; column < num_column_pins; column++) {
digitalio_digitalinout_obj_t *dio =
mp_obj_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type);
dio->base.type = &digitalio_digitalinout_type;
common_hal_digitalio_digitalinout_construct(dio, column_pins[column]);
common_hal_digitalio_digitalinout_switch_to_input(dio, PULL_UP);
common_hal_digitalio_digitalinout_switch_to_input(dio, columns_to_anodes ? PULL_UP : PULL_DOWN);
column_dios[column] = dio;
}
self->column_digitalinouts = mp_obj_new_tuple(num_column_pins, column_dios);

self->columns_to_anodes = columns_to_anodes;
self->transpose = transpose;
self->funcs = &keymatrix_funcs;

keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold);
Expand All @@ -79,11 +86,15 @@ void common_hal_keypad_demux_demuxkeymatrix_deinit(keypad_demux_demuxkeymatrix_o
}

size_t common_hal_keypad_demux_demuxkeymatrix_get_row_count(keypad_demux_demuxkeymatrix_obj_t *self) {
return 1 << self->row_addr_digitalinouts->len;
return self->transpose
? self->column_digitalinouts->len
: (size_t)(1 << self->row_addr_digitalinouts->len);
}

size_t common_hal_keypad_demux_demuxkeymatrix_get_column_count(keypad_demux_demuxkeymatrix_obj_t *self) {
return self->column_digitalinouts->len;
return self->transpose
? (size_t)(1 << self->row_addr_digitalinouts->len)
: self->column_digitalinouts->len;
}

mp_uint_t common_hal_keypad_demux_demuxkeymatrix_row_column_to_key_number(keypad_demux_demuxkeymatrix_obj_t *self, mp_uint_t row, mp_uint_t column) {
Expand All @@ -105,11 +116,11 @@ static void demuxkeymatrix_scan_now(void *self_in, mp_obj_t timestamp) {
keypad_demux_demuxkeymatrix_obj_t *self = self_in;

for (size_t row = 0; row < common_hal_keypad_demux_demuxkeymatrix_get_row_count(self); row++) {
// Set the row address on the demultiplexer. This currently assumes an inverting
// demux like the 74hc138 which outputs low on the selected line and high on non-selected ones.
// This class should probably support a columns_to_anodes parameter where this case would
// be True (the row gets pulled low), and a non-inverting demux like 74hc238 would
// set columns_to_anodes=False.
// Set the row address on the demultiplexer.
// When columns_to_anodes is True (default) we've got an inverting demux
// so the selected line is pulled low, and we look for rows that get pulled low.
// When columns_to_anodes is False we do the reverse.
// We can safely ignore transposition since it's handled by row_column_to_key_number
size_t mask = 0b00000001;
for (size_t row_addr_pin = 0; row_addr_pin < self->row_addr_digitalinouts->len; row_addr_pin++) {
digitalio_digitalinout_obj_t *dio = self->row_addr_digitalinouts->items[row_addr_pin];
Expand All @@ -128,9 +139,11 @@ static void demuxkeymatrix_scan_now(void *self_in, mp_obj_t timestamp) {
for (size_t column = 0; column < common_hal_keypad_demux_demuxkeymatrix_get_column_count(self); column++) {
mp_uint_t key_number = row_column_to_key_number(self, row, column);

// Get the current state, by reading whether the column got pulled to the row value or not.
// (with a columns_to_anodes parameter this could mimic the KeyMatrix code)
const bool current = !common_hal_digitalio_digitalinout_get_value(self->column_digitalinouts->items[column]);
// Get the current state, by reading whether the column got pulled to the row value or not,
// which is the opposite of columns_to_anodes.
const bool current =
common_hal_digitalio_digitalinout_get_value(self->column_digitalinouts->items[column]) !=
self->columns_to_anodes;

// Record any transitions.
if (keypad_debounce((keypad_scanner_obj_t *)self, key_number, current)) {
Expand Down
2 changes: 2 additions & 0 deletions shared-module/keypad_demux/DemuxKeyMatrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ typedef struct {
KEYPAD_SCANNER_COMMON_FIELDS;
mp_obj_tuple_t *row_addr_digitalinouts;
mp_obj_tuple_t *column_digitalinouts;
bool columns_to_anodes;
bool transpose;
} keypad_demux_demuxkeymatrix_obj_t;

void keypad_demux_demuxkeymatrix_scan(keypad_demux_demuxkeymatrix_obj_t *self);
Expand Down

0 comments on commit fdb38cc

Please sign in to comment.