diff options
-rw-r--r-- | quantum/matrix.c | 292 | ||||
-rw-r--r-- | tmk_core/common/avr/suspend.c | 6 | ||||
-rw-r--r-- | tmk_core/common/bootmagic.c | 16 | ||||
-rw-r--r-- | tmk_core/common/keyboard.c | 107 | ||||
-rw-r--r-- | tmk_core/common/matrix.h | 57 |
5 files changed, 261 insertions, 217 deletions
diff --git a/quantum/matrix.c b/quantum/matrix.c index a38c13f15b..0949170255 100644 --- a/quantum/matrix.c +++ b/quantum/matrix.c @@ -26,32 +26,46 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "util.h" #include "matrix.h" -#ifdef MATRIX_HAS_GHOST -# error "The universal matrix.c file cannot be used for this keyboard." -#endif +/* Set 0 if debouncing isn't needed */ +/* + * This constant define not debouncing time in msecs, but amount of matrix + * scan loops which should be made to get stable debounced results. + * + * On Ergodox matrix scan rate is relatively low, because of slow I2C. + * Now it's only 317 scans/second, or about 3.15 msec/scan. + * According to Cherry specs, debouncing time is 5 msec. + * + * And so, there is no sense to have DEBOUNCE higher than 2. + */ #ifndef DEBOUNCING_DELAY # define DEBOUNCING_DELAY 5 #endif +static uint8_t debouncing = DEBOUNCING_DELAY; static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; -/* matrix state */ -#if DIODE_DIRECTION == COL2ROW + +/* matrix state(1:on, 0:off) */ static matrix_row_t matrix[MATRIX_ROWS]; -#else -static matrix_col_t matrix[MATRIX_COLS]; +static matrix_row_t matrix_debouncing[MATRIX_ROWS]; + +#if DIODE_DIRECTION == ROW2COL + static matrix_row_t matrix_reversed[MATRIX_COLS]; + static matrix_row_t matrix_reversed_debouncing[MATRIX_COLS]; #endif -static int8_t debouncing_delay = -1; -#if DIODE_DIRECTION == COL2ROW -static void toggle_row(uint8_t row); -static matrix_row_t read_cols(void); +#if MATRIX_COLS > 16 + #define SHIFTER 1UL #else -static void toggle_col(uint8_t col); -static matrix_col_t read_rows(void); + #define SHIFTER 1 #endif +static matrix_row_t read_cols(void); +static void init_cols(void); +static void unselect_rows(void); +static void select_row(uint8_t row); + __attribute__ ((weak)) void matrix_init_quantum(void) { matrix_init_kb(); @@ -80,10 +94,12 @@ __attribute__ ((weak)) void matrix_scan_user(void) { } +inline uint8_t matrix_rows(void) { return MATRIX_ROWS; } +inline uint8_t matrix_cols(void) { return MATRIX_COLS; } @@ -113,161 +129,179 @@ uint8_t matrix_cols(void) { // } void matrix_init(void) { - /* frees PORTF by setting the JTD bit twice within four cycles */ + // To use PORTF disable JTAG with writing JTD bit twice within four cycles. #ifdef __AVR_ATmega32U4__ MCUCR |= _BV(JTD); MCUCR |= _BV(JTD); #endif - /* initializes the I/O pins */ -#if DIODE_DIRECTION == COL2ROW - for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) { - /* DDRxn */ - _SFR_IO8((row_pins[r] >> 4) + 1) |= _BV(row_pins[r] & 0xF); - toggle_row(r); - } - for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) { - /* PORTxn */ - _SFR_IO8((col_pins[c] >> 4) + 2) |= _BV(col_pins[c] & 0xF); - } -#else - for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) { - /* DDRxn */ - _SFR_IO8((col_pins[c] >> 4) + 1) |= _BV(col_pins[c] & 0xF); - toggle_col(c); - } - for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) { - /* PORTxn */ - _SFR_IO8((row_pins[r] >> 4) + 2) |= _BV(row_pins[r] & 0xF); + + // initialize row and col + unselect_rows(); + init_cols(); + + // initialize matrix state: all keys off + for (uint8_t i=0; i < MATRIX_ROWS; i++) { + matrix[i] = 0; + matrix_debouncing[i] = 0; } -#endif + matrix_init_quantum(); } +uint8_t matrix_scan(void) +{ + #if DIODE_DIRECTION == COL2ROW -uint8_t matrix_scan(void) { - static matrix_row_t debouncing_matrix[MATRIX_ROWS]; - for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) { - toggle_row(r); - matrix_row_t state = read_cols(); - if (debouncing_matrix[r] != state) { - debouncing_matrix[r] = state; - debouncing_delay = DEBOUNCING_DELAY; - } - toggle_row(r); - } - if (debouncing_delay >= 0) { - dprintf("Debouncing delay remaining: %X\n", debouncing_delay); - --debouncing_delay; - if (debouncing_delay >= 0) { - wait_ms(1); - } - else { - for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) { - matrix[r] = debouncing_matrix[r]; + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + select_row(i); + wait_us(30); // without this wait read unstable value. + matrix_row_t cols = read_cols(); + if (matrix_debouncing[i] != cols) { + matrix_debouncing[i] = cols; + if (debouncing) { + debug("bounce!: "); debug_hex(debouncing); debug("\n"); } + debouncing = DEBOUNCING_DELAY; } + unselect_rows(); } - matrix_scan_quantum(); - return 1; -} - -static void toggle_row(uint8_t row) { - /* PINxn */ - _SFR_IO8((row_pins[row] >> 4)) = _BV(row_pins[row] & 0xF); -} -static matrix_row_t read_cols(void) { - matrix_row_t state = 0; - for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) { - /* PINxn */ - if (!(_SFR_IO8((col_pins[c] >> 4)) & _BV(col_pins[c] & 0xF))) { - state |= (matrix_row_t)1 << c; + if (debouncing) { + if (--debouncing) { + wait_us(1); + } else { + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + matrix[i] = matrix_debouncing[i]; + } } } - return state; -} - -matrix_row_t matrix_get_row(uint8_t row) { - return matrix[row]; -} - #else -uint8_t matrix_scan(void) { - static matrix_col_t debouncing_matrix[MATRIX_COLS]; - for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) { - toggle_col(c); - matrix_col_t state = read_rows(); - if (debouncing_matrix[c] != state) { - debouncing_matrix[c] = state; - debouncing_delay = DEBOUNCING_DELAY; + for (uint8_t i = 0; i < MATRIX_COLS; i++) { + select_row(i); + wait_us(30); // without this wait read unstable value. + matrix_row_t rows = read_cols(); + if (matrix_reversed_debouncing[i] != rows) { + matrix_reversed_debouncing[i] = rows; + if (debouncing) { + debug("bounce!: "); debug_hex(debouncing); debug("\n"); + } + debouncing = DEBOUNCING_DELAY; } - toggle_col(c); + unselect_rows(); } - if (debouncing_delay >= 0) { - dprintf("Debouncing delay remaining: %X\n", debouncing_delay); - --debouncing_delay; - if (debouncing_delay >= 0) { - wait_ms(1); - } - else { - for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) { - matrix[c] = debouncing_matrix[c]; + + if (debouncing) { + if (--debouncing) { + wait_us(1); + } else { + for (uint8_t i = 0; i < MATRIX_COLS; i++) { + matrix_reversed[i] = matrix_reversed_debouncing[i]; } } } + for (uint8_t y = 0; y < MATRIX_ROWS; y++) { + matrix_row_t row = 0; + for (uint8_t x = 0; x < MATRIX_COLS; x++) { + row |= ((matrix_reversed[x] & (1<<y)) >> y) << x; + } + matrix[y] = row; + } +#endif + matrix_scan_quantum(); + return 1; } -static void toggle_col(uint8_t col) { - /* PINxn */ - _SFR_IO8((col_pins[col] >> 4)) = _BV(col_pins[col] & 0xF); +bool matrix_is_modified(void) +{ + if (debouncing) return false; + return true; } -static matrix_col_t read_rows(void) { - matrix_col_t state = 0; - for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) { - /* PINxn */ - if (!(_SFR_IO8((row_pins[r] >> 4)) & _BV(row_pins[r] & 0xF))) { - state |= (matrix_col_t)1 << r; - } +inline +bool matrix_is_on(uint8_t row, uint8_t col) +{ + return (matrix[row] & ((matrix_row_t)1<col)); +} + +inline +matrix_row_t matrix_get_row(uint8_t row) +{ + return matrix[row]; +} + +void matrix_print(void) +{ + print("\nr/c 0123456789ABCDEF\n"); + for (uint8_t row = 0; row < MATRIX_ROWS; row++) { + phex(row); print(": "); + pbin_reverse16(matrix_get_row(row)); + print("\n"); } - return state; } -matrix_row_t matrix_get_row(uint8_t row) { - matrix_row_t state = 0; - matrix_col_t mask = (matrix_col_t)1 << row; - for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) { - if (matrix[c] & mask) { - state |= (matrix_row_t)1 << c; - } +uint8_t matrix_key_count(void) +{ + uint8_t count = 0; + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + count += bitpop16(matrix[i]); } - return state; + return count; } +static void init_cols(void) +{ +#if DIODE_DIRECTION == COL2ROW + for(int x = 0; x < MATRIX_COLS; x++) { + int pin = col_pins[x]; +#else + for(int x = 0; x < MATRIX_ROWS; x++) { + int pin = row_pins[x]; #endif - -bool matrix_is_modified(void) { - if (debouncing_delay >= 0) return false; - return true; + _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); + _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); + } } -bool matrix_is_on(uint8_t row, uint8_t col) { - return matrix_get_row(row) & (matrix_row_t)1 << col; -} +static matrix_row_t read_cols(void) +{ + matrix_row_t result = 0; -void matrix_print(void) { - dprintln("Human-readable matrix state:"); - for (uint8_t r = 0; r < MATRIX_ROWS; r++) { - dprintf("State of row %X: %016b\n", r, bitrev16(matrix_get_row(r))); +#if DIODE_DIRECTION == COL2ROW + for(int x = 0; x < MATRIX_COLS; x++) { + int pin = col_pins[x]; +#else + for(int x = 0; x < MATRIX_ROWS; x++) { + int pin = row_pins[x]; +#endif + result |= (_SFR_IO8(pin >> 4) & _BV(pin & 0xF)) ? 0 : (SHIFTER << x); } + return result; } -uint8_t matrix_key_count(void) { - uint8_t count = 0; - for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) { - count += bitpop16(matrix_get_row(r)); +static void unselect_rows(void) +{ +#if DIODE_DIRECTION == COL2ROW + for(int x = 0; x < MATRIX_ROWS; x++) { + int pin = row_pins[x]; +#else + for(int x = 0; x < MATRIX_COLS; x++) { + int pin = col_pins[x]; +#endif + _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); + _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); } - return count; +} + +static void select_row(uint8_t row) +{ + +#if DIODE_DIRECTION == COL2ROW + int pin = row_pins[row]; +#else + int pin = col_pins[row]; +#endif + _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); + _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); } diff --git a/tmk_core/common/avr/suspend.c b/tmk_core/common/avr/suspend.c index a6f3c64414..8a7272bbc5 100644 --- a/tmk_core/common/avr/suspend.c +++ b/tmk_core/common/avr/suspend.c @@ -114,8 +114,10 @@ bool suspend_wakeup_condition(void) matrix_power_up(); matrix_scan(); matrix_power_down(); - if (matrix_key_count()) return true; - return false; + for (uint8_t r = 0; r < MATRIX_ROWS; r++) { + if (matrix_get_row(r)) return true; + } + return false; } // run immediately after wakeup diff --git a/tmk_core/common/bootmagic.c b/tmk_core/common/bootmagic.c index 90275a18ba..6730a2a4aa 100644 --- a/tmk_core/common/bootmagic.c +++ b/tmk_core/common/bootmagic.c @@ -106,13 +106,15 @@ void bootmagic(void) } } -static bool scan_keycode(uint8_t keycode) { - for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) { +static bool scan_keycode(uint8_t keycode) +{ + for (uint8_t r = 0; r < MATRIX_ROWS; r++) { matrix_row_t matrix_row = matrix_get_row(r); - for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) { - if (matrix_row & (matrix_row_t)1 << c) { - keypos_t key = (keypos_t){ .row = r, .col = c }; - if (keycode == keymap_key_to_keycode(0, key)) return true; + for (uint8_t c = 0; c < MATRIX_COLS; c++) { + if (matrix_row & ((matrix_row_t)1<<c)) { + if (keycode == keymap_key_to_keycode(0, (keypos_t){ .row = r, .col = c })) { + return true; + } } } } @@ -124,4 +126,4 @@ bool bootmagic_scan_keycode(uint8_t keycode) if (!scan_keycode(BOOTMAGIC_KEY_SALT)) return false; return scan_keycode(keycode); -} +}
\ No newline at end of file diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c index 34e1ceeca5..81df8eb73b 100644 --- a/tmk_core/common/keyboard.c +++ b/tmk_core/common/keyboard.c @@ -51,17 +51,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #endif #ifdef MATRIX_HAS_GHOST -static bool is_row_ghosting(uint8_t row){ - matrix_row_t state = matrix_get_row(row); - /* no ghosting happens when only one key in the row is pressed */ - if (!(state - 1 & state)) return false; - /* ghosting occurs when two keys in the same column are pressed */ - for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) { - if (r != row && matrix_get_row(r) & state) return true; +static bool has_ghost_in_row(uint8_t row) +{ + matrix_row_t matrix_row = matrix_get_row(row); + // No ghost exists when less than 2 keys are down on the row + if (((matrix_row - 1) & matrix_row) == 0) + return false; + + // Ghost occurs when the row shares column line with other row + for (uint8_t i=0; i < MATRIX_ROWS; i++) { + if (i != row && (matrix_get_row(i) & matrix_row)) + return true; } return false; } - #endif __attribute__ ((weak)) @@ -100,72 +103,86 @@ void keyboard_init(void) { #endif } -/* does routine keyboard jobs */ -void keyboard_task(void) { - static uint8_t led_status; +/* + * Do keyboard routine jobs: scan mantrix, light LEDs, ... + * This is repeatedly called as fast as possible. + */ +void keyboard_task(void) +{ + static matrix_row_t matrix_prev[MATRIX_ROWS]; +#ifdef MATRIX_HAS_GHOST + static matrix_row_t matrix_ghost[MATRIX_ROWS]; +#endif + static uint8_t led_status = 0; + matrix_row_t matrix_row = 0; + matrix_row_t matrix_change = 0; + matrix_scan(); - for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) { - static matrix_row_t previous_matrix[MATRIX_ROWS]; - matrix_row_t state = matrix_get_row(r); - matrix_row_t changes = state ^ previous_matrix[r]; - if (changes) { + for (uint8_t r = 0; r < MATRIX_ROWS; r++) { + matrix_row = matrix_get_row(r); + matrix_change = matrix_row ^ matrix_prev[r]; + if (matrix_change) { #ifdef MATRIX_HAS_GHOST - static matrix_row_t deghosting_matrix[MATRIX_ROWS]; - if (is_row_ghosting(r)) { - /* debugs the deghosting mechanism */ - /* doesn't update previous_matrix until the ghosting has stopped - * in order to prevent the last key from being lost + if (has_ghost_in_row(r)) { + /* Keep track of whether ghosted status has changed for + * debugging. But don't update matrix_prev until un-ghosted, or + * the last key would be lost. */ - if (debug_matrix && deghosting_matrix[r] != state) { + if (debug_matrix && matrix_ghost[r] != matrix_row) { matrix_print(); } - deghosting_matrix[r] = state; + matrix_ghost[r] = matrix_row; continue; } - deghosting_matrix[r] = state; + matrix_ghost[r] = matrix_row; #endif if (debug_matrix) matrix_print(); - for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) { - matrix_row_t mask = (matrix_row_t)1 << c; - if (changes & mask) { - keyevent_t event; - event.key = (keypos_t){ .row = r, .col = c }; - event.pressed = state & mask; - /* the time should not be 0 */ - event.time = timer_read() | 1; - action_exec(event); - /* records the processed key event */ - previous_matrix[r] ^= mask; - /* processes one key event per call */ - goto event_processed; + for (uint8_t c = 0; c < MATRIX_COLS; c++) { + if (matrix_change & ((matrix_row_t)1<<c)) { + action_exec((keyevent_t){ + .key = (keypos_t){ .row = r, .col = c }, + .pressed = (matrix_row & ((matrix_row_t)1<<c)), + .time = (timer_read() | 1) /* time should not be 0 */ + }); + // record a processed key + matrix_prev[r] ^= ((matrix_row_t)1<<c); + // process a key per task call + goto MATRIX_LOOP_END; } } } } - /* sends tick events when the keyboard is idle */ + // call with pseudo tick event when no real key event. action_exec(TICK); -event_processed: + +MATRIX_LOOP_END: + #ifdef MOUSEKEY_ENABLE - /* repeats and accelerates the mouse keys */ + // mousekey repeat & acceleration mousekey_task(); #endif + #ifdef PS2_MOUSE_ENABLE ps2_mouse_task(); #endif + #ifdef SERIAL_MOUSE_ENABLE - serial_mouse_task(); + serial_mouse_task(); #endif + #ifdef ADB_MOUSE_ENABLE - adb_mouse_task(); + adb_mouse_task(); #endif - /* updates the LEDs */ + + // update LED if (led_status != host_keyboard_leds()) { led_status = host_keyboard_leds(); keyboard_set_leds(led_status); } } -void keyboard_set_leds(uint8_t leds) { - if (debug_keyboard) dprintf("Keyboard LEDs state: %x\n", leds); +void keyboard_set_leds(uint8_t leds) +{ + if (debug_keyboard) { debug("keyboard_set_led: "); debug_hex8(leds); debug("\n"); } led_set(leds); } diff --git a/tmk_core/common/matrix.h b/tmk_core/common/matrix.h index 5f2f831b45..71153a5f58 100644 --- a/tmk_core/common/matrix.h +++ b/tmk_core/common/matrix.h @@ -20,59 +20,48 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include <stdint.h> #include <stdbool.h> -#if MATRIX_COLS <= 8 -typedef uint8_t matrix_row_t; -#elif MATRIX_COLS <= 16 -typedef uint16_t matrix_row_t; -#elif MATRIX_COLS <= 32 -typedef uint32_t matrix_row_t; + +#if (MATRIX_COLS <= 8) +typedef uint8_t matrix_row_t; +#elif (MATRIX_COLS <= 16) +typedef uint16_t matrix_row_t; +#elif (MATRIX_COLS <= 32) +typedef uint32_t matrix_row_t; #else -# error "There are too many columns." +#error "MATRIX_COLS: invalid value" #endif -#if DIODE_DIRECTION == ROW2COL -# if MATRIX_ROWS <= 8 -typedef uint8_t matrix_col_t; -# elif MATRIX_ROWS <= 16 -typedef uint16_t matrix_col_t; -# elif MATRIX_ROWS <= 32 -typedef uint32_t matrix_col_t; -# else -# error "There are too many rows." -# endif -#endif +#define MATRIX_IS_ON(row, col) (matrix_get_row(row) && (1<<col)) -typedef struct { - uint8_t input_addr:4; - uint8_t bit:4; -} io_pin_t; #ifdef __cplusplus extern "C" { #endif -/* counts the number of rows in the matrix */ + +/* number of matrix rows */ uint8_t matrix_rows(void); -/* counts the number of columns in the matrix */ +/* number of matrix columns */ uint8_t matrix_cols(void); -/* sets up the matrix before matrix_init */ +/* should be called at early stage of startup before matrix_init.(optional) */ void matrix_setup(void); -/* intializes the matrix */ +/* intialize matrix for scaning. */ void matrix_init(void); -/* scans the entire matrix */ +/* scan all key states on matrix */ uint8_t matrix_scan(void); -/* checks if the matrix has been modified */ +/* whether modified from previous scan. used after matrix_scan. */ bool matrix_is_modified(void) __attribute__ ((deprecated)); -/* checks if a key is pressed */ +/* whether a swtich is on */ bool matrix_is_on(uint8_t row, uint8_t col); -/* inspects the state of a row in the matrix */ +/* matrix state on row */ matrix_row_t matrix_get_row(uint8_t row); -/* prints the matrix for debugging */ +/* print matrix for debug */ void matrix_print(void); -/* counts the total number of keys pressed */ -uint8_t matrix_key_count(void); -/* controls power to the matrix */ + + +/* power control */ void matrix_power_up(void); void matrix_power_down(void); + /* executes code for Quantum */ void matrix_init_quantum(void); void matrix_scan_quantum(void); |