Since I updated my FreeRTOS tick management code from v7.4.2 to v9.0.0 I have been having some issues related to low power tickles mode management.
I use EFM32 family, with the provided low_power_tick_management code.
Randomly it happens that the vTaskStepTick(ulCompleteTickPeriods);, that is called at the end of vPortSuppressTicksAndSleep(), is called with an invalid number of complete tick periods, which causes this one to assert in the following validation configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );.
Anyone aware of this problem, what may be causing it or what can be done to avoid it?
You might want to check task stack size by display “vTaskGetRunTimeStats()”
in a low priority task and setting up Malloc Failed Hook and check for
stack overflow functions…
Since I updated my FreeRTOS tick management code from v7.4.2 to v9.0.0 I
have been having some issues related to low power tickles mode management.
I use EFM32 family, with the provided low_power_tick_management code.
Randomly it happens that the vTaskStepTick(ulCompleteTickPeriods);, that
is called at the end of vPortSuppressTicksAndSleep(), is called with an
invalid number of complete tick periods, with causes this one to assert in
the following validation
configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );.
Anyone aware of this problem, what may be causing it or what can be done
to avoid it?
I have all the overflow handlers enabled (MallocOverflow, StackOverflow).
The problem seems to be on the most recent version of the low_power_management fucntions implemented for the EFM32 family. If I roll back those from v9.0.0 to v7.4.2, the system is stable without causing any problems with the xTicksToJump value.
It seems that in some situations the tickless mode will sleep for longer periods than expected, causing the xTickCount + xTicksToJump to be bigger than the xNextTaskUnblockTime.
the FreeRTOS layer + low_power_tick_management_RTC libraries are the same as the original ones, as application goes I just have a single empty task running every 1 sec. (+ the idle task).
It’s not easy to replicate, at this point, it still seems really random to me. If I leave 2 devices side by side, running the same image, 1 may trigger this error only after running for a couple hours while the other may be running for a full week without ever triggering the error.
The major difference I see between v7.4.2 and v9.0.0 is the introduction of the ulCountBeforeSleep adjustment variable, that is added to the ulCountAfterSleep, I’m trying to figure out if that may be the cause of this problem.
If you have any suggestion on how to get more debug information on this, please let me know.
I spent some time looking at the state of the variables when the error condition happens and it seems that the system tick, in this case, generated by the RTC, is somehow skipping 1 interrupt at some point.
The ulTickFlag variable is false, so the ulCompleteTickPeriods is calculated with the following expression ulCompleteTickPeriods = ulCountAfterSleep / ulReloadValueForOneTick;.
For one exemple I had: xExpectedIdleTime = 8 and ulCompleteTickPeriods = 17 as the ulReloadValueForOneTick = 40 (read only variable) this means that the ulCountAfterSleep = 680
So, the RTC was supposed to trigger an interrupt after 8 ticks, but it didn’t. At this point, some other interrupt happens (I have some GPIOs that trigger interrupts with motion events) and the logic afterwards fails.
The RTC configuration and interrupt handler between v7.4.2 and v9.0.0 is really not that different, there are only some minor tweaks.
Can’t really understand what may be causing this, I would appreciate If someone can give any clue.
I think I may have found the culprit, I 'd appreciate if someone could throw a second opinion!
So the only difference I spot looking into the registers, between v7.4.2 and v9.0.0 is that in v7.4.2 the RTC is configured to clear the counter when it reaches the COMP0 value, by setting the COMP0TOP bit in the RTC CTR register, while in v9.0.0 the COMP0TOP is not set, so the RTC counter top value is 0xFFFF. As the RTC COMP0 interrupt is configured with the lowest priority, it means that at some point another ISR will be processing and the RTC interrupt will be shortly delayed (even if all other interrupts in the system have the same lowest priority). When the RTC COMP0 ISR runs the RTC counter value will be bigger than the xExpectedIdleTime, and this will trigger the problem.
What do you guys think? Am I missing something or can this actually make sense?
Without digging the manuals out to check, it would seem to make sense.
Did you get the 7.4.2 implementation from us?
I would be grateful if you could send me the file that contains this
code in from both your 7.4.2 project and your 9.0.0 project so I can
compare. Please send the files to r dot barry at freertos dot org.
I’m experiencing the exact same thing.
I also tried updating FreeRTOS tickless example to 9.0.1 and Sleep module from EMDRV to 5.1.2, where both have updates related to interrupts disable/enable, but that didn’t help.
the issue is only related to FreeRTOS v9.0.0 tick_management functions for the EFM32 family, for both available examples, the EFM32GG and the EMF32PG.
I’m using the latest emlib release together with v7.4.2 tick_management and the v9.0.0 FreeRTOS core and that works fine for the EFM32LG. Unfortunately there’s no tick_management v7.4.2 for the EFM32PG and that’s what’s worrying me because I can’t release those into production with this bug.
I will let you know when/if I found a solution for this.
I have been running the demo from FreeRTOS V9 on a Giant Geckco with the RTC providing the low power clock for days with no issues. Also, we didn’t provide an equivalent example in FreeRTOS V7.4.2, so assume you got the code from somewhere else.
v7.4.2 can be found in the Silicon Labs examples, e.g. STK3600_freertos_tickless. As the files have the FreeRTOS headers, FreeRTOS V7.4.2 - Copyright (C) 2013 Real Time Engineers Ltd. I assumed they were made by you guys.
As I said before, this bug seems to be triggered when there are more interrupts happening in the system, if you are just using the RTC interrupt I don’t think that will trigger the problem.
thanks for looking into it, for the time beeing my production firmware will be running v7.4.2 for the tick management, hopefully, you guys find a solution for this in the next releases!
Hi everybody,
I also found that problem in my application. Hardly investigated it and maybe I found solution.
The reason of the problem is behaviour of BURTC - when you will stop the timer, the counter is cleared. It means there is necessary to read the state of counter when it is still running and stop it after it. And there can be issue between this two instruction - counter will be read before achievieng compare value and stopped after achieving compare value. It means interrupt is pending and big value from counter is prepared in value ulCountAfterSleep for next computation.
Bellow you can see snippet of my code how I solved it.
As you know this problem is not easy to reproduce and I’m not sure if it can be also source of your problems. Give me message if it helped to you.
My condition :
EFM32GG, FreeRTOS v.9.0.0, BURTC used for tickless idle, based on file FreeRTOSv9.0.0\FreeRTOSv9.0.0\FreeRTOS\Demo\CORTEX_EFM32_Giant_Gecko_Simplicity_Studio\Low_Power_Demo\low_power_tick_management_BURTC.c
I changed code (started from line 252, finished before line 267) :
/* Stop BURTC. Again, the time the SysTick is stopped for is accounted
for as best it can be, but using the tickless mode will inevitably
result in some tiny drift of the time maintained by the kernel with
respect to calendar time. The count value is latched before stopping
the timer as stopping the timer appears to clear the count. */
intCrossPending = BURTC_IntGet() & _BURTC_IF_COMP0_MASK; /* read interrupt pending and save it for next comparision */
ulCountAfterSleep = BURTC_CounterGet();
BURTC_Enable( false );
intCrossPending = ((BURTC_IntGet() & _BURTC_IF_COMP0_MASK) != intCrossPending); /* read interrupt pending and compare with the state before reading of counter value*/
/* Re-enable interrupts - see comments above the INT_Enable() call
above. */
INT_Enable();
__asm volatile( "dsb" );
__asm volatile( "isb" );
if( (ulTickFlag != pdFALSE) && (intCrossPending == 0U) )