qmk_firmware

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

matrix.c (3748B)


      1 // Copyright 2022 @sadekbaroudi (Sadek Baroudi)
      2 // Copyright 2023 @jasonhazel (Jason Hazel)
      3 // SPDX-License-Identifier: GPL-3.0-or-later
      4 
      5 #include "matrix.h"
      6 #include <string.h>
      7 #include "spi_master.h"
      8 #include "debug.h"
      9 #include "wait.h"
     10 
     11 #if (!defined(SHIFTREG_MATRIX_COL_CS))
     12 #    error Missing shift register I/O pin definitions
     13 #endif
     14 
     15 int matrixArraySize = SHIFTREG_ROWS * sizeof(matrix_row_t);
     16 matrix_row_t oldMatrix[SHIFTREG_ROWS];
     17 
     18 #define SHIFTREG_OUTPUT_BITS 8
     19 pin_t rowPinsSR[SHIFTREG_ROWS] = MATRIX_ROW_PINS_SR;
     20 
     21 // semaphore to make sure SPI doesn't get called multiple times
     22 static bool shiftRegisterSPILocked = false;
     23 
     24 void semaphore_lock(bool value) {
     25     shiftRegisterSPILocked = value;
     26 }
     27 
     28 bool semaphore_is_locked(void) {
     29     return shiftRegisterSPILocked;
     30 }
     31 
     32 void sr_74hc595_spi_stop(void) {
     33     spi_stop();
     34     semaphore_lock(false);
     35 }
     36 
     37 bool sr_74hc595_spi_start(void) {
     38     if (!spi_start(SHIFTREG_MATRIX_COL_CS, false, 0, SHIFTREG_DIVISOR)) {
     39         dprintf("74hc595 matrix: failed to start spi\n");
     40         sr_74hc595_spi_stop();
     41         return false;
     42     }
     43 
     44     semaphore_lock(true);
     45     wait_us(1); // not sure if I need this
     46     return true;
     47 }
     48 
     49 bool sr_74hc595_spi_send_byte(uint8_t data) {
     50     sr_74hc595_spi_start();
     51     gpio_write_pin_low(SHIFTREG_MATRIX_COL_CS);
     52     matrix_io_delay();
     53     spi_write(data);
     54     matrix_io_delay();
     55     gpio_write_pin_high(SHIFTREG_MATRIX_COL_CS);
     56     sr_74hc595_spi_stop();
     57     return true;
     58 }
     59 
     60 /**
     61  * Set the entire shift register to be full of inactive bits
     62  */
     63 void clearColumns(void) {
     64     uint8_t value = 0b00000000;
     65     sr_74hc595_spi_send_byte(value);
     66 }
     67 
     68 void setColumn(int columnShift, bool test_run) {
     69     uint8_t columnShiftByte = ((uint8_t)1 << columnShift);
     70     if(test_run) {
     71         dprintf("byte sent: %d\n", columnShiftByte);
     72     }
     73     sr_74hc595_spi_send_byte(columnShiftByte);
     74 }
     75 
     76 /*
     77  * override of the qmk intialization function
     78  */
     79 void matrix_init_custom(void) {
     80     wait_ms(300);
     81     spi_init();
     82     // Set up the initial states for all the row pins
     83     for (int r = 0; r < SHIFTREG_ROWS; r++) {
     84         // Note: This needs to use the internal pull down resistors, and atmegas do *not* support that
     85         gpio_set_pin_input_low(rowPinsSR[r]);
     86     }
     87 
     88     // Set the CS to low by default, and specify as an output pin
     89     gpio_write_pin_high(SHIFTREG_MATRIX_COL_CS); // should be high when using SPI?
     90     gpio_set_pin_output(SHIFTREG_MATRIX_COL_CS);
     91 
     92     // Since it's the init, deactivate all the columns. We'll activate once we get to the matrix scan
     93     clearColumns();
     94 }
     95 
     96 bool matrix_scan_custom(matrix_row_t current_matrix[]) {
     97     // respect the semaphore
     98     if (semaphore_is_locked()) {
     99         return false;
    100     }
    101 
    102     // Keep track of if something was modified
    103     bool matrix_has_changed = false;
    104 
    105     // reset the current matrix, as we'll be updating and comparing to the old matrix
    106     memset(current_matrix, 0, matrixArraySize);
    107 
    108 
    109     bool debug_output = false;
    110     // Loop through the columns, activating one at a time, and read the rows, and place in the new current_matrix
    111     for (int c = 0; c < SHIFTREG_COLS; c++) {
    112         if (debug_output) {
    113             dprintf("column iteration: %d\n", c);
    114         }
    115         setColumn(c, debug_output);
    116         matrix_io_delay();
    117 
    118         for (int r = 0; r < SHIFTREG_ROWS; r++) {
    119             current_matrix[r] |= ((gpio_read_pin(rowPinsSR[r]) ? 1 : 0) << c);
    120         }
    121     }
    122 
    123     matrix_has_changed = memcmp(current_matrix, oldMatrix, matrixArraySize) != 0;
    124     memcpy(oldMatrix, current_matrix, matrixArraySize);
    125 
    126     if (matrix_has_changed) {
    127         matrix_print();
    128     }
    129 
    130 
    131     // Deactivate all the columns for the next run.
    132     clearColumns();
    133     matrix_io_delay();
    134 
    135     return matrix_has_changed;
    136 }