I’m using SiliconLabs Gecko SDK v4.1.2 which comes with FreeRTOS Kernel V10.4.3. I’m using FreeRTOS timer to trigger messages to another task after 5 seconds. My code starts/resets the timer when the button is pressed, and stops the timer when released. If I hold the button for 5 seconds, the callback function is called as expected. The problem i’m having is if I press the button (start/reset timer) and release the button (stop timer), then wait 5 seconds, and press the button again (start/reset timer), the timer callback function is called immediately, which is unexpected. I added some code to check the timer expiration tick value vs current, and for the normal case, the timer ticks are -1 which is expected. For the bad case, I can see timer tick delta of -5000+, etc. Then when i added some guard code to check the timer tick delta to see if it was a ‘real’ timer expiration, the timer stopped working at all. I’ve spent more than 2 days trying different things, running out of ideas.
#define MEDIUM_DURATION_MS ((TickType_t) 5000 )
#define LONG_DURATION_MS ((TickType_t) 10000 - MEDIUM_DURATION_MS )
/* Button press timer handles */
static TimerHandle_t medium_button_timer = NULL;
static TimerHandle_t long_button_timer = NULL;
#define MEDIUM_TIMER_ID (size_t)1
#define LONG_TIMER_ID (size_t)2
/* timer callback function */
void button_timer_cb( TimerHandle_t xTimer )
{
BaseType_t timer_stat = pdFALSE;
if( xTimerIsTimerActive( medium_button_timer ) == pdTRUE) {
//printf("M EXP\n");
}
if( xTimerIsTimerActive( long_button_timer ) == pdTRUE) {
//printf("L EXP\n");
}
size_t timer_id = (size_t) pvTimerGetTimerID(xTimer);
if( timer_id == MEDIUM_TIMER_ID ) {
send_rx_msg_button( BTN_MEDIUM_HOLD );
/* start long timer, without task block time */
timer_stat = xTimerStart(long_button_timer, 0);
//printf("L START\n");
app_assert( timer_stat == pdPASS, "Unable start timer" );
}
// else if ( timer_id == LONG_TIMER_ID && realExpiry == true ) {
else if ( timer_id == LONG_TIMER_ID ) {
send_rx_msg_button( BTN_LONG_HOLD );
}
else {
;
}
}
void button_init(void) {
medium_button_timer = xTimerCreate ( "medium button timer",
pdMS_TO_TICKS(MEDIUM_DURATION_MS),
pdFALSE,
(void *)MEDIUM_TIMER_ID,
button_timer_cb);
long_button_timer = xTimerCreate ( "long button timer",
pdMS_TO_TICKS(LONG_DURATION_MS),
pdFALSE,
(void *)LONG_TIMER_ID,
button_timer_cb);
}
/* on button change callback, executed in interrupt context */
void sl_button_on_change(const sl_button_t *handle) {
//printf("B-ENTRY\n");
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
BaseType_t timer_stat = pdFALSE;
if (sl_button_get_state(handle) == SL_SIMPLE_BUTTON_PRESSED) {
/* reset medium timer */
timer_stat = xTimerStartFromISR(medium_button_timer, &xHigherPriorityTaskWoken);
//printf("M START\n");
app_assert( timer_stat == pdPASS, "Unable start timer" );
}
else if (sl_button_get_state(handle) == SL_SIMPLE_BUTTON_RELEASED) {
if( xTimerIsTimerActive( medium_button_timer ) == pdTRUE) {
/* medium button timer is active, assume 'short press/release' */
send_rx_msg_button_from_isr( BTN_SHORT_PRESS );
}
else if ( xTimerIsTimerActive( long_button_timer ) == pdTRUE) {
}
else {
/* both timers already have expired (long press) */
;
}
timer_stat = xTimerStopFromISR(medium_button_timer, &xHigherPriorityTaskWoken );
app_assert( timer_stat == pdPASS, "Unable stop timer" );
//printf("M STOP\n");
timer_stat = xTimerStopFromISR(long_button_timer, &xHigherPriorityTaskWoken );
app_assert( timer_stat == pdPASS, "Unable stop timer" );
}
else {
//printf("NEITHER\n");
app_assert_s(false);
}
if( xHigherPriorityTaskWoken != pdFALSE )
{
/* Call the interrupt safe yield function here (actual function
depends on the FreeRTOS port being used). */
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
//printf("B-EXIT\n");
}