qmk_firmware

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

matrix.c (6982B)


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