qmk_firmware

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

matrix.c (6040B)


      1 /*
      2 Copyright 2018 listofoptions <listofoptions@gmail.com>
      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 <stdint.h>
     19 #include <stdbool.h>
     20 #include <string.h>
     21 #if defined(__AVR__)
     22 #include <avr/io.h>
     23 #endif
     24 #include <util/delay.h>
     25 
     26 #include "wait.h"
     27 #include "print.h"
     28 #include "debug.h"
     29 #include "util.h"
     30 #include "matrix.h"
     31 #include "timer.h"
     32 #include <LUFA/Drivers/Peripheral/SPI.h>
     33 
     34 #ifndef DEBOUNCE
     35 #   define DEBOUNCE 5
     36 #endif
     37 
     38 #if ( DEBOUNCE > 0 )
     39 static uint16_t debouncing_time         ;
     40 static bool     debouncing      = false ;
     41 #endif
     42 
     43 static uint8_t matrix [MATRIX_ROWS] = {0};
     44 
     45 #if ( DEBOUNCE > 0 )
     46 static uint8_t matrix_debounce_old [MATRIX_ROWS] = {0};
     47 static uint8_t matrix_debounce_new [MATRIX_ROWS] = {0};
     48 #endif 
     49 
     50 __attribute__ ((weak))
     51 void matrix_init_kb(void) {    
     52     matrix_init_user();
     53 }
     54 
     55 __attribute__ ((weak))
     56 void matrix_scan_kb(void) {
     57     matrix_scan_user();
     58 }
     59 
     60 __attribute__ ((weak))
     61 void matrix_init_user(void) {
     62 }
     63 
     64 __attribute__ ((weak))
     65 void matrix_scan_user(void) {
     66 }
     67 
     68 // the keyboard's internal wiring is such that the inputs to the logic are
     69 // a clock signal, and a reset line.
     70 // the output is a single output pin. im bitbanging here, but the SPI controller
     71 // would work normally
     72 //
     73 // the device functions, by using the clock signal to count 128 bits, the lower
     74 // 3 bits of this 7 bit counter are tied to a 1-of-8 multiplexer, this forms 
     75 // the columns.
     76 // the upper 4 bits form the rows, and are decoded using bcd to decimal 
     77 // decoders, so that 14 out of 16 of the outputs are wired to the rows of the 
     78 // matrix. each switch has a diode, such that the row signal feeds into the
     79 // switch, and then into the diode, then into one of the columns into the 
     80 // matrix. the reset pin can be used to reset the entire counter.
     81 
     82 #define HP_46010A_RESET_PIN B0
     83 #define HP_46010A_SCLK_PIN  B1
     84 #define HP_46010A_SDATA_PIN B3
     85 #define HP_46010A_LED_PIN   D6
     86 
     87 inline
     88 static
     89 void SCLK_increment(void) {
     90     gpio_write_pin_low(HP_46010A_SCLK_PIN);
     91     _delay_us( 4 ) ; // make sure the line is stable
     92     gpio_write_pin_high(HP_46010A_SCLK_PIN);
     93     _delay_us( 4 ) ;
     94     
     95     return ;
     96 }    
     97 
     98 inline
     99 static
    100 void Matrix_Reset(void) {
    101     gpio_write_pin_high(HP_46010A_RESET_PIN);
    102     _delay_us( 4 ) ; // make sure the line is stable
    103     gpio_write_pin_low(HP_46010A_RESET_PIN);
    104     
    105     return ;
    106 }
    107 
    108 inline
    109 static
    110 uint8_t Matrix_ReceiveByte (void) {
    111     uint8_t received = 0 ;
    112     uint8_t temp     = 0 ;
    113     for ( uint8_t bit = 0; bit < MATRIX_COLS; ++bit ) {
    114         // toggle the clock
    115         SCLK_increment();
    116         temp      = gpio_read_pin(HP_46010A_SDATA_PIN) << 4 ;
    117         received |= temp >> bit ;
    118     }
    119 
    120     return received ;
    121 }
    122 
    123 inline
    124 static
    125 void Matrix_ThrowByte(void) {
    126     // we use MATRIX_COLS - 1 here because that would put us at 7 clocks
    127     for ( uint8_t bit = 0; bit < MATRIX_COLS - 1; ++bit ) {
    128         // toggle the clock
    129         SCLK_increment();
    130     }
    131     
    132     return ;
    133 }
    134 
    135 void matrix_init (void) {
    136     // debug_matrix = 1;
    137     // PB0 (SS) and PB1 (SCLK) set to outputs
    138     gpio_set_pin_output(HP_46010A_RESET_PIN);
    139     gpio_set_pin_output(HP_46010A_SCLK_PIN);
    140     // PB2, is unused, and PB3 is our serial input
    141     gpio_set_pin_input(HP_46010A_SDATA_PIN);
    142     
    143     // SS is reset for this board, and is active High
    144     // SCLK is the serial clock and is active High
    145     gpio_write_pin_low(HP_46010A_RESET_PIN);
    146     gpio_write_pin_high(HP_46010A_SCLK_PIN);
    147 
    148     // led pin
    149     gpio_set_pin_output(HP_46010A_LED_PIN);
    150     gpio_write_pin_low(HP_46010A_LED_PIN);
    151 
    152     matrix_init_kb();
    153 
    154     //toggle reset, to put the keyboard logic into a known state
    155     Matrix_Reset() ;
    156 }
    157 
    158 uint8_t matrix_scan(void)  {
    159 
    160     // the first byte of the keyboard's output data can be ignored
    161     Matrix_ThrowByte();
    162     
    163 #if ( DEBOUNCE > 0 )
    164 
    165     for ( uint8_t row = 0 ; row < MATRIX_ROWS ; ++row ) {
    166         //transfer old debouncing values
    167         matrix_debounce_old[row] = matrix_debounce_new[row] ;
    168         // read new key-states in
    169         matrix_debounce_new[row] = Matrix_ReceiveByte() ;
    170             
    171         if ( matrix_debounce_new[row] != matrix_debounce_old[row] ) {
    172             debouncing      = true ;
    173             debouncing_time = timer_read() ;
    174         }
    175     }
    176     
    177 #else
    178     // without debouncing we simply just read in the raw matrix
    179     for ( uint8_t row = 0 ; row < MATRIX_ROWS ; ++row ) {
    180         matrix[row] = Matrix_ReceiveByte ;
    181     }
    182 #endif 
    183 
    184     
    185 #if ( DEBOUNCE > 0 )
    186     if ( debouncing && ( timer_elapsed( debouncing_time ) > DEBOUNCE ) ) {
    187         
    188         for ( uint8_t row = 0 ; row < MATRIX_ROWS ; ++row ) {
    189             matrix[row] = matrix_debounce_new[row] ;
    190         }
    191 
    192         debouncing = false ;
    193     }
    194 #endif
    195     Matrix_Reset() ;
    196     
    197     matrix_scan_kb() ;
    198     return 1;
    199 }
    200 
    201 inline
    202 uint8_t matrix_get_row( uint8_t row ) {
    203     return matrix[row];
    204 }
    205 
    206 void matrix_print(void)
    207 {
    208     print("\nr/c 01234567\n");
    209 
    210     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    211         print_hex8(row); print(": ");
    212         print_bin_reverse8(matrix_get_row(row));
    213         print("\n");
    214     }
    215 }
    216 
    217 inline
    218 uint8_t matrix_rows(void) {
    219     return MATRIX_ROWS;
    220 }
    221 
    222 inline
    223 uint8_t matrix_cols(void) {
    224     return MATRIX_COLS;
    225 }
    226 
    227 // as an aside, I used the M0110 converter:
    228 // tmk_core/common/keyboard.c, quantum/matrix.c, and the project layout of the planck
    229 // the online ducmentation starting from : 
    230 // https://docs.qmk.fm/#/config_options
    231 // https://docs.qmk.fm/#/understanding_qmk
    232 // and probably a few i forgot....