qmk_firmware

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

matrix.c (7179B)


      1 /*
      2 Copyright 2012-2017 Jun Wako, Jack Humbert
      3 
      4 This program is free software: you can redistribute it and/or modify
      5 it under the terms of the GNU General Public License as published by
      6 the Free Software Foundation, either version 2 of the License, or
      7 (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 GNU General Public License for more details.
     13 
     14 You should have received a copy of the GNU General Public License
     15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16 */
     17 #include <stdint.h>
     18 #include <stdbool.h>
     19 #if defined(__AVR__)
     20 #include <avr/io.h>
     21 #endif
     22 #include "wait.h"
     23 #include "print.h"
     24 #include "debug.h"
     25 #include "util.h"
     26 #include "matrix.h"
     27 #include "timer.h"
     28 #include "sx60.h"
     29 
     30 
     31 /* Set 0 if debouncing isn't needed */
     32 
     33 #ifndef DEBOUNCE
     34 #   define DEBOUNCE 5
     35 #endif
     36 
     37 #if (DEBOUNCE > 0)
     38     static uint16_t debouncing_time;
     39     static bool debouncing = false;
     40 #endif
     41 
     42 #if (MATRIX_COLS <= 8)
     43 #    define print_matrix_header()  print("\nr/c 01234567\n")
     44 #    define print_matrix_row(row)  print_bin_reverse8(matrix_get_row(row))
     45 #    define ROW_SHIFTER ((uint8_t)1)
     46 #elif (MATRIX_COLS <= 16)
     47 #    define print_matrix_header()  print("\nr/c 0123456789ABCDEF\n")
     48 #    define print_matrix_row(row)  print_bin_reverse16(matrix_get_row(row))
     49 #    define ROW_SHIFTER ((uint16_t)1)
     50 #elif (MATRIX_COLS <= 32)
     51 #    define print_matrix_header()  print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n")
     52 #    define print_matrix_row(row)  print_bin_reverse32(matrix_get_row(row))
     53 #    define ROW_SHIFTER  ((uint32_t)1)
     54 #endif
     55 
     56 #ifdef MATRIX_MASKED
     57     extern const matrix_row_t matrix_mask[];
     58 #endif
     59 
     60 static const uint8_t col_pins[ATMEGA_COLS] = MATRIX_COL_PINS;
     61 static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
     62 
     63 /* matrix state(1:on, 0:off) */
     64 static matrix_row_t matrix[MATRIX_ROWS];
     65 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
     66 static uint8_t mcp23018_reset_loop;
     67 
     68 
     69 static void init_cols(void);
     70 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
     71 static void unselect_rows(void);
     72 static void select_row(uint8_t row);
     73 
     74 __attribute__ ((weak))
     75 void matrix_init_kb(void) {
     76     matrix_init_user();
     77 }
     78 
     79 __attribute__ ((weak))
     80 void matrix_scan_kb(void) {
     81     matrix_scan_user();
     82 }
     83 
     84 __attribute__ ((weak))
     85 void matrix_init_user(void) {
     86 }
     87 
     88 __attribute__ ((weak))
     89 void matrix_scan_user(void) {
     90 }
     91 
     92 inline
     93 uint8_t matrix_rows(void) {
     94     return MATRIX_ROWS;
     95 }
     96 
     97 inline
     98 uint8_t matrix_cols(void) {
     99     return MATRIX_COLS;
    100 }
    101 
    102 void matrix_init(void) {
    103     mcp23018_status = true;
    104 
    105     /* initialize row and col */
    106     unselect_rows();
    107     init_cols();
    108 
    109     /* initialize matrix state: all keys off */
    110     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
    111         matrix[i] = 0;
    112         matrix_debouncing[i] = 0;
    113     }
    114 
    115     matrix_init_kb();
    116 }
    117 
    118 uint8_t matrix_scan(void)
    119 {
    120     if (mcp23018_status) {
    121         /* if there was an error */
    122         if (++mcp23018_reset_loop == 0) {
    123             /* since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
    124                this will be approx bit more frequent than once per second */
    125             print("trying to reset mcp23018\n");
    126             mcp23018_status = init_mcp23018();
    127             if (mcp23018_status) {
    128                 print("left side not responding\n");
    129             } else {
    130                 print("left side attached\n");
    131             }
    132         }
    133     }
    134 
    135     /* Set row, read cols */
    136     for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
    137 #       if (DEBOUNCE > 0)
    138             bool matrix_changed = read_cols_on_row(matrix_debouncing, current_row);
    139 
    140             if (matrix_changed) {
    141                 debouncing = true;
    142                 debouncing_time = timer_read();
    143             }
    144 #       else
    145             read_cols_on_row(matrix, current_row);
    146 #       endif
    147     }
    148 
    149 #   if (DEBOUNCE > 0)
    150         if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCE)) {
    151             for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
    152                 matrix[i] = matrix_debouncing[i];
    153             }
    154             debouncing = false;
    155         }
    156 #   endif
    157 
    158     matrix_scan_kb();
    159     return 1;
    160 }
    161 
    162 inline
    163 bool matrix_is_on(uint8_t row, uint8_t col)
    164 {
    165     return (matrix[row] & ((matrix_row_t)1<<col));
    166 }
    167 
    168 inline
    169 matrix_row_t matrix_get_row(uint8_t row)
    170 {
    171     /* Matrix mask lets you disable switches in the returned matrix data. For example, if you have a
    172        switch blocker installed and the switch is always pressed. */
    173 #ifdef MATRIX_MASKED
    174     return matrix[row] & matrix_mask[row];
    175 #else
    176     return matrix[row];
    177 #endif
    178 }
    179 
    180 void matrix_print(void)
    181 {
    182     print_matrix_header();
    183 
    184     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    185         print_hex8(row); print(": ");
    186         print_matrix_row(row);
    187         print("\n");
    188     }
    189 }
    190 
    191 static void init_cols(void)
    192 {
    193     for(uint8_t x = 0; x < ATMEGA_COLS; x++) {
    194         uint8_t pin = col_pins[x];
    195         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); /* IN */
    196         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); /* HI */
    197     }
    198 }
    199 
    200 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
    201 {
    202     /* Store last value of row prior to reading */
    203     matrix_row_t last_row_value = current_matrix[current_row];
    204 
    205     /* Clear data in matrix row */
    206     current_matrix[current_row] = 0;
    207 
    208     /* Select row and wait for row selecton to stabilize */
    209     select_row(current_row);
    210     wait_us(30);
    211 
    212     if (mcp23018_status) {
    213         /* if there was an error */
    214         return 0;
    215     } else {
    216         uint8_t data = 0;
    217         mcp23018_status = i2c_read_register(I2C_ADDR, GPIOA, &data, 1, I2C_TIMEOUT);
    218         if (!mcp23018_status) {
    219             current_matrix[current_row] |= (~((uint16_t)data) << 8);
    220         }
    221     }
    222 
    223     /* For each col... */
    224     for(uint8_t col_index = 0; col_index < ATMEGA_COLS; col_index++) {
    225         /* Select the col pin to read (active low) */
    226         uint8_t pin = col_pins[col_index];
    227         uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF));
    228 
    229         /* Populate the matrix row with the state of the col pin */
    230         current_matrix[current_row] |=  pin_state ? 0 : (ROW_SHIFTER << col_index);
    231     }
    232 
    233     /* Unselect row */
    234     unselect_rows();
    235 
    236     return (last_row_value != current_matrix[current_row]);
    237 }
    238 
    239 static void select_row(uint8_t row)
    240 {
    241     if (mcp23018_status) {
    242         /* if there was an error do nothing */
    243     } else {
    244         /* set active row low  : 0
    245            set active row output : 1
    246            set other rows hi-Z : 1 */
    247         uint8_t port = 0xFF & ~(1<<abs(row-4));
    248         mcp23018_status = i2c_write_register(I2C_ADDR, GPIOB, &port, 1, I2C_TIMEOUT);
    249     }
    250 
    251     uint8_t pin = row_pins[row];
    252     _SFR_IO8((pin >> 4) + 1) |=  _BV(pin & 0xF); /*  OUT  */
    253     _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); /* LOW  */
    254 }
    255 
    256 static void unselect_rows(void)
    257 {
    258     for(uint8_t x = 0; x < MATRIX_ROWS; x++) {
    259         uint8_t pin = row_pins[x];
    260         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); /* IN */
    261         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); /* HI */
    262     }
    263 }