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
2829static 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
8088size_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
8494size_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
88100mp_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
103115static 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 )) {
0 commit comments