136 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			136 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // Copyright 2022 @sadekbaroudi (Sadek Baroudi)
 | |
| // Copyright 2023 @jasonhazel (Jason Hazel)
 | |
| // SPDX-License-Identifier: GPL-3.0-or-later
 | |
| 
 | |
| #include "matrix.h"
 | |
| #include <string.h>
 | |
| #include "spi_master.h"
 | |
| #include "debug.h"
 | |
| #include "wait.h"
 | |
| 
 | |
| #if (!defined(SHIFTREG_MATRIX_COL_CS))
 | |
| #    error Missing shift register I/O pin definitions
 | |
| #endif
 | |
| 
 | |
| int matrixArraySize = SHIFTREG_ROWS * sizeof(matrix_row_t);
 | |
| matrix_row_t oldMatrix[SHIFTREG_ROWS];
 | |
| 
 | |
| #define SHIFTREG_OUTPUT_BITS 8
 | |
| pin_t rowPinsSR[SHIFTREG_ROWS] = MATRIX_ROW_PINS_SR;
 | |
| 
 | |
| // semaphore to make sure SPI doesn't get called multiple times
 | |
| static bool shiftRegisterSPILocked = false;
 | |
| 
 | |
| void semaphore_lock(bool value) {
 | |
|     shiftRegisterSPILocked = value;
 | |
| }
 | |
| 
 | |
| bool semaphore_is_locked(void) {
 | |
|     return shiftRegisterSPILocked;
 | |
| }
 | |
| 
 | |
| void sr_74hc595_spi_stop(void) {
 | |
|     spi_stop();
 | |
|     semaphore_lock(false);
 | |
| }
 | |
| 
 | |
| bool sr_74hc595_spi_start(void) {
 | |
|     if (!spi_start(SHIFTREG_MATRIX_COL_CS, false, 0, SHIFTREG_DIVISOR)) {
 | |
|         dprintf("74hc595 matrix: failed to start spi\n");
 | |
|         sr_74hc595_spi_stop();
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     semaphore_lock(true);
 | |
|     wait_us(1); // not sure if I need this
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool sr_74hc595_spi_send_byte(uint8_t data) {
 | |
|     sr_74hc595_spi_start();
 | |
|     gpio_write_pin_low(SHIFTREG_MATRIX_COL_CS);
 | |
|     matrix_io_delay();
 | |
|     spi_write(data);
 | |
|     matrix_io_delay();
 | |
|     gpio_write_pin_high(SHIFTREG_MATRIX_COL_CS);
 | |
|     sr_74hc595_spi_stop();
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Set the entire shift register to be full of inactive bits
 | |
|  */
 | |
| void clearColumns(void) {
 | |
|     uint8_t value = 0b00000000;
 | |
|     sr_74hc595_spi_send_byte(value);
 | |
| }
 | |
| 
 | |
| void setColumn(int columnShift, bool test_run) {
 | |
|     uint8_t columnShiftByte = ((uint8_t)1 << columnShift);
 | |
|     if(test_run) {
 | |
|         dprintf("byte sent: %d\n", columnShiftByte);
 | |
|     }
 | |
|     sr_74hc595_spi_send_byte(columnShiftByte);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * override of the qmk intialization function
 | |
|  */
 | |
| void matrix_init_custom(void) {
 | |
|     wait_ms(300);
 | |
|     spi_init();
 | |
|     // Set up the initial states for all the row pins
 | |
|     for (int r = 0; r < SHIFTREG_ROWS; r++) {
 | |
|         // Note: This needs to use the internal pull down resistors, and atmegas do *not* support that
 | |
|         gpio_set_pin_input_low(rowPinsSR[r]);
 | |
|     }
 | |
| 
 | |
|     // Set the CS to low by default, and specify as an output pin
 | |
|     gpio_write_pin_high(SHIFTREG_MATRIX_COL_CS); // should be high when using SPI?
 | |
|     gpio_set_pin_output(SHIFTREG_MATRIX_COL_CS);
 | |
| 
 | |
|     // Since it's the init, deactivate all the columns. We'll activate once we get to the matrix scan
 | |
|     clearColumns();
 | |
| }
 | |
| 
 | |
| bool matrix_scan_custom(matrix_row_t current_matrix[]) {
 | |
|     // respect the semaphore
 | |
|     if (semaphore_is_locked()) {
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // Keep track of if something was modified
 | |
|     bool matrix_has_changed = false;
 | |
| 
 | |
|     // reset the current matrix, as we'll be updating and comparing to the old matrix
 | |
|     memset(current_matrix, 0, matrixArraySize);
 | |
| 
 | |
| 
 | |
|     bool debug_output = false;
 | |
|     // Loop through the columns, activating one at a time, and read the rows, and place in the new current_matrix
 | |
|     for (int c = 0; c < SHIFTREG_COLS; c++) {
 | |
|         if (debug_output) {
 | |
|             dprintf("column iteration: %d\n", c);
 | |
|         }
 | |
|         setColumn(c, debug_output);
 | |
|         matrix_io_delay();
 | |
| 
 | |
|         for (int r = 0; r < SHIFTREG_ROWS; r++) {
 | |
|             current_matrix[r] |= ((gpio_read_pin(rowPinsSR[r]) ? 1 : 0) << c);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     matrix_has_changed = memcmp(current_matrix, oldMatrix, matrixArraySize) != 0;
 | |
|     memcpy(oldMatrix, current_matrix, matrixArraySize);
 | |
| 
 | |
|     if (matrix_has_changed) {
 | |
|         matrix_print();
 | |
|     }
 | |
| 
 | |
| 
 | |
|     // Deactivate all the columns for the next run.
 | |
|     clearColumns();
 | |
|     matrix_io_delay();
 | |
| 
 | |
|     return matrix_has_changed;
 | |
| }
 | 
