matrix.c (7819B)
1 /* 2 3 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com> 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include "matrix.h" 20 #include "wait.h" 21 #include "debug.h" 22 #include "util.h" 23 #include "ergotaco.h" 24 25 #ifndef DEBOUNCE 26 # define DEBOUNCE 5 27 #endif 28 29 // ATmega pin defs 30 #define ROW1 (1<<5) 31 #define COL6 (1<<0) 32 #define COL7 (1<<1) 33 #define COL8 (1<<2) 34 #define COL9 (1<<3) 35 #define COL10 (1<<2) 36 #define COL11 (1<<3) 37 38 39 // bit masks 40 #define BMASK (COL7 | COL8 | COL9 | COL6) 41 #define DMASK (COL10 | COL11) 42 #define FMASK (ROW1) 43 44 /* matrix state(1:on, 0:off) */ 45 static matrix_row_t matrix[MATRIX_ROWS]; 46 /* 47 * matrix state(1:on, 0:off) 48 * contains the raw values without debounce filtering of the last read cycle. 49 */ 50 static matrix_row_t raw_matrix[MATRIX_ROWS]; 51 52 // Debouncing: store for each key the number of scans until it's eligible to 53 // change. When scanning the matrix, ignore any changes in keys that have 54 // already changed in the last DEBOUNCE scans. 55 static uint8_t debounce_matrix[MATRIX_ROWS * MATRIX_COLS]; 56 57 static matrix_row_t read_cols(uint8_t row); 58 static void init_cols(void); 59 static void unselect_rows(void); 60 static void select_row(uint8_t row); 61 62 static uint8_t mcp23018_reset_loop; 63 // static uint16_t mcp23018_reset_loop; 64 65 __attribute__ ((weak)) 66 void matrix_init_user(void) {} 67 68 __attribute__ ((weak)) 69 void matrix_scan_user(void) {} 70 71 __attribute__ ((weak)) 72 void matrix_init_kb(void) { 73 matrix_init_user(); 74 } 75 76 __attribute__ ((weak)) 77 void matrix_scan_kb(void) { 78 matrix_scan_user(); 79 } 80 81 inline 82 uint8_t matrix_rows(void) 83 { 84 return MATRIX_ROWS; 85 } 86 87 inline 88 uint8_t matrix_cols(void) 89 { 90 return MATRIX_COLS; 91 } 92 93 94 void matrix_init(void) 95 { 96 // initialize row and col 97 mcp23018_status = init_mcp23018(); 98 unselect_rows(); 99 init_cols(); 100 101 // initialize matrix state: all keys off 102 for (uint8_t i=0; i < MATRIX_ROWS; i++) { 103 matrix[i] = 0; 104 raw_matrix[i] = 0; 105 for (uint8_t j=0; j < MATRIX_COLS; ++j) { 106 debounce_matrix[i * MATRIX_COLS + j] = 0; 107 } 108 } 109 110 matrix_init_kb(); 111 } 112 113 void matrix_power_up(void) { 114 mcp23018_status = init_mcp23018(); 115 116 unselect_rows(); 117 init_cols(); 118 119 // initialize matrix state: all keys off 120 for (uint8_t i=0; i < MATRIX_ROWS; i++) { 121 matrix[i] = 0; 122 } 123 } 124 125 // Returns a matrix_row_t whose bits are set if the corresponding key should be 126 // eligible to change in this scan. 127 matrix_row_t debounce_mask(matrix_row_t rawcols, uint8_t row) { 128 matrix_row_t result = 0; 129 matrix_row_t change = rawcols ^ raw_matrix[row]; 130 raw_matrix[row] = rawcols; 131 for (uint8_t i = 0; i < MATRIX_COLS; ++i) { 132 if (debounce_matrix[row * MATRIX_COLS + i]) { 133 --debounce_matrix[row * MATRIX_COLS + i]; 134 } else { 135 result |= (1 << i); 136 } 137 if (change & (1 << i)) { 138 debounce_matrix[row * MATRIX_COLS + i] = DEBOUNCE; 139 } 140 } 141 return result; 142 } 143 144 matrix_row_t debounce_read_cols(uint8_t row) { 145 // Read the row without debouncing filtering and store it for later usage. 146 matrix_row_t cols = read_cols(row); 147 // Get the Debounce mask. 148 matrix_row_t mask = debounce_mask(cols, row); 149 // debounce the row and return the result. 150 return (cols & mask) | (matrix[row] & ~mask);; 151 } 152 153 uint8_t matrix_scan(void) 154 { 155 // Then the keyboard 156 if (mcp23018_status) { // if there was an error 157 if (++mcp23018_reset_loop == 0) { 158 // if (++mcp23018_reset_loop >= 1300) { 159 // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans 160 // this will be approx bit more frequent than once per second 161 print("trying to reset mcp23018\n"); 162 mcp23018_status = init_mcp23018(); 163 if (mcp23018_status) { 164 print("left side not responding\n"); 165 } else { 166 print("left side attached\n"); 167 } 168 } 169 } 170 171 for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) { 172 select_row(i); 173 // and select on left hand 174 select_row(i + MATRIX_ROWS_PER_SIDE); 175 // we don't need a 30us delay anymore, because selecting a 176 // left-hand row requires more than 30us for i2c. 177 178 // grab cols from left hand 179 matrix[i] = debounce_read_cols(i); 180 // grab cols from right hand 181 matrix[i + MATRIX_ROWS_PER_SIDE] = debounce_read_cols(i + MATRIX_ROWS_PER_SIDE); 182 183 unselect_rows(); 184 } 185 186 matrix_scan_kb(); 187 188 #ifdef DEBUG_MATRIX 189 for (uint8_t c = 0; c < MATRIX_COLS; c++) 190 for (uint8_t r = 0; r < MATRIX_ROWS; r++) 191 if (matrix_is_on(r, c)) xprintf("r:%d c:%d \n", r, c); 192 #endif 193 194 return 1; 195 } 196 197 inline 198 bool matrix_is_on(uint8_t row, uint8_t col) 199 { 200 return (matrix[row] & ((matrix_row_t)1<<col)); 201 } 202 203 inline 204 matrix_row_t matrix_get_row(uint8_t row) 205 { 206 return matrix[row]; 207 } 208 209 void matrix_print(void) 210 { 211 print("\nr/c 0123456789ABCDEF\n"); 212 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 213 print_hex8(row); print(": "); 214 print_bin_reverse16(matrix_get_row(row)); 215 print("\n"); 216 } 217 } 218 219 // Remember this means ROWS 220 static void init_cols(void) 221 { 222 // init on mcp23018 223 // not needed, already done as part of init_mcp23018() 224 225 // Input with pull-up(DDR:0, PORT:1) 226 DDRF &= ~FMASK; 227 PORTF |= FMASK; 228 } 229 230 static matrix_row_t read_cols(uint8_t row) 231 { 232 if (row < 6) { 233 if (mcp23018_status) { // if there was an error 234 return 0; 235 } else { 236 uint8_t data = 0; 237 mcp23018_status = i2c_read_register(I2C_ADDR, GPIOB, &data, 1, ERGODOX_EZ_I2C_TIMEOUT); 238 data = (~((uint8_t)data) >> 2) & 0x01 ; 239 #ifdef DEBUG_MATRIX 240 if (data != 0x00) xprintf("I2C: %d\n", data); 241 #endif 242 return data; 243 } 244 } else { 245 // Read using bitmask 246 return ~((((PINF & ROW1) >> 5)) & 0x1); 247 } 248 } 249 250 // Row pin configuration 251 static void unselect_rows(void) 252 { 253 // no need to unselect on mcp23018, because the select step sets all 254 // the other row bits high, and it's not changing to a different 255 // direction 256 // Hi-Z(DDR:0, PORT:0) to unselect 257 DDRB &= ~BMASK; 258 PORTB &= ~BMASK; 259 DDRD &= ~DMASK; 260 PORTD &= ~DMASK; 261 } 262 263 static void select_row(uint8_t row) 264 { 265 if (row < 6) { 266 // select on mcp23018 267 if (mcp23018_status) { // do nothing on error 268 // Read using bitmask 269 } else { // set active row low : 0 // set other rows hi-Z : 1 270 uint8_t data = ~(1<<row); 271 mcp23018_status = i2c_write_register(I2C_ADDR, GPIOA, &data, 1, ERGODOX_EZ_I2C_TIMEOUT); 272 } 273 } else { 274 // Output low(DDR:1, PORT:0) to select 275 switch (row) { 276 case 6: 277 DDRB |= COL6; 278 PORTB &= ~COL6; 279 break; 280 case 7: 281 DDRB |= COL7; 282 PORTB &= ~COL7; 283 break; 284 case 8: 285 DDRB |= COL8; 286 PORTB &= ~COL8; 287 break; 288 case 9: 289 DDRB |= COL9; 290 PORTB &= ~COL9; 291 break; 292 case 10: 293 DDRD |= COL10; 294 PORTD &= ~COL10; 295 break; 296 case 11: 297 DDRD |= COL11; 298 PORTD &= ~COL11; 299 break; 300 } 301 } 302 }