qmk_firmware

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

matrix.c (3775B)


      1 /*
      2   Copyright (c) 2022 David Kuehling <dvdkhlng TA posteo TOD de>
      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 
     18 #include "spi_master.h"
     19 #include "matrix.h"
     20 
     21 static pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
     22 
     23 static void unselect_rows(void);
     24 
     25 void matrix_init_custom(void) {
     26     /* initialize row pins */
     27     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
     28         gpio_set_pin_output(row_pins[row]);
     29     }
     30     unselect_rows();
     31 
     32     /* columns read via shift-register on SPI lines */
     33 
     34     /* Enable SPI, Master, set clock rate fck/16.  First bit already at Qh
     35      * output before clock edge (CPHA=0).  SN74HC165 shift register shifts
     36      * on low-to-high transition (CPOL=1).  Receive the LSB first (DORD=1).
     37      */
     38     bool lsbFirst = true;
     39     uint8_t mode = 2;  /* CPOL=1, CPHA=0 */
     40     uint16_t divisor = 16;
     41 
     42     /* According to Atmega32U4 datasheet, PB0 *must* be set to output,
     43      * otherwise it will interfere with SPI master operation.  On pro-micro
     44      * it's connected to a yellew LED. */
     45     pin_t slavePin = PB0;
     46     spi_init();
     47     spi_start(slavePin, lsbFirst, mode, divisor);
     48 
     49     /* Initialize pin controlling the shift register's SH/~LD pin */
     50     gpio_set_pin_output(ROW_SHIFT_PIN);
     51 }
     52 
     53 static void select_row(uint8_t row) {
     54     pin_t pin = row_pins[row];
     55     if (pin != NO_PIN) {
     56         gpio_write_pin_high(pin);
     57     }
     58 }
     59 
     60 static void unselect_row(uint8_t row) {
     61     pin_t pin = row_pins[row];
     62     if (pin != NO_PIN) {
     63         gpio_write_pin_low(pin);
     64     }
     65 }
     66 
     67 static void unselect_rows(void) {
     68     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
     69         unselect_row(row);
     70     }
     71 }
     72 
     73 bool matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
     74     /* Start with a clear matrix row */
     75     matrix_row_t current_row_value = 0;
     76 
     77     /* Set shift register SH/~LD pin to "load" mode */
     78     gpio_write_pin_low(ROW_SHIFT_PIN);
     79     select_row(current_row);
     80     matrix_output_select_delay();
     81 
     82     /* Set shift register SH/~LD pin to "shift" mode */
     83     gpio_write_pin_high(ROW_SHIFT_PIN);
     84 
     85     /* For each octet of columns... */
     86     for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index += 8) {
     87         spi_status_t read_result = spi_read();
     88         if (read_result >= 0) {
     89             /* only if SPI read successful: populate the matrix row with the
     90                state of the 8 consecutive column bits */
     91             current_row_value |= ((matrix_row_t)read_result << col_index);
     92         }
     93     }
     94 
     95     /* Unselect row & wait for all columns signals to go high. */
     96     unselect_row(current_row);
     97     matrix_output_unselect_delay(current_row, current_row_value != 0); 
     98 
     99     /* Update row in matrix. */
    100     if (current_row_value != current_matrix[current_row]) {
    101         current_matrix[current_row] = current_row_value;
    102         return true;
    103     }
    104 
    105     return false;
    106 }
    107 
    108 bool matrix_scan_custom(matrix_row_t curr_matrix[]) {
    109     bool changed = false;
    110 
    111     /* set row, read cols */
    112     for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
    113         changed |= matrix_read_cols_on_row(curr_matrix, current_row);
    114     }
    115 
    116     return changed;
    117 }
    118 
    119 /*
    120  * Local Variables:
    121  * c-basic-offset:4
    122  * fill-column: 76
    123  * End:
    124  */