You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

matrix.c 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /*
  2. Copyright 2016 Kai Ryu <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. /*
  15. * scan matrix
  16. */
  17. #include <stdint.h>
  18. #include <stdbool.h>
  19. #include <avr/io.h>
  20. #include <util/delay.h>
  21. #include "debug.h"
  22. #include "util.h"
  23. #include "matrix.h"
  24. #include "expander.h"
  25. #include "keymap_in_eeprom.h"
  26. #include "timer.h"
  27. #ifndef DEBOUNCE
  28. # define DEBOUNCE 5
  29. #endif
  30. /* matrix state(1:on, 0:off) */
  31. static matrix_row_t matrix[MATRIX_ROWS];
  32. #define IMPROVED_DEBOUNCE 1
  33. #if IMPROVED_DEBOUNCE
  34. #define DEBOUNCE_MASK ((1 << DEBOUNCE) - 1)
  35. static uint8_t matrix_current_row;
  36. static uint16_t matrix_row_timestamp[MATRIX_ROWS];
  37. static uint8_t matrix_debouncing[MATRIX_ROWS][MATRIX_COLS];
  38. #else
  39. static uint8_t debouncing = DEBOUNCE;
  40. static matrix_row_t matrix_debouncing[MATRIX_ROWS];
  41. static matrix_row_t read_row(void);
  42. #endif
  43. static uint16_t matrix_scan_timestamp;
  44. static void read_cols(void);
  45. static uint8_t get_col(uint8_t col);
  46. static void init_cols(void);
  47. static void unselect_rows(void);
  48. static void select_row(uint8_t row);
  49. inline
  50. uint8_t matrix_rows(void)
  51. {
  52. return MATRIX_ROWS;
  53. }
  54. inline
  55. uint8_t matrix_cols(void)
  56. {
  57. return MATRIX_COLS;
  58. }
  59. void matrix_init(void)
  60. {
  61. // disable JTAG
  62. MCUCR = (1<<JTD);
  63. MCUCR = (1<<JTD);
  64. timer_init();
  65. _delay_ms(1);
  66. matrix_scan_timestamp = timer_read();
  67. // initialize row and col
  68. unselect_rows();
  69. init_cols();
  70. // initialize matrix state: all keys off
  71. #if IMPROVED_DEBOUNCE
  72. for (uint8_t i = 0; i < matrix_rows(); i++) {
  73. matrix[i] = 0;
  74. matrix_current_row = 0;
  75. matrix_row_timestamp[i] = timer_read();
  76. for (uint8_t j = 0; j < matrix_cols(); j++) {
  77. matrix_debouncing[i][j] = 0;
  78. }
  79. }
  80. #else
  81. for (uint8_t i=0; i < matrix_rows(); i++) {
  82. matrix[i] = 0;
  83. matrix_debouncing[i] = 0;
  84. }
  85. #endif
  86. }
  87. uint8_t matrix_scan(void)
  88. {
  89. if (timer_elapsed(matrix_scan_timestamp) >= 1000) {
  90. dprintf("======== 1s task ========\n");
  91. dprintf("Scan: %u\n", matrix_scan_timestamp);
  92. matrix_scan_timestamp = timer_read();
  93. expander_scan();
  94. dprintf("=========================\n");
  95. }
  96. #if IMPROVED_DEBOUNCE
  97. uint16_t elapsed = timer_elapsed(matrix_row_timestamp[matrix_current_row]);
  98. if (elapsed >= 1) {
  99. matrix_row_timestamp[matrix_current_row] = timer_read();
  100. select_row(matrix_current_row);
  101. _delay_us(30);
  102. read_cols();
  103. for (uint8_t i = 0; i < matrix_cols(); i++) {
  104. uint8_t *debounce = &matrix_debouncing[matrix_current_row][i];
  105. uint8_t col = get_col(i);
  106. uint8_t count = elapsed;
  107. do {
  108. *debounce <<= 1;
  109. *debounce |= col;
  110. } while (--count);
  111. matrix_row_t *row = &matrix[matrix_current_row];
  112. matrix_row_t mask = ((matrix_row_t)1 << i);
  113. switch (*debounce & DEBOUNCE_MASK) {
  114. case DEBOUNCE_MASK:
  115. #if DEBOUNCE > 1
  116. case (DEBOUNCE_MASK >> 1):
  117. #if DEBOUNCE > 2
  118. case (DEBOUNCE_MASK >> 2):
  119. #if DEBOUNCE > 3
  120. case (DEBOUNCE_MASK >> 3):
  121. #if DEBOUNCE > 4
  122. case (DEBOUNCE_MASK >> 4):
  123. #if DEBOUNCE > 5
  124. case (DEBOUNCE_MASK >> 5):
  125. #if DEBOUNCE > 6
  126. case (DEBOUNCE_MASK >> 6):
  127. #if DEBOUNCE > 7
  128. case (DEBOUNCE_MASK >> 7):
  129. #if DEBOUNCE > 8
  130. case (DEBOUNCE_MASK >> 8):
  131. #if DEBOUNCE > 9
  132. case (DEBOUNCE_MASK >> 9):
  133. #if DEBOUNCE > 10
  134. case (DEBOUNCE_MASK >> 10):
  135. #endif
  136. #endif
  137. #endif
  138. #endif
  139. #endif
  140. #endif
  141. #endif
  142. #endif
  143. #endif
  144. #endif
  145. if ((*row & mask) == 0) {
  146. *row |= mask;
  147. }
  148. break;
  149. #if DEBOUNCE > 1
  150. case ((DEBOUNCE_MASK << 1) & DEBOUNCE_MASK):
  151. #if DEBOUNCE > 2
  152. case ((DEBOUNCE_MASK << 2) & DEBOUNCE_MASK):
  153. #if DEBOUNCE > 3
  154. case ((DEBOUNCE_MASK << 3) & DEBOUNCE_MASK):
  155. #if DEBOUNCE > 4
  156. case ((DEBOUNCE_MASK << 4) & DEBOUNCE_MASK):
  157. #if DEBOUNCE > 5
  158. case ((DEBOUNCE_MASK << 5) & DEBOUNCE_MASK):
  159. #if DEBOUNCE > 6
  160. case ((DEBOUNCE_MASK << 6) & DEBOUNCE_MASK):
  161. #if DEBOUNCE > 7
  162. case ((DEBOUNCE_MASK << 7) & DEBOUNCE_MASK):
  163. #if DEBOUNCE > 8
  164. case ((DEBOUNCE_MASK << 8) & DEBOUNCE_MASK):
  165. #if DEBOUNCE > 9
  166. case ((DEBOUNCE_MASK << 9) & DEBOUNCE_MASK):
  167. #if DEBOUNCE > 10
  168. case ((DEBOUNCE_MASK << 10) & DEBOUNCE_MASK):
  169. #endif
  170. #endif
  171. #endif
  172. #endif
  173. #endif
  174. #endif
  175. #endif
  176. #endif
  177. #endif
  178. #endif
  179. break;
  180. case 0:
  181. if ((*row & mask) != 0) {
  182. *row &= ~mask;
  183. }
  184. break;
  185. default:
  186. debug("bounce!: ");
  187. debug_bin8(*debounce & DEBOUNCE_MASK);
  188. debug("\n");
  189. break;
  190. }
  191. }
  192. unselect_rows();
  193. }
  194. matrix_current_row++;
  195. if (matrix_current_row >= matrix_rows()) {
  196. matrix_current_row = 0;
  197. }
  198. #else
  199. for (uint8_t i = 0; i < matrix_rows(); i++) {
  200. select_row(i);
  201. _delay_us(30); // without this wait read unstable value.
  202. matrix_row_t cols = read_row();
  203. if (matrix_debouncing[i] != cols) {
  204. matrix_debouncing[i] = cols;
  205. if (debouncing) {
  206. debug("bounce!: "); debug_hex(debouncing); debug("\n");
  207. }
  208. debouncing = DEBOUNCE;
  209. }
  210. unselect_rows();
  211. }
  212. if (debouncing) {
  213. if (--debouncing) {
  214. _delay_ms(1);
  215. } else {
  216. for (uint8_t i = 0; i < matrix_rows(); i++) {
  217. matrix[i] = matrix_debouncing[i];
  218. }
  219. }
  220. }
  221. #endif
  222. return 1;
  223. }
  224. #if IMPROVED_DEBOUNCE
  225. #else
  226. bool matrix_is_modified(void)
  227. {
  228. if (debouncing) return false;
  229. return true;
  230. }
  231. #endif
  232. inline
  233. bool matrix_is_on(uint8_t row, uint8_t col)
  234. {
  235. return (matrix[row] & ((matrix_row_t)1<<col));
  236. }
  237. inline
  238. matrix_row_t matrix_get_row(uint8_t row)
  239. {
  240. return matrix[row];
  241. }
  242. void matrix_print(void)
  243. {
  244. print("\nr/c 0123456789ABCDEF\n");
  245. for (uint8_t row = 0; row < matrix_rows(); row++) {
  246. phex(row); print(": ");
  247. print_bin_reverse32(matrix_get_row(row));
  248. print("\n");
  249. }
  250. }
  251. uint8_t matrix_key_count(void)
  252. {
  253. uint8_t count = 0;
  254. for (uint8_t i = 0; i < matrix_rows(); i++) {
  255. count += bitpop32(matrix[i]);
  256. }
  257. return count;
  258. }
  259. /* Column pin configuration
  260. * col: 0 1 2 3 4 5 6 7 8 9 10 11 12 13
  261. * pin: EX EX EX EX EX EX EX D3 D2 D4 C6 D7 E6 B4
  262. */
  263. static void init_cols(void)
  264. {
  265. // Input with pull-up(DDR:0, PORT:1)
  266. DDRE &= ~(1<<PE6);
  267. PORTE |= (1<<PE6);
  268. DDRD &= ~(1<<PD2 | 1<<PD3 | 1<<PD4 | 1<<PD7);
  269. PORTD |= (1<<PD2 | 1<<PD3 | 1<<PD4 | 1<<PD7);
  270. DDRC &= ~(1<<PC6);
  271. PORTC |= (1<<PC6);
  272. DDRB &= ~(1<<PB4);
  273. PORTB |= (1<<PB4);
  274. // Init I/O expander
  275. expander_init();
  276. }
  277. #if !IMPROVED_DEBOUNCE
  278. static matrix_row_t read_row(void)
  279. {
  280. return expander_read_row() |
  281. (PIND&(1<<PD3) ? 0 : (1<<7)) |
  282. (PIND&(1<<PD2) ? 0 : (1<<8)) |
  283. (PIND&(1<<PD4) ? 0 : (1<<9)) |
  284. (PINC&(1<<PC6) ? 0 : (1<<10)) |
  285. (PIND&(1<<PD7) ? 0 : (1<<11)) |
  286. (PINE&(1<<PE6) ? 0 : (1<<12)) |
  287. (PINB&(1<<PB4) ? 0 : (1<<13));
  288. }
  289. #endif
  290. static void read_cols(void)
  291. {
  292. expander_read_cols();
  293. }
  294. static uint8_t get_col(uint8_t col)
  295. {
  296. switch (col) {
  297. #ifdef VER_PROTOTYPE
  298. case 0 ... 6:
  299. return expander_get_col(col);
  300. case 7:
  301. return PIND&(1<<PD3) ? 0 : 1;
  302. case 8:
  303. return PIND&(1<<PD2) ? 0 : 1;
  304. case 9:
  305. return PIND&(1<<PD4) ? 0 : 1;
  306. case 10:
  307. return PINC&(1<<PC6) ? 0 : 1;
  308. case 11:
  309. return PIND&(1<<PD7) ? 0 : 1;
  310. case 12:
  311. return PINE&(1<<PE6) ? 0 : 1;
  312. case 13:
  313. return PINB&(1<<PB4) ? 0 : 1;
  314. #else
  315. case 0:
  316. return PINB&(1<<PB4) ? 0 : 1;
  317. case 1:
  318. return PINE&(1<<PE6) ? 0 : 1;
  319. case 2:
  320. return PIND&(1<<PD7) ? 0 : 1;
  321. case 3:
  322. return PINC&(1<<PC6) ? 0 : 1;
  323. case 4:
  324. return PIND&(1<<PD4) ? 0 : 1;
  325. case 5:
  326. return PIND&(1<<PD2) ? 0 : 1;
  327. case 6:
  328. return PIND&(1<<PD3) ? 0 : 1;
  329. case 7 ... 13:
  330. return expander_get_col(13 - col);
  331. #endif
  332. default:
  333. return 0;
  334. }
  335. }
  336. /* Row pin configuration
  337. * row: 0 1 2 3 4 5
  338. * pin: F4 F5 F6 F7 B1 B2
  339. */
  340. static void unselect_rows(void)
  341. {
  342. // Hi-Z(DDR:0, PORT:0) to unselect
  343. DDRF &= ~(1<<PF4 | 1<<PF5 | 1<<PF6 | 1<<PF7);
  344. PORTF &= ~(1<<PF4 | 1<<PF5 | 1<<PF6 | 1<<PF7);
  345. DDRB &= ~(1<<PB1 | 1<<PB2);
  346. PORTB &= ~(1<<PB1 | 1<<PB2);
  347. // I/O expander
  348. expander_unselect_rows();
  349. }
  350. static void select_row(uint8_t row)
  351. {
  352. // Output low(DDR:1, PORT:0) to select
  353. switch (row) {
  354. case 0:
  355. DDRF |= (1<<PF4);
  356. PORTF &= ~(1<<PF4);
  357. break;
  358. case 1:
  359. DDRF |= (1<<PF5);
  360. PORTF &= ~(1<<PF5);
  361. break;
  362. case 2:
  363. DDRF |= (1<<PF6);
  364. PORTF &= ~(1<<PF6);
  365. break;
  366. case 3:
  367. DDRF |= (1<<PF7);
  368. PORTF &= ~(1<<PF7);
  369. break;
  370. case 4:
  371. DDRB |= (1<<PB1);
  372. PORTB &= ~(1<<PB1);
  373. break;
  374. case 5:
  375. DDRB |= (1<<PB2);
  376. PORTB &= ~(1<<PB2);
  377. break;
  378. }
  379. // I/O expander
  380. expander_select_row(row);
  381. }