qmk_firmware

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

matrix.c (6980B)


      1 /*
      2 Copyright 2012 Jun Wako <wakojun@gmail.com>
      3 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
      4 Copyright 2015 ZSA Technology Labs Inc (@zsa)
      5 Copyright 2020 Christopher Courtney <drashna@live.com> (@drashna)
      6 
      7 This program is free software: you can redistribute it and/or modify
      8 it under the terms of the GNU General Public License as published by
      9 the Free Software Foundation, either version 2 of the License, or
     10 (at your option) any later version.
     11 
     12 This program is distributed in the hope that it will be useful,
     13 but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with this program.  If not, see <http://www.gnu.org/licenses/>.
     19 */
     20 
     21 
     22 /*
     23  * scan matrix
     24  */
     25 #include <stdint.h>
     26 #include <stdbool.h>
     27 #include <avr/io.h>
     28 #include "wait.h"
     29 #include "action_layer.h"
     30 #include "print.h"
     31 #include "debug.h"
     32 #include "util.h"
     33 #include "matrix.h"
     34 #include "debounce.h"
     35 #include "ergodox_ez.h"
     36 
     37 
     38 /*
     39  * This constant define not debouncing time in msecs, assuming eager_pr.
     40  *
     41  * On Ergodox matrix scan rate is relatively low, because of slow I2C.
     42  * Now it's only 317 scans/second, or about 3.15 msec/scan.
     43  * According to Cherry specs, debouncing time is 5 msec.
     44  *
     45  * However, some switches seem to have higher debouncing requirements, or
     46  * something else might be wrong. (Also, the scan speed has improved since
     47  * that comment was written.)
     48  */
     49 
     50 /* matrix state(1:on, 0:off) */
     51 extern matrix_row_t matrix[MATRIX_ROWS];      // debounced values
     52 extern matrix_row_t raw_matrix[MATRIX_ROWS];  // raw values
     53 
     54 static matrix_row_t read_cols(uint8_t row);
     55 static void         init_cols(void);
     56 static void         unselect_rows(void);
     57 static void         select_row(uint8_t row);
     58 
     59 static uint8_t mcp23018_reset_loop;
     60 
     61 void matrix_init_custom(void) {
     62     // initialize row and col
     63 
     64     mcp23018_status = init_mcp23018();
     65 
     66     unselect_rows();
     67     init_cols();
     68 }
     69 
     70 // Reads and stores a row, returning
     71 // whether a change occurred.
     72 static inline bool store_raw_matrix_row(uint8_t index) {
     73     matrix_row_t temp = 0x3F & read_cols(index);
     74     if (raw_matrix[index] != temp) {
     75         raw_matrix[index] = temp;
     76         return true;
     77     }
     78     return false;
     79 }
     80 
     81 bool matrix_scan_custom(matrix_row_t current_matrix[]) {
     82     if (mcp23018_status) {  // if there was an error
     83         if (++mcp23018_reset_loop == 0) {
     84             print("trying to reset mcp23018\n");
     85             mcp23018_status = init_mcp23018();
     86             if (mcp23018_status) {
     87                 print("left side not responding\n");
     88             } else {
     89                 print("left side attached\n");
     90                 ergodox_blink_all_leds();
     91 #ifdef RGB_MATRIX_ENABLE
     92                 rgb_matrix_init();  // re-init driver on reconnect
     93 #endif
     94             }
     95         }
     96     }
     97 
     98 #ifdef LEFT_LEDS
     99     mcp23018_status = ergodox_left_leds_update();
    100 #endif  // LEFT_LEDS
    101     bool changed = false;
    102     for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
    103         // select rows from left and right hands
    104         uint8_t left_index  = i;
    105         uint8_t right_index = i + MATRIX_ROWS_PER_SIDE;
    106         select_row(left_index);
    107         select_row(right_index);
    108 
    109         changed |= store_raw_matrix_row(left_index);
    110         changed |= store_raw_matrix_row(right_index);
    111 
    112         unselect_rows();
    113     }
    114 
    115     return changed;
    116 }
    117 
    118 /* Column pin configuration
    119  *
    120  * Teensy
    121  * col: 0   1   2   3   4   5
    122  * pin: F0  F1  F4  F5  F6  F7
    123  *
    124  * MCP23018
    125  * col: 0   1   2   3   4   5
    126  * pin: B5  B4  B3  B2  B1  B0
    127  */
    128 static void init_cols(void) {
    129     // init on mcp23018
    130     // not needed, already done as part of init_mcp23018()
    131 
    132     // init on teensy
    133     gpio_set_pin_input_high(F0);
    134     gpio_set_pin_input_high(F1);
    135     gpio_set_pin_input_high(F4);
    136     gpio_set_pin_input_high(F5);
    137     gpio_set_pin_input_high(F6);
    138     gpio_set_pin_input_high(F7);
    139 }
    140 
    141 static matrix_row_t read_cols(uint8_t row) {
    142     if (row < 7) {
    143         if (mcp23018_status) {  // if there was an error
    144             return 0;
    145         } else {
    146             uint8_t data = 0;
    147             // reading GPIOB (column port) since in mcp23018's sequential mode
    148             // it is addressed directly after writing to GPIOA in select_row()
    149             mcp23018_status = i2c_receive(I2C_ADDR, &data, 1, ERGODOX_EZ_I2C_TIMEOUT);
    150             return ~data;
    151         }
    152     } else {
    153         /* read from teensy
    154          * bitmask is 0b11110011, but we want those all
    155          * in the lower six bits.
    156          * we'll return 1s for the top two, but that's harmless.
    157          */
    158 
    159         return ~((PINF & 0x03) | ((PINF & 0xF0) >> 2));
    160     }
    161 }
    162 
    163 /* Row pin configuration
    164  *
    165  * Teensy
    166  * row: 7   8   9   10  11  12  13
    167  * pin: B0  B1  B2  B3  D2  D3  C6
    168  *
    169  * MCP23018
    170  * row: 0   1   2   3   4   5   6
    171  * pin: A0  A1  A2  A3  A4  A5  A6
    172  */
    173 static void unselect_rows(void) {
    174     // no need to unselect on mcp23018, because the select step sets all
    175     // the other row bits high, and it's not changing to a different
    176     // direction
    177 
    178     // unselect on teensy
    179     gpio_set_pin_input(B0);
    180     gpio_set_pin_input(B1);
    181     gpio_set_pin_input(B2);
    182     gpio_set_pin_input(B3);
    183     gpio_set_pin_input(D2);
    184     gpio_set_pin_input(D3);
    185     gpio_set_pin_input(C6);
    186 }
    187 
    188 static void select_row(uint8_t row) {
    189     if (row < 7) {
    190         // select on mcp23018
    191         if (!mcp23018_status) {
    192             // set active row low  : 0
    193             // set other rows hi-Z : 1
    194             uint8_t data;
    195             data = 0xFF & ~(1 << row);
    196             mcp23018_status = i2c_write_register(I2C_ADDR, GPIOA, &data, 1, ERGODOX_EZ_I2C_TIMEOUT);
    197         }
    198     } else {
    199         // select on teensy
    200         // Output low(DDR:1, PORT:0) to select
    201         switch (row) {
    202             case 7:
    203                 gpio_set_pin_output(B0);
    204                 gpio_write_pin_low(B0);
    205                 break;
    206             case 8:
    207                 gpio_set_pin_output(B1);
    208                 gpio_write_pin_low(B1);
    209                 break;
    210             case 9:
    211                 gpio_set_pin_output(B2);
    212                 gpio_write_pin_low(B2);
    213                 break;
    214             case 10:
    215                 gpio_set_pin_output(B3);
    216                 gpio_write_pin_low(B3);
    217                 break;
    218             case 11:
    219                 gpio_set_pin_output(D2);
    220                 gpio_write_pin_low(D2);
    221                 break;
    222             case 12:
    223                 gpio_set_pin_output(D3);
    224                 gpio_write_pin_low(D3);
    225                 break;
    226             case 13:
    227                 gpio_set_pin_output(C6);
    228                 gpio_write_pin_low(C6);
    229                 break;
    230         }
    231     }
    232 }
    233 
    234 // DO NOT REMOVE
    235 // Needed for proper wake/sleep
    236 void matrix_power_up(void) {
    237     mcp23018_status = init_mcp23018();
    238 
    239     unselect_rows();
    240     init_cols();
    241 
    242     // initialize matrix state: all keys off
    243     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
    244         matrix[i] = 0;
    245     }
    246 
    247 }