I want to use tickless idle to save power and at the same time I want to use the GPIO interrupts. Can I use both? Currently it seems if I enable tickless Idle, I can’t use GPIO interrupt as it causes the timers to go nuts.
Richard,
I am using 8.2.3 version
For tickless mode, I have just enabled
configUSETICKLESSIDLE to 1 and configUSE_TICK_HOOK to 1 and application tickhook function is doing nothing:
The STM32 port uses processor’s STOP (low power) mode. This code to put the device in STOP mode is called in vPortSuppressTicksAndSleep function. In this mode, RTC Wakeup timer is used to get out of the stop mode.
This is the code that is causing all the trouble.
If I keep Tickless Idle ON but disable STOP Mode, it works but then the device obviously wouldn’t go to low power mode.
My guess is that the RTC_Wakeup timer is running at a different rate than what FreeRTOS thinks it is. That can cause all kind of havok when the processor wakes back up from the interrupt, as FreeRTOS may think more time has passed than really has.
The version you are using is old and some original versions of
tickless idle didn’t allow the simultaneous use of software timers. I’m
not sure without checking the version history when that was changed, but
it’s probably worth updating the FreeRTOS kernel files (including header
files and port layer files) to the latest version in case that is your
issue.
From your description it is clear you are not using the ‘generic’
tickless idle mode, which cannot enter a very deep sleep as it uses the
SysTick timer, but a chip specific version, which is using a low power
timer and entering a much deeper sleep mode. It could be the
implementation is not re-calculating the time correctly when low power
mode is exited because of an interrupt - and that is making it appear
that time has moved on past where the timers should have expired, and
that the timers are catching up with where they should have been if the
time were correct.
The problem was in STM32 port code. For STM32 there is mode called STOP mode which is used in conjunction with TicklessDelay feature. When Stop mode is used to put device in sleep, vPortSuppressTicksAndSleep function (in file port.c) makes call to function xPortSTM32StopMode (in file freertos_stopmode.c). This function puts the device in stop mode and returns the amount of time it slept, after it wakes up.
The existing code uses RTC Wakeup Interrupt to wake up the device and the interrupt timer is set to expire at the end of the duration for which the device is supposed to sleep (i.e., the argument to the functon xPortSTM32StopMode). This function always returns the same value (=value it was supposed to sleep). This works as long as only the Wakeup interrupt wakes it up. If GPIO interrupt wakes it up, it doesn’t re-calculate how long it slept. It just returns (the incorrect) value which it was supposed to return if Wakeup interrupt woke it up. That means it returns a value much larger thatn the time for which it actually slept. This further means the freeRTOS is provided incorrect info and the timers will now expire fast.
Fix for this problem is to read the RTC minutes/seconds/SubSeconds register before and after the device goes to sleep and on wakeup and then calculate the elapsed time and return. This fixed it for me.
Make sure to :
Change resolution of the subseconds register by changing the prediv_a and prediv_s registers
Disable shadow registers update
Read the subseconds register twice, compare and if it doesn’t match read again.