From 541e77cfc9a0943778e5d240444160177ccac577 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Mon, 30 Aug 2021 20:37:43 +0200 Subject: [PATCH] gd32: matrix-based keyscanner Signed-off-by: Gergely Nagy --- .../device/gd32/eval/KeyScanner.cpp | 100 ++++++++++++------ .../device/gd32/eval/KeyScanner.h | 45 ++++++-- 2 files changed, 103 insertions(+), 42 deletions(-) diff --git a/plugins/Kaleidoscope-Hardware-GD32-Eval/src/kaleidoscope/device/gd32/eval/KeyScanner.cpp b/plugins/Kaleidoscope-Hardware-GD32-Eval/src/kaleidoscope/device/gd32/eval/KeyScanner.cpp index 1099d912..d95efafd 100644 --- a/plugins/Kaleidoscope-Hardware-GD32-Eval/src/kaleidoscope/device/gd32/eval/KeyScanner.cpp +++ b/plugins/Kaleidoscope-Hardware-GD32-Eval/src/kaleidoscope/device/gd32/eval/KeyScanner.cpp @@ -26,16 +26,20 @@ namespace device { namespace gd32 { namespace eval { -uint8_t KeyScanner::keyState; -uint8_t KeyScanner::previousKeyState; -int KeyScanner::prevPinState[2]; +KeyScanner::col_state_t KeyScanner::matrix_state_[KeyScannerProps::matrix_columns]; +const uint8_t KeyScannerProps::matrix_rows; +const uint8_t KeyScannerProps::matrix_columns; +constexpr uint8_t KeyScannerProps::matrix_row_pins[matrix_rows]; +constexpr uint8_t KeyScannerProps::matrix_col_pins[matrix_columns]; void KeyScanner::setup() { - pinMode(PA3, INPUT); - pinMode(PB13, INPUT); + for (uint8_t i = 0; i < Props_::matrix_columns; i++) { + pinMode(Props_::matrix_row_pins[i], INPUT_PULLUP); + } - prevPinState[0] = HIGH; - prevPinState[1] = HIGH; + for (uint8_t i = 0; i < Props_::matrix_rows; i++) { + pinMode(Props_::matrix_row_pins[i], INPUT); + } } void KeyScanner::scanMatrix() { @@ -43,39 +47,73 @@ void KeyScanner::scanMatrix() { actOnMatrixScan(); } +uint16_t KeyScanner::readRows() { + uint16_t hot_pins = 0; + + for (uint8_t i = 0; i < Props_::matrix_rows; i++) { + uint8_t rowPin = Props_::matrix_row_pins[i]; + pinMode(rowPin, INPUT_PULLUP); + uint8_t v = !!digitalRead(rowPin); + pinMode(rowPin, INPUT); + hot_pins |= v << i; + } + + return hot_pins; +} + +uint16_t KeyScanner::debounce(uint16_t sample, debounce_t *debouncer) { + uint16_t delta, changes; + + // Use xor to detect changes from last stable state: + // if a key has changed, it's bit will be 1, otherwise 0 + delta = sample ^ debouncer->debounced_state; + + // Increment counters and reset any unchanged bits: + // increment bit 1 for all changed keys + debouncer->db1 = ((debouncer->db1) ^ (debouncer->db0)) & delta; + // increment bit 0 for all changed keys + debouncer->db0 = ~(debouncer->db0) & delta; + + // Calculate returned change set: if delta is still true + // and the counter has wrapped back to 0, the key is changed. + + changes = ~(~delta | (debouncer->db0) | (debouncer->db1)); + // Update state: in this case use xor to flip any bit that is true in changes. + debouncer->debounced_state ^= changes; + + return changes; +} + void KeyScanner::readMatrix() { - int b1, b2; + uint16_t any_debounced_changes = 0; - b1 = digitalRead(PA3); - b2 = digitalRead(PB13); + for (uint8_t col = 0; col < Props_::matrix_columns; col++) { + uint8_t colPin = Props_::matrix_col_pins[col]; + pinMode(colPin, OUTPUT); + digitalWrite(colPin, LOW); - previousKeyState = keyState; + uint16_t hot_pins = readRows(); + pinMode(colPin, INPUT); - if ((b1 != prevPinState[0]) && (b1 == HIGH)) { - bitSet(keyState, 0); - } - prevPinState[0] = b1; + any_debounced_changes |= debounce(hot_pins, &matrix_state_[col].debouncer); - if ((b2 != prevPinState[1]) && (b2 == HIGH)) { - bitSet(keyState, 1); + if (any_debounced_changes) { + for (uint8_t i = 0; i < Props_::matrix_columns; i++) { + matrix_state_[i].current = matrix_state_[i].debouncer.debounced_state; + } + } } - prevPinState[1] = b2; } void KeyScanner::actOnMatrixScan() { - if (bitRead(keyState, 0) != bitRead(previousKeyState, 0)) { - ThisType::handleKeyswitchEvent( - Key_NoKey, - typename Props_::KeyAddr(0, 0), - keyState - ); - } - if (bitRead(keyState, 1) != bitRead(previousKeyState, 1)) { - ThisType::handleKeyswitchEvent( - Key_NoKey, - typename Props_::KeyAddr(0, 1), - keyState - ); + for (byte col = 0; col < Props_::matrix_columns; col++) { + for (byte row = 0; row < Props_::matrix_rows; row++) { + uint8_t keyState = (bitRead(matrix_state_[col].previous, row) << 0) | (bitRead(matrix_state_[col].current, row) << 1); + if (keyState) { + ThisType::handleKeyswitchEvent(Key_NoKey, typename Props_::KeyAddr(row, col), keyState); + } + } + matrix_state_[col].previous = matrix_state_[col].current; } } diff --git a/plugins/Kaleidoscope-Hardware-GD32-Eval/src/kaleidoscope/device/gd32/eval/KeyScanner.h b/plugins/Kaleidoscope-Hardware-GD32-Eval/src/kaleidoscope/device/gd32/eval/KeyScanner.h index 3cd0dc3d..650f6b27 100644 --- a/plugins/Kaleidoscope-Hardware-GD32-Eval/src/kaleidoscope/device/gd32/eval/KeyScanner.h +++ b/plugins/Kaleidoscope-Hardware-GD32-Eval/src/kaleidoscope/device/gd32/eval/KeyScanner.h @@ -31,6 +31,10 @@ namespace eval { struct KeyScannerProps : public kaleidoscope::driver::keyscanner::BaseProps { static constexpr uint8_t matrix_rows = 1; static constexpr uint8_t matrix_columns = 2; + + static constexpr uint8_t matrix_row_pins[] = { PA3 }; + static constexpr uint8_t matrix_col_pins[] = { PE4, PD12 }; + typedef MatrixAddr KeyAddr; }; @@ -45,25 +49,44 @@ class KeyScanner: public kaleidoscope::driver::keyscanner::Base static void actOnMatrixScan(); static bool isKeyswitchPressed(KeyAddr key_addr) { - if (key_addr.row() != 0) - return false; - return bitRead(keyState, key_addr.col()); + //return bitRead(keyState, key_addr.col()); + return false; } static uint8_t pressedKeyswitchCount() { - return __builtin_popcount(keyState); + //return __builtin_popcount(keyState); + return 0; } static bool wasKeyswitchPressed(KeyAddr key_addr) { - if (key_addr.row() != 0) - return false; - return bitRead(previousKeyState, key_addr.col()); + //return bitRead(previousKeyState, key_addr.col()); + return false; } static uint8_t previousPressedKeyswitchCount() { - return __builtin_popcount(previousKeyState); + //return __builtin_popcount(previousKeyState); + return 0; } - protected: - static uint8_t keyState, previousKeyState; - static int prevPinState[2]; + private: + /* + each of these variables are storing the state for a row of keys + + so for key 0, the counter is represented by db0[0] and db1[0] + and the state in debounced_state[0]. + */ + struct debounce_t { + uint16_t db0; // counter bit 0 + uint16_t db1; // counter bit 1 + uint16_t debounced_state; // debounced state + }; + + struct col_state_t { + uint16_t previous; + uint16_t current; + debounce_t debouncer; + }; + static col_state_t matrix_state_[Props_::matrix_columns]; + + static inline uint16_t debounce(uint16_t sample, debounce_t *debouncer); + static uint16_t readRows(); }; } // namespace eval