qmk_firmware

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

matrix.c (4140B)


      1 /*
      2 Copyright 2017 Luiz Ribeiro <luizribeiro@gmail.com>
      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 #define I2C_TIMEOUT     10
     29 #define MCP23018_TWI_ADDRESS 0b0100000
     30 #define TW_READ        1
     31 #define TW_WRITE    0
     32 #define TWI_ADDR_WRITE ( (MCP23018_TWI_ADDRESS<<1) | TW_WRITE )
     33 #define TWI_ADDR_READ  ( (MCP23018_TWI_ADDRESS<<1) | TW_READ  )
     34 #define IODIRA 0x00  // i/o direction register
     35 #define IODIRB 0x01
     36 #define IODIRA 0x00  // i/o direction register
     37 #define IODIRB 0x01
     38 #define GPPUA  0x0C  // GPIO pull-up resistor register
     39 #define GPPUB  0x0D
     40 #define GPIOA  0x12  // general purpose i/o port register (write modifies OLAT)
     41 #define GPIOB  0x13
     42 #define OLATA  0x14  // output latch register
     43 #define OLATB  0x15
     44 #define MCP_ROWS_START    8
     45 
     46 static uint8_t mcp23018_init(void) {
     47     uint8_t ret;
     48     uint8_t data[3];
     49     // set pin direction
     50     // - unused  : input  : 1
     51     // - input   : input  : 1
     52     // - driving : output : 0
     53     data[0] = IODIRA;
     54     data[1] = 0b00000000;  // IODIRA
     55     data[2] = (0b11111111);  // IODIRB
     56 
     57     ret = i2c_transmit(TWI_ADDR_WRITE, (uint8_t *)data, 3, I2C_TIMEOUT);
     58     if (ret) goto out;  // make sure we got an ACK
     59 
     60     // set pull-up
     61     // - unused  : on  : 1
     62     // - input   : on  : 1
     63     // - driving : off : 0
     64     data[0] = GPPUA;
     65     data[1] = 0b00000000;  // IODIRA
     66     data[2] = (0b11111111);  // IODIRB
     67 
     68     ret = i2c_transmit(TWI_ADDR_WRITE, (uint8_t *)data, 3, I2C_TIMEOUT);
     69     if (ret) goto out;  // make sure we got an ACK
     70 
     71     // set logical value (doesn't matter on inputs)
     72     // - unused  : hi-Z : 1
     73     // - input   : hi-Z : 1
     74     // - driving : hi-Z : 1
     75     data[0] = OLATA;
     76     data[1] = 0b11111111;  // IODIRA
     77     data[2] = (0b11111111);  // IODIRB
     78 
     79     ret = i2c_transmit(TWI_ADDR_WRITE, (uint8_t *)data, 3, I2C_TIMEOUT);
     80 
     81 out:
     82     return ret;
     83 }
     84 #endif
     85 
     86 void matrix_init_custom(void) {
     87     // Set rows as output starting high
     88     DDRB = 0xFF;
     89     PORTB = 0xFF;
     90 
     91     // Set columns as inputs with pull-up enabled
     92     DDRA = 0x00;
     93     PORTA = 0xFF;
     94 
     95     // Initialize i2c communication
     96     i2c_init();
     97 
     98 #if defined(RIGHT_HALF)
     99     // Initialize the chip on the other half
    100     mcp23018_init();
    101 #endif
    102 
    103 }
    104 
    105 bool matrix_scan_custom(matrix_row_t current_matrix[]) {
    106     bool matrix_has_changed = false;
    107 
    108     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    109         // Store last value of row prior to reading
    110         matrix_row_t last_row_value = current_matrix[row];
    111 
    112         matrix_row_t cols = 0;
    113 	    // Select the row to scan
    114         matrix_set_row_status(row);
    115 
    116         matrix_io_delay();
    117 	    //Set the local row
    118 
    119 #if defined(RIGHT_HALF)
    120 		// Initialize to 0x7F in case I2C read fails, 
    121 		// as 0x75 would be no keys pressed
    122 		uint8_t data = 0x7F;
    123 		// Receive the columns from right half
    124 		i2c_receive(TWI_ADDR_WRITE, &data, 1, I2C_TIMEOUT);
    125 #endif
    126 
    127         cols |= ((~(PINA | 0x80)) & 0x7F);
    128 #if defined(RIGHT_HALF)
    129 		cols |= (((~(data | 0x80)) & 0x7F) << 7);
    130 #endif
    131 
    132         current_matrix[row] = cols;
    133         matrix_has_changed |= (last_row_value != current_matrix[row]);
    134     }
    135 
    136     return matrix_has_changed;
    137 }
    138 
    139 void matrix_set_row_status(uint8_t row) {
    140 #if defined(RIGHT_HALF)
    141     uint8_t txdata[3];
    142 
    143     //Set the remote row on port A
    144     txdata[0] = (GPIOA);
    145     txdata[1] = ( 0xFF & ~(1<<row) );
    146     i2c_transmit(TWI_ADDR_WRITE, (uint8_t *)txdata, 2, I2C_TIMEOUT);
    147 #endif
    148 
    149     //Set the local row on port B
    150     DDRB = (1 << row);
    151     PORTB = ~(1 << row);
    152 }