/* * scan matrix */ #include <stdint.h> #include <stdbool.h> #include <avr/io.h> #include <util/delay.h> #include "print.h" #include "util.h" #include "matrix.h" #if (MATRIX_COLS > 16) # error "MATRIX_COLS must not exceed 16" #endif #if (MATRIX_ROWS > 255) # error "MATRIX_ROWS must not exceed 255" #endif // matrix state buffer(1:on, 0:off) #if (MATRIX_COLS <= 8) static uint8_t *matrix; static uint8_t *matrix_prev; static uint8_t _matrix0[MATRIX_ROWS]; static uint8_t _matrix1[MATRIX_ROWS]; #else static uint16_t *matrix; static uint16_t *matrix_prev; static uint16_t _matrix0[MATRIX_ROWS]; static uint16_t _matrix1[MATRIX_ROWS]; #endif #ifdef MATRIX_HAS_GHOST static bool matrix_has_ghost_in_row(uint8_t row); #endif static uint8_t read_col(void); static void unselect_rows(void); static void select_row(uint8_t row); inline uint8_t matrix_rows(void) { return MATRIX_ROWS; } inline uint8_t matrix_cols(void) { return MATRIX_COLS; } void matrix_init(void) { // initialize row and col unselect_rows(); // Input with pull-up(DDR:0, PORT:1) DDRB = 0x00; PORTB = 0xFF; // initialize matrix state: all keys off for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00; for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00; matrix = _matrix0; matrix_prev = _matrix1; } uint8_t matrix_scan(void) { uint8_t *tmp; tmp = matrix_prev; matrix_prev = matrix; matrix = tmp; for (uint8_t i = 0; i < MATRIX_ROWS; i++) { unselect_rows(); select_row(i); _delay_us(30); // without this wait read unstable value. matrix[i] = ~read_col(); } unselect_rows(); return 1; } bool matrix_is_modified(void) { for (uint8_t i = 0; i < MATRIX_ROWS; i++) { if (matrix[i] != matrix_prev[i]) return true; } return false; } inline bool matrix_has_ghost(void) { #ifdef MATRIX_HAS_GHOST for (uint8_t i = 0; i < MATRIX_ROWS; i++) { if (matrix_has_ghost_in_row(i)) return true; } #endif return false; } inline bool matrix_is_on(uint8_t row, uint8_t col) { return (matrix[row] & (1<<col)); } inline #if (MATRIX_COLS <= 8) uint8_t matrix_get_row(uint8_t row) #else uint16_t matrix_get_row(uint8_t row) #endif { return matrix[row]; } void matrix_print(void) { print("\nr/c 01234567\n"); for (uint8_t row = 0; row < matrix_rows(); row++) { phex(row); print(": "); #if (MATRIX_COLS <= 8) pbin_reverse(matrix_get_row(row)); #else pbin_reverse16(matrix_get_row(row)); #endif #ifdef MATRIX_HAS_GHOST if (matrix_has_ghost_in_row(row)) { print(" <ghost"); } #endif print("\n"); } } uint8_t matrix_key_count(void) { uint8_t count = 0; for (uint8_t i = 0; i < MATRIX_ROWS; i++) { #if (MATRIX_COLS <= 8) count += bitpop(matrix[i]); #else count += bitpop16(matrix[i]); #endif } return count; } #ifdef MATRIX_HAS_GHOST inline static bool matrix_has_ghost_in_row(uint8_t row) { // no ghost exists in case less than 2 keys on if (((matrix[row] - 1) & matrix[row]) == 0) return false; // ghost exists in case same state as other row for (uint8_t i=0; i < MATRIX_ROWS; i++) { if (i != row && (matrix[i] & matrix[row]) == matrix[row]) return true; } return false; } #endif inline static uint8_t read_col(void) { return PINB; } inline static void unselect_rows(void) { // Hi-Z(DDR:0, PORT:0) to unselect DDRC &= ~0b11000000; // PC: 7,6 PORTC &= ~0b11000000; DDRD &= ~0b11000111; // PD: 7,6,2,1,0 PORTD &= ~0b11000111; DDRF &= ~0b11000000; // PF: 7,6 PORTF &= ~0b11000000; } inline static void select_row(uint8_t row) { // Output low(DDR:1, PORT:0) to select // row: 0 1 2 3 4 5 6 7 8 // pin: PD0, PC7, PD7, PF6, PD6, PD1, PD2, PC6, PF7 switch (row) { case 0: DDRD |= (1<<0); PORTD &= ~(1<<0); break; case 1: DDRC |= (1<<7); PORTC &= ~(1<<7); break; case 2: DDRD |= (1<<7); PORTD &= ~(1<<7); break; case 3: DDRF |= (1<<6); PORTF &= ~(1<<6); break; case 4: DDRD |= (1<<6); PORTD &= ~(1<<6); break; case 5: DDRD |= (1<<1); PORTD &= ~(1<<1); break; case 6: DDRD |= (1<<2); PORTD &= ~(1<<2); break; case 7: DDRC |= (1<<6); PORTC &= ~(1<<6); break; case 8: DDRF |= (1<<7); PORTF &= ~(1<<7); break; } }