logo

qmk_firmware

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

matrix.c (6982B)


  1. /*
  2. Copyright 2012 Jun Wako <wakojun@gmail.com>
  3. Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
  4. Copyright 2015 ZSA Technology Labs Inc (@zsa)
  5. Copyright 2020 Christopher Courtney <drashna@live.com> (@drashna)
  6. Copyright 2021 Gary Kong <kongkm88@gmail.com> (@garykong)
  7. This program is free software: you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation, either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /*
  19. * scan matrix
  20. */
  21. #include <stdint.h>
  22. #include <stdbool.h>
  23. #include <avr/io.h>
  24. #include "wait.h"
  25. #include "action_layer.h"
  26. #include "print.h"
  27. #include "debug.h"
  28. #include "util.h"
  29. #include "matrix.h"
  30. #include "debounce.h"
  31. #include "bajjak.h"
  32. /*
  33. * This constant define not debouncing time in msecs, assuming eager_pr.
  34. *
  35. * On BAJJAK matrix scan rate is relatively low, because of slow I2C.
  36. * Now it's only 317 scans/second, or about 3.15 msec/scan.
  37. * According to Cherry specs, debouncing time is 5 msec.
  38. *
  39. * However, some switches seem to have higher debouncing requirements, or
  40. * something else might be wrong. (Also, the scan speed has improved since
  41. * that comment was written.)
  42. */
  43. /* matrix state(1:on, 0:off) */
  44. extern matrix_row_t matrix[MATRIX_ROWS]; // debounced values
  45. extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values
  46. static matrix_row_t read_cols(uint8_t row);
  47. static void init_cols(void);
  48. static void unselect_rows(void);
  49. static void select_row(uint8_t row);
  50. static uint8_t mcp23018_reset_loop;
  51. void matrix_init_custom(void) {
  52. // initialize row and col
  53. mcp23018_status = init_mcp23018();
  54. unselect_rows();
  55. init_cols();
  56. }
  57. // Reads and stores a row, returning
  58. // whether a change occurred.
  59. static inline bool store_raw_matrix_row(uint8_t index) {
  60. matrix_row_t temp = read_cols(index);
  61. if (raw_matrix[index] != temp) {
  62. raw_matrix[index] = temp;
  63. return true;
  64. }
  65. return false;
  66. }
  67. bool matrix_scan_custom(matrix_row_t current_matrix[]) {
  68. if (mcp23018_status) { // if there was an error
  69. if (++mcp23018_reset_loop == 0) {
  70. print("trying to reset mcp23018\n");
  71. mcp23018_status = init_mcp23018();
  72. if (mcp23018_status) {
  73. print("left side not responding\n");
  74. } else {
  75. print("left side attached\n");
  76. bajjak_blink_all_leds();
  77. }
  78. }
  79. }
  80. #ifdef LEFT_LEDS
  81. mcp23018_status = bajjak_left_leds_update();
  82. #endif // LEFT_LEDS
  83. bool changed = false;
  84. for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
  85. // select rows from left and right hands
  86. uint8_t left_index = i;
  87. uint8_t right_index = i + MATRIX_ROWS_PER_SIDE;
  88. select_row(left_index);
  89. select_row(right_index);
  90. changed |= store_raw_matrix_row(left_index);
  91. changed |= store_raw_matrix_row(right_index);
  92. unselect_rows();
  93. }
  94. return changed;
  95. }
  96. /* Column pin configuration
  97. *
  98. * Teensy
  99. * col: 0 1 2 3 4 5
  100. * pin: F0 F1 F4 F5 F6 F7
  101. *
  102. * MCP23018
  103. * col: 0 1 2 3 4 5
  104. * pin: B5 B4 B3 B2 B1 B0
  105. */
  106. static void init_cols(void) {
  107. // init on mcp23018
  108. // not needed, already done as part of init_mcp23018()
  109. // init on teensy
  110. gpio_set_pin_input_high(F0);
  111. gpio_set_pin_input_high(F1);
  112. gpio_set_pin_input_high(F4);
  113. gpio_set_pin_input_high(F5);
  114. gpio_set_pin_input_high(F6);
  115. gpio_set_pin_input_high(F7);
  116. gpio_set_pin_input_high(D7);
  117. }
  118. static matrix_row_t read_cols(uint8_t row) {
  119. if (row < 7) {
  120. if (mcp23018_status) { // if there was an error
  121. return 0;
  122. } else {
  123. uint8_t data = 0;
  124. // reading GPIOB (column port) since in mcp23018's sequential mode
  125. // it is addressed directly after writing to GPIOA in select_row()
  126. mcp23018_status = i2c_receive(I2C_ADDR, &data, 1, BAJJAK_EZ_I2C_TIMEOUT);
  127. return ~data;
  128. }
  129. } else {
  130. /* read from teensy
  131. * bitmask is 0b11110011, but we want those all
  132. * in the lower six bits.
  133. * we'll return 1s for the top two, but that's harmless.
  134. */
  135. return ~( (PINF & 0x03) | ((PINF & 0xF0) >> 2) | ((PIND & 0x80) >> 1) );
  136. }
  137. }
  138. /* Row pin configuration
  139. *
  140. * Teensy
  141. * row: 7 8 9 10 11 12 13
  142. * pin: B0 B1 B2 B3 D2 D3 C6
  143. *
  144. * MCP23018
  145. * row: 0 1 2 3 4 5 6
  146. * pin: A0 A1 A2 A3 A4 A5 A6
  147. */
  148. static void unselect_rows(void) {
  149. // no need to unselect on mcp23018, because the select step sets all
  150. // the other row bits high, and it's not changing to a different
  151. // direction
  152. // unselect on teensy
  153. gpio_set_pin_input(B0);
  154. gpio_set_pin_input(B1);
  155. gpio_set_pin_input(B2);
  156. gpio_set_pin_input(B3);
  157. gpio_set_pin_input(D2);
  158. gpio_set_pin_input(D3);
  159. gpio_set_pin_input(C6);
  160. }
  161. static void select_row(uint8_t row) {
  162. if (row < 7) {
  163. // select on mcp23018
  164. if (!mcp23018_status) {
  165. // set active row low : 0
  166. // set other rows hi-Z : 1
  167. uint8_t data;
  168. data = 0xFF & ~(1 << row);
  169. mcp23018_status = i2c_write_register(I2C_ADDR, GPIOA, &data, 1, BAJJAK_EZ_I2C_TIMEOUT);
  170. }
  171. } else {
  172. // select on teensy
  173. // Output low(DDR:1, PORT:0) to select
  174. switch (row) {
  175. case 7:
  176. gpio_set_pin_output(B0);
  177. gpio_write_pin_low(B0);
  178. break;
  179. case 8:
  180. gpio_set_pin_output(B1);
  181. gpio_write_pin_low(B1);
  182. break;
  183. case 9:
  184. gpio_set_pin_output(B2);
  185. gpio_write_pin_low(B2);
  186. break;
  187. case 10:
  188. gpio_set_pin_output(B3);
  189. gpio_write_pin_low(B3);
  190. break;
  191. case 11:
  192. gpio_set_pin_output(D2);
  193. gpio_write_pin_low(D2);
  194. break;
  195. case 12:
  196. gpio_set_pin_output(D3);
  197. gpio_write_pin_low(D3);
  198. break;
  199. case 13:
  200. gpio_set_pin_output(C6);
  201. gpio_write_pin_low(C6);
  202. break;
  203. }
  204. }
  205. }
  206. // DO NOT REMOVE
  207. // Needed for proper wake/sleep
  208. void matrix_power_up(void) {
  209. mcp23018_status = init_mcp23018();
  210. unselect_rows();
  211. init_cols();
  212. // initialize matrix state: all keys off
  213. for (uint8_t i=0; i < MATRIX_ROWS; i++) {
  214. matrix[i] = 0;
  215. }
  216. }