qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

matrix.c (4138B)


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