qmk_firmware

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

matrix.c (8461B)


      1 /*
      2 
      3 Note to self: adapted from ergodox EZ matrix
      4 The "column" and "row" in here actually refers to the opposite on the keyboard
      5 see definition of KEYMAP in v1.h, the grid is transposed so that a "row" in here is actually a "column" on the physical keyboard
      6 Nicolas
      7 
      8 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
      9 Copyright 2013 Nicolas Poirey <nicolas.poirey@gmail.com>
     10 
     11 This program is free software: you can redistribute it and/or modify
     12 it under the terms of the GNU General Public License as published by
     13 the Free Software Foundation, either version 2 of the License, or
     14 (at your option) any later version.
     15 
     16 This program is distributed in the hope that it will be useful,
     17 but WITHOUT ANY WARRANTY; without even the implied warranty of
     18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     19 GNU General Public License for more details.
     20 
     21 You should have received a copy of the GNU General Public License
     22 along with this program.  If not, see <http://www.gnu.org/licenses/>.
     23 */
     24 
     25 /*
     26  * scan matrix
     27  */
     28 #include <stdint.h>
     29 #include <stdbool.h>
     30 #include <avr/io.h>
     31 #include "wait.h"
     32 #include "action_layer.h"
     33 #include "print.h"
     34 #include "debug.h"
     35 #include "util.h"
     36 #include "matrix.h"
     37 #include "frenchdev.h"
     38 
     39 /*
     40  * This constant define not debouncing time in msecs, but amount of matrix
     41  * scan loops which should be made to get stable debounced results.
     42  *
     43  * On Ergodox matrix scan rate is relatively low, because of slow I2C.
     44  * Now it's only 317 scans/second, or about 3.15 msec/scan.
     45  * According to Cherry specs, debouncing time is 5 msec.
     46  *
     47  * And so, there is no sense to have DEBOUNCE higher than 2.
     48  */
     49 
     50 #ifndef DEBOUNCE
     51 #   define DEBOUNCE	5
     52 #endif
     53 static uint8_t debouncing = DEBOUNCE;
     54 
     55 /* matrix state(1:on, 0:off) */
     56 static matrix_row_t matrix[MATRIX_ROWS];
     57 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
     58 
     59 static matrix_row_t read_cols(uint8_t row);
     60 static void init_cols(void);
     61 static void unselect_rows(void);
     62 static void select_row(uint8_t row);
     63 
     64 static uint8_t mcp23018_reset_loop;
     65 
     66 __attribute__ ((weak))
     67 void matrix_init_user(void) {}
     68 
     69 __attribute__ ((weak))
     70 void matrix_scan_user(void) {}
     71 
     72 __attribute__ ((weak))
     73 void matrix_init_kb(void) {
     74   matrix_init_user();
     75 }
     76 
     77 __attribute__ ((weak))
     78 void matrix_scan_kb(void) {
     79   matrix_scan_user();
     80 }
     81 
     82 inline
     83 uint8_t matrix_rows(void)
     84 {
     85     return MATRIX_ROWS;
     86 }
     87 
     88 inline
     89 uint8_t matrix_cols(void)
     90 {
     91     return MATRIX_COLS;
     92 }
     93 
     94 void matrix_init(void)
     95 {
     96     // initialize row and col
     97     debug_enable = true;
     98     debug_matrix = true;
     99     debug_keyboard = true;
    100     debug_mouse = true;
    101 
    102     mcp23018_status = init_mcp23018();
    103 
    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         matrix_debouncing[i] = 0;
    112     }
    113 
    114     matrix_init_kb();
    115 }
    116 
    117 void matrix_power_up(void) {
    118     mcp23018_status = init_mcp23018();
    119 
    120     unselect_rows();
    121     init_cols();
    122 
    123     // initialize matrix state: all keys off
    124     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
    125         matrix[i] = 0;
    126         matrix_debouncing[i] = 0;
    127     }
    128 }
    129 
    130 uint8_t matrix_scan(void)
    131 {
    132     if (mcp23018_status) { // if there was an error
    133         if (++mcp23018_reset_loop == 0) {
    134             // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
    135             // this will be approx bit more frequent than once per second
    136             print("trying to reset mcp23018\n");
    137             mcp23018_status = init_mcp23018();
    138             if (mcp23018_status) {
    139                 print("left side not responding\n");
    140             } else {
    141                 print("left side attached\n");
    142                 frenchdev_blink_all_leds();
    143             }
    144         }
    145     }
    146 
    147     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
    148         select_row(i);
    149         wait_us(30);  // without this wait read unstable value.
    150         matrix_row_t cols = read_cols(i);
    151         if (matrix_debouncing[i] != cols) {
    152             matrix_debouncing[i] = cols;
    153             if (debouncing) {
    154                 dprintf("bounce!: %02X\n", debouncing);
    155             }
    156             debouncing = DEBOUNCE;
    157         }
    158         unselect_rows();
    159     }
    160 
    161     if (debouncing) {
    162         if (--debouncing) {
    163             wait_us(1);
    164             // this should be wait_ms(1) but has been left as-is at EZ's request
    165         } else {
    166             for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
    167                 matrix[i] = matrix_debouncing[i];
    168             }
    169         }
    170     }
    171 
    172     matrix_scan_kb();
    173 
    174     return 1;
    175 }
    176 
    177 inline
    178 bool matrix_is_on(uint8_t row, uint8_t col)
    179 {
    180     return (matrix[row] & ((matrix_row_t)1<<col));
    181 }
    182 
    183 inline
    184 matrix_row_t matrix_get_row(uint8_t row)
    185 {
    186     return matrix[row];
    187 }
    188 
    189 void matrix_print(void)
    190 {
    191     print("\nr/c 0123456789ABCDEF\n");
    192     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    193         print_hex8(row); print(": ");
    194         print_bin_reverse16(matrix_get_row(row));
    195         print("\n");
    196     }
    197 }
    198 
    199 /* Column pin configuration
    200  *
    201  * Teensy
    202  * col: 0   1   2   3   4   5
    203  * pin: F0  F1  F4  F5  F6  F7
    204  *
    205  * MCP23018
    206  * col: 0   1   2   3   4   5
    207  * pin: B5  B4  B3  B2  B1  B0
    208  */
    209 static void  init_cols(void)
    210 {
    211     // init on mcp23018
    212     // not needed, already done as part of init_mcp23018()
    213 
    214     // init on teensy
    215     // Input with pull-up(DDR:0, PORT:1)
    216     gpio_set_pin_input_high(F0);
    217     gpio_set_pin_input_high(F1);
    218     gpio_set_pin_input_high(F4);
    219     gpio_set_pin_input_high(F5);
    220     gpio_set_pin_input_high(F6);
    221     gpio_set_pin_input_high(F7);
    222 }
    223 
    224 static matrix_row_t read_cols(uint8_t row)
    225 {
    226     if (row < 8) {
    227         if (mcp23018_status) { // if there was an error
    228             return 0;
    229         } else {
    230             uint8_t data = 0;
    231             mcp23018_status = i2c_read_register(I2C_ADDR, GPIOB, &data, 1, I2C_TIMEOUT);
    232 
    233             return ~data;
    234         }
    235     } else {
    236         // read from teensy
    237         return
    238             (PINF&(1<<0) ? 0 : (1<<0)) |
    239             (PINF&(1<<1) ? 0 : (1<<1)) |
    240             (PINF&(1<<4) ? 0 : (1<<2)) |
    241             (PINF&(1<<5) ? 0 : (1<<3)) |
    242             (PINF&(1<<6) ? 0 : (1<<4)) |
    243             (PINF&(1<<7) ? 0 : (1<<5)) ;
    244     }
    245 }
    246 
    247 /* Row pin configuration
    248  *
    249  * Teensy
    250  * row: 7   8   9   10  11  12  13
    251  * pin: B0  B1  B2  B3  D2  D3  C6
    252  *
    253  * MCP23018
    254  * row: 0   1   2   3   4   5   6
    255  * pin: A0  A1  A2  A3  A4  A5  A6
    256  */
    257 static void unselect_rows(void)
    258 {
    259     // unselect on mcp23018
    260     if (mcp23018_status) { // if there was an error
    261         // do nothing
    262     } else {
    263         // set all rows hi-Z : 1
    264         uint8_t data;
    265         data = 0xFF & ~(0<<8);
    266         mcp23018_status = i2c_write_register(I2C_ADDR, GPIOA, &data, 1, I2C_TIMEOUT);
    267 
    268     }
    269 
    270     // unselect on teensy
    271     // Hi-Z(DDR:0, PORT:0) to unselect
    272     gpio_set_pin_input(B0);
    273     gpio_set_pin_input(B1);
    274     gpio_set_pin_input(B2);
    275     gpio_set_pin_input(B3);
    276     gpio_set_pin_input(D2);
    277     gpio_set_pin_input(D3);
    278     gpio_set_pin_input(C6);
    279     gpio_set_pin_input(C7);
    280 }
    281 
    282 static void select_row(uint8_t row)
    283 {
    284     if (row < 8) {
    285         // select on mcp23018
    286         if (mcp23018_status) { // if there was an error
    287             // do nothing
    288         } else {
    289             // set active row low  : 0
    290             // set other rows hi-Z : 1
    291             uint8_t data = 0xFF & ~(1<<row) & ~(0<<8);
    292             mcp23018_status = i2c_write_register(I2C_ADDR, GPIOA, &data, 1, I2C_TIMEOUT);
    293         }
    294     } else {
    295         // select on teensy
    296         // Output low(DDR:1, PORT:0) to select
    297         switch (row) {
    298             case 8:
    299                 gpio_set_pin_output(B0);
    300                 gpio_write_pin_low(B0);
    301                 break;
    302             case 9:
    303                 gpio_set_pin_output(B1);
    304                 gpio_write_pin_low(B1);
    305                 break;
    306             case 10:
    307                 gpio_set_pin_output(B2);
    308                 gpio_write_pin_low(B2);
    309                 break;
    310             case 11:
    311                 gpio_set_pin_output(B3);
    312                 gpio_write_pin_low(B3);
    313                 break;
    314             case 12:
    315                 gpio_set_pin_output(D2);
    316                 gpio_write_pin_low(D2);
    317                 break;
    318             case 13:
    319                 gpio_set_pin_output(D3);
    320                 gpio_write_pin_low(D3);
    321                 break;
    322             case 14:
    323                 gpio_set_pin_output(C6);
    324                 gpio_write_pin_low(C6);
    325                 break;
    326             case 15:
    327                 gpio_set_pin_output(C7);
    328                 gpio_write_pin_low(C7);
    329                 break;
    330         }
    331     }
    332 }