qmk_firmware

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

matrix.c (13877B)


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