You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

253 lines
9.4 KiB

Write firmware for the Ferris keyboard (#9634) * Write firmware for the Ferris keyboard Took inspiration from the gergoplex and the ergodox_ez firmware for the split matrix with io_expander on the right hand. Cleaned up a lot of bit fiddling on the mcu side by taking inspiration from the `split_custom` in quantum. Still bit fiddling on the mcp side as it is particularly natural to do so with the abstractions provided by the i2c protocol. Would be good to clean that up and abstract away the wiring from the generic i2c code in a similar fashion as quantum and the mcp side behave. One improvement over the ergodox_ez and the gergoplex firmwares is that the wiring is straight forward as opposed to swapping rows and columns in two different places that end up cancelling out for some reason. At this stage, I have flashed this firmware to a board and have verified that all keys are behaving as intended by shorting pins. I still have to solder in some switches and test that everything works correctly at normal typing speeds, but I don't expect any major issues given I'm building up on previous effort, including the debouncing code from the ergodox_ez. * Remove rotation from info.json and label the keys as per default keymap * Comply with minor review feedback points * Use CUSTOM_MATRIX=lite to remove boilerplate * Update keyboards/handwired/ferris/info.json Didn't play nicely in the configurator Co-authored-by: Ryan <fauxpark@gmail.com> * Remove MIDI_ENABLE from rules.mk Co-authored-by: Ryan <fauxpark@gmail.com> * Remove FAUXCLICKY_ENABLE from rules.mk Co-authored-by: Ryan <fauxpark@gmail.com> * Prefer wait_ms over _delay_ms Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused includeh Co-authored-by: Ryan <fauxpark@gmail.com> * Use dprint over print and remove include for print.h * Remove all unused includes * Remove unused code * Cleanups thanks to code review * Move more personal settings from the ferris config to the default keymap config These setting happen to be unused in the default keymap at the moment, as it has only one layer with no homerow modifiers and no mouse key; but I would like to keep it there for two reasons: * It can serve as an example to people creating their own keymap * I plan to design a more usable default keymap that uses these features once this PR which adds the Ferris keyboard is merged. * Consolidate mcp logic inside matrix.c Co-authored-by: Ryan <fauxpark@gmail.com>
3 years ago
Write firmware for the Ferris keyboard (#9634) * Write firmware for the Ferris keyboard Took inspiration from the gergoplex and the ergodox_ez firmware for the split matrix with io_expander on the right hand. Cleaned up a lot of bit fiddling on the mcu side by taking inspiration from the `split_custom` in quantum. Still bit fiddling on the mcp side as it is particularly natural to do so with the abstractions provided by the i2c protocol. Would be good to clean that up and abstract away the wiring from the generic i2c code in a similar fashion as quantum and the mcp side behave. One improvement over the ergodox_ez and the gergoplex firmwares is that the wiring is straight forward as opposed to swapping rows and columns in two different places that end up cancelling out for some reason. At this stage, I have flashed this firmware to a board and have verified that all keys are behaving as intended by shorting pins. I still have to solder in some switches and test that everything works correctly at normal typing speeds, but I don't expect any major issues given I'm building up on previous effort, including the debouncing code from the ergodox_ez. * Remove rotation from info.json and label the keys as per default keymap * Comply with minor review feedback points * Use CUSTOM_MATRIX=lite to remove boilerplate * Update keyboards/handwired/ferris/info.json Didn't play nicely in the configurator Co-authored-by: Ryan <fauxpark@gmail.com> * Remove MIDI_ENABLE from rules.mk Co-authored-by: Ryan <fauxpark@gmail.com> * Remove FAUXCLICKY_ENABLE from rules.mk Co-authored-by: Ryan <fauxpark@gmail.com> * Prefer wait_ms over _delay_ms Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused includeh Co-authored-by: Ryan <fauxpark@gmail.com> * Use dprint over print and remove include for print.h * Remove all unused includes * Remove unused code * Cleanups thanks to code review * Move more personal settings from the ferris config to the default keymap config These setting happen to be unused in the default keymap at the moment, as it has only one layer with no homerow modifiers and no mouse key; but I would like to keep it there for two reasons: * It can serve as an example to people creating their own keymap * I plan to design a more usable default keymap that uses these features once this PR which adds the Ferris keyboard is merged. * Consolidate mcp logic inside matrix.c Co-authored-by: Ryan <fauxpark@gmail.com>
3 years ago
Write firmware for the Ferris keyboard (#9634) * Write firmware for the Ferris keyboard Took inspiration from the gergoplex and the ergodox_ez firmware for the split matrix with io_expander on the right hand. Cleaned up a lot of bit fiddling on the mcu side by taking inspiration from the `split_custom` in quantum. Still bit fiddling on the mcp side as it is particularly natural to do so with the abstractions provided by the i2c protocol. Would be good to clean that up and abstract away the wiring from the generic i2c code in a similar fashion as quantum and the mcp side behave. One improvement over the ergodox_ez and the gergoplex firmwares is that the wiring is straight forward as opposed to swapping rows and columns in two different places that end up cancelling out for some reason. At this stage, I have flashed this firmware to a board and have verified that all keys are behaving as intended by shorting pins. I still have to solder in some switches and test that everything works correctly at normal typing speeds, but I don't expect any major issues given I'm building up on previous effort, including the debouncing code from the ergodox_ez. * Remove rotation from info.json and label the keys as per default keymap * Comply with minor review feedback points * Use CUSTOM_MATRIX=lite to remove boilerplate * Update keyboards/handwired/ferris/info.json Didn't play nicely in the configurator Co-authored-by: Ryan <fauxpark@gmail.com> * Remove MIDI_ENABLE from rules.mk Co-authored-by: Ryan <fauxpark@gmail.com> * Remove FAUXCLICKY_ENABLE from rules.mk Co-authored-by: Ryan <fauxpark@gmail.com> * Prefer wait_ms over _delay_ms Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused includeh Co-authored-by: Ryan <fauxpark@gmail.com> * Use dprint over print and remove include for print.h * Remove all unused includes * Remove unused code * Cleanups thanks to code review * Move more personal settings from the ferris config to the default keymap config These setting happen to be unused in the default keymap at the moment, as it has only one layer with no homerow modifiers and no mouse key; but I would like to keep it there for two reasons: * It can serve as an example to people creating their own keymap * I plan to design a more usable default keymap that uses these features once this PR which adds the Ferris keyboard is merged. * Consolidate mcp logic inside matrix.c Co-authored-by: Ryan <fauxpark@gmail.com>
3 years ago
Write firmware for the Ferris keyboard (#9634) * Write firmware for the Ferris keyboard Took inspiration from the gergoplex and the ergodox_ez firmware for the split matrix with io_expander on the right hand. Cleaned up a lot of bit fiddling on the mcu side by taking inspiration from the `split_custom` in quantum. Still bit fiddling on the mcp side as it is particularly natural to do so with the abstractions provided by the i2c protocol. Would be good to clean that up and abstract away the wiring from the generic i2c code in a similar fashion as quantum and the mcp side behave. One improvement over the ergodox_ez and the gergoplex firmwares is that the wiring is straight forward as opposed to swapping rows and columns in two different places that end up cancelling out for some reason. At this stage, I have flashed this firmware to a board and have verified that all keys are behaving as intended by shorting pins. I still have to solder in some switches and test that everything works correctly at normal typing speeds, but I don't expect any major issues given I'm building up on previous effort, including the debouncing code from the ergodox_ez. * Remove rotation from info.json and label the keys as per default keymap * Comply with minor review feedback points * Use CUSTOM_MATRIX=lite to remove boilerplate * Update keyboards/handwired/ferris/info.json Didn't play nicely in the configurator Co-authored-by: Ryan <fauxpark@gmail.com> * Remove MIDI_ENABLE from rules.mk Co-authored-by: Ryan <fauxpark@gmail.com> * Remove FAUXCLICKY_ENABLE from rules.mk Co-authored-by: Ryan <fauxpark@gmail.com> * Prefer wait_ms over _delay_ms Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused includeh Co-authored-by: Ryan <fauxpark@gmail.com> * Use dprint over print and remove include for print.h * Remove all unused includes * Remove unused code * Cleanups thanks to code review * Move more personal settings from the ferris config to the default keymap config These setting happen to be unused in the default keymap at the moment, as it has only one layer with no homerow modifiers and no mouse key; but I would like to keep it there for two reasons: * It can serve as an example to people creating their own keymap * I plan to design a more usable default keymap that uses these features once this PR which adds the Ferris keyboard is merged. * Consolidate mcp logic inside matrix.c Co-authored-by: Ryan <fauxpark@gmail.com>
3 years ago
Write firmware for the Ferris keyboard (#9634) * Write firmware for the Ferris keyboard Took inspiration from the gergoplex and the ergodox_ez firmware for the split matrix with io_expander on the right hand. Cleaned up a lot of bit fiddling on the mcu side by taking inspiration from the `split_custom` in quantum. Still bit fiddling on the mcp side as it is particularly natural to do so with the abstractions provided by the i2c protocol. Would be good to clean that up and abstract away the wiring from the generic i2c code in a similar fashion as quantum and the mcp side behave. One improvement over the ergodox_ez and the gergoplex firmwares is that the wiring is straight forward as opposed to swapping rows and columns in two different places that end up cancelling out for some reason. At this stage, I have flashed this firmware to a board and have verified that all keys are behaving as intended by shorting pins. I still have to solder in some switches and test that everything works correctly at normal typing speeds, but I don't expect any major issues given I'm building up on previous effort, including the debouncing code from the ergodox_ez. * Remove rotation from info.json and label the keys as per default keymap * Comply with minor review feedback points * Use CUSTOM_MATRIX=lite to remove boilerplate * Update keyboards/handwired/ferris/info.json Didn't play nicely in the configurator Co-authored-by: Ryan <fauxpark@gmail.com> * Remove MIDI_ENABLE from rules.mk Co-authored-by: Ryan <fauxpark@gmail.com> * Remove FAUXCLICKY_ENABLE from rules.mk Co-authored-by: Ryan <fauxpark@gmail.com> * Prefer wait_ms over _delay_ms Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused includeh Co-authored-by: Ryan <fauxpark@gmail.com> * Use dprint over print and remove include for print.h * Remove all unused includes * Remove unused code * Cleanups thanks to code review * Move more personal settings from the ferris config to the default keymap config These setting happen to be unused in the default keymap at the moment, as it has only one layer with no homerow modifiers and no mouse key; but I would like to keep it there for two reasons: * It can serve as an example to people creating their own keymap * I plan to design a more usable default keymap that uses these features once this PR which adds the Ferris keyboard is merged. * Consolidate mcp logic inside matrix.c Co-authored-by: Ryan <fauxpark@gmail.com>
3 years ago
Write firmware for the Ferris keyboard (#9634) * Write firmware for the Ferris keyboard Took inspiration from the gergoplex and the ergodox_ez firmware for the split matrix with io_expander on the right hand. Cleaned up a lot of bit fiddling on the mcu side by taking inspiration from the `split_custom` in quantum. Still bit fiddling on the mcp side as it is particularly natural to do so with the abstractions provided by the i2c protocol. Would be good to clean that up and abstract away the wiring from the generic i2c code in a similar fashion as quantum and the mcp side behave. One improvement over the ergodox_ez and the gergoplex firmwares is that the wiring is straight forward as opposed to swapping rows and columns in two different places that end up cancelling out for some reason. At this stage, I have flashed this firmware to a board and have verified that all keys are behaving as intended by shorting pins. I still have to solder in some switches and test that everything works correctly at normal typing speeds, but I don't expect any major issues given I'm building up on previous effort, including the debouncing code from the ergodox_ez. * Remove rotation from info.json and label the keys as per default keymap * Comply with minor review feedback points * Use CUSTOM_MATRIX=lite to remove boilerplate * Update keyboards/handwired/ferris/info.json Didn't play nicely in the configurator Co-authored-by: Ryan <fauxpark@gmail.com> * Remove MIDI_ENABLE from rules.mk Co-authored-by: Ryan <fauxpark@gmail.com> * Remove FAUXCLICKY_ENABLE from rules.mk Co-authored-by: Ryan <fauxpark@gmail.com> * Prefer wait_ms over _delay_ms Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused includeh Co-authored-by: Ryan <fauxpark@gmail.com> * Use dprint over print and remove include for print.h * Remove all unused includes * Remove unused code * Cleanups thanks to code review * Move more personal settings from the ferris config to the default keymap config These setting happen to be unused in the default keymap at the moment, as it has only one layer with no homerow modifiers and no mouse key; but I would like to keep it there for two reasons: * It can serve as an example to people creating their own keymap * I plan to design a more usable default keymap that uses these features once this PR which adds the Ferris keyboard is merged. * Consolidate mcp logic inside matrix.c Co-authored-by: Ryan <fauxpark@gmail.com>
3 years ago
Write firmware for the Ferris keyboard (#9634) * Write firmware for the Ferris keyboard Took inspiration from the gergoplex and the ergodox_ez firmware for the split matrix with io_expander on the right hand. Cleaned up a lot of bit fiddling on the mcu side by taking inspiration from the `split_custom` in quantum. Still bit fiddling on the mcp side as it is particularly natural to do so with the abstractions provided by the i2c protocol. Would be good to clean that up and abstract away the wiring from the generic i2c code in a similar fashion as quantum and the mcp side behave. One improvement over the ergodox_ez and the gergoplex firmwares is that the wiring is straight forward as opposed to swapping rows and columns in two different places that end up cancelling out for some reason. At this stage, I have flashed this firmware to a board and have verified that all keys are behaving as intended by shorting pins. I still have to solder in some switches and test that everything works correctly at normal typing speeds, but I don't expect any major issues given I'm building up on previous effort, including the debouncing code from the ergodox_ez. * Remove rotation from info.json and label the keys as per default keymap * Comply with minor review feedback points * Use CUSTOM_MATRIX=lite to remove boilerplate * Update keyboards/handwired/ferris/info.json Didn't play nicely in the configurator Co-authored-by: Ryan <fauxpark@gmail.com> * Remove MIDI_ENABLE from rules.mk Co-authored-by: Ryan <fauxpark@gmail.com> * Remove FAUXCLICKY_ENABLE from rules.mk Co-authored-by: Ryan <fauxpark@gmail.com> * Prefer wait_ms over _delay_ms Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused include Co-authored-by: Ryan <fauxpark@gmail.com> * Remove unused includeh Co-authored-by: Ryan <fauxpark@gmail.com> * Use dprint over print and remove include for print.h * Remove all unused includes * Remove unused code * Cleanups thanks to code review * Move more personal settings from the ferris config to the default keymap config These setting happen to be unused in the default keymap at the moment, as it has only one layer with no homerow modifiers and no mouse key; but I would like to keep it there for two reasons: * It can serve as an example to people creating their own keymap * I plan to design a more usable default keymap that uses these features once this PR which adds the Ferris keyboard is merged. * Consolidate mcp logic inside matrix.c Co-authored-by: Ryan <fauxpark@gmail.com>
3 years ago
  1. /*
  2. Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
  3. 2020 Pierre Chevalier <pierrechevalier83@gmail.com>
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. /*
  16. * This code was heavily inspired by the ergodox_ez keymap, and modernized
  17. * to take advantage of the quantum.h microcontroller agnostics gpio control
  18. * abstractions and use the macros defined in config.h for the wiring as opposed
  19. * to repeating that information all over the place.
  20. */
  21. #include QMK_KEYBOARD_H
  22. #include "i2c_master.h"
  23. extern i2c_status_t mcp23017_status;
  24. #define I2C_TIMEOUT 1000
  25. // For a better understanding of the i2c protocol, this is a good read:
  26. // https://www.robot-electronics.co.uk/i2c-tutorial
  27. // I2C address:
  28. // See the datasheet, section 3.3.1 on addressing I2C devices and figure 3-6 for an
  29. // illustration
  30. // http://ww1.microchip.com/downloads/en/devicedoc/20001952c.pdf
  31. // All address pins of the mcp23017 are connected to the ground on the ferris
  32. // | 0 | 1 | 0 | 0 | A2 | A1 | A0 |
  33. // | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
  34. #define I2C_ADDR 0b0100000
  35. #define I2C_ADDR_WRITE ((I2C_ADDR << 1) | I2C_WRITE)
  36. #define I2C_ADDR_READ ((I2C_ADDR << 1) | I2C_READ)
  37. // Register addresses
  38. // See https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library/blob/master/Adafruit_MCP23017.h
  39. #define IODIRA 0x00 // i/o direction register
  40. #define IODIRB 0x01
  41. #define GPPUA 0x0C // GPIO pull-up resistor register
  42. #define GPPUB 0x0D
  43. #define GPIOA 0x12 // general purpose i/o port register (write modifies OLAT)
  44. #define GPIOB 0x13
  45. #define OLATA 0x14 // output latch register
  46. #define OLATB 0x15
  47. bool i2c_initialized = 0;
  48. i2c_status_t mcp23017_status = I2C_ADDR;
  49. uint8_t init_mcp23017(void) {
  50. print("starting init");
  51. mcp23017_status = I2C_ADDR;
  52. // I2C subsystem
  53. if (i2c_initialized == 0) {
  54. i2c_init(); // on pins D(1,0)
  55. i2c_initialized = true;
  56. wait_ms(I2C_TIMEOUT);
  57. }
  58. // set pin direction
  59. // - unused : input : 1
  60. // - input : input : 1
  61. // - driving : output : 0
  62. // This means: we will read all the bits on GPIOA
  63. // This means: we will write to the pins 0-4 on GPIOB (in select_rows)
  64. uint8_t buf[] = {IODIRA, 0b11111111, 0b11110000};
  65. mcp23017_status = i2c_transmit(I2C_ADDR_WRITE, buf, sizeof(buf), I2C_TIMEOUT);
  66. if (!mcp23017_status) {
  67. // set pull-up
  68. // - unused : on : 1
  69. // - input : on : 1
  70. // - driving : off : 0
  71. // This means: we will read all the bits on GPIOA
  72. // This means: we will write to the pins 0-4 on GPIOB (in select_rows)
  73. uint8_t pullup_buf[] = {GPPUA, 0b11111111, 0b11110000};
  74. mcp23017_status = i2c_transmit(I2C_ADDR_WRITE, pullup_buf, sizeof(pullup_buf), I2C_TIMEOUT);
  75. }
  76. return mcp23017_status;
  77. }
  78. /* matrix state(1:on, 0:off) */
  79. static matrix_row_t matrix[MATRIX_ROWS]; // debounced values
  80. static matrix_row_t read_cols(uint8_t row);
  81. static void init_cols(void);
  82. static void unselect_rows(void);
  83. static void select_row(uint8_t row);
  84. static uint8_t mcp23017_reset_loop;
  85. void matrix_init_custom(void) {
  86. // initialize row and col
  87. mcp23017_status = init_mcp23017();
  88. unselect_rows();
  89. init_cols();
  90. // initialize matrix state: all keys off
  91. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  92. matrix[i] = 0;
  93. }
  94. }
  95. void matrix_power_up(void) {
  96. mcp23017_status = init_mcp23017();
  97. unselect_rows();
  98. init_cols();
  99. // initialize matrix state: all keys off
  100. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  101. matrix[i] = 0;
  102. }
  103. }
  104. // Reads and stores a row, returning
  105. // whether a change occurred.
  106. static inline bool store_matrix_row(matrix_row_t current_matrix[], uint8_t index) {
  107. matrix_row_t temp = read_cols(index);
  108. if (current_matrix[index] != temp) {
  109. current_matrix[index] = temp;
  110. return true;
  111. }
  112. return false;
  113. }
  114. bool matrix_scan_custom(matrix_row_t current_matrix[]) {
  115. if (mcp23017_status) { // if there was an error
  116. if (++mcp23017_reset_loop == 0) {
  117. // if (++mcp23017_reset_loop >= 1300) {
  118. // since mcp23017_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
  119. // this will be approx bit more frequent than once per second
  120. dprint("trying to reset mcp23017\n");
  121. mcp23017_status = init_mcp23017();
  122. if (mcp23017_status) {
  123. dprint("right side not responding\n");
  124. } else {
  125. dprint("right side attached\n");
  126. }
  127. }
  128. }
  129. bool changed = false;
  130. for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
  131. // select rows from left and right hands
  132. uint8_t left_index = i;
  133. uint8_t right_index = i + MATRIX_ROWS_PER_SIDE;
  134. select_row(left_index);
  135. select_row(right_index);
  136. // we don't need a 30us delay anymore, because selecting a
  137. // left-hand row requires more than 30us for i2c.
  138. changed |= store_matrix_row(current_matrix, left_index);
  139. changed |= store_matrix_row(current_matrix, right_index);
  140. unselect_rows();
  141. }
  142. return changed;
  143. }
  144. static void init_cols(void) {
  145. // init on mcp23017
  146. // not needed, already done as part of init_mcp23017()
  147. // init on mcu
  148. pin_t matrix_col_pins_mcu[MATRIX_COLS_PER_SIDE] = MATRIX_COL_PINS_MCU;
  149. for (int pin_index = 0; pin_index < MATRIX_COLS_PER_SIDE; pin_index++) {
  150. pin_t pin = matrix_col_pins_mcu[pin_index];
  151. setPinInput(pin);
  152. writePinHigh(pin);
  153. }
  154. }
  155. static matrix_row_t read_cols(uint8_t row) {
  156. if (row < MATRIX_ROWS_PER_SIDE) {
  157. pin_t matrix_col_pins_mcu[MATRIX_COLS_PER_SIDE] = MATRIX_COL_PINS_MCU;
  158. matrix_row_t current_row_value = 0;
  159. // For each col...
  160. for (uint8_t col_index = 0; col_index < MATRIX_COLS_PER_SIDE; col_index++) {
  161. // Select the col pin to read (active low)
  162. uint8_t pin_state = readPin(matrix_col_pins_mcu[col_index]);
  163. // Populate the matrix row with the state of the col pin
  164. current_row_value |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index);
  165. }
  166. return current_row_value;
  167. } else {
  168. if (mcp23017_status) { // if there was an error
  169. return 0;
  170. } else {
  171. uint8_t buf[] = {GPIOA};
  172. mcp23017_status = i2c_transmit(I2C_ADDR_WRITE, buf, sizeof(buf), I2C_TIMEOUT);
  173. // We read all the pins on GPIOA.
  174. // The initial state was all ones and any depressed key at a given column for the currently selected row will have its bit flipped to zero.
  175. // The return value is a row as represented in the generic matrix code were the rightmost bits represent the lower columns and zeroes represent non-depressed keys while ones represent depressed keys.
  176. // Since the pins connected to eact columns are sequential, and counting from zero up (col 5 -> GPIOA0, col 6 -> GPIOA1 and so on), the only transformation needed is a bitwise not to swap all zeroes and ones.
  177. uint8_t data[] = {0};
  178. if (!mcp23017_status) {
  179. mcp23017_status = i2c_receive(I2C_ADDR_READ, data, sizeof(data), I2C_TIMEOUT);
  180. data[0] = ~(data[0]);
  181. }
  182. return data[0];
  183. }
  184. }
  185. }
  186. static void unselect_rows(void) {
  187. // no need to unselect on mcp23017, because the select step sets all
  188. // the other row bits high, and it's not changing to a different
  189. // direction
  190. // unselect rows on microcontroller
  191. pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_MCU;
  192. for (int pin_index = 0; pin_index < MATRIX_ROWS_PER_SIDE; pin_index++) {
  193. pin_t pin = matrix_row_pins_mcu[pin_index];
  194. setPinInput(pin);
  195. writePinLow(pin);
  196. }
  197. }
  198. static void select_row(uint8_t row) {
  199. if (row < MATRIX_ROWS_PER_SIDE) {
  200. // select on atmega32u4
  201. pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_MCU;
  202. pin_t pin = matrix_row_pins_mcu[row];
  203. setPinOutput(pin);
  204. writePinLow(pin);
  205. } else {
  206. // select on mcp23017
  207. if (mcp23017_status) { // if there was an error
  208. // do nothing
  209. } else {
  210. // Select the desired row by writing a byte for the entire GPIOB bus where only the bit representing the row we want to select is a zero (write instruction) and every other bit is a one.
  211. // Note that the row - MATRIX_ROWS_PER_SIDE reflects the fact that being on the right hand, the columns are numbered from MATRIX_ROWS_PER_SIDE to MATRIX_ROWS, but the pins we want to write to are indexed from zero up on the GPIOB bus.
  212. uint8_t buf[] = {GPIOB, 0xFF & ~(1 << (row - MATRIX_ROWS_PER_SIDE))};
  213. mcp23017_status = i2c_transmit(I2C_ADDR_WRITE, buf, sizeof(buf), I2C_TIMEOUT);
  214. }
  215. }
  216. }