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 }