logo

qmk_firmware

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

matrix.c (5644B)


  1. /*
  2. Copyright 2011 Jun Wako <wakojun@gmail.com>
  3. Copyright 2020 Kan-Ru Chen <kanru@kanru.info>
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #include "matrix.h"
  16. #include "debug.h"
  17. #include "timer.h"
  18. #include "wait.h"
  19. #include "suspend.h"
  20. #include <avr/interrupt.h>
  21. #ifdef BLUETOOTH_ENABLE
  22. # include "adafruit_ble.h"
  23. #endif
  24. #define RELAX_TIME_US 5
  25. #define ADC_READ_TIME_US 5
  26. uint8_t power_save_level;
  27. static uint32_t matrix_last_modified = 0;
  28. static inline void key_strobe_high(void) { gpio_write_pin_low(B6); }
  29. static inline void key_strobe_low(void) { gpio_write_pin_high(B6); }
  30. static inline bool key_state(void) { return gpio_read_pin(D7); }
  31. static inline void key_prev_on(void) { gpio_write_pin_high(B7); }
  32. static inline void key_prev_off(void) { gpio_write_pin_low(B7); }
  33. static inline bool key_power_state(void) { return !gpio_read_pin(D6); }
  34. static inline void suspend_power_down_longer(void) {
  35. uint8_t times = 60;
  36. while (--times) suspend_power_down();
  37. }
  38. void matrix_power_up(void) {
  39. dprint("[matrix_on]\n");
  40. // change pins output
  41. DDRB = 0xFF;
  42. PORTB = 0x40;
  43. // switch MOS FET on
  44. gpio_set_pin_output(D6);
  45. gpio_write_pin_low(D6);
  46. }
  47. void matrix_power_down(void) {
  48. dprint("[matrix_off]\n");
  49. // input with pull-up consumes less than without it when pin is open
  50. DDRB = 0x00;
  51. PORTB = 0xFF;
  52. // switch MOS FET off
  53. gpio_set_pin_output(D6);
  54. gpio_write_pin_high(D6);
  55. }
  56. static inline void key_select_row(uint8_t row) { PORTB = (PORTB & 0b11111000) | ((row)&0b111); }
  57. static inline void key_select_col(uint8_t col) { PORTB = (PORTB & 0b11000111) | (((col)&0b111) << 3); }
  58. static inline bool key_prev_was_on(matrix_row_t matrix[], uint8_t row, uint8_t col) { return matrix[row] & (1 << col); }
  59. void matrix_init_custom(void) { power_save_level = 0; }
  60. bool matrix_scan_custom(matrix_row_t current_matrix[]) {
  61. bool matrix_has_changed = false;
  62. // power on
  63. if (!key_power_state()) {
  64. matrix_power_up();
  65. }
  66. for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
  67. matrix_row_t last_row_value = current_matrix[row];
  68. key_select_row(row);
  69. wait_us(RELAX_TIME_US);
  70. for (uint8_t col = 0; col < MATRIX_COLS; col++) {
  71. // Hysteresis control: assert(1) when previous key state is on
  72. if (key_prev_was_on(current_matrix, row, col)) {
  73. key_prev_on();
  74. } else {
  75. key_prev_off();
  76. }
  77. // Disable interrupts to encure the ADC timing is correct
  78. cli();
  79. // strobe
  80. key_select_col(col);
  81. key_strobe_high();
  82. // Wait for ADC to outputs its value.
  83. // 1us was ok on one HHKB, but not worked on another.
  84. // no wait doesn't work on Teensy++ with pro(1us works)
  85. // no wait does work on tmk PCB(8MHz) with pro2
  86. // 1us wait does work on both of above
  87. // 1us wait doesn't work on tmk(16MHz)
  88. // 5us wait does work on tmk(16MHz)
  89. // 5us wait does work on tmk(16MHz/2)
  90. // 5us wait does work on tmk(8MHz)
  91. // 10us wait does work on Teensy++ with pro
  92. // 10us wait does work on 328p+iwrap with pro
  93. // 10us wait doesn't work on tmk PCB(8MHz) with pro2(very lagged scan)
  94. wait_us(ADC_READ_TIME_US);
  95. if (key_state()) {
  96. current_matrix[row] &= ~(1 << col);
  97. } else {
  98. current_matrix[row] |= (1 << col);
  99. }
  100. key_strobe_low();
  101. sei();
  102. // Make sure enough time has elapsed since the last call
  103. // This is to ensure the matrix voltages have relaxed
  104. wait_us(RELAX_TIME_US);
  105. }
  106. if (current_matrix[row] ^ last_row_value) {
  107. matrix_has_changed = true;
  108. matrix_last_modified = timer_read32();
  109. }
  110. }
  111. // Power saving
  112. uint32_t time_diff = timer_elapsed32(matrix_last_modified);
  113. if (time_diff > MATRIX_POWER_SAVE_TIMEOUT_L3_MS) {
  114. power_save_level = 3;
  115. suspend_power_down_longer();
  116. } else if (time_diff > MATRIX_POWER_SAVE_TIMEOUT_L2_MS) {
  117. power_save_level = 2;
  118. #ifdef BLUETOOTH_ENABLE
  119. if (!adafruit_ble_is_connected()) {
  120. power_save_level = 3;
  121. }
  122. #endif
  123. suspend_power_down_longer();
  124. } else if (time_diff > MATRIX_POWER_SAVE_TIMEOUT_MS) {
  125. power_save_level = 1;
  126. suspend_power_down();
  127. } else {
  128. if (power_save_level != 0) {
  129. power_save_level = 0;
  130. suspend_wakeup_init();
  131. }
  132. }
  133. return matrix_has_changed;
  134. }
  135. bool adafruit_ble_delbonds(void);
  136. bool adafruit_ble_reconnect(void);
  137. bool command_extra(uint8_t code) {
  138. switch (code) {
  139. #ifdef BLUETOOTH_ENABLE
  140. case KC_R:
  141. adafruit_ble_delbonds();
  142. return true;
  143. case KC_S:
  144. adafruit_ble_reconnect();
  145. return true;
  146. #endif
  147. default:
  148. return false;
  149. }
  150. }