qmk_firmware

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

matrix.c (8352B)


      1 /* Copyright 2018 Evy Dekkers
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 2 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     15  */
     16 #include <stdint.h>
     17 #include <stdbool.h>
     18 #if defined(__AVR__)
     19 #include <avr/io.h>
     20 #endif
     21 #include "wait.h"
     22 #include "print.h"
     23 #include "debug.h"
     24 #include "util.h"
     25 #include "matrix.h"
     26 #include "timer.h"
     27 
     28 
     29 /* Set 0 if debouncing isn't needed */
     30 #ifndef DEBOUNCE
     31 #   define DEBOUNCE 5
     32 #endif
     33 
     34 #define COL_SHIFTER ((uint32_t)1)
     35 
     36 static uint16_t debouncing_time;
     37 static bool debouncing = false;
     38 
     39 
     40 static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
     41 
     42 /* matrix state(1:on, 0:off) */
     43 static matrix_row_t matrix[MATRIX_ROWS];
     44 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
     45 
     46 static void init_rows(void);
     47 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
     48 static void unselect_cols(void);
     49 static void select_col(uint8_t col);
     50 
     51 __attribute__ ((weak))
     52 void matrix_init_user(void) {}
     53 
     54 __attribute__ ((weak))
     55 void matrix_scan_user(void) {}
     56 
     57 __attribute__ ((weak))
     58 void matrix_init_kb(void) {
     59   matrix_init_user();
     60 }
     61 
     62 __attribute__ ((weak))
     63 void matrix_scan_kb(void) {
     64   matrix_scan_user();
     65 }
     66 
     67 inline
     68 uint8_t matrix_rows(void) {
     69     return MATRIX_ROWS;
     70 }
     71 
     72 inline
     73 uint8_t matrix_cols(void) {
     74     return MATRIX_COLS;
     75 }
     76 
     77 void matrix_init(void) {
     78     unselect_cols();
     79     init_rows();
     80 
     81     // initialize matrix state: all keys off
     82     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
     83         matrix[i] = 0;
     84         matrix_debouncing[i] = 0;
     85     }
     86 
     87     matrix_init_kb();
     88 }
     89 
     90 uint8_t matrix_scan(void)
     91 {
     92     // Set col, read rows
     93     for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
     94         bool matrix_changed = read_rows_on_col(matrix_debouncing, current_col);
     95         if (matrix_changed) {
     96             debouncing = true;
     97             debouncing_time = timer_read();
     98         }
     99     }
    100 
    101     if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCE)) {
    102         for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
    103             matrix[i] = matrix_debouncing[i];
    104         }
    105         debouncing = false;
    106     }
    107 
    108     matrix_scan_kb();
    109     return 1;
    110 }
    111 
    112 inline
    113 bool matrix_is_on(uint8_t row, uint8_t col)
    114 {
    115     return (matrix[row] & ((matrix_row_t)1<<col));
    116 }
    117 
    118 inline
    119 matrix_row_t matrix_get_row(uint8_t row)
    120 {
    121     return matrix[row];
    122 }
    123 
    124 void matrix_print(void)
    125 {
    126     print("\nr/c 0123456789ABCDEFGHIJKLMNOPQRSTUV  \n");
    127 
    128     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    129         print_hex8(row); print(": ");
    130         print_bin_reverse32(matrix_get_row(row));
    131         print("\n");
    132     }
    133 }
    134 
    135 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
    136 {
    137     bool matrix_changed = false;
    138 
    139     // Select col and wait for col selecton to stabilize
    140     select_col(current_col);
    141     wait_us(30);
    142 
    143     // For each row...
    144     for(uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++)
    145     {
    146         // Store last value of row prior to reading
    147         matrix_row_t last_row_value = current_matrix[row_index];
    148 
    149         // Check row pin state
    150         // Use the otherwise unused row: 3, col: 0 for caps lock
    151         if (row_index == 2 && current_col == 2) {
    152             // Pin E2 uses active low
    153             if ((_SFR_IO8(E2 >> 4) & _BV(E2 & 0xF)) == 0)
    154             {
    155                 // Pin LO, set col bit
    156                 current_matrix[row_index] |= (COL_SHIFTER << current_col);
    157             }
    158             else
    159             {
    160                 // Pin HI, clear col bit
    161                 current_matrix[row_index] &= ~(COL_SHIFTER << current_col);
    162             }
    163         }
    164         else {
    165             if ((_SFR_IO8(row_pins[row_index] >> 4) & _BV(row_pins[row_index] & 0xF)))
    166             {
    167                 // Pin HI, set col bit
    168                 current_matrix[row_index] |= (COL_SHIFTER << current_col);
    169             }
    170             else
    171             {
    172                 // Pin LO, clear col bit
    173                 current_matrix[row_index] &= ~(COL_SHIFTER << current_col);
    174             }
    175         }
    176 
    177         // Determine if the matrix changed state
    178         if ((last_row_value != current_matrix[row_index]) && !(matrix_changed))
    179         {
    180             matrix_changed = true;
    181         }
    182     }
    183 
    184     // Unselect cols
    185     unselect_cols();
    186 
    187     return matrix_changed;
    188 }
    189 
    190 /* Row pin configuration
    191  * row: 0   1   2   3   4
    192  * pin: D0  D1  D2  D3  D5
    193  *
    194  * Caps lock uses its own pin E2
    195  */
    196 static void init_rows(void) {
    197     gpio_set_pin_input(D0);
    198     gpio_set_pin_input(D1);
    199     gpio_set_pin_input(D2);
    200     gpio_set_pin_input(D3);
    201     gpio_set_pin_input(D5);
    202 
    203     gpio_set_pin_input_high(E2);
    204 }
    205 
    206 /* Columns 0 - 16
    207  * col 0: B5
    208  * col 1: B6
    209  * These columns use a 74HC237D 3 to 8 bit demultiplexer.
    210  *                A    B    C   GL1
    211  * col / pin:    PF0  PF1  PC7  PC6
    212  * 2:             0    0    0    1
    213  * 3:             1    0    0    1
    214  * 4:             0    1    0    1
    215  * 5:             1    1    0    1
    216  * 6:             0    0    1    1
    217  * 7:             1    0    1    1
    218  * 8:             0    1    1    1
    219  * 9:             1    1    1    1
    220  * col 10: E6
    221  * col 11: B0
    222  * col 12: B7
    223  * col 13: D4
    224  * col 14: D6
    225  * col 15: D7
    226  * col 16: B4
    227  */
    228 static void unselect_cols(void) {
    229     gpio_set_pin_output(B0);
    230     gpio_set_pin_output(B4);
    231     gpio_set_pin_output(B5);
    232     gpio_set_pin_output(B6);
    233     gpio_set_pin_output(B7);
    234     gpio_write_pin_low(B0);
    235     gpio_write_pin_low(B4);
    236     gpio_write_pin_low(B5);
    237     gpio_write_pin_low(B6);
    238     gpio_write_pin_low(B7);
    239 
    240     gpio_set_pin_output(D4);
    241     gpio_set_pin_output(D6);
    242     gpio_set_pin_output(D7);
    243     gpio_write_pin_low(D4);
    244     gpio_write_pin_low(D6);
    245     gpio_write_pin_low(D7);
    246 
    247     gpio_set_pin_output(E6);
    248     gpio_write_pin_low(E6);
    249 
    250     gpio_set_pin_output(F0);
    251     gpio_set_pin_output(F1);
    252     gpio_write_pin_low(F0);
    253     gpio_write_pin_low(F1);
    254 
    255     gpio_set_pin_output(C6);
    256     gpio_set_pin_output(C7);
    257     gpio_write_pin_low(C6);
    258     gpio_write_pin_low(C7);
    259 }
    260 
    261 static void select_col(uint8_t col)
    262 {
    263     switch (col) {
    264         case 0:
    265             gpio_write_pin_high(B5); // HI
    266             break;
    267         case 1:
    268             gpio_write_pin_high(B6); // HI
    269             break;
    270         case 2:
    271             gpio_write_pin_high(C6); // HI
    272             break;
    273         case 3:
    274             gpio_write_pin_high(C6); // HI
    275             gpio_write_pin_high(F0); // HI
    276             break;
    277         case 4:
    278             gpio_write_pin_high(C6); // HI
    279             gpio_write_pin_high(F1); // HI
    280             break;
    281         case 5:
    282             gpio_write_pin_high(C6); // HI
    283             gpio_write_pin_high(F0); // HI
    284             gpio_write_pin_high(F1); // HI
    285             break;
    286         case 6:
    287             gpio_write_pin_high(C6); // HI
    288             gpio_write_pin_high(C7); // HI
    289             break;
    290         case 7:
    291             gpio_write_pin_high(C6); // HI
    292             gpio_write_pin_high(F0); // HI
    293             gpio_write_pin_high(C7); // HI
    294             break;
    295         case 8:
    296             gpio_write_pin_high(C6); // HI
    297             gpio_write_pin_high(F1); // HI
    298             gpio_write_pin_high(C7); // HI
    299             break;
    300         case 9:
    301             gpio_write_pin_high(C6); // HI
    302             gpio_write_pin_high(F0); // HI
    303             gpio_write_pin_high(F1); // HI
    304             gpio_write_pin_high(C7); // HI
    305             break;
    306         case 10:
    307             gpio_write_pin_high(E6); // HI
    308             break;
    309         case 11:
    310             gpio_write_pin_high(B0); // HI
    311             break;
    312         case 12:
    313             gpio_write_pin_high(B7); // HI
    314             break;
    315         case 13:
    316             gpio_write_pin_high(D4); // HI
    317             break;
    318         case 14:
    319             gpio_write_pin_high(D6); // HI
    320             break;
    321         case 15:
    322             gpio_write_pin_high(D7); // HI
    323             break;
    324         case 16:
    325             gpio_write_pin_high(B4); // HI
    326             break;
    327     }
    328 }