logo

qmk_firmware

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

ec.c (5323B)


  1. /* Copyright 2023 Viktus Design LLC
  2. *
  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. *
  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. *
  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. #include "ec.h"
  17. #include <avr/interrupt.h>
  18. #include "analog.h"
  19. //#include "debug.h"
  20. // sensing channel definitions
  21. #define A0 0
  22. #define A1 1
  23. #define A2 2
  24. #define A3 3
  25. #define A4 4
  26. #define A5 5
  27. #define A6 6
  28. #define A7 7
  29. // analog connection settings
  30. #define DISCHARGE_PIN D3
  31. #define ANALOG_PORT D4
  32. #ifndef MUX_SEL_PIN
  33. # define MUX_SEL_PINS \
  34. { D0, D1, D2 }
  35. #endif
  36. // pin connections
  37. const uint8_t row_channels[] = MATRIX_ROW_PINS;
  38. const uint8_t col_pins[] = MATRIX_COL_PINS;
  39. const uint8_t mux_sel_pins[] = MUX_SEL_PINS;
  40. _Static_assert(sizeof(mux_sel_pins) == 3, "invalid MUX_SEL_PINS");
  41. static ec_config_t config;
  42. static uint16_t ec_sw_value[MATRIX_COLS][MATRIX_ROWS];
  43. static inline void discharge_capacitor(void) { gpio_set_pin_output(DISCHARGE_PIN); }
  44. static inline void charge_capacitor(uint8_t col) {
  45. gpio_set_pin_input(DISCHARGE_PIN);
  46. gpio_write_pin_high(col_pins[col]);
  47. }
  48. static inline void clear_all_col_pins(void) {
  49. for (int col = 0; col < sizeof(col_pins); col++) {
  50. gpio_write_pin_low(col_pins[col]);
  51. }
  52. }
  53. void init_mux_sel(void) {
  54. for (int idx = 0; idx < sizeof(mux_sel_pins); idx++) {
  55. gpio_set_pin_output(mux_sel_pins[idx]);
  56. }
  57. }
  58. void select_mux(uint8_t row) {
  59. uint8_t ch = row_channels[row];
  60. gpio_write_pin(mux_sel_pins[0], ch & 1);
  61. gpio_write_pin(mux_sel_pins[1], ch & 2);
  62. gpio_write_pin(mux_sel_pins[2], ch & 4);
  63. }
  64. void init_col(void) {
  65. for (int idx = 0; idx < sizeof(col_pins); idx++) {
  66. gpio_set_pin_output(col_pins[idx]);
  67. gpio_write_pin_low(col_pins[idx]);
  68. }
  69. }
  70. void ec_init(ec_config_t const* const ec_config) {
  71. // save config
  72. config = *ec_config;
  73. // initialize discharge pin as discharge mode
  74. gpio_write_pin_low(DISCHARGE_PIN);
  75. gpio_set_pin_output(DISCHARGE_PIN);
  76. // set analog reference
  77. analogReference(ADC_REF_POWER);
  78. // initialize drive lines
  79. init_col();
  80. // initialize multiplexer select pin
  81. init_mux_sel();
  82. // set discharge pin to charge mode
  83. gpio_set_pin_input(DISCHARGE_PIN);
  84. }
  85. uint16_t ec_readkey_raw(uint8_t col, uint8_t row) {
  86. uint16_t sw_value = 0;
  87. discharge_capacitor();
  88. select_mux(row);
  89. clear_all_col_pins();
  90. cli();
  91. charge_capacitor(col);
  92. sw_value = analogReadPin(ANALOG_PORT);
  93. sei();
  94. return sw_value;
  95. }
  96. bool ec_update_key(matrix_row_t* current_row, matrix_row_t col, uint16_t sw_value, uint16_t reset_pt, uint16_t actuation_pt) {
  97. bool current_state = (*current_row >> col) & 1;
  98. // press to release
  99. if (current_state && sw_value < reset_pt) {
  100. *current_row &= ~(MATRIX_ROW_SHIFTER << col);
  101. return true;
  102. }
  103. // release to press
  104. if ((!current_state) && sw_value > actuation_pt) {
  105. *current_row |= (MATRIX_ROW_SHIFTER << col);
  106. return true;
  107. }
  108. return false;
  109. }
  110. bool ec_matrix_scan(matrix_row_t current_matrix[]) {
  111. bool updated = false;
  112. for (int row = 0; row < sizeof(row_channels); row++) {
  113. for (int col = 0; col < sizeof(col_pins); col++) {
  114. uint16_t reset_pt = config.reset_pt;
  115. uint16_t actuation_pt = config.actuation_pt;
  116. switch(row) {
  117. case 0:
  118. switch(col) {
  119. case 15: // lower threshold for split backspace:
  120. case 16: // lower threshold for 2U backspace: 2U(37 rest, 62 btm)
  121. reset_pt = 45;
  122. actuation_pt = 50;
  123. break;
  124. }
  125. break;
  126. case 4:
  127. switch(col) {
  128. case 8: // Lower threshold for spacebar: 7U(37 rest, 63 btm)
  129. reset_pt = 55;
  130. actuation_pt = 60;
  131. break;
  132. case 13: // Lower threshold for right bottom mods: 1.5U(40 rest, 65 btm)
  133. reset_pt = 47;
  134. actuation_pt = 53;
  135. break;
  136. }
  137. break;
  138. }
  139. ec_sw_value[col][row] = ec_readkey_raw(col, row);
  140. updated |= ec_update_key(&current_matrix[row], col, ec_sw_value[col][row], reset_pt, actuation_pt);
  141. }
  142. }
  143. return updated;
  144. }
  145. // console debugging for pad values
  146. /*void ec_dprint_matrix(void) {
  147. for (int row = 0; row < sizeof(row_channels); row++) {
  148. for (int col = 0; col < sizeof(col_pins); col++) {
  149. dprintf("%5d", ec_sw_value[col][row]);
  150. }
  151. dprintf("\n");
  152. }
  153. }*/