Skip to content

Commit

Permalink
Interlace both hands during matrix scan for faster performance
Browse files Browse the repository at this point in the history
Right hand is scanned through i2c which incurs some delay,
we can use this delay instead of sleeping when scanning the
left hand.
When the right hand isn't present fallback to sleep.
And stop trying to re-init right hand multiple times per scan.
I've been able to hit 380 matrix scans seconds
on moonlander mark I and more than 2000 scans per seconds with
right hand detached, without the change I measure it to be at
320 scans seconds in both cases.

This work it inspired by:
https://michael.stapelberg.ch/posts/2021-05-08-keyboard-input-latency-qmk-kinesis/
  • Loading branch information
izissise committed Aug 2, 2021
1 parent c2f227d commit 1a6b2ef
Showing 1 changed file with 82 additions and 76 deletions.
158 changes: 82 additions & 76 deletions keyboards/moonlander/matrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,105 +129,111 @@ void matrix_init(void) {
uint8_t matrix_scan(void) {
bool changed = false;

// Try to re-init right side
if (!mcp23018_initd) {
if (++mcp23018_reset_loop == 0) {
// if (++mcp23018_reset_loop >= 1300) {
// since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
// this will be approx bit more frequent than once per second
print("trying to reset mcp23018\n");
mcp23018_init();
if (!mcp23018_initd) {
print("left side not responding\n");
} else {
print("left side attached\n");
#ifdef RGB_MATRIX_ENABLE
rgb_matrix_init();
#endif
}
}
}

matrix_row_t data = 0;
// actual matrix
for (uint8_t row = 0; row < ROWS_PER_HAND; row++) {
// strobe row
for (uint8_t row = 0; row <= ROWS_PER_HAND; row++) {
// strobe row
switch (row) {
case 0: writePinHigh(B10); break;
case 1: writePinHigh(B11); break;
case 2: writePinHigh(B12); break;
case 3: writePinHigh(B13); break;
case 4: writePinHigh(B14); break;
case 5: writePinHigh(B15); break;
case 6: break; // Left hand has 6 rows
}

// need wait to settle pin state
matrix_io_delay();

// read col data
data = (
(readPin(A0) << 0 ) |
(readPin(A1) << 1 ) |
(readPin(A2) << 2 ) |
(readPin(A3) << 3 ) |
(readPin(A6) << 4 ) |
(readPin(A7) << 5 ) |
(readPin(B0) << 6 )
);

// unstrobe row
switch (row) {
case 0: writePinLow(B10); break;
case 1: writePinLow(B11); break;
case 2: writePinLow(B12); break;
case 3: writePinLow(B13); break;
case 4: writePinLow(B14); break;
case 5: writePinLow(B15); break;
}

if (matrix_debouncing[row] != data) {
matrix_debouncing[row] = data;
debouncing = true;
debouncing_time = timer_read();
changed = true;
}
}

for (uint8_t row = 0; row <= ROWS_PER_HAND; row++) {
// right side

if (!mcp23018_initd) {
if (++mcp23018_reset_loop == 0) {
// if (++mcp23018_reset_loop >= 1300) {
// since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
// this will be approx bit more frequent than once per second
print("trying to reset mcp23018\n");
mcp23018_init();
if (!mcp23018_initd) {
print("left side not responding\n");
} else {
print("left side attached\n");
#ifdef RGB_MATRIX_ENABLE
rgb_matrix_init();
#endif
}
if (mcp23018_initd) {
// #define MCP23_ROW_PINS { GPB5, GBP4, GBP3, GBP2, GBP1, GBP0 } outputs
// #define MCP23_COL_PINS { GPA0, GBA1, GBA2, GBA3, GBA4, GBA5, GBA6 } inputs

// select row
mcp23018_tx[0] = 0x12; // GPIOA
mcp23018_tx[1] = (0b01111111 & ~(1 << (row))) | ((uint8_t)!mcp23018_leds[2] << 7); // activate row
mcp23018_tx[2] = ((uint8_t)!mcp23018_leds[1] << 6) | ((uint8_t)!mcp23018_leds[0] << 7); // activate row

if (MSG_OK != i2c_transmit(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx, 3, I2C_TIMEOUT)) {
dprintf("error hori\n");
mcp23018_initd = false;
}
}

// #define MCP23_ROW_PINS { GPB5, GBP4, GBP3, GBP2, GBP1, GBP0 } outputs
// #define MCP23_COL_PINS { GPA0, GBA1, GBA2, GBA3, GBA4, GBA5, GBA6 } inputs
// read col

// select row

mcp23018_tx[0] = 0x12; // GPIOA
mcp23018_tx[1] = (0b01111111 & ~(1 << (row))) | ((uint8_t)!mcp23018_leds[2] << 7); // activate row
mcp23018_tx[2] = ((uint8_t)!mcp23018_leds[1] << 6) | ((uint8_t)!mcp23018_leds[0] << 7); // activate row

if (MSG_OK != i2c_transmit(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx, 3, I2C_TIMEOUT)) {
dprintf("error hori\n");
mcp23018_initd = false;
}
mcp23018_tx[0] = 0x13; // GPIOB
if (MSG_OK != i2c_readReg(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx[0], &mcp23018_rx[0], 1, I2C_TIMEOUT)) {
dprintf("error vert\n");
mcp23018_initd = false;
}

// read col
data = ~(mcp23018_rx[0] & 0b00111111);
// data = 0x01;

mcp23018_tx[0] = 0x13; // GPIOB
if (MSG_OK != i2c_readReg(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx[0], &mcp23018_rx[0], 1, I2C_TIMEOUT)) {
dprintf("error vert\n");
mcp23018_initd = false;
if (matrix_debouncing_right[row] != data) {
matrix_debouncing_right[row] = data;
debouncing_right = true;
debouncing_time_right = timer_read();
changed = true;
}
}

data = ~(mcp23018_rx[0] & 0b00111111);
// data = 0x01;
// left side
if (row < ROWS_PER_HAND) {
// i2c comm incur enough wait time
if (!mcp23018_initd) {
// need wait to settle pin state
matrix_io_delay();
}
// read col data
data = (
(readPin(A0) << 0 ) |
(readPin(A1) << 1 ) |
(readPin(A2) << 2 ) |
(readPin(A3) << 3 ) |
(readPin(A6) << 4 ) |
(readPin(A7) << 5 ) |
(readPin(B0) << 6 )
);
// unstrobe row
switch (row) {
case 0: writePinLow(B10); break;
case 1: writePinLow(B11); break;
case 2: writePinLow(B12); break;
case 3: writePinLow(B13); break;
case 4: writePinLow(B14); break;
case 5: writePinLow(B15); break;
case 6: break;
}

if (matrix_debouncing_right[row] != data) {
matrix_debouncing_right[row] = data;
debouncing_right = true;
debouncing_time_right = timer_read();
changed = true;
if (matrix_debouncing[row] != data) {
matrix_debouncing[row] = data;
debouncing = true;
debouncing_time = timer_read();
changed = true;
}
}
}

// Debounce both hands
if (debouncing && timer_elapsed(debouncing_time) > DEBOUNCE) {
for (int row = 0; row < ROWS_PER_HAND; row++) {
matrix[row] = matrix_debouncing[row];
Expand Down

0 comments on commit 1a6b2ef

Please sign in to comment.