matrix.c (6353B)
1 /* 2 Copyright 2012 Jun Wako <wakojun@gmail.com> 3 Copyright 2017 Cole Markham <cole@ccmcomputing.net> 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 /* 20 * scan matrix 21 */ 22 #include "matrix.h" 23 #include "meira.h" 24 #include "wait.h" 25 #include "print.h" 26 #include "debug.h" 27 #include "timer.h" 28 29 #ifndef DEBOUNCE 30 # define DEBOUNCE 5 31 #endif 32 33 #if (DEBOUNCE > 0) 34 static uint16_t debouncing_time; 35 static bool debouncing = false; 36 #endif 37 38 #if (MATRIX_COLS <= 8) 39 # define print_matrix_header() print("\nr/c 01234567\n") 40 # define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row)) 41 # define ROW_SHIFTER ((uint8_t)1) 42 #elif (MATRIX_COLS <= 16) 43 # define print_matrix_header() print("\nr/c 0123456789ABCDEF\n") 44 # define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row)) 45 # define ROW_SHIFTER ((uint16_t)1) 46 #elif (MATRIX_COLS <= 32) 47 # define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n") 48 # define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row)) 49 # define ROW_SHIFTER ((uint32_t)1) 50 #endif 51 52 static matrix_row_t matrix_debouncing[MATRIX_ROWS]; 53 54 static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; 55 static const uint8_t col_pins[4] = MATRIX_COL_PINS_SCANNED; 56 //static const uint8_t lrow_pins[MATRIX_ROWS] = LED_ROW_PINS; 57 //static const uint8_t lcol_pins[4] = LED_COL_PINS; 58 59 /* matrix state(1:on, 0:off) */ 60 static matrix_row_t matrix[MATRIX_ROWS]; 61 static matrix_row_t matrix_debouncing[MATRIX_ROWS]; 62 static void init_rows(void); 63 //static void init_lcols(void); 64 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col); 65 static void unselect_cols(void); 66 static void select_col(uint8_t col); 67 68 69 __attribute__ ((weak)) 70 void matrix_init_kb(void) { 71 matrix_init_user(); 72 } 73 74 __attribute__ ((weak)) 75 void matrix_scan_kb(void) { 76 matrix_scan_user(); 77 } 78 79 __attribute__ ((weak)) 80 void matrix_init_user(void) { 81 } 82 83 __attribute__ ((weak)) 84 void matrix_scan_user(void) { 85 } 86 87 inline 88 uint8_t matrix_rows(void) 89 { 90 return MATRIX_ROWS; 91 } 92 93 inline 94 uint8_t matrix_cols(void) 95 { 96 return MATRIX_COLS; 97 } 98 99 void matrix_init(void) 100 { 101 debug_enable = true; 102 debug_matrix = true; 103 debug_mouse = true; 104 // initialize row and col 105 unselect_cols(); 106 init_rows(); 107 // init_lcols(); 108 109 // initialize matrix state: all keys off 110 for (uint8_t i=0; i < MATRIX_ROWS; i++) { 111 matrix[i] = 0; 112 matrix_debouncing[i] = 0; 113 } 114 115 matrix_init_kb(); 116 117 } 118 119 uint8_t _matrix_scan(void) 120 { 121 // Set col, read rows 122 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) { 123 # if (DEBOUNCE > 0) 124 bool matrix_changed = read_rows_on_col(matrix_debouncing, current_col); 125 if (matrix_changed) { 126 debouncing = true; 127 debouncing_time = timer_read(); 128 } 129 # else 130 read_rows_on_col(matrix, current_col); 131 # endif 132 133 } 134 135 # if (DEBOUNCE > 0) 136 if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCE)) { 137 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 138 matrix[i] = matrix_debouncing[i]; 139 } 140 debouncing = false; 141 } 142 # endif 143 144 return 1; 145 } 146 147 uint8_t matrix_scan(void) 148 { 149 uint8_t ret = _matrix_scan(); 150 matrix_scan_kb(); 151 return ret; 152 } 153 154 inline 155 bool matrix_is_on(uint8_t row, uint8_t col) 156 { 157 return (matrix[row] & ((matrix_row_t)1<<col)); 158 } 159 160 inline 161 matrix_row_t matrix_get_row(uint8_t row) 162 { 163 return matrix[row]; 164 } 165 166 void matrix_print(void) 167 { 168 print("\nr/c 0123456789ABCDEF\n"); 169 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 170 print_hex8(row); print(": "); 171 print_bin_reverse16(matrix_get_row(row)); 172 print("\n"); 173 } 174 } 175 176 static void init_rows(void) 177 { 178 for(uint8_t x = 0; x < MATRIX_ROWS; x++) { 179 uint8_t pin = row_pins[x]; 180 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN 181 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI 182 } 183 } 184 185 186 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) 187 { 188 bool matrix_changed = false; 189 190 // Select col and wait for col selection to stabilize 191 select_col(current_col); 192 wait_us(30); 193 194 // For each row... 195 for(uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++) 196 { 197 198 // Store last value of row prior to reading 199 matrix_row_t last_row_value = current_matrix[row_index]; 200 201 // Check row pin state 202 if ((_SFR_IO8(row_pins[row_index] >> 4) & _BV(row_pins[row_index] & 0xF)) == 0) 203 { 204 // Pin LO, set col bit 205 current_matrix[row_index] |= (ROW_SHIFTER << current_col); 206 } 207 else 208 { 209 // Pin HI, clear col bit 210 current_matrix[row_index] &= ~(ROW_SHIFTER << current_col); 211 } 212 213 // Determine if the matrix changed state 214 if ((last_row_value != current_matrix[row_index]) && !(matrix_changed)) 215 { 216 matrix_changed = true; 217 } 218 } 219 220 // Unselect col 221 unselect_cols(); 222 223 return matrix_changed; 224 } 225 226 static void select_col(uint8_t col) 227 { 228 #ifdef FLIPPED_BOARD 229 col = MATRIX_COLS - col - 1; 230 #endif 231 for(uint8_t x = 0; x < 4; x++) { 232 uint8_t pin = col_pins[x]; 233 _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT 234 if (((col >> x) & 0x1) == 1){ 235 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HIGH 236 } else { 237 _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW 238 } 239 } 240 } 241 242 static void unselect_cols(void) 243 { 244 // FIXME This really needs to use the global enable on the decoder, because currently this sets the value to col1 245 for(uint8_t x = 0; x < 4; x++) { 246 uint8_t pin = col_pins[x]; 247 _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT 248 _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW 249 } 250 }