|
|
@ -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); |
|
|
|
} |