logo

qmk_firmware

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

matrix.c (9195B)


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