logo

qmk_firmware

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

matrix.c (4138B)


  1. // Copyright 2023 John Barbero Unenge (@jbarberu)
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "matrix.h"
  4. #include "gpio.h"
  5. #include "wait.h"
  6. #include "string.h"
  7. #define SNES_CLOCK GP0
  8. #define SNES_LATCH GP1
  9. #define SNES_D0 GP2
  10. #define SNES_D1 GP3
  11. #define SNES_IO GP4
  12. #define KBD_ROW0 GP24
  13. #define KBD_ROW1 GP23
  14. #define KBD_ROW2 GP22
  15. #define KBD_NUM_ROWS 3
  16. #define KBD_COL0 GP18
  17. #define KBD_COL1 GP19
  18. #define KBD_COL2 GP20
  19. #define KBD_COL3 GP21
  20. #define KBD_ROW_SETUP_DELAY_US 5
  21. // The real snes will clock 16 bits out of the controller, but only really has 12 bits of data
  22. #define SNES_DATA_BITS 16
  23. #define SNES_DATA_SETUP_DELAY_US 10
  24. #define SNES_CLOCK_PULSE_DURATION 10
  25. static const int kbd_pin_map[] = {
  26. KBD_ROW0,
  27. KBD_ROW1,
  28. KBD_ROW2
  29. };
  30. void matrix_init_custom(void) {
  31. // init snes controller
  32. gpio_set_pin_input_high(SNES_D0);
  33. // todo: look into protocol for other strange snes controllers that use D1 and IO
  34. // gpio_set_pin_input_high(SNES_D1);
  35. // gpio_set_pin_input_high(SNES_IO);
  36. gpio_set_pin_output(SNES_CLOCK);
  37. gpio_set_pin_output(SNES_LATCH);
  38. gpio_write_pin_low(SNES_CLOCK);
  39. gpio_write_pin_low(SNES_LATCH);
  40. // init rows
  41. gpio_set_pin_output(KBD_ROW0);
  42. gpio_set_pin_output(KBD_ROW1);
  43. gpio_set_pin_output(KBD_ROW2);
  44. gpio_write_pin_high(KBD_ROW0);
  45. gpio_write_pin_high(KBD_ROW1);
  46. gpio_write_pin_high(KBD_ROW2);
  47. // init columns
  48. gpio_set_pin_input_high(KBD_COL0);
  49. gpio_set_pin_input_high(KBD_COL1);
  50. gpio_set_pin_input_high(KBD_COL2);
  51. gpio_set_pin_input_high(KBD_COL3);
  52. }
  53. static matrix_row_t readRow(size_t row, int setupDelay) {
  54. const int pin = kbd_pin_map[row];
  55. // select the row
  56. gpio_set_pin_output(pin);
  57. gpio_write_pin_low(pin);
  58. wait_us(setupDelay);
  59. // read the column data
  60. const matrix_row_t ret =
  61. (gpio_read_pin(KBD_COL0) ? 0 : 1 << 0)
  62. | (gpio_read_pin(KBD_COL1) ? 0 : 1 << 1)
  63. | (gpio_read_pin(KBD_COL2) ? 0 : 1 << 2)
  64. | (gpio_read_pin(KBD_COL3) ? 0 : 1 << 3);
  65. // deselect the row
  66. gpio_set_pin_output(pin);
  67. gpio_write_pin_high(pin);
  68. return ret;
  69. }
  70. static void readKeyboard(matrix_row_t current_matrix[]) {
  71. for (size_t row = 0; row < KBD_NUM_ROWS; ++row) {
  72. current_matrix[row] = readRow(row, KBD_ROW_SETUP_DELAY_US);
  73. }
  74. }
  75. static matrix_row_t getBits(uint16_t value, size_t bit0, size_t bit1, size_t bit2, size_t bit3) {
  76. matrix_row_t ret = 0;
  77. ret |= (value >> bit3) & 1;
  78. ret <<= 1;
  79. ret |= (value >> bit2) & 1;
  80. ret <<= 1;
  81. ret |= (value >> bit1) & 1;
  82. ret <<= 1;
  83. ret |= (value >> bit0) & 1;
  84. return ret;
  85. }
  86. static void readSnesController(matrix_row_t current_matrix[]) {
  87. uint16_t controller = 0;
  88. gpio_write_pin_high(SNES_LATCH);
  89. for (size_t bit = 0; bit < SNES_DATA_BITS; ++bit) {
  90. // Wait for shift register to setup the data line
  91. wait_us(SNES_DATA_SETUP_DELAY_US);
  92. // Shift accumulated data and read data pin
  93. controller <<= 1;
  94. controller |= gpio_read_pin(SNES_D0) ? 0 : 1;
  95. // todo: maybe read D1 and IO here too
  96. // Shift next bit in
  97. gpio_write_pin_high(SNES_CLOCK);
  98. wait_us(SNES_CLOCK_PULSE_DURATION);
  99. gpio_write_pin_low(SNES_CLOCK);
  100. }
  101. gpio_write_pin_low(SNES_LATCH);
  102. controller >>= 4;
  103. // SNES button order is pretty random, and we'd like them to be a bit tidier
  104. current_matrix[3] = getBits(controller, 1, 0, 8, 9);
  105. current_matrix[4] = getBits(controller, 7, 6, 5, 4);
  106. current_matrix[5] = getBits(controller, 3, 11, 2, 10);
  107. }
  108. bool matrix_scan_custom(matrix_row_t current_matrix[]) {
  109. const size_t MATRIX_ARRAY_SIZE = MATRIX_ROWS * sizeof(matrix_row_t);
  110. // create a copy of the current_matrix, before we read hardware state
  111. matrix_row_t last_value[MATRIX_ROWS];
  112. memcpy(last_value, current_matrix, MATRIX_ARRAY_SIZE);
  113. // read hardware state into current_matrix
  114. readKeyboard(current_matrix);
  115. readSnesController(current_matrix);
  116. // check if anything changed
  117. return memcmp(last_value, current_matrix, MATRIX_ARRAY_SIZE) != 0;
  118. }