X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=Scan%2FMatrixARM%2Fmatrix_scan.c;h=669314329efff3079c93dc065e45800b54cae004;hb=88670ac72f51e5f1f68b72ca300bdb0c999a37f7;hp=eaea368f4b01e6a8635879e4f9ba1b25e92ca3dc;hpb=a9c5898ba5fcb06f11ff97c4fe1fbafb836ebd87;p=kiibohd-controller.git diff --git a/Scan/MatrixARM/matrix_scan.c b/Scan/MatrixARM/matrix_scan.c index eaea368..6693143 100644 --- a/Scan/MatrixARM/matrix_scan.c +++ b/Scan/MatrixARM/matrix_scan.c @@ -26,9 +26,11 @@ // Project Includes #include +#include #include #include #include +#include // Local Includes #include "matrix_scan.h" @@ -38,6 +40,14 @@ +// ----- Defines ----- + +#if ( DebounceThrottleDiv_define > 0 ) +nat_ptr_t Matrix_divCounter = 0; +#endif + + + // ----- Function Declarations ----- // CLI Functions @@ -61,6 +71,15 @@ CLIDict_Def( matrixCLIDict, "Matrix Module Commands" ) = { // Debounce Array KeyState Matrix_scanArray[ Matrix_colsNum * Matrix_rowsNum ]; +// Ghost Arrays +#ifdef GHOSTING_MATRIX +KeyGhost Matrix_ghostArray[ Matrix_colsNum * Matrix_rowsNum ]; + +uint8_t col_use[Matrix_colsNum], row_use[Matrix_rowsNum]; // used count +uint8_t col_ghost[Matrix_colsNum], row_ghost[Matrix_rowsNum]; // marked as having ghost if 1 +#endif + + // Matrix debug flag - If set to 1, for each keypress the scan code is displayed in hex // If set to 2, for each key state change, the scan code is displayed along with the state uint8_t matrixDebugMode = 0; @@ -73,6 +92,9 @@ uint16_t matrixMaxScans = 0; uint16_t matrixCurScans = 0; uint16_t matrixPrevScans = 0; +// System Timer used for delaying debounce decisions +extern volatile uint32_t systick_millis_count; + // ----- Functions ----- @@ -89,7 +111,9 @@ uint8_t Matrix_pin( GPIO_Pin gpio, Type type ) // Assumes 0x40 between GPIO Port registers and 0x1000 between PORT pin registers // See Lib/mk20dx.h volatile unsigned int *GPIO_PDDR = (unsigned int*)(&GPIOA_PDDR) + gpio_offset; + #ifndef GHOSTING_MATRIX volatile unsigned int *GPIO_PSOR = (unsigned int*)(&GPIOA_PSOR) + gpio_offset; + #endif volatile unsigned int *GPIO_PCOR = (unsigned int*)(&GPIOA_PCOR) + gpio_offset; volatile unsigned int *GPIO_PDIR = (unsigned int*)(&GPIOA_PDIR) + gpio_offset; volatile unsigned int *PORT_PCR = (unsigned int*)(&PORTA_PCR0) + port_offset; @@ -98,16 +122,30 @@ uint8_t Matrix_pin( GPIO_Pin gpio, Type type ) switch ( type ) { case Type_StrobeOn: + #ifdef GHOSTING_MATRIX + *GPIO_PCOR |= (1 << gpio.pin); + *GPIO_PDDR |= (1 << gpio.pin); // output, low + #else *GPIO_PSOR |= (1 << gpio.pin); + #endif break; case Type_StrobeOff: + #ifdef GHOSTING_MATRIX + // Ghosting martix needs to put not used (off) strobes in high impedance state + *GPIO_PDDR &= ~(1 << gpio.pin); // input, high Z state + #endif *GPIO_PCOR |= (1 << gpio.pin); break; case Type_StrobeSetup: + #ifdef GHOSTING_MATRIX + *GPIO_PDDR &= ~(1 << gpio.pin); // input, high Z state + *GPIO_PCOR |= (1 << gpio.pin); + #else // Set as output pin *GPIO_PDDR |= (1 << gpio.pin); + #endif // Configure pin with slow slew, high drive strength and GPIO mux *PORT_PCR = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); @@ -126,7 +164,11 @@ uint8_t Matrix_pin( GPIO_Pin gpio, Type type ) break; case Type_Sense: + #ifdef GHOSTING_MATRIX // inverted + return *GPIO_PDIR & (1 << gpio.pin) ? 0 : 1; + #else return *GPIO_PDIR & (1 << gpio.pin) ? 1 : 0; + #endif case Type_SenseSetup: // Set as input pin @@ -184,14 +226,21 @@ void Matrix_setup() print( NL ); info_msg("Max Keys: "); printHex( Matrix_maxKeys ); + print( NL ); // Clear out Debounce Array for ( uint8_t item = 0; item < Matrix_maxKeys; item++ ) { - Matrix_scanArray[ item ].prevState = KeyState_Off; - Matrix_scanArray[ item ].curState = KeyState_Off; - Matrix_scanArray[ item ].activeCount = 0; - Matrix_scanArray[ item ].inactiveCount = DebounceDivThreshold_define; // Start at 'off' steady state + Matrix_scanArray[ item ].prevState = KeyState_Off; + Matrix_scanArray[ item ].curState = KeyState_Off; + Matrix_scanArray[ item ].activeCount = 0; + Matrix_scanArray[ item ].inactiveCount = DebounceDivThreshold_define; // Start at 'off' steady state + Matrix_scanArray[ item ].prevDecisionTime = 0; + #ifdef GHOSTING_MATRIX + Matrix_ghostArray[ item ].prev = KeyState_Off; + Matrix_ghostArray[ item ].cur = KeyState_Off; + Matrix_ghostArray[ item ].saved = KeyState_Off; + #endif } // Clear scan stats counters @@ -232,6 +281,15 @@ void Matrix_keyPositionDebug( KeyPosition pos ) // NOTE: scanNum should be reset to 0 after a USB send (to reset all the counters) void Matrix_scan( uint16_t scanNum ) { +#if ( DebounceThrottleDiv_define > 0 ) + // Scan-rate throttling + // By scanning using a divider, the scan rate slowed down + // DebounceThrottleDiv_define == 1 means -> /2 or half scan rate + // This helps with bouncy switches on fast uCs + if ( !( Matrix_divCounter++ & (1 << ( DebounceThrottleDiv_define - 1 )) ) ) + return; +#endif + // Increment stats counters if ( scanNum > matrixMaxScans ) matrixMaxScans = scanNum; if ( scanNum == 0 ) @@ -244,12 +302,25 @@ void Matrix_scan( uint16_t scanNum ) matrixCurScans++; } + // Read systick for event scheduling + uint8_t currentTime = (uint8_t)systick_millis_count; + // For each strobe, scan each of the sense pins for ( uint8_t strobe = 0; strobe < Matrix_colsNum; strobe++ ) { + #ifdef STROBE_DELAY + uint32_t start = micros(); + while ((micros() - start) < STROBE_DELAY); + #endif + // Strobe Pin Matrix_pin( Matrix_cols[ strobe ], Type_StrobeOn ); + #ifdef STROBE_DELAY + start = micros(); + while ((micros() - start) < STROBE_DELAY); + #endif + // Scan each of the sense pins for ( uint8_t sense = 0; sense < Matrix_rowsNum; sense++ ) { @@ -287,11 +358,16 @@ void Matrix_scan( uint16_t scanNum ) } // Check for state change if it hasn't been set + // But only if enough time has passed since last state change // Only check if the minimum number of scans has been met // the current state is invalid // and either active or inactive count is over the debounce threshold if ( state->curState == KeyState_Invalid ) { + // Determine time since last decision + uint8_t lastTransition = currentTime - state->prevDecisionTime; + + // Attempt state transition switch ( state->prevState ) { case KeyState_Press: @@ -302,6 +378,15 @@ void Matrix_scan( uint16_t scanNum ) } else { + // If not enough time has passed since Hold + // Keep previous state + if ( lastTransition < MinDebounceTime_define ) + { + //warn_print("FAST Release stopped"); + state->curState = state->prevState; + continue; + } + state->curState = KeyState_Release; } break; @@ -310,6 +395,15 @@ void Matrix_scan( uint16_t scanNum ) case KeyState_Off: if ( state->activeCount > state->inactiveCount ) { + // If not enough time has passed since Hold + // Keep previous state + if ( lastTransition < MinDebounceTime_define ) + { + //warn_print("FAST Press stopped"); + state->curState = state->prevState; + continue; + } + state->curState = KeyState_Press; } else @@ -324,8 +418,13 @@ void Matrix_scan( uint16_t scanNum ) break; } + // Update decision time + state->prevDecisionTime = currentTime; + // Send keystate to macro module + #ifndef GHOSTING_MATRIX Macro_keyState( key, state->curState ); + #endif // Matrix Debug, only if there is a state change if ( matrixDebugMode && state->curState != state->prevState ) @@ -351,6 +450,97 @@ void Matrix_scan( uint16_t scanNum ) Matrix_pin( Matrix_cols[ strobe ], Type_StrobeOff ); } + + // Matrix ghosting check and elimination + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +#ifdef GHOSTING_MATRIX + // strobe = column, sense = row + + // Count (rows) use for columns + //print("C "); + for ( uint8_t col = 0; col < Matrix_colsNum; col++ ) + { + uint8_t used = 0; + for ( uint8_t row = 0; row < Matrix_rowsNum; row++ ) + { + uint8_t key = Matrix_colsNum * row + col; + KeyState *state = &Matrix_scanArray[ key ]; + if ( keyOn(state->curState) ) + used++; + } + //printInt8(used); + col_use[col] = used; + col_ghost[col] = 0; // clear + } + + // Count (columns) use for rows + //print(" R "); + for ( uint8_t row = 0; row < Matrix_rowsNum; row++ ) + { + uint8_t used = 0; + for ( uint8_t col = 0; col < Matrix_colsNum; col++ ) + { + uint8_t key = Matrix_colsNum * row + col; + KeyState *state = &Matrix_scanArray[ key ]; + if ( keyOn(state->curState) ) + used++; + } + //printInt8(used); + row_use[row] = used; + row_ghost[row] = 0; // clear + } + + // Check if matrix has ghost + // Happens when key is pressed and some other key is pressed in same row and another in same column + //print(" G "); + for ( uint8_t col = 0; col < Matrix_colsNum; col++ ) + { + for ( uint8_t row = 0; row < Matrix_rowsNum; row++ ) + { + uint8_t key = Matrix_colsNum * row + col; + KeyState *state = &Matrix_scanArray[ key ]; + if ( keyOn(state->curState) && col_use[col] >= 2 && row_use[row] >= 2 ) + { + // mark col and row as having ghost + col_ghost[col] = 1; + row_ghost[row] = 1; + //print(" "); printInt8(col); print(","); printInt8(row); + } + } + } + //print( NL ); + + // Send keys + for ( uint8_t col = 0; col < Matrix_colsNum; col++ ) + { + for ( uint8_t row = 0; row < Matrix_rowsNum; row++ ) + { + uint8_t key = Matrix_colsNum * row + col; + KeyState *state = &Matrix_scanArray[ key ]; + KeyGhost *st = &Matrix_ghostArray[ key ]; + + // col or row is ghosting (crossed) + uint8_t ghost = (col_ghost[col] > 0 || row_ghost[row] > 0) ? 1 : 0; + + st->prev = st->cur; // previous + // save state if no ghost or outside ghosted area + if ( ghost == 0 ) + st->saved = state->curState; // save state if no ghost + // final + // use saved state if ghosting, or current if not + st->cur = ghost > 0 ? st->saved : state->curState; + + // Send keystate to macro module + KeyPosition k = !st->cur + ? (!st->prev ? KeyState_Off : KeyState_Release) + : ( st->prev ? KeyState_Hold : KeyState_Press); + Macro_keyState( key, k ); + } + } +#endif + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + // State Table Output Debug if ( matrixDebugStateCounter > 0 ) {