logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

matrix.c (8562B)


  1. /*
  2. Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
  3. 2020 Pierre Chevalier <pierrechevalier83@gmail.com>
  4. 2021 weteor
  5. 2023 beekeeb
  6. */
  7. // SPDX-License-Identifier: GPL-2.0-or-later
  8. /*
  9. * This code was heavily inspired by the ergodox_ez keymap, and modernized
  10. * to take advantage of the quantum.h microcontroller agnostics gpio control
  11. * abstractions and use the macros defined in config.h for the wiring as opposed
  12. * to repeating that information all over the place.
  13. */
  14. #include "matrix.h"
  15. #include "debug.h"
  16. #include "wait.h"
  17. #include "i2c_master.h"
  18. extern i2c_status_t tca9555_status;
  19. //#define I2C_TIMEOUT 1000
  20. // I2C address:
  21. // All address pins of the tca9555 are connected to the ground
  22. // | 0 | 1 | 0 | 0 | A2 | A1 | A0 |
  23. // | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
  24. #define I2C_ADDR (0b0100000 << 1)
  25. // Register addresses
  26. #define IODIRA 0x06 // i/o direction register
  27. #define IODIRB 0x07
  28. #define IREGP0 0x00 // GPIO pull-up resistor register
  29. #define IREGP1 0x01
  30. #define OREGP0 0x02 // general purpose i/o port register (write modifies OLAT)
  31. #define OREGP1 0x03
  32. bool i2c_initialized = 0;
  33. i2c_status_t tca9555_status = I2C_ADDR;
  34. uint8_t init_tca9555(void) {
  35. dprint("starting init\n");
  36. tca9555_status = I2C_ADDR;
  37. // I2C subsystem
  38. if (i2c_initialized == 0) {
  39. i2c_init(); // on pins D(1,0)
  40. i2c_initialized = true;
  41. wait_ms(I2C_TIMEOUT);
  42. }
  43. // set pin direction
  44. // - unused : input : 1
  45. // - input : input : 1
  46. // - driving : output : 0
  47. uint8_t conf[2] = {
  48. // This means: read all pins of port 0
  49. 0b11111111,
  50. // This means: we will write on pins 0 to 3 on port 1. read rest
  51. 0b11110000,
  52. };
  53. tca9555_status = i2c_write_register(I2C_ADDR, IODIRA, conf, 2, I2C_TIMEOUT);
  54. return tca9555_status;
  55. }
  56. /* matrix state(1:on, 0:off) */
  57. static matrix_row_t matrix[MATRIX_ROWS]; // debounced values
  58. static matrix_row_t read_cols(uint8_t row);
  59. static void init_cols(void);
  60. static void unselect_rows(void);
  61. static void select_row(uint8_t row);
  62. static uint8_t tca9555_reset_loop;
  63. void matrix_init_custom(void) {
  64. // initialize row and col
  65. tca9555_status = init_tca9555();
  66. unselect_rows();
  67. init_cols();
  68. // initialize matrix state: all keys off
  69. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  70. matrix[i] = 0;
  71. }
  72. }
  73. void matrix_power_up(void) {
  74. tca9555_status = init_tca9555();
  75. unselect_rows();
  76. init_cols();
  77. // initialize matrix state: all keys off
  78. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  79. matrix[i] = 0;
  80. }
  81. }
  82. // Reads and stores a row, returning
  83. // whether a change occurred.
  84. static inline bool store_matrix_row(matrix_row_t current_matrix[], uint8_t index) {
  85. matrix_row_t temp = read_cols(index);
  86. if (current_matrix[index] != temp) {
  87. current_matrix[index] = temp;
  88. return true;
  89. }
  90. return false;
  91. }
  92. bool matrix_scan_custom(matrix_row_t current_matrix[]) {
  93. if (tca9555_status) { // if there was an error
  94. if (++tca9555_reset_loop == 0) {
  95. // since tca9555_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
  96. // this will be approx bit more frequent than once per second
  97. dprint("trying to reset tca9555\n");
  98. tca9555_status = init_tca9555();
  99. if (tca9555_status) {
  100. dprint("right side not responding\n");
  101. } else {
  102. dprint("right side attached\n");
  103. }
  104. }
  105. }
  106. bool changed = false;
  107. for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
  108. // select rows from left and right hands
  109. uint8_t left_index = i;
  110. uint8_t right_index = i + MATRIX_ROWS_PER_SIDE;
  111. select_row(left_index);
  112. select_row(right_index);
  113. // we don't need a 30us delay anymore, because selecting a
  114. // left-hand row requires more than 30us for i2c.
  115. changed |= store_matrix_row(current_matrix, left_index);
  116. changed |= store_matrix_row(current_matrix, right_index);
  117. unselect_rows();
  118. }
  119. return changed;
  120. }
  121. static void init_cols(void) {
  122. // init on tca9555
  123. // not needed, already done as part of init_tca9555()
  124. // init on mcu
  125. pin_t matrix_col_pins_mcu[MATRIX_COLS_PER_SIDE] = MATRIX_COL_PINS_L;
  126. for (int pin_index = 0; pin_index < MATRIX_COLS_PER_SIDE; pin_index++) {
  127. pin_t pin = matrix_col_pins_mcu[pin_index];
  128. gpio_set_pin_input_high(pin);
  129. gpio_write_pin_high(pin);
  130. }
  131. }
  132. static matrix_row_t read_cols(uint8_t row) {
  133. if (row < MATRIX_ROWS_PER_SIDE) {
  134. pin_t matrix_col_pins_mcu[MATRIX_COLS_PER_SIDE] = MATRIX_COL_PINS_L;
  135. matrix_row_t current_row_value = 0;
  136. // For each col...
  137. for (uint8_t col_index = 0; col_index < MATRIX_COLS_PER_SIDE; col_index++) {
  138. // Select the col pin to read (active low)
  139. uint8_t pin_state = gpio_read_pin(matrix_col_pins_mcu[col_index]);
  140. // Populate the matrix row with the state of the col pin
  141. current_row_value |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index);
  142. }
  143. return current_row_value;
  144. } else {
  145. if (tca9555_status) { // if there was an error
  146. return 0;
  147. } else {
  148. uint8_t data = 0;
  149. uint8_t port0 = 0;
  150. tca9555_status = i2c_read_register(I2C_ADDR, IREGP0, &port0, 1, I2C_TIMEOUT);
  151. if (tca9555_status) { // if there was an error
  152. // do nothing
  153. return 0;
  154. } else {
  155. port0 = ~port0;
  156. // We read all the pins on GPIOA.
  157. // 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.
  158. // 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.
  159. // the pins connected to eact columns are sequential, but in reverse order, and counting from zero down (col 5 -> GPIO04, col6 -> GPIO03 and so on).
  160. data |= (port0 & 0x01) << 4;
  161. data |= (port0 & 0x02) << 2;
  162. data |= (port0 & 0x04);
  163. data |= (port0 & 0x08) >> 2;
  164. data |= (port0 & 0x10) >> 4;
  165. tca9555_status = I2C_STATUS_SUCCESS;
  166. return data;
  167. }
  168. }
  169. }
  170. }
  171. static void unselect_rows(void) {
  172. // no need to unselect on tca9555, because the select step sets all
  173. // the other row bits high, and it's not changing to a different
  174. // direction
  175. // unselect rows on microcontroller
  176. pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_L;
  177. for (int pin_index = 0; pin_index < MATRIX_ROWS_PER_SIDE; pin_index++) {
  178. pin_t pin = matrix_row_pins_mcu[pin_index];
  179. gpio_set_pin_input_high(pin);
  180. gpio_write_pin_low(pin);
  181. }
  182. }
  183. static void select_row(uint8_t row) {
  184. uint8_t port1 = 0xff;
  185. if (row < MATRIX_ROWS_PER_SIDE) {
  186. // select on atmega32u4
  187. pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_L;
  188. pin_t pin = matrix_row_pins_mcu[row];
  189. gpio_set_pin_output(pin);
  190. gpio_write_pin_low(pin);
  191. } else {
  192. // select on tca9555
  193. if (tca9555_status) { // if there was an error
  194. // do nothing
  195. } else {
  196. switch(row) {
  197. case 4: port1 &= ~(1 << 0); break;
  198. case 5: port1 &= ~(1 << 1); break;
  199. case 6: port1 &= ~(1 << 2); break;
  200. case 7:
  201. port1 &= ~(1 << 3);
  202. break;
  203. default: break;
  204. }
  205. tca9555_status = i2c_write_register(I2C_ADDR, OREGP1, &port1, 1, I2C_TIMEOUT);
  206. // 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.
  207. // 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.
  208. }
  209. }
  210. }