Timer Reset Does Not Work In Tickless From an ISR (CORTEX M3)

cjbissonnette wrote on Tuesday, March 19, 2019:

I’m developing an application using the EFM32GG Cortex M3 Processor. I am running freeRTOS (V10.1.1) in tickless mode. I’ve observed that when I try to reset a software timer from a GPIO interrupt, that timer fires much sooner than expected. I’ve traced the issue to to the fact that xTimerResetFromISR will remember the current tick count. This value has not yet been adjusted by vPortSuppressTicksAndSleep because it is still in an interrupt context. Then vPortSuppressTicksAndSleep adjusts the tickcount. When prvProcessReceivedCommands is run it now thinks much more time has passed (the difference in the tick adjustment when the RTOS was asleep) and the timer is run before expected. My work around right now is to use the current time when the tmrCOMMAND_START_FROM_ISR or tmrCOMMAND_RESET_FROM_ISR is received (instead of the stored message time). This is not ideal because the timer will now lose the time it takes prior to processing the message. Is there a better way to handle this situation? Do I have something configured wrong.? Thanks in advance.

rtel wrote on Tuesday, March 19, 2019:

I don’t know if you are using the ‘default’ low power mode, but if so I
can see why this happens, and I think it is because people wanted the
old way it worked to be changed so interrupt can execute as early as
possible. You will see in this code that interrupts are enabled
momentarily to enable the interrupt to execute, then disabled again
before adjusting the clock (code from Source/portable/GCC/ARM_CM4F/port.c):

/* Re-enable interrupts to allow the interrupt that brought the MCU
out of sleep mode to execute immediately.  see comments above
__disable_interrupt() call above. */
__asm volatile( "cpsie i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );

/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__asm volatile( "cpsid i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );

You could try removing the cpsie i (and also the first dsb and isb)
instructions to see if that helps you as then the clock will have been
adjusted before the interrupts executes. Also you could defer the
resetting of the timer to the daemon task, which would then only execute
after everything was up and running again.

cjbissonnette wrote on Tuesday, March 19, 2019:

We were using a custom sleep, but the concept was the same. I changed the code to only re-enable the interrupts after the adjustment had occured. Thanks for the help!