qmk_firmware

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

matrix.c (9195B)


      1 /*
      2 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
      3           2020 Pierre Chevalier <pierrechevalier83@gmail.com>
      4           2021 weteor
      5 
      6 This program is free software: you can redistribute it and/or modify
      7 it under the terms of the GNU General Public License as published by
      8 the Free Software Foundation, either version 2 of the License, or
      9 (at your option) any later version.
     10 
     11 This program is distributed in the hope that it will be useful,
     12 but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 GNU General Public License for more details.
     15 
     16 You should have received a copy of the GNU General Public License
     17 along with this program.  If not, see <http://www.gnu.org/licenses/>.
     18 */
     19 
     20 /*
     21  * This code was heavily inspired by the ergodox_ez keymap, and modernized
     22  * to take advantage of the quantum.h microcontroller agnostics gpio control
     23  * abstractions and use the macros defined in config.h for the wiring as opposed
     24  * to repeating that information all over the place.
     25  */
     26 
     27 #include "matrix.h"
     28 #include "debug.h"
     29 #include "wait.h"
     30 #include "i2c_master.h"
     31 
     32 extern i2c_status_t tca9555_status;
     33 #define I2C_TIMEOUT 1000
     34 
     35 // I2C address:
     36 // All address pins of the tca9555 are connected to the ground
     37 // | 0  | 1  | 0  | 0  | A2 | A1 | A0 |
     38 // | 0  | 1  | 0  | 0  | 0  | 0  | 0  |
     39 #define I2C_ADDR (0b0100000 << 1)
     40 
     41 // Register addresses
     42 #define IODIRA 0x06  // i/o direction register
     43 #define IODIRB 0x07
     44 #define IREGP0 0x00  // GPIO pull-up resistor register
     45 #define IREGP1 0x01
     46 #define OREGP0 0x02  // general purpose i/o port register (write modifies OLAT)
     47 #define OREGP1 0x03
     48 
     49 bool         i2c_initialized = 0;
     50 i2c_status_t tca9555_status = I2C_ADDR;
     51 
     52 uint8_t init_tca9555(void) {
     53     print("starting init");
     54     tca9555_status = I2C_ADDR;
     55 
     56     // I2C subsystem
     57     if (i2c_initialized == 0) {
     58         i2c_init();  // on pins D(1,0)
     59         i2c_initialized = true;
     60         wait_ms(I2C_TIMEOUT);
     61     }
     62 
     63     // set pin direction
     64     // - unused  : input  : 1
     65     // - input   : input  : 1
     66     // - driving : output : 0
     67     uint8_t conf[2] = {
     68         // This means: write on pin 5 of port 0, read on rest
     69         0b11011111,
     70         // This means: we will write on pins 0 to 2 on port 1. read rest
     71         0b11111000,
     72     };
     73     tca9555_status = i2c_write_register(I2C_ADDR, IODIRA, conf, 2, I2C_TIMEOUT);
     74 
     75     return tca9555_status;
     76 }
     77 
     78 /* matrix state(1:on, 0:off) */
     79 static matrix_row_t matrix[MATRIX_ROWS];      // debounced values
     80 
     81 static matrix_row_t read_cols(uint8_t row);
     82 static void         init_cols(void);
     83 static void         unselect_rows(void);
     84 static void         select_row(uint8_t row);
     85 
     86 static uint8_t tca9555_reset_loop;
     87 
     88 void matrix_init_custom(void) {
     89     // initialize row and col
     90 
     91     tca9555_status = init_tca9555();
     92 
     93     unselect_rows();
     94     init_cols();
     95 
     96     // initialize matrix state: all keys off
     97     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
     98         matrix[i]     = 0;
     99     }
    100 }
    101 
    102 void matrix_power_up(void) {
    103     tca9555_status = init_tca9555();
    104 
    105     unselect_rows();
    106     init_cols();
    107 
    108     // initialize matrix state: all keys off
    109     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
    110         matrix[i] = 0;
    111     }
    112 }
    113 
    114 // Reads and stores a row, returning
    115 // whether a change occurred.
    116 static inline bool store_matrix_row(matrix_row_t current_matrix[], uint8_t index) {
    117     matrix_row_t temp = read_cols(index);
    118     if (current_matrix[index] != temp) {
    119         current_matrix[index] = temp;
    120         return true;
    121     }
    122     return false;
    123 }
    124 
    125 bool matrix_scan_custom(matrix_row_t current_matrix[]) {
    126     if (tca9555_status) {  // if there was an error
    127         if (++tca9555_reset_loop == 0) {
    128             // since tca9555_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
    129             // this will be approx bit more frequent than once per second
    130             dprint("trying to reset tca9555\n");
    131             tca9555_status = init_tca9555();
    132             if (tca9555_status) {
    133                 dprint("right side not responding\n");
    134             } else {
    135                 dprint("right side attached\n");
    136             }
    137         }
    138     }
    139 
    140     bool changed = false;
    141     for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
    142         // select rows from left and right hands
    143         uint8_t left_index  = i;
    144         uint8_t right_index = i + MATRIX_ROWS_PER_SIDE;
    145         select_row(left_index);
    146         select_row(right_index);
    147 
    148         // we don't need a 30us delay anymore, because selecting a
    149         // left-hand row requires more than 30us for i2c.
    150 
    151         changed |= store_matrix_row(current_matrix, left_index);
    152         changed |= store_matrix_row(current_matrix, right_index);
    153 
    154         unselect_rows();
    155     }
    156 
    157     return changed;
    158 }
    159 
    160 static void init_cols(void) {
    161     // init on tca9555
    162     // not needed, already done as part of init_tca9555()
    163 
    164     // init on mcu
    165     pin_t matrix_col_pins_mcu[MATRIX_COLS_PER_SIDE] = MATRIX_COL_PINS_L;
    166     for (int pin_index = 0; pin_index < MATRIX_COLS_PER_SIDE; pin_index++) {
    167         pin_t pin = matrix_col_pins_mcu[pin_index];
    168         gpio_set_pin_input(pin);
    169         gpio_write_pin_high(pin);
    170     }
    171 }
    172 
    173 static matrix_row_t read_cols(uint8_t row) {
    174     if (row < MATRIX_ROWS_PER_SIDE) {
    175         pin_t        matrix_col_pins_mcu[MATRIX_COLS_PER_SIDE] = MATRIX_COL_PINS_L;
    176         matrix_row_t current_row_value                         = 0;
    177         // For each col...
    178         for (uint8_t col_index = 0; col_index < MATRIX_COLS_PER_SIDE; col_index++) {
    179             // Select the col pin to read (active low)
    180             uint8_t pin_state = gpio_read_pin(matrix_col_pins_mcu[col_index]);
    181 
    182             // Populate the matrix row with the state of the col pin
    183             current_row_value |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index);
    184         }
    185         return current_row_value;
    186     } else {
    187         if (tca9555_status) {  // if there was an error
    188             return 0;
    189         } else {
    190             uint8_t data     = 0;
    191             uint8_t ports[2] = {0};
    192             tca9555_status = i2c_read_register(I2C_ADDR, IREGP0, ports, 2, I2C_TIMEOUT);
    193             if (tca9555_status) {  // if there was an error
    194                 // do nothing
    195                 return 0;
    196             } else {
    197                 uint8_t port0 = ports[0];
    198                 uint8_t port1 = ports[1];
    199 
    200                 // The initial state was all ones and any depressed key at a given column for the currently selected row will have its bit flipped to zero.
    201                 // The return value is a row as represented in the generic matrix code were the rightmost bits represent the lower columns and zeroes represent non-depressed keys while ones represent depressed keys.
    202                 // Since the pins are not ordered sequentially, we have to build the correct dataset from the two ports. Refer to the schematic to see where every pin is connected.
    203                 data |= ( port0 & 0x01 ); 
    204                 data |= ( port0 & 0x02 ); 
    205                 data |= ( port1 & 0x10 ) >> 2; 
    206                 data |= ( port1 & 0x08 ); 
    207                 data |= ( port0 & 0x40 ) >> 2; 
    208                 data = ~(data);
    209 
    210                 tca9555_status = I2C_STATUS_SUCCESS;
    211                 return data;
    212             }
    213         }
    214     }
    215 }
    216 
    217 static void unselect_rows(void) {
    218     // no need to unselect on tca9555, because the select step sets all
    219     // the other row bits high, and it's not changing to a different
    220     // direction
    221 
    222     // unselect rows on microcontroller
    223     pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_L;
    224     for (int pin_index = 0; pin_index < MATRIX_ROWS_PER_SIDE; pin_index++) {
    225         pin_t pin = matrix_row_pins_mcu[pin_index];
    226         gpio_set_pin_input(pin);
    227         gpio_write_pin_low(pin);
    228     }
    229 }
    230 
    231 static void select_row(uint8_t row) {
    232     uint8_t port0 = 0xff;
    233     uint8_t port1 = 0xff;
    234 
    235     if (row < MATRIX_ROWS_PER_SIDE) {
    236         // select on atmega32u4
    237         pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_L;
    238         pin_t pin                                       = matrix_row_pins_mcu[row];
    239         gpio_set_pin_output(pin);
    240         gpio_write_pin_low(pin);
    241     } else {
    242         // select on tca9555
    243         if (tca9555_status) {  // if there was an error
    244                                 // do nothing
    245         } else {
    246             switch(row) {
    247                 case 4: port1 &= ~(1 << 0); break;
    248                 case 5: port1 &= ~(1 << 1); break;
    249                 case 6: port1 &= ~(1 << 2); break;
    250                 case 7: port0 &= ~(1 << 5); break;
    251                 default:                    break;
    252             }
    253 
    254             uint8_t ports[2] = {port0, port1};
    255             tca9555_status = i2c_write_register(I2C_ADDR, OREGP0, ports, 2, I2C_TIMEOUT);
    256             // Select the desired row by writing a byte for the entire GPIOB bus where only the bit representing the row we want to select is a zero (write instruction) and every other bit is a one.
    257             // Note that the row - MATRIX_ROWS_PER_SIDE reflects the fact that being on the right hand, the columns are numbered from MATRIX_ROWS_PER_SIDE to MATRIX_ROWS, but the pins we want to write to are indexed from zero up on the GPIOB bus.
    258         }
    259     }
    260 }