qmk_firmware

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

matrix.c (5299B)


      1 /*
      2 Copyright 2021 MajorKoos <github.com/majorkoos>
      3 
      4 This program is free software: you can redistribute it and/or modify
      5 it under the terms of the GNU General Public License as published by
      6 the Free Software Foundation, either version 2 of the License, or
      7 (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 GNU General Public License for more details.
     13 
     14 You should have received a copy of the GNU General Public License
     15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16 */
     17 
     18 #include "matrix.h"
     19 #include "i2c_master.h"
     20 
     21 #define RIGHT_HALF
     22 
     23 
     24 void matrix_set_row_status(uint8_t row);
     25 
     26 
     27 #if defined(RIGHT_HALF)
     28 /* ----------------------- hardware I/O abstraction ------------------------ */
     29 #define PORTCOLUMNS PORTB  ///< port on which we read the state of the columns
     30 #define PINCOLUMNS  PINB   ///< port on which we read the state of the columns
     31 #define DDRCOLUMNS  DDRB   ///< port on which we read the state of the columns
     32 #define PORTROWS1   PORTA  ///< first port connected to the matrix rows
     33 #define PINROWS1    PINA   ///< first port connected to the matrix rows
     34 #define DDRROWS1    DDRA   ///< first port connected to the matrix rows
     35 #define PORTROWS2   PORTC  ///< second port connected to the matrix rows
     36 #define PINROWS2    PINC   ///< second port connected to the matrix rows
     37 #define DDRROWS2    DDRC   ///< second port connected to the matrix rows
     38 
     39 
     40 // register addresses (see "mcp23018.md")
     41 #define IODIRA 0x00  // i/o direction register
     42 #define IODIRB 0x01
     43 #define GPPUA  0x0C  // GPIO pull-up resistor register
     44 #define GPPUB  0x0D
     45 #define GPIOA  0x12  // general purpose i/o port register (write modifies OLAT)
     46 #define GPIOB  0x13
     47 #define OLATA  0x14  // output latch register
     48 #define OLATB  0x15
     49 
     50 #define TW_READ		1
     51 #define TW_WRITE	0
     52 
     53 #define MCP23018_TWI_ADDRESS 0b0100000
     54 
     55 // TWI aliases
     56 #define TWI_ADDR_WRITE ( (MCP23018_TWI_ADDRESS<<1) | TW_WRITE )
     57 #define TWI_ADDR_READ  ( (MCP23018_TWI_ADDRESS<<1) | TW_READ  )
     58 
     59 #define I2C_TIMEOUT     10
     60 #define MCP_ROWS_START	8
     61 
     62 uint8_t mcp23018_init(void) {
     63 	uint8_t ret;
     64 	uint8_t data[3];
     65 	// set pin direction
     66 	// - unused  : input  : 1
     67 	// - input   : input  : 1
     68 	// - driving : output : 0
     69 	data[0] = IODIRA;
     70 	data[1] = 0b00000000;  // IODIRA
     71 	data[2] = (0b11111111);  // IODIRB
     72 
     73 	ret = i2c_transmit(TWI_ADDR_WRITE, (uint8_t *)data, 3, I2C_TIMEOUT);
     74 	if (ret) goto out;  // make sure we got an ACK
     75 	// set pull-up
     76 	// - unused  : on  : 1
     77 	// - input   : on  : 1
     78 	// - driving : off : 0
     79 	data[0] = GPPUA;
     80 	data[1] = 0b00000000;  // IODIRA
     81 	data[2] = (0b11111111);  // IODIRB
     82 
     83 	ret = i2c_transmit(TWI_ADDR_WRITE, (uint8_t *)data, 3, I2C_TIMEOUT);
     84 	if (ret) goto out;  // make sure we got an ACK
     85 
     86 	// set logical value (doesn't matter on inputs)
     87 	// - unused  : hi-Z : 1
     88 	// - input   : hi-Z : 1
     89 	// - driving : hi-Z : 1
     90 	data[0] = OLATA;
     91 	data[1] = 0b11111111;  // IODIRA
     92 	data[2] = (0b11111111);  // IODIRB
     93 
     94 	ret = i2c_transmit(TWI_ADDR_WRITE, (uint8_t *)data, 3, I2C_TIMEOUT);
     95 out:
     96 	return ret;
     97 }
     98 #endif
     99 
    100 void matrix_init_custom(void) {
    101     // initialize matrix ports - cols, rows
    102 	// PB0-PB7 : col0 .. col7
    103 	// PA0-PA7 : row0 .. row7
    104 	// PC7-PC2 : row8 .. row13
    105 
    106 	// PD0 : NUM
    107     // PD1 : CAPS
    108     // PD2 : D+ / Clock
    109     // PD3 : D- / Data
    110     // PD4 : FULL LED
    111     // PD5 : 3.6V switch TR
    112 	// PD6 : SCRL
    113     // PD7 : row14
    114 
    115 
    116 	// signal direction : col -> row
    117 
    118     // pc(PORTROWS1)0, 1 : twi
    119 	DDRCOLUMNS 	= 0xFF;	// all outputs for cols
    120 	PORTCOLUMNS	= 0xFF;	// high
    121 
    122 	// all inputs for rows
    123 	DDRROWS1	= 0x00;
    124 	DDRROWS2	&= ~(0x111111<<2); //0x00;
    125 	DDRD        &= ~(1<<PIND7); // row 14
    126 
    127 	// all rows pull-up.
    128 	PORTROWS1	= 0xFF;
    129 	PORTROWS2	|= (0b111111<<2); //0x11111100;
    130 	PORTD 		|= (1<<PIND7);// row 14
    131 
    132     i2c_init();
    133 
    134 #if defined(RIGHT_HALF)
    135     // Initialize the chip on the other half
    136     mcp23018_init();
    137 #endif
    138 
    139 }
    140 
    141 bool matrix_scan_custom(matrix_row_t current_matrix[]) {
    142     bool matrix_has_changed = false;
    143 
    144     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    145         // Store last value of row prior to reading
    146         matrix_row_t last_row_value = current_matrix[row];
    147 
    148         matrix_row_t cols = 0;
    149 	    // Select the row to scan
    150         matrix_set_row_status(row);
    151 
    152         matrix_io_delay();
    153 	    //Set the local row
    154 
    155 #if defined(RIGHT_HALF)
    156 		// Initialize to 0x7F in case I2C read fails,
    157 		// as 0x75 would be no keys pressed
    158 		uint8_t data = 0x7F;
    159 		// Receive the columns from right half
    160 		i2c_receive(TWI_ADDR_WRITE, &data, 1, I2C_TIMEOUT);
    161 #endif
    162 
    163         // cols |= ((~(PINA | 0x80)) & 0x7F);
    164         cols |= ((~(PINA)) & 0xFF);
    165 #if defined(RIGHT_HALF)
    166 		cols |= (((~(data | 0x80)) & 0x7F) << MCP_ROWS_START);
    167 #endif
    168 
    169         current_matrix[row] = cols;
    170         matrix_has_changed |= (last_row_value != current_matrix[row]);
    171     }
    172 
    173     return matrix_has_changed;
    174 }
    175 
    176 void matrix_set_row_status(uint8_t row) {
    177 #if defined(RIGHT_HALF)
    178     uint8_t txdata[3];
    179 
    180     //Set the remote row on port A
    181     txdata[0] = (GPIOA);
    182     txdata[1] = ( 0xFF & ~(1<<row) );
    183     i2c_transmit(TWI_ADDR_WRITE, (uint8_t *)txdata, 2, I2C_TIMEOUT);
    184 #endif
    185 
    186     //Set the local row on port B
    187     DDRB = (1 << row);
    188     PORTB = ~(1 << row);
    189 }