10000 Merge pull request #9912 from patricksurry/demux-keymatrix-delay · supcik/circuitpython@57cf054 · GitHub
[go: up one dir, main page]

Skip to content

Commit 57cf054

Browse files
authored
Merge pull request adafruit#9912 from patricksurry/demux-keymatrix-delay
fix: Add delay to DemuxKeyMatrix along with columns_to_anodes and transpose options
2 parents fda920a + e185c28 commit 57cf054

File tree

6 files changed

+72
-19
lines changed

6 files changed

+72
-19
lines changed

ports/espressif/boards/m5stack_cardputer/cardputer_keyboard.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ void cardputer_keyboard_init(void) {
110110
row_addr_pins, // row_addr_pins
111111
7, // num_column_pins
112112
column_pins, // column_pins
113+
true, // columns_to_anodes
114+
false, // transpose
113115
0.01f, // interval
114116
20, // max_events
115117
2 // debounce_threshold

shared-bindings/keypad_demux/DemuxKeyMatrix.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
//| self,
3737
//| row_addr_pins: Sequence[microcontroller.Pin],
3838
//| column_pins: Sequence[microcontroller.Pin],
39+
//| columns_to_anodes: bool = True,
40+
//| transpose: bool = False,
3941
//| interval: float = 0.020,
4042
//| max_events: int = 64,
4143
//| debounce_threshold: int = 1,
@@ -51,7 +53,18 @@
5153
//| An `keypad.EventQueue` is created when this object is created and is available in the `events` attribute.
5254
//|
5355
//| :param Sequence[microcontroller.Pin] row_addr_pins: The pins attached to the rows demultiplexer.
56+
//| If your columns are multiplexed, set ``transpose`` to ``True``.
5457
//| :param Sequence[microcontroller.Pin] column_pins: The pins attached to the columns.
58+
//| :param bool columns_to_anodes: Default ``True``.
59+
//| If the matrix uses diodes, the diode anodes are typically connected to the column pins
60+
//| with the cathodes connected to the row pins. This implies an inverting multiplexer that drives
61+
//| the selected row pin low. If your diodes are reversed, with a non-inverting multiplexer
62+
//| that drives the selected row high, set ``columns_to_anodes`` to ``False``.
63+
//| If ``transpose`` is ``True`` the sense of columns and rows are reversed here.
64+
//| :param bool transpose: Default ``False``.
65+
//| If your matrix is multiplexed on columns rather than rows, set ``transpose`` to ``True``.
66+
//| This swaps the meaning of ``row_addr_pins`` to ``column_addr_pins``;
67+
//| ``column_pins`` to ``row_pins``; and ``columns_to_anodes`` to ``rows_to_anodes``.
5568
//| :param float interval: Scan keys no more often than ``interval`` to allow for debouncing.
5669
//| ``interval`` is in float seconds. The default is 0.020 (20 msecs).
5770
//| :param int max_events: maximum size of `events` `keypad.EventQueue`:
@@ -67,10 +80,12 @@
6780

6881
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) {
6982
keypad_demux_demuxkeymatrix_obj_t *self = mp_obj_malloc(keypad_demux_demuxkeymatrix_obj_t, &keypad_demux_demuxkeymatrix_type);
70-
enum { ARG_row_addr_pins, ARG_column_pins, ARG_interval, ARG_max_events, ARG_debounce_threshold };
83+
enum { ARG_row_addr_pins, ARG_column_pins, ARG_columns_to_anodes, ARG_transpose, ARG_interval, ARG_max_events, ARG_debounce_threshold };
7184
static const mp_arg_t allowed_args[] = {
7285
{ MP_QSTR_row_addr_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
7386
{ MP_QSTR_column_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
87+
{ MP_QSTR_columns_to_anodes, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
88+
{ MP_QSTR_transpose, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
7489
{ MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
7590
{ MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
7691
{ MP_QSTR_debounce_threshold, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
@@ -107,7 +122,7 @@ static mp_obj_t keypad_demux_demuxkeymatrix_make_new(const mp_obj_type_t *type,
107122
column_pins_array[column] = pin;
108123
}
109124

110-
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);
125+
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);
111126
return MP_OBJ_FROM_PTR(self);
112127
}
113128

shared-bindings/keypad_demux/DemuxKeyMatrix.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
extern const mp_obj_type_t keypad_demux_demuxkeymatrix_type;
1313

14-
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);
14+
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);
1515

1616
void common_hal_keypad_demux_demuxkeymatrix_deinit(keypad_demux_demuxkeymatrix_obj_t *self);
1717

shared-bindings/keypad_demux/__init__.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,14 @@
1111

1212
//| """Support for scanning key matrices that use a demultiplexer
1313
//|
14-
//| The `keypad_demux` module provides native support to scan sets of keys or buttons,
15-
//| connected in a row-and-column matrix.
14+
//| The `keypad_demux` module provides native support to scan a matrix of keys or buttons
15+
//| where either the row or column axis is controlled by a demultiplexer or decoder IC
16+
//| such as the 74LS138 or 74LS238. In this arrangement a binary input value
17+
//| determines which column (or row) to select, thereby reducing the number of input pins.
18+
//| For example the input 101 would select line 5 in the matrix.
19+
//| Set ``columns_to_anodes`` to ``False`` with a non-inverting demultiplexer
20+
//| which drives the selected line high.
21+
//| Set ``transpose`` to ``True`` if columns are multiplexed rather than rows.
1622
//|
1723
//| .. jinja
1824
//| """

shared-module/keypad_demux/DemuxKeyMatrix.c

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <string.h>
88

99
#include "py/gc.h"
10+
#include "py/mphal.h"
1011
#include "py/runtime.h"
1112
#include "shared-bindings/digitalio/DigitalInOut.h"
1213
#include "shared-bindings/keypad/EventQueue.h"
@@ -26,11 +27,15 @@ static keypad_scanner_funcs_t keymatrix_funcs = {
2627
};
2728

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

32-
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) {
34+
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) {
3335

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

49+
// the column pins are always inputs, with default state based on columns_to_anodes
4450
mp_obj_t column_dios[num_column_pins];
4551
for (size_t column = 0; column < num_column_pins; column++) {
4652
digitalio_digitalinout_obj_t *dio =
4753
mp_obj_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type);
4854
dio->base.type = &digitalio_digitalinout_type;
4955
common_hal_digitalio_digitalinout_construct(dio, column_pins[column]);
50-
common_hal_digitalio_digitalinout_switch_to_input(dio, PULL_UP);
56+
common_hal_digitalio_digitalinout_switch_to_input(dio, columns_to_anodes ? PULL_UP : PULL_DOWN);
5157
column_dios[column] = dio;
5258
}
5359
self->column_digitalinouts = mp_obj_new_tuple(num_column_pins, column_dios);
5460

61+
self->columns_to_anodes = columns_to_anodes;
62+
self->transpose = transpose;
5563
self->funcs = &keymatrix_funcs;
5664

5765
keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold);
@@ -78,11 +86,15 @@ void common_hal_keypad_demux_demuxkeymatrix_deinit(keypad_demux_demuxkeymatrix_o
7886
}
7987

8088
size_t common_hal_keypad_demux_demuxkeymatrix_get_row_count(keypad_demux_demuxkeymatrix_obj_t *self) {
81-
return 1 << self->row_addr_digitalinouts->len;
89+
return self->transpose
90+
? self->column_digitalinouts->len
91+
: (size_t)(1 << self->row_addr_digitalinouts->len);
8292
}
8393

8494
size_t common_hal_keypad_demux_demuxkeymatrix_get_column_count(keypad_demux_demuxkeymatrix_obj_t *self) {
85-
return self->column_digitalinouts->len;
95+
return self->transpose
96+
? (size_t)(1 << self->row_addr_digitalinouts->len)
97+
: self->column_digitalinouts->len;
8698
}
8799

88100
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) {
@@ -102,22 +114,38 @@ static size_t demuxkeymatrix_get_key_count(void *self_in) {
102114

103115
static void demuxkeymatrix_scan_now(void *self_in, mp_obj_t timestamp) {
104116
keypad_demux_demuxkeymatrix_obj_t *self = self_in;
105-
106-
for (size_t row = 0; row < common_hal_keypad_demux_demuxkeymatrix_get_row_count(self); row++) {
107-
// Set the row address on demultiplexer
117+
// We always scan through the multiplexed lines using the array sizes directly
118+
// and apply transposition only when translating to key number.
119+
for (int row = 0; row < (1 << self->row_addr_digitalinouts->len); row++) {
120+
// Set the row address on the demultiplexer.
121+
// When columns_to_anodes is True (default) we've got an inverting demux
122+
// so the selected line is pulled low, and we look for rows that get pulled low.
123+
// When columns_to_anodes is False we do the reverse.
108124
size_t mask = 0b00000001;
109125
for (size_t row_addr_pin = 0; row_addr_pin < self->row_addr_digitalinouts->len; row_addr_pin++) {
110126
digitalio_digitalinout_obj_t *dio = self->row_addr_digitalinouts->items[row_addr_pin];
111127
common_hal_digitalio_digitalinout_set_value(dio, (mask & row) != 0);
112128
mask = mask << 1;
113129
}
114130

115-
for (size_t column = 0; column < common_hal_keypad_demux_demuxkeymatrix_get_column_count(self); column++) {
116-
mp_uint_t key_number = row_column_to_key_number(self, row, column);
117-
118-
// Get the current state, by reading whether the column got pulled to the row value or not.
119-
// If low, the key is pressed.
120-
const bool current = !common_hal_digitalio_digitalinout_get_value(self->column_digitalinouts->items[column]);
131+
// Wait a moment to let the columns settle.
132+
// The normal KeyMatrix uses a 1us delay but that still gave echoes on my
133+
// nullbitsco nibble 65% (16 x 5 matrix). For example when key (row, col) is pressed
134+
// both (row, col) and (row+1, col) (and sometimes row+2) are registered,
135+
// especially when row+1 is a power of 2 (all mux bits change) and col is 0.
136+
// The QMK implementation for this keyboard uses a 5us delay which works here too
137+
mp_hal_delay_us(5);
138+
139+
for (size_t column = 0; column < self->column_digitalinouts->len; column++) {
140+
mp_uint_t key_number = self->transpose
141+
? row_column_to_key_number(self, column, row)
142+
: row_column_to_key_number(self, row, column);
143+
144+
// Get the current state, by reading whether the column got pulled to the row value or not,
145+
// which is the opposite of columns_to_anodes.
146+
const bool current =
147+
common_hal_digitalio_digitalinout_get_value(self->column_digitalinouts->items[column]) !=
148+
self->columns_to_anodes;
121149

122150
// Record any transitions.
123151
if (keypad_debounce((keypad_scanner_obj_t *)self, key_number, current)) {

shared-module/keypad_demux/DemuxKeyMatrix.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ typedef struct {
1717
KEYPAD_SCANNER_COMMON_FIELDS;
1818
mp_obj_tuple_t *row_addr_digitalinouts;
1919
mp_obj_tuple_t *column_digitalinouts;
20+
bool columns_to_anodes;
21+
bool transpose;
2022
} keypad_demux_demuxkeymatrix_obj_t;
2123

2224
void keypad_demux_demuxkeymatrix_scan(keypad_demux_demuxkeymatrix_obj_t *self);

0 commit comments

Comments
 (0)
0