qmk_firmware

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

matrix.c (4585B)


      1 /*
      2 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
      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 This program is distributed in the hope that it will be useful,
      8 but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 GNU General Public License for more details.
     11 You should have received a copy of the GNU General Public License
     12 along with this program.  If not, see <http://www.gnu.org/licenses/>.
     13 */
     14 
     15 #include "matrix.h"
     16 #include <stdint.h>
     17 #include <stdbool.h>
     18 #include <avr/io.h>
     19 #include "wait.h"
     20 #include "action_layer.h"
     21 #include "print.h"
     22 #include "debug.h"
     23 #include "util.h"
     24 #include "sp64.h"
     25 #include "debounce.h"
     26 
     27 /* matrix state(1:on, 0:off) */
     28 static matrix_row_t matrix[MATRIX_ROWS];
     29 
     30 // Debouncing: store for each key the number of scans until it's eligible to
     31 // change.  When scanning the matrix, ignore any changes in keys that have
     32 // already changed in the last DEBOUNCE scans.
     33 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
     34 
     35 static void matrix_select_row(uint8_t row);
     36 
     37 #ifdef RIGHT_HALF
     38 static uint8_t mcp23018_reset_loop = 0;
     39 #endif
     40 
     41 // user-defined overridable functions
     42 
     43 __attribute__((weak)) void matrix_init_kb(void) {
     44     matrix_init_user();
     45 }
     46 
     47 __attribute__((weak)) void matrix_scan_kb(void) {
     48     matrix_scan_user();
     49 }
     50 
     51 __attribute__((weak)) void matrix_init_user(void) {}
     52 
     53 __attribute__((weak)) void matrix_scan_user(void) {}
     54 
     55 // helper functions
     56 void matrix_init(void) {
     57     // all outputs for rows high
     58     DDRB  = 0xFF;
     59     PORTB = 0xFF;
     60     // all inputs for columns
     61     DDRA = 0x00;
     62     DDRC &= ~(0x111111 << 2);
     63     DDRD &= ~(1 << PIND7);
     64     // all columns are pulled-up
     65     PORTA = 0xFF;
     66     PORTC |= (0b111111 << 2);
     67     PORTD |= (1 << PIND7);
     68 
     69 #ifdef RIGHT_HALF
     70     // initialize row and col
     71     mcp23018_status = init_mcp23018();
     72 #endif
     73 
     74     // initialize matrix state: all keys off
     75     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
     76         matrix[row]            = 0;
     77         matrix_debouncing[row] = 0;
     78     }
     79     debounce_init();
     80     matrix_init_kb();
     81 }
     82 
     83 uint8_t matrix_scan(void) {
     84 #ifdef RIGHT_HALF
     85     // Then the keyboard
     86     if (mcp23018_status != I2C_STATUS_SUCCESS) {
     87         if (++mcp23018_reset_loop == 0) {
     88             // if (++mcp23018_reset_loop >= 1300) {
     89             // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
     90             // this will be approx bit more frequent than once per second
     91             print("trying to reset mcp23018\n");
     92             mcp23018_status = init_mcp23018();
     93             if (mcp23018_status) {
     94                 print("left side not responding\n");
     95             } else {
     96                 print("left side attached\n");
     97             }
     98         }
     99     }
    100 #endif
    101     bool changed = false;
    102     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    103         matrix_row_t cols;
    104 
    105         matrix_select_row(row);
    106 #ifndef RIGHT_HALF
    107         _delay_us(5);
    108 #endif
    109 
    110         cols = (
    111             // cols 0..7, PORTA 0 -> 7
    112             (~PINA) & 0xFF);
    113 
    114 #ifdef RIGHT_HALF
    115         uint8_t data = 0x7F;
    116         // Receive the columns from right half
    117         i2c_receive(I2C_ADDR, &data, 1, MCP23018_I2C_TIMEOUT);
    118         cols |= ((~(data) & 0x7F) << 7);
    119 #endif
    120 
    121         if (matrix_debouncing[row] != cols) {
    122             matrix_debouncing[row] = cols;
    123             // debouncing = DEBOUNCE;
    124             changed = true;
    125         }
    126     }
    127 
    128     debounce(matrix_debouncing, matrix, changed);
    129 
    130     matrix_scan_kb();
    131 
    132 #ifdef DEBUG_MATRIX
    133     for (uint8_t c = 0; c < MATRIX_COLS; c++)
    134         for (uint8_t r = 0; r < MATRIX_ROWS; r++)
    135             if (matrix_is_on(r, c)) xprintf("r:%d c:%d \n", r, c);
    136 #endif
    137 
    138     return (uint8_t)changed;
    139 }
    140 
    141 inline matrix_row_t matrix_get_row(uint8_t row) {
    142     return matrix[row];
    143 }
    144 
    145 void matrix_print(void) {
    146     print("\nr/c 0123456789ABCDEF\n");
    147     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    148         print_hex8(row);
    149         print(": ");
    150         print_bin_reverse16(matrix_get_row(row));
    151         print("\n");
    152     }
    153 }
    154 
    155 static void matrix_select_row(uint8_t row) {
    156 #ifdef RIGHT_HALF
    157     uint8_t txdata[3];
    158 
    159     // Set the remote row on port A
    160     txdata[0]       = GPIOA;
    161     txdata[1]       = 0xFF & ~(1 << row);
    162     mcp23018_status = i2c_transmit(I2C_ADDR, (uint8_t *)txdata, 2, MCP23018_I2C_TIMEOUT);
    163 #endif
    164 
    165     // select other half
    166     DDRB  = (1 << row);
    167     PORTB = ~(1 << row);
    168 }