logo

qmk_firmware

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

matrix.c (5823B)


  1. // Copyright 2022 QMK
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "gpio.h"
  4. #include "matrix.h"
  5. #include "mcp23018.h"
  6. #include "util.h"
  7. #include "wait.h"
  8. #include "debug.h"
  9. #define I2C_ADDR 0x20
  10. static uint8_t mcp23018_errors = 0;
  11. static void expander_init(void) {
  12. mcp23018_init(I2C_ADDR);
  13. }
  14. static void expander_init_cols(void) {
  15. mcp23018_errors += !mcp23018_set_config(I2C_ADDR, mcp23018_PORTA, ALL_INPUT);
  16. mcp23018_errors += !mcp23018_set_config(I2C_ADDR, mcp23018_PORTB, ALL_INPUT);
  17. }
  18. static void expander_select_row(uint8_t row) {
  19. if (mcp23018_errors) {
  20. // wait to mimic i2c interactions
  21. wait_us(100);
  22. return;
  23. }
  24. mcp23018_errors += !mcp23018_set_config(I2C_ADDR, mcp23018_PORTB, ~(1 << (row + 1)));
  25. }
  26. static void expander_unselect_row(uint8_t row) {
  27. // No need to unselect row as the next `select_row` will blank everything anyway
  28. }
  29. static void expander_unselect_rows(void) {
  30. if (mcp23018_errors) {
  31. return;
  32. }
  33. mcp23018_errors += !mcp23018_set_config(I2C_ADDR, mcp23018_PORTB, ALL_INPUT);
  34. }
  35. static matrix_row_t expander_read_row(void) {
  36. if (mcp23018_errors) {
  37. return 0;
  38. }
  39. uint8_t ret = 0xFF;
  40. mcp23018_errors += !mcp23018_read_pins(I2C_ADDR, mcp23018_PORTA, &ret);
  41. ret = bitrev(~ret);
  42. ret = ((ret & 0b11111000) >> 1) | (ret & 0b00000011);
  43. return ((uint16_t)ret) << 7;
  44. }
  45. static void expander_scan(void) {
  46. if (!mcp23018_errors) {
  47. return;
  48. }
  49. static uint16_t mcp23018_reset_loop = 0;
  50. if (++mcp23018_reset_loop > 0x1FFF) {
  51. // tuned to about 5s given the current scan rate
  52. dprintf("trying to reset mcp23018\n");
  53. mcp23018_reset_loop = 0;
  54. mcp23018_errors = 0;
  55. expander_unselect_rows();
  56. expander_init_cols();
  57. }
  58. }
  59. /* Column pin configuration
  60. *
  61. * Pro Micro: 6 5 4 3 2 1 0
  62. * PD3 PD2 PD4 PC6 PD7 PE6 PB4
  63. *
  64. * Expander: 13 12 11 10 9 8 7
  65. */
  66. static void init_cols(void) {
  67. // Pro Micro
  68. gpio_set_pin_input_high(E6);
  69. gpio_set_pin_input_high(D2);
  70. gpio_set_pin_input_high(D3);
  71. gpio_set_pin_input_high(D4);
  72. gpio_set_pin_input_high(D7);
  73. gpio_set_pin_input_high(C6);
  74. gpio_set_pin_input_high(B4);
  75. // Expander
  76. expander_init_cols();
  77. }
  78. static matrix_row_t read_cols(void) {
  79. // clang-format off
  80. return expander_read_row() |
  81. (gpio_read_pin(D3) ? 0 : (1<<6)) |
  82. (gpio_read_pin(D2) ? 0 : (1<<5)) |
  83. (gpio_read_pin(D4) ? 0 : (1<<4)) |
  84. (gpio_read_pin(C6) ? 0 : (1<<3)) |
  85. (gpio_read_pin(D7) ? 0 : (1<<2)) |
  86. (gpio_read_pin(E6) ? 0 : (1<<1)) |
  87. (gpio_read_pin(B4) ? 0 : (1<<0)) ;
  88. // clang-format on
  89. }
  90. /* Row pin configuration
  91. *
  92. * Pro Micro: 0 1 2 3 4 5
  93. * F4 F5 F6 F7 B1 B2
  94. *
  95. * Expander: 0 1 2 3 4 5
  96. */
  97. static void unselect_rows(void) {
  98. // Pro Micro
  99. gpio_set_pin_input(B1);
  100. gpio_set_pin_input(B2);
  101. gpio_set_pin_input(F4);
  102. gpio_set_pin_input(F5);
  103. gpio_set_pin_input(F6);
  104. gpio_set_pin_input(F7);
  105. gpio_write_pin_low(B1);
  106. gpio_write_pin_low(B2);
  107. gpio_write_pin_low(F4);
  108. gpio_write_pin_low(F5);
  109. gpio_write_pin_low(F6);
  110. gpio_write_pin_low(F7);
  111. // Expander
  112. expander_unselect_rows();
  113. }
  114. static void unselect_row(uint8_t row) {
  115. // Pro Micro
  116. switch (row) {
  117. case 0:
  118. gpio_set_pin_input(F4);
  119. gpio_write_pin_low(F4);
  120. break;
  121. case 1:
  122. gpio_set_pin_input(F5);
  123. gpio_write_pin_low(F5);
  124. break;
  125. case 2:
  126. gpio_set_pin_input(F6);
  127. gpio_write_pin_low(F6);
  128. break;
  129. case 3:
  130. gpio_set_pin_input(F7);
  131. gpio_write_pin_low(F7);
  132. break;
  133. case 4:
  134. gpio_set_pin_input(B1);
  135. gpio_write_pin_low(B1);
  136. break;
  137. case 5:
  138. gpio_set_pin_input(B2);
  139. gpio_write_pin_low(B2);
  140. break;
  141. }
  142. // Expander
  143. expander_unselect_row(row);
  144. }
  145. static void select_row(uint8_t row) {
  146. // Pro Micro
  147. switch (row) {
  148. case 0:
  149. gpio_set_pin_output(F4);
  150. gpio_write_pin_low(F4);
  151. break;
  152. case 1:
  153. gpio_set_pin_output(F5);
  154. gpio_write_pin_low(F5);
  155. break;
  156. case 2:
  157. gpio_set_pin_output(F6);
  158. gpio_write_pin_low(F6);
  159. break;
  160. case 3:
  161. gpio_set_pin_output(F7);
  162. gpio_write_pin_low(F7);
  163. break;
  164. case 4:
  165. gpio_set_pin_output(B1);
  166. gpio_write_pin_low(B1);
  167. break;
  168. case 5:
  169. gpio_set_pin_output(B2);
  170. gpio_write_pin_low(B2);
  171. break;
  172. }
  173. // Expander
  174. expander_select_row(row);
  175. }
  176. static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
  177. // Store last value of row prior to reading
  178. matrix_row_t last_row_value = current_matrix[current_row];
  179. // Clear data in matrix row
  180. current_matrix[current_row] = 0;
  181. // Select row and wait for row selection to stabilize
  182. select_row(current_row);
  183. // Skip the wait_us(30); as i2c is slow enough to debounce the io changes
  184. current_matrix[current_row] = read_cols();
  185. unselect_row(current_row);
  186. return (last_row_value != current_matrix[current_row]);
  187. }
  188. void matrix_init_custom(void) {
  189. expander_init();
  190. unselect_rows();
  191. init_cols();
  192. }
  193. bool matrix_scan_custom(matrix_row_t current_matrix[]) {
  194. expander_scan();
  195. bool changed = false;
  196. for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
  197. changed |= read_cols_on_row(current_matrix, current_row);
  198. }
  199. return changed;
  200. }