matrix.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  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 QMK_KEYBOARD_H
  23. #include "i2c_master.h"
  24. extern i2c_status_t tca9555_status;
  25. #define I2C_TIMEOUT 1000
  26. // I2C address:
  27. // All address pins of the tca9555 are connected to the ground
  28. // | 0 | 1 | 0 | 0 | A2 | A1 | A0 |
  29. // | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
  30. #define I2C_ADDR (0b0100000 << 1)
  31. // Register addresses
  32. #define IODIRA 0x06 // i/o direction register
  33. #define IODIRB 0x07
  34. #define IREGP0 0x00 // GPIO pull-up resistor register
  35. #define IREGP1 0x01
  36. #define OREGP0 0x02 // general purpose i/o port register (write modifies OLAT)
  37. #define OREGP1 0x03
  38. bool i2c_initialized = 0;
  39. i2c_status_t tca9555_status = I2C_ADDR;
  40. uint8_t init_tca9555(void) {
  41. print("starting init");
  42. tca9555_status = I2C_ADDR;
  43. // I2C subsystem
  44. if (i2c_initialized == 0) {
  45. i2c_init(); // on pins D(1,0)
  46. i2c_initialized = true;
  47. wait_ms(I2C_TIMEOUT);
  48. }
  49. // set pin direction
  50. // - unused : input : 1
  51. // - input : input : 1
  52. // - driving : output : 0
  53. uint8_t conf[2] = {
  54. // This means: write on pin 5 of port 0, read on rest
  55. 0b11011111,
  56. // This means: we will write on pins 0 to 2 on port 1. read rest
  57. 0b11111000,
  58. };
  59. tca9555_status = i2c_writeReg(I2C_ADDR, IODIRA, conf, 2, I2C_TIMEOUT);
  60. return tca9555_status;
  61. }
  62. /* matrix state(1:on, 0:off) */
  63. static matrix_row_t matrix[MATRIX_ROWS]; // debounced values
  64. static matrix_row_t read_cols(uint8_t row);
  65. static void init_cols(void);
  66. static void unselect_rows(void);
  67. static void select_row(uint8_t row);
  68. static uint8_t tca9555_reset_loop;
  69. void matrix_init_custom(void) {
  70. // initialize row and col
  71. tca9555_status = init_tca9555();
  72. unselect_rows();
  73. init_cols();
  74. // initialize matrix state: all keys off
  75. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  76. matrix[i] = 0;
  77. }
  78. }
  79. void matrix_power_up(void) {
  80. tca9555_status = init_tca9555();
  81. unselect_rows();
  82. init_cols();
  83. // initialize matrix state: all keys off
  84. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  85. matrix[i] = 0;
  86. }
  87. }
  88. // Reads and stores a row, returning
  89. // whether a change occurred.
  90. static inline bool store_matrix_row(matrix_row_t current_matrix[], uint8_t index) {
  91. matrix_row_t temp = read_cols(index);
  92. if (current_matrix[index] != temp) {
  93. current_matrix[index] = temp;
  94. return true;
  95. }
  96. return false;
  97. }
  98. bool matrix_scan_custom(matrix_row_t current_matrix[]) {
  99. if (tca9555_status) { // if there was an error
  100. if (++tca9555_reset_loop == 0) {
  101. // since tca9555_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
  102. // this will be approx bit more frequent than once per second
  103. dprint("trying to reset tca9555\n");
  104. tca9555_status = init_tca9555();
  105. if (tca9555_status) {
  106. dprint("right side not responding\n");
  107. } else {
  108. dprint("right side attached\n");
  109. }
  110. }
  111. }
  112. bool changed = false;
  113. for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
  114. // select rows from left and right hands
  115. uint8_t left_index = i;
  116. uint8_t right_index = i + MATRIX_ROWS_PER_SIDE;
  117. select_row(left_index);
  118. select_row(right_index);
  119. // we don't need a 30us delay anymore, because selecting a
  120. // left-hand row requires more than 30us for i2c.
  121. changed |= store_matrix_row(current_matrix, left_index);
  122. changed |= store_matrix_row(current_matrix, right_index);
  123. unselect_rows();
  124. }
  125. return changed;
  126. }
  127. static void init_cols(void) {
  128. // init on tca9555
  129. // not needed, already done as part of init_tca9555()
  130. // init on mcu
  131. pin_t matrix_col_pins_mcu[MATRIX_COLS_PER_SIDE] = MATRIX_COL_PINS_L;
  132. for (int pin_index = 0; pin_index < MATRIX_COLS_PER_SIDE; pin_index++) {
  133. pin_t pin = matrix_col_pins_mcu[pin_index];
  134. setPinInput(pin);
  135. writePinHigh(pin);
  136. }
  137. }
  138. static matrix_row_t read_cols(uint8_t row) {
  139. if (row < MATRIX_ROWS_PER_SIDE) {
  140. pin_t matrix_col_pins_mcu[MATRIX_COLS_PER_SIDE] = MATRIX_COL_PINS_L;
  141. matrix_row_t current_row_value = 0;
  142. // For each col...
  143. for (uint8_t col_index = 0; col_index < MATRIX_COLS_PER_SIDE; col_index++) {
  144. // Select the col pin to read (active low)
  145. uint8_t pin_state = readPin(matrix_col_pins_mcu[col_index]);
  146. // Populate the matrix row with the state of the col pin
  147. current_row_value |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index);
  148. }
  149. return current_row_value;
  150. } else {
  151. if (tca9555_status) { // if there was an error
  152. return 0;
  153. } else {
  154. uint8_t data = 0;
  155. uint8_t ports[2] = {0};
  156. tca9555_status = i2c_readReg(I2C_ADDR, IREGP0, ports, 2, I2C_TIMEOUT);
  157. if (tca9555_status) { // if there was an error
  158. // do nothing
  159. return 0;
  160. } else {
  161. uint8_t port0 = ports[0];
  162. uint8_t port1 = ports[1];
  163. // 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.
  164. // 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.
  165. // 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.
  166. data |= ( port0 & 0x01 );
  167. data |= ( port0 & 0x02 );
  168. data |= ( port1 & 0x10 ) >> 2;
  169. data |= ( port1 & 0x08 );
  170. data |= ( port0 & 0x40 ) >> 2;
  171. data = ~(data);
  172. tca9555_status = I2C_STATUS_SUCCESS;
  173. return data;
  174. }
  175. }
  176. }
  177. }
  178. static void unselect_rows(void) {
  179. // no need to unselect on tca9555, because the select step sets all
  180. // the other row bits high, and it's not changing to a different
  181. // direction
  182. // unselect rows on microcontroller
  183. pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_L;
  184. for (int pin_index = 0; pin_index < MATRIX_ROWS_PER_SIDE; pin_index++) {
  185. pin_t pin = matrix_row_pins_mcu[pin_index];
  186. setPinInput(pin);
  187. writePinLow(pin);
  188. }
  189. }
  190. static void select_row(uint8_t row) {
  191. uint8_t port0 = 0xff;
  192. uint8_t port1 = 0xff;
  193. if (row < MATRIX_ROWS_PER_SIDE) {
  194. // select on atmega32u4
  195. pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_L;
  196. pin_t pin = matrix_row_pins_mcu[row];
  197. setPinOutput(pin);
  198. writePinLow(pin);
  199. } else {
  200. // select on tca9555
  201. if (tca9555_status) { // if there was an error
  202. // do nothing
  203. } else {
  204. switch(row) {
  205. case 4: port1 &= ~(1 << 0); break;
  206. case 5: port1 &= ~(1 << 1); break;
  207. case 6: port1 &= ~(1 << 2); break;
  208. case 7: port0 &= ~(1 << 5); break;
  209. default: break;
  210. }
  211. uint8_t ports[2] = {port0, port1};
  212. tca9555_status = i2c_writeReg(I2C_ADDR, OREGP0, ports, 2, I2C_TIMEOUT);
  213. // 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.
  214. // 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.
  215. }
  216. }
  217. }