qmk_firmware

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

matrix.c (13706B)


      1 /*
      2 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
      3 Copyright 2017 Erin Call <hello@erincall.com>
      4 
      5 This program is free software: you can redistribute it and/or modify
      6 it under the terms of the GNU General Public License as published by
      7 the Free Software Foundation, either version 2 of the License, or
      8 (at your option) any later version.
      9 
     10 This program is distributed in the hope that it will be useful,
     11 but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 */
     18 #include <stdint.h>
     19 #include <stdbool.h>
     20 #include <avr/io.h>
     21 #include "wait.h"
     22 #include "action_layer.h"
     23 #include "print.h"
     24 #include "debug.h"
     25 #include "util.h"
     26 #include "matrix.h"
     27 #include "i2c_master.h"
     28 #include "timer.h"
     29 
     30 #define I2C_TIMEOUT 100
     31 
     32 #define I2C_ADDR        (0b0100000<<1)
     33 #define IODIRA          0x00            // i/o direction register
     34 #define IODIRB          0x01
     35 #define GPPUA           0x0C            // GPIO pull-up resistor register
     36 #define GPPUB           0x0D
     37 #define GPIOA           0x12            // general purpose i/o port register (write modifies OLAT)
     38 #define GPIOB           0x13
     39 
     40 void init_expander(void);
     41 
     42 /* Set 0 if debouncing isn't needed */
     43 
     44 #ifndef DEBOUNCE
     45 #   define DEBOUNCE 5
     46 #endif
     47 
     48 #if (DEBOUNCE > 0)
     49     static uint16_t debouncing_time;
     50     static bool debouncing = false;
     51 #endif
     52 
     53 #ifdef MATRIX_MASKED
     54     extern const matrix_row_t matrix_mask[];
     55 #endif
     56 
     57 #if (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW)
     58 static const uint8_t onboard_row_pins[MATRIX_ROWS] = MATRIX_ONBOARD_ROW_PINS;
     59 static const uint8_t onboard_col_pins[MATRIX_COLS] = MATRIX_ONBOARD_COL_PINS;
     60 static const bool col_expanded[MATRIX_COLS] = COL_EXPANDED;
     61 #endif
     62 
     63 /* matrix state(1:on, 0:off) */
     64 static matrix_row_t matrix[MATRIX_ROWS];
     65 
     66 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
     67 
     68 #if (DIODE_DIRECTION == COL2ROW)
     69     static const uint8_t expander_col_pins[MATRIX_COLS] = MATRIX_EXPANDER_COL_PINS;
     70     static void init_cols(void);
     71     static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
     72     static void unselect_rows(void);
     73     static void select_row(uint8_t row);
     74     static void unselect_row(uint8_t row);
     75 #elif (DIODE_DIRECTION == ROW2COL)
     76     static const uint8_t expander_row_pins[MATRIX_ROWS] = MATRIX_EXPANDER_ROW_PINS;
     77     static void init_rows(void);
     78     static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
     79     static void unselect_cols(void);
     80     static void select_col(uint8_t col);
     81     static void unselect_col(uint8_t col);
     82 #endif
     83 
     84 static uint8_t expander_reset_loop;
     85 uint8_t expander_status;
     86 uint8_t expander_input_pin_mask;
     87 bool i2c_initialized = false;
     88 
     89 #define ROW_SHIFTER ((matrix_row_t)1)
     90 
     91 __attribute__ ((weak))
     92 void matrix_init_user(void) {}
     93 
     94 __attribute__ ((weak))
     95 void matrix_scan_user(void) {}
     96 
     97 __attribute__ ((weak))
     98 void matrix_init_kb(void) {
     99   matrix_init_user();
    100 }
    101 
    102 __attribute__ ((weak))
    103 void matrix_scan_kb(void) {
    104   matrix_scan_user();
    105 }
    106 
    107 inline
    108 uint8_t matrix_rows(void)
    109 {
    110     return MATRIX_ROWS;
    111 }
    112 
    113 inline
    114 uint8_t matrix_cols(void)
    115 {
    116     return MATRIX_COLS;
    117 }
    118 
    119 void matrix_init(void)
    120 {
    121     init_expander();
    122 
    123 #if (DIODE_DIRECTION == COL2ROW)
    124     unselect_rows();
    125     init_cols();
    126 #elif (DIODE_DIRECTION == ROW2COL)
    127     unselect_cols();
    128     init_rows();
    129 #endif
    130 
    131     // initialize matrix state: all keys off
    132     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
    133         matrix[i] = 0;
    134         matrix_debouncing[i] = 0;
    135     }
    136 
    137     matrix_init_kb();
    138 }
    139 
    140 void init_expander(void) {
    141     if (! i2c_initialized) {
    142         i2c_init();
    143         wait_ms(1000);
    144     }
    145 
    146     if (! expander_input_pin_mask) {
    147 #if (DIODE_DIRECTION == COL2ROW)
    148         for (int col = 0; col < MATRIX_COLS; col++) {
    149             if (col_expanded[col]) {
    150                 expander_input_pin_mask |= (1 << expander_col_pins[col]);
    151             }
    152         }
    153 #elif (DIODE_DIRECTION == ROW2COL)
    154         for (int row = 0; row < MATRIX_ROWS; row++) {
    155             expander_input_pin_mask |= (1 << expander_row_pins[row]);
    156         }
    157 #endif
    158     }
    159 
    160     /*
    161     Pin direction and pull-up depends on both the diode direction
    162     and on whether the column register is GPIOA or GPIOB
    163     +-------+---------------+---------------+
    164     |       | ROW2COL       | COL2ROW       |
    165     +-------+---------------+---------------+
    166     | GPIOA | input, output | output, input |
    167     +-------+---------------+---------------+
    168     | GPIOB | output, input | input, output |
    169     +-------+---------------+---------------+
    170     */
    171 
    172 #if (EXPANDER_COL_REGISTER == GPIOA)
    173 #   if (DIODE_DIRECTION == COL2ROW)
    174     uint8_t data[] = { expander_input_pin_mask, 0};
    175 #   elif (DIODE_DIRECTION == ROW2COL)
    176     uint8_t data[] = { 0, expander_input_pin_mask};
    177 #   endif
    178 #elif (EXPANDER_COL_REGISTER == GPIOB)
    179 #   if (DIODE_DIRECTION == COL2ROW)
    180     uint8_t data[] = { 0, expander_input_pin_mask};
    181 #   elif (DIODE_DIRECTION == ROW2COL)
    182     uint8_t data[] = { expander_input_pin_mask, 0};
    183 #   endif
    184 #endif
    185     expander_status = i2c_write_register(I2C_ADDR, IODIRA, data, sizeof(data), I2C_TIMEOUT);
    186 
    187     if (!expander_status) {
    188         // set pull-up
    189         // - unused  : off : 0
    190         // - input   : on  : 1
    191         // - driving : off : 0
    192         expander_status = i2c_write_register(I2C_ADDR, GPPUA, data, sizeof(data), I2C_TIMEOUT);
    193     }
    194 
    195 }
    196 
    197 uint8_t matrix_scan(void)
    198 {
    199     if (expander_status) { // if there was an error
    200         if (++expander_reset_loop == 0) {
    201             // since expander_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
    202             // this will be approx bit more frequent than once per second
    203             print("trying to reset expander\n");
    204             init_expander();
    205             if (expander_status) {
    206                 print("left side not responding\n");
    207             } else {
    208                 print("left side attached\n");
    209             }
    210         }
    211     }
    212 
    213 #if (DIODE_DIRECTION == COL2ROW)
    214     for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
    215 #       if (DEBOUNCE > 0)
    216             bool matrix_changed = read_cols_on_row(matrix_debouncing, current_row);
    217 
    218             if (matrix_changed) {
    219                 debouncing = true;
    220                 debouncing_time = timer_read();
    221             }
    222 #       else
    223             read_cols_on_row(matrix, current_row);
    224 #       endif
    225     }
    226 
    227 #elif (DIODE_DIRECTION == ROW2COL)
    228     for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
    229 #       if (DEBOUNCE > 0)
    230             bool matrix_changed = read_rows_on_col(matrix_debouncing, current_col);
    231 
    232             if (matrix_changed) {
    233                 debouncing = true;
    234                 debouncing_time = timer_read();
    235             }
    236 #       else
    237             read_rows_on_col(matrix, current_col);
    238 #       endif
    239 
    240     }
    241 #endif
    242 
    243 #   if (DEBOUNCE > 0)
    244         if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCE)) {
    245             for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
    246                 matrix[i] = matrix_debouncing[i];
    247             }
    248             debouncing = false;
    249         }
    250 #   endif
    251 
    252     matrix_scan_kb();
    253     return 1;
    254 }
    255 
    256 inline
    257 bool matrix_is_on(uint8_t row, uint8_t col)
    258 {
    259     return (matrix[row] & (ROW_SHIFTER << col));
    260 }
    261 
    262 inline
    263 matrix_row_t matrix_get_row(uint8_t row)
    264 {
    265 #ifdef MATRIX_MASKED
    266     return matrix[row] & matrix_mask[row];
    267 #else
    268     return matrix[row];
    269 #endif
    270 }
    271 
    272 void matrix_print(void)
    273 {
    274     print("\nr/c 0123456789ABCDEF\n");
    275     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    276         print_hex8(row); print(": ");
    277         print_bin_reverse16(matrix_get_row(row));
    278         print("\n");
    279     }
    280 }
    281 
    282 #if (DIODE_DIRECTION == COL2ROW)
    283 
    284 static void init_cols(void) {
    285     for (uint8_t x = 0; x < MATRIX_COLS; x++) {
    286         if (! col_expanded[x]) {
    287             uint8_t pin = onboard_col_pins[x];
    288             _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
    289             _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
    290         }
    291     }
    292 }
    293 
    294 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
    295     // Store last value of row prior to reading
    296     matrix_row_t last_row_value = current_matrix[current_row];
    297 
    298     // Clear data in matrix row
    299     current_matrix[current_row] = 0;
    300 
    301     // Select row and wait for row selection to stabilize
    302     select_row(current_row);
    303     wait_us(30);
    304 
    305     // Read columns from expander, unless it's in an error state
    306     if (! expander_status) {
    307         uint8_t data;
    308         i2c_read_register(I2C_ADDR, EXPANDER_COL_REGISTER, &data, 1, I2C_TIMEOUT);
    309         current_matrix[current_row] |= (~data) & expander_input_pin_mask;
    310     }
    311 
    312     // Read columns from onboard pins
    313     for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
    314         if (! col_expanded[col_index]) {
    315             uint8_t pin = onboard_col_pins[col_index];
    316             uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF));
    317             current_matrix[current_row] |= pin_state ? 0 : (ROW_SHIFTER << col_index);
    318         }
    319     }
    320 
    321     unselect_row(current_row);
    322 
    323     return (last_row_value != current_matrix[current_row]);
    324 }
    325 
    326 static void select_row(uint8_t row) {
    327     // select on expander, unless it's in an error state
    328     if (! expander_status) {
    329         // set active row low  : 0
    330         // set other rows hi-Z : 1
    331         uint8_t data = 0xFF & ~(1<<row);
    332         i2c_write_register(I2C_ADDR, EXPANDER_ROW_REGISTER, &data, 1, I2C_TIMEOUT);
    333     }
    334 
    335     // select on teensy
    336     uint8_t pin = onboard_row_pins[row];
    337     _SFR_IO8((pin >> 4) + 1) |=  _BV(pin & 0xF); // OUT
    338     _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
    339 }
    340 
    341 static void unselect_row(uint8_t row)
    342 {
    343     // No need to explicitly unselect expander pins--their I/O state is
    344     // set simultaneously, with a single bitmask sent to i2c_write. When
    345     // select_row selects a single pin, it implicitly unselects all the
    346     // other ones.
    347 
    348     // unselect on teensy
    349     uint8_t pin = onboard_row_pins[row];
    350     _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // OUT
    351     _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // LOW
    352 }
    353 
    354 static void unselect_rows(void) {
    355     for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
    356         unselect_row(x);
    357     }
    358 }
    359 
    360 #elif (DIODE_DIRECTION == ROW2COL)
    361 
    362 static void init_rows(void)
    363 {
    364     for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
    365         uint8_t pin = onboard_row_pins[x];
    366         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
    367         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
    368     }
    369 }
    370 
    371 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
    372 {
    373     bool matrix_changed = false;
    374 
    375     uint8_t column_state = 0;
    376 
    377     //select col and wait for selection to stabilize
    378     select_col(current_col);
    379     wait_us(30);
    380 
    381     if (current_col < 6) {
    382         // read rows from expander
    383         if (expander_status) {
    384             // it's already in an error state; nothing we can do
    385             return false;
    386         }
    387 
    388         i2c_write_register(I2C_ADDR, EXPANDER_ROW_REGISTER, &column_state, 1, I2C_TIMEOUT);
    389         column_state = ~column_state;
    390     } else {
    391         for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
    392             if ((_SFR_IO8(onboard_row_pins[current_row] >> 4) & _BV(onboard_row_pins[current_row] & 0xF)) == 0) {
    393                 column_state |= (1 << current_row);
    394             }
    395         }
    396     }
    397 
    398     for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
    399         // Store last value of row prior to reading
    400         matrix_row_t last_row_value = current_matrix[current_row];
    401 
    402         if (column_state & (1 << current_row)) {
    403             // key closed; set state bit in matrix
    404             current_matrix[current_row] |= (ROW_SHIFTER << current_col);
    405         } else {
    406             // key open; clear state bit in matrix
    407             current_matrix[current_row] &= ~(ROW_SHIFTER << current_col);
    408         }
    409 
    410         // Determine whether the matrix changed state
    411         if ((last_row_value != current_matrix[current_row]) && !(matrix_changed))
    412         {
    413             matrix_changed = true;
    414         }
    415     }
    416 
    417     unselect_col(current_col);
    418 
    419     return matrix_changed;
    420 }
    421 
    422 static void select_col(uint8_t col)
    423 {
    424     if (col_expanded[col]) {
    425         // select on expander
    426         if (expander_status) { // if there was an error
    427             // do nothing
    428         } else {
    429             // set active col low  : 0
    430             // set other cols hi-Z : 1
    431             expander_status = i2c_start(I2C_ADDR_WRITE);          if (expander_status) goto out;
    432             expander_status = i2c_write(EXPANDER_COL_REGISTER);   if (expander_status) goto out;
    433             expander_status = i2c_write(0xFF & ~(1<<col));        if (expander_status) goto out;
    434         out:
    435             i2c_stop();
    436         }
    437     } else {
    438         // select on teensy
    439         uint8_t pin = onboard_col_pins[col];
    440         _SFR_IO8((pin >> 4) + 1) |=  _BV(pin & 0xF); // OUT
    441         _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
    442     }
    443 }
    444 
    445 static void unselect_col(uint8_t col)
    446 {
    447     if (col_expanded[col]) {
    448         // No need to explicitly unselect expander pins--their I/O state is
    449         // set simultaneously, with a single bitmask sent to i2c_write. When
    450         // select_col selects a single pin, it implicitly unselects all the
    451         // other ones.
    452     } else {
    453         // unselect on teensy
    454         uint8_t pin = onboard_col_pins[col];
    455         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
    456         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
    457     }
    458 }
    459 
    460 static void unselect_cols(void)
    461 {
    462     for(uint8_t x = 0; x < MATRIX_COLS; x++) {
    463         unselect_col(x);
    464     }
    465 }
    466 #endif