Skip to content

Commit 3e184e9

Browse files
committed
Add state integration based debouncing to the keypad module
1 parent 50c504d commit 3e184e9

File tree

14 files changed

+83
-61
lines changed

14 files changed

+83
-61
lines changed

shared-bindings/keypad/KeyMatrix.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
//| columns_to_anodes: bool = True,
6060
//| interval: float = 0.020,
6161
//| max_events: int = 64,
62+
//| debounce_threshold: int = 1,
6263
//| ) -> None:
6364
//| """
6465
//| Create a `Keys` object that will scan the key matrix attached to the given row and column pins.
@@ -82,19 +83,24 @@
8283
//| maximum number of key transition events that are saved.
8384
//| Must be >= 1.
8485
//| If a new event arrives when the queue is full, the oldest event is discarded.
86+
//| :param int debounce_threshold: Emit events for state changes only after a key has been
87+
//| in the respective state for ``debounce_threshold`` times on average.
88+
//| Successive measurements are spaced apart by ``interval`` seconds.
89+
//| The default is 1, which resolves immediately. The maximum is 127.
8590
//| """
8691
//| ...
8792

8893
STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
8994
#if CIRCUITPY_KEYPAD_KEYMATRIX
9095
keypad_keymatrix_obj_t *self = mp_obj_malloc(keypad_keymatrix_obj_t, &keypad_keymatrix_type);
91-
enum { ARG_row_pins, ARG_column_pins, ARG_columns_to_anodes, ARG_interval, ARG_max_events };
96+
enum { ARG_row_pins, ARG_column_pins, ARG_columns_to_anodes, ARG_interval, ARG_max_events, ARG_debounce_threshold };
9297
static const mp_arg_t allowed_args[] = {
9398
{ MP_QSTR_row_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
9499
{ MP_QSTR_column_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
95100
{ MP_QSTR_columns_to_anodes, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
96101
{ MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
97102
{ MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
103+
{ MP_QSTR_debounce_threshold, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
98104
};
99105
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
100106
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@@ -109,6 +115,7 @@ STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_ar
109115
const mp_float_t interval =
110116
mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval);
111117
const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events);
118+
const uint8_t debounce_threshold = (uint8_t)mp_arg_validate_int_range(args[ARG_debounce_threshold].u_int, 1, 127, MP_QSTR_debounce_threshold);
112119

113120
const mcu_pin_obj_t *row_pins_array[num_row_pins];
114121
const mcu_pin_obj_t *column_pins_array[num_column_pins];
@@ -127,7 +134,7 @@ STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_ar
127134
column_pins_array[column] = pin;
128135
}
129136

130-
common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_column_pins, column_pins_array, args[ARG_columns_to_anodes].u_bool, interval, max_events);
137+
common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_column_pins, column_pins_array, args[ARG_columns_to_anodes].u_bool, interval, max_events, debounce_threshold);
131138
return MP_OBJ_FROM_PTR(self);
132139
#else
133140
mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_KeyMatrix);

shared-bindings/keypad/KeyMatrix.h

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

3333
extern const mp_obj_type_t keypad_keymatrix_type;
3434

35-
void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, const mcu_pin_obj_t *row_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events);
35+
void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, const mcu_pin_obj_t *row_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events, uint8_t debounce_threshold);
3636

3737
void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self);
3838

shared-bindings/keypad/Keys.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@
5959
//| value_when_pressed: bool,
6060
//| pull: bool = True,
6161
//| interval: float = 0.020,
62-
//| max_events: int = 64
62+
//| max_events: int = 64,
63+
//| debounce_threshold: int = 1,
6364
//| ) -> None:
6465
//| """
6566
//| Create a `Keys` object that will scan keys attached to the given sequence of pins.
@@ -84,19 +85,24 @@
8485
//| maximum number of key transition events that are saved.
8586
//| Must be >= 1.
8687
//| If a new event arrives when the queue is full, the oldest event is discarded.
88+
//| :param int debounce_threshold: Emit events for state changes only after a key has been
89+
//| in the respective state for ``debounce_threshold`` times on average.
90+
//| Successive measurements are spaced apart by ``interval`` seconds.
91+
//| The default is 1, which resolves immediately. The maximum is 127.
8792
//| """
8893
//| ...
8994

9095
STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
9196
#if CIRCUITPY_KEYPAD_KEYS
9297
keypad_keys_obj_t *self = mp_obj_malloc(keypad_keys_obj_t, &keypad_keys_type);
93-
enum { ARG_pins, ARG_value_when_pressed, ARG_pull, ARG_interval, ARG_max_events };
98+
enum { ARG_pins, ARG_value_when_pressed, ARG_pull, ARG_interval, ARG_max_events, ARG_debounce_threshold };
9499
static const mp_arg_t allowed_args[] = {
95100
{ MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
96101
{ MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL },
97102
{ MP_QSTR_pull, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
98103
{ MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL } },
99104
{ MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
105+
{ MP_QSTR_debounce_threshold, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
100106
};
101107
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
102108
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@@ -110,6 +116,7 @@ STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, s
110116
const mp_float_t interval =
111117
mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval);
112118
const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events);
119+
const uint8_t debounce_threshold = (uint8_t)mp_arg_validate_int_range(args[ARG_debounce_threshold].u_int, 1, 127, MP_QSTR_debounce_threshold);
113120

114121
const mcu_pin_obj_t *pins_array[num_pins];
115122

@@ -118,7 +125,7 @@ STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, s
118125
validate_obj_is_free_pin(mp_obj_subscr(pins, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL), MP_QSTR_pin);
119126
}
120127

121-
common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool, interval, max_events);
128+
common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool, interval, max_events, debounce_threshold);
122129

123130
return MP_OBJ_FROM_PTR(self);
124131
#else

shared-bindings/keypad/Keys.h

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

3333
extern const mp_obj_type_t keypad_keys_type;
3434

35-
void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, const mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, mp_float_t interval, size_t max_events);
35+
void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, const mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, mp_float_t interval, size_t max_events, uint8_t debounce_threshold);
3636

3737
void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self);
3838

shared-bindings/keypad/ShiftRegisterKeys.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@
6262
//| key_count: Union[int, Sequence[int]],
6363
//| value_when_pressed: bool,
6464
//| interval: float = 0.020,
65-
//| max_events: int = 64
65+
//| max_events: int = 64,
66+
//| debounce_threshold: int = 1,
6667
//| ) -> None:
6768
//| """
6869
//| Create a `Keys` object that will scan keys attached to a parallel-in serial-out shift register
@@ -95,14 +96,18 @@
9596
//| maximum number of key transition events that are saved.
9697
//| Must be >= 1.
9798
//| If a new event arrives when the queue is full, the oldest event is discarded.
99+
//| :param int debounce_threshold: Emit events for state changes only after a key has been
100+
//| in the respective state for ``debounce_threshold`` times on average.
101+
//| Successive measurements are spaced apart by ``interval`` seconds.
102+
//| The default is 1, which resolves immediately. The maximum is 127.
98103
//| """
99104
//| ...
100105

101106
STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
102107
#if CIRCUITPY_KEYPAD_SHIFTREGISTERKEYS
103108
keypad_shiftregisterkeys_obj_t *self =
104109
mp_obj_malloc(keypad_shiftregisterkeys_obj_t, &keypad_shiftregisterkeys_type);
105-
enum { ARG_clock, ARG_data, ARG_latch, ARG_value_to_latch, ARG_key_count, ARG_value_when_pressed, ARG_interval, ARG_max_events };
110+
enum { ARG_clock, ARG_data, ARG_latch, ARG_value_to_latch, ARG_key_count, ARG_value_when_pressed, ARG_interval, ARG_max_events, ARG_debounce_threshold };
106111
static const mp_arg_t allowed_args[] = {
107112
{ MP_QSTR_clock, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
108113
{ MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
@@ -112,6 +117,7 @@ STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, siz
112117
{ MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL },
113118
{ MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
114119
{ MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
120+
{ MP_QSTR_debounce_threshold, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
115121
};
116122
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
117123
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@@ -168,9 +174,10 @@ STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, siz
168174
const mp_float_t interval =
169175
mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval);
170176
const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events);
177+
const uint8_t debounce_threshold = (uint8_t)mp_arg_validate_int_range(args[ARG_debounce_threshold].u_int, 1, 127, MP_QSTR_debounce_threshold);
171178

172179
common_hal_keypad_shiftregisterkeys_construct(
173-
self, clock, num_data_pins, data_pins_array, latch, value_to_latch, num_key_counts, key_count_array, value_when_pressed, interval, max_events);
180+
self, clock, num_data_pins, data_pins_array, latch, value_to_latch, num_key_counts, key_count_array, value_when_pressed, interval, max_events, debounce_threshold);
174181

175182
return MP_OBJ_FROM_PTR(self);
176183

shared-bindings/keypad/ShiftRegisterKeys.h

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

3333
extern const mp_obj_type_t keypad_shiftregisterkeys_type;
3434

35-
void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, const mcu_pin_obj_t *clock_pin, mp_uint_t num_data_pins, const mcu_pin_obj_t *data_pins[], const mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t num_key_count, size_t key_counts[], bool value_when_pressed, mp_float_t interval, size_t max_events);
35+
void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, const mcu_pin_obj_t *clock_pin, mp_uint_t num_data_pins, const mcu_pin_obj_t *data_pins[], const mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t num_key_count, size_t key_counts[], bool value_when_pressed, mp_float_t interval, size_t max_events, uint8_t debounce_threshold);
3636

3737
void common_hal_keypad_shiftregisterkeys_deinit(keypad_shiftregisterkeys_obj_t *self);
3838

shared-bindings/keypad_demux/DemuxKeyMatrix.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
//| column_pins: Sequence[microcontroller.Pin],
5959
//| interval: float = 0.020,
6060
//| max_events: int = 64,
61+
//| debounce_threshold: int = 1,
6162
//| ) -> None:
6263
//| """
6364
//| Create a `keypad.Keys` object that will scan the key matrix attached to the given row and column pins.
@@ -77,17 +78,22 @@
7778
//| maximum number of key transition events that are saved.
7879
//| Must be >= 1.
7980
//| If a new event arrives when the queue is full, the oldest event is discarded.
81+
//| :param int debounce_threshold: Emit events for state changes only after a key has been
82+
//| in the respective state for ``debounce_threshold`` times on average.
83+
//| Successive measurements are spaced apart by ``interval`` seconds.
84+
//| The default is 1, which resolves immediately. The maximum is 127.
8085
//| """
8186
//| ...
8287

8388
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) {
8489
keypad_demux_demuxkeymatrix_obj_t *self = mp_obj_malloc(keypad_demux_demuxkeymatrix_obj_t, &keypad_demux_demuxkeymatrix_type);
85-
enum { ARG_row_addr_pins, ARG_column_pins, ARG_interval, ARG_max_events };
90+
enum { ARG_row_addr_pins, ARG_column_pins, ARG_interval, ARG_max_events, ARG_debounce_threshold };
8691
static const mp_arg_t allowed_args[] = {
8792
{ MP_QSTR_row_addr_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
8893
{ MP_QSTR_column_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
8994
{ MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
9095
{ MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
96+
{ MP_QSTR_debounce_threshold, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
9197
};
9298
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
9399
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@@ -102,6 +108,7 @@ STATIC mp_obj_t keypad_demux_demuxkeymatrix_make_new(const mp_obj_type_t *type,
102108
const mp_float_t interval =
103109
mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval);
104110
const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events);
111+
const uint8_t debounce_threshold = (uint8_t)mp_arg_validate_int_range(args[ARG_debounce_threshold].u_int, 1, 127, MP_QSTR_debounce_threshold);
105112

106113
const mcu_pin_obj_t *row_addr_pins_array[num_row_addr_pins];
107114
const mcu_pin_obj_t *column_pins_array[num_column_pins];
@@ -120,7 +127,7 @@ STATIC mp_obj_t keypad_demux_demuxkeymatrix_make_new(const mp_obj_type_t *type,
120127
column_pins_array[column] = pin;
121128
}
122129

123-
common_hal_keypad_demux_demuxkeymatrix_construct(self, num_row_addr_pins, row_addr_pins_array, num_column_pins, column_pins_array, interval, max_events);
130+
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);
124131
return MP_OBJ_FROM_PTR(self);
125132
}
126133

shared-bindings/keypad_demux/DemuxKeyMatrix.h

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

3333
extern const mp_obj_type_t keypad_demux_demuxkeymatrix_type;
3434

35-
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);
35+
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);
3636

3737
void common_hal_keypad_demux_demuxkeymatrix_deinit(keypad_demux_demuxkeymatrix_obj_t *self);
3838

shared-module/keypad/KeyMatrix.c

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ static mp_uint_t row_column_to_key_number(keypad_keymatrix_obj_t *self, mp_uint_
4949
return row * self->column_digitalinouts->len + column;
5050
}
5151

52-
void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, const mcu_pin_obj_t *row_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events) {
52+
void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, const mcu_pin_obj_t *row_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events, uint8_t debounce_threshold) {
5353

5454
mp_obj_t row_dios[num_row_pins];
5555
for (size_t row = 0; row < num_row_pins; row++) {
@@ -72,13 +72,10 @@ void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint
7272
}
7373
self->column_digitalinouts = mp_obj_new_tuple(num_column_pins, column_dios);
7474

75-
self->currently_pressed = (bool *)m_malloc(sizeof(bool) * num_row_pins * num_column_pins);
76-
self->previously_pressed = (bool *)m_malloc(sizeof(bool) * num_row_pins * num_column_pins);
77-
7875
self->columns_to_anodes = columns_to_anodes;
7976
self->funcs = &keymatrix_funcs;
8077

81-
keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events);
78+
keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold);
8279
}
8380

8481
void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self) {
@@ -138,19 +135,16 @@ static void keymatrix_scan_now(void *self_in, mp_obj_t timestamp) {
138135

139136
for (size_t column = 0; column < common_hal_keypad_keymatrix_get_column_count(self); column++) {
140137
mp_uint_t key_number = row_column_to_key_number(self, row, column);
141-
const bool previous = self->currently_pressed[key_number];
142-
self->previously_pressed[key_number] = previous;
143138

144139
// Get the current state, by reading whether the column got pulled to the row value or not.
145140
// If low and columns_to_anodes is true, the key is pressed.
146141
// If high and columns_to_anodes is false, the key is pressed.
147142
const bool current =
148143
common_hal_digitalio_digitalinout_get_value(self->column_digitalinouts->items[column]) !=
149144
self->columns_to_anodes;
150-
self->currently_pressed[key_number] = current;
151145

152146
// Record any transitions.
153-
if (previous != current) {
147+
if (keypad_debounce((keypad_scanner_obj_t *)self, key_number, current)) {
154148
keypad_eventqueue_record(self->events, key_number, current, timestamp);
155149
}
156150
}

0 commit comments

Comments
 (0)