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 }