From 98f796d4df16c5aa14d0d07a5250c589dfb5f13a Mon Sep 17 00:00:00 2001 From: Jacob Alexander Date: Fri, 19 Jun 2015 01:50:56 -0700 Subject: [PATCH] Adding timing based debounce code - Uses expiry timer to decide on when to allow a state change - Initial state transitions are unaffected - Use MinDebounceTime define in kll to configure - ms granularity --- Scan/MatrixARM/capabilities.kll | 7 ++++++ Scan/MatrixARM/matrix_scan.c | 41 +++++++++++++++++++++++++++++---- Scan/MatrixARM/matrix_scan.h | 13 ++++++++--- 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/Scan/MatrixARM/capabilities.kll b/Scan/MatrixARM/capabilities.kll index 8221ec8..fe0192d 100644 --- a/Scan/MatrixARM/capabilities.kll +++ b/Scan/MatrixARM/capabilities.kll @@ -32,3 +32,10 @@ DebounceThrottleDiv => DebounceThrottleDiv_define; DebounceThrottleDiv = 0; # Default #DebounceThrottleDiv = 2; # /4 divider +# This defines the minimum amount of time after a transition until allowing another transition +# Generally switches require a minimum 5 ms debounce period +# Since a decision can usually be made quite quickly, there is little latency on each press +# However, this defines the latency at which the switch state can change +MinDebounceTime => MinDebounceTime_define; +MinDebounceTime = 5; # 5 ms + diff --git a/Scan/MatrixARM/matrix_scan.c b/Scan/MatrixARM/matrix_scan.c index 85f8205..a48e287 100644 --- a/Scan/MatrixARM/matrix_scan.c +++ b/Scan/MatrixARM/matrix_scan.c @@ -82,6 +82,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 ----- @@ -197,10 +200,11 @@ void Matrix_setup() // 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; } // Clear scan stats counters @@ -262,6 +266,9 @@ 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++ ) { @@ -305,11 +312,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: @@ -320,6 +332,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; @@ -328,6 +349,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 @@ -342,6 +372,9 @@ void Matrix_scan( uint16_t scanNum ) break; } + // Update decision time + state->prevDecisionTime = currentTime; + // Send keystate to macro module Macro_keyState( key, state->curState ); diff --git a/Scan/MatrixARM/matrix_scan.h b/Scan/MatrixARM/matrix_scan.h index 06ae75f..810e6d9 100644 --- a/Scan/MatrixARM/matrix_scan.h +++ b/Scan/MatrixARM/matrix_scan.h @@ -40,6 +40,12 @@ #error "Debounce threshold is too high... 32 bit max. Check .kll defines." #endif +#if ( MinDebounceTime_define > 0xFF ) +#error "MinDebounceTime is a maximum of 255 ms" +#elif ( MinDebounceTime_define < 0x00 ) +#error "MinDebounceTime is a minimum 0 ms" +#endif + // ----- Enums ----- @@ -126,11 +132,12 @@ typedef struct GPIO_Pin { // Debounce Element typedef struct KeyState { - KeyPosition prevState; - KeyPosition curState; DebounceCounter activeCount; DebounceCounter inactiveCount; -} KeyState; + KeyPosition prevState; + KeyPosition curState; + uint8_t prevDecisionTime; +} __attribute__((packed)) KeyState;