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.

243 lines
5.8 KiB

  1. /*
  2. Copyright 2018 listofoptions <listofoptions@gmail.com>
  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. #include <stdint.h>
  15. #include <stdbool.h>
  16. #include <string.h>
  17. #if defined(__AVR__)
  18. #include <avr/io.h>
  19. #endif
  20. #include <util/delay.h>
  21. #include "wait.h"
  22. #include "print.h"
  23. #include "debug.h"
  24. #include "util.h"
  25. #include "matrix.h"
  26. #include "timer.h"
  27. #include <LUFA/Drivers/Peripheral/SPI.h>
  28. #include "config.h"
  29. #ifndef DEBOUNCE
  30. # define DEBOUNCE 5
  31. #endif
  32. #if ( DEBOUNCE > 0 )
  33. static uint16_t debouncing_time ;
  34. static bool debouncing = false ;
  35. #endif
  36. static uint8_t matrix [MATRIX_ROWS] = {0};
  37. #if ( DEBOUNCE > 0 )
  38. static uint8_t matrix_debounce_old [MATRIX_ROWS] = {0};
  39. static uint8_t matrix_debounce_new [MATRIX_ROWS] = {0};
  40. #endif
  41. __attribute__ ((weak))
  42. void matrix_init_quantum(void) {
  43. matrix_init_kb();
  44. }
  45. __attribute__ ((weak))
  46. void matrix_scan_quantum(void) {
  47. matrix_scan_kb();
  48. }
  49. __attribute__ ((weak))
  50. void matrix_init_kb(void) {
  51. matrix_init_user();
  52. }
  53. __attribute__ ((weak))
  54. void matrix_scan_kb(void) {
  55. matrix_scan_user();
  56. }
  57. __attribute__ ((weak))
  58. void matrix_init_user(void) {
  59. }
  60. __attribute__ ((weak))
  61. void matrix_scan_user(void) {
  62. }
  63. // the keyboard's internal wiring is such that the inputs to the logic are
  64. // a clock signal, and a reset line.
  65. // the output is a single output pin. im bitbanging here, but the SPI controller
  66. // would work normally
  67. //
  68. // the device functions, by using the clock signal to count 128 bits, the lower
  69. // 3 bits of this 7 bit counter are tied to a 1-of-8 multiplexer, this forms
  70. // the columns.
  71. // the upper 4 bits form the rows, and are decoded using bcd to decimal
  72. // decoders, so that 14 out of 16 of the outputs are wired to the rows of the
  73. // matrix. each switch has a diode, such that the row signal feeds into the
  74. // switch, and then into the diode, then into one of the columns into the
  75. // matrix. the reset pin can be used to reset the entire counter.
  76. #define RESET _BV(PB0)
  77. #define SCLK _BV(PB1)
  78. #define SDATA _BV(PB3)
  79. #define LED _BV(PD6)
  80. inline
  81. static
  82. void SCLK_increment(void) {
  83. PORTB &= ~SCLK ;
  84. _delay_us( 4 ) ; // make sure the line is stable
  85. PORTB |= SCLK ;
  86. _delay_us( 4 ) ;
  87. return ;
  88. }
  89. inline
  90. static
  91. void Matrix_Reset(void) {
  92. PORTB |= RESET ;
  93. _delay_us( 4 ) ; // make sure the line is stable
  94. PORTB &= ~RESET ;
  95. return ;
  96. }
  97. inline
  98. static
  99. uint8_t Matrix_ReceiveByte (void) {
  100. uint8_t received = 0 ;
  101. uint8_t temp = 0 ;
  102. for ( uint8_t bit = 0; bit < MATRIX_COLS; ++bit ) {
  103. // toggle the clock
  104. SCLK_increment();
  105. temp = (PINB & SDATA) << 4 ;
  106. received |= temp >> bit ;
  107. }
  108. return received ;
  109. }
  110. inline
  111. static
  112. void Matrix_ThrowByte(void) {
  113. // we use MATRIX_COLS - 1 here because that would put us at 7 clocks
  114. for ( uint8_t bit = 0; bit < MATRIX_COLS - 1; ++bit ) {
  115. // toggle the clock
  116. SCLK_increment();
  117. }
  118. return ;
  119. }
  120. void matrix_init () {
  121. // debug_matrix = 1;
  122. // PB0 (SS) and PB1 (SCLK) set to outputs
  123. DDRB |= RESET | SCLK ;
  124. // PB2, is unused, and PB3 is our serial input
  125. DDRB &= ~SDATA ;
  126. // SS is reset for this board, and is active High
  127. // SCLK is the serial clock and is active High
  128. PORTB &= ~RESET ;
  129. PORTB |= SCLK ;
  130. // led pin
  131. DDRD |= LED ;
  132. PORTD &= ~LED ;
  133. matrix_init_quantum();
  134. //toggle reset, to put the keyboard logic into a known state
  135. Matrix_Reset() ;
  136. }
  137. uint8_t matrix_scan(void) {
  138. // the first byte of the keyboard's output data can be ignored
  139. Matrix_ThrowByte();
  140. #if ( DEBOUNCE > 0 )
  141. for ( uint8_t row = 0 ; row < MATRIX_ROWS ; ++row ) {
  142. //transfer old debouncing values
  143. matrix_debounce_old[row] = matrix_debounce_new[row] ;
  144. // read new key-states in
  145. matrix_debounce_new[row] = Matrix_ReceiveByte() ;
  146. if ( matrix_debounce_new[row] != matrix_debounce_old[row] ) {
  147. debouncing = true ;
  148. debouncing_time = timer_read() ;
  149. }
  150. }
  151. #else
  152. // without debouncing we simply just read in the raw matrix
  153. for ( uint8_t row = 0 ; row < MATRIX_ROWS ; ++row ) {
  154. matrix[row] = Matrix_ReceiveByte ;
  155. }
  156. #endif
  157. #if ( DEBOUNCE > 0 )
  158. if ( debouncing && ( timer_elapsed( debouncing_time ) > DEBOUNCE ) ) {
  159. for ( uint8_t row = 0 ; row < MATRIX_ROWS ; ++row ) {
  160. matrix[row] = matrix_debounce_new[row] ;
  161. }
  162. debouncing = false ;
  163. }
  164. #endif
  165. Matrix_Reset() ;
  166. matrix_scan_quantum() ;
  167. return 1;
  168. }
  169. inline
  170. uint8_t matrix_get_row( uint8_t row ) {
  171. return matrix[row];
  172. }
  173. void matrix_print(void)
  174. {
  175. print("\nr/c 01234567\n");
  176. for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
  177. print_hex8(row); print(": ");
  178. print_bin_reverse8(matrix_get_row(row));
  179. print("\n");
  180. }
  181. }
  182. inline
  183. uint8_t matrix_rows(void) {
  184. return MATRIX_ROWS;
  185. }
  186. inline
  187. uint8_t matrix_cols(void) {
  188. return MATRIX_COLS;
  189. }
  190. // as an aside, I used the M0110 converter:
  191. // tmk_core/common/keyboard.c, quantum/matrix.c, and the project layout of the planck
  192. // the online ducmentation starting from :
  193. // https://docs.qmk.fm/#/config_options
  194. // https://docs.qmk.fm/#/understanding_qmk
  195. // and probably a few i forgot....