we’re using freeRTOS 6.0.0 together with a Renesas RH850 microcontroller (R7F7010233AFP), which has 32kb RAM. I’ve got an implementation where several tasks (1ms, 10ms, 100ms, 200ms, 500ms, 1s) are running.
When I add e.g. SCI transmit function call in 100ms I recognize in my MULTI debugger that it hangs in vApplicationStackOverflowHook which calls OS_ApplStackOverflowHook and has an endless loop.
In FreeRTOSConfig.h I set configMINIMAL_STACK_SIZE to 1024 and configTOTAL_HEAP_SIZE to 0x5500.
When it stays in endless loop and hangs I see this call stack:
0 vApplicationStackOverflowHook(pxTask=0, pcTaskName=0x34) [src\app\os_tasks.c:149,2]
1 vTaskSwitchContext() [src\os\freeRTOS\RTOS\tasks.c:1593,26]
2 INTOSTM0() [src\os\freeRTOS\RTOS\portable\GHS\RH850F1L\portasm.850:245,10]
3 .intvectApp() [src\bspRH850\startup\dr7f701057_startup.850:136,1]
So it was called from 1ms interrupt which handles the tasks.
Both pointers pxTask and pcTaskName are at 0x0:
Could you give me a hint what I can do?
How can I find the reason of the stack overflow?
Which values should I change to fix the overflow?
Yikes, the current version in 9.0.1. We cannot really support V6.
In FreeRTOSConfig.h I set configMINIMAL_STACK_SIZE to 1024 and
configTOTAL_HEAP_SIZE to 0x5500.
That only changes the size of the stack used by the Idle task.
Could you give me a hint what I can do?
Increase the size of the stack allocated to the offending task. The
name of the task will be passed into the stack overflow hook function,
but you may find in V6 the name gets corrupted by the stack overflow
(that doesn’t happen in later versions) and you will instead use the
task’s handle (which is also passed into the hook function).
Yikes, the current version in 9.0.1. We cannot really support V6.
Yes, I know but I can’t change it at the moment.
That only changes the size of the stack used by the Idle task.
No, I use this define also for 1ms tasks etc.
Increase the size of the stack allocated to the offending task. The name of the task will be passed into the stack overflow hook function, but you may find in V6 the name gets corrupted by the stack overflow (that doesn’t happen in later versions) and you will instead use the task’s handle (which is also passed into the hook function).
How can I change the allocated stack for a task?
How can I get the task’s handle? (pxTask is 0x0)
The size of the stack is specified when you create the task. In version
6 probably the only way of getting the task’s handle is using the last
parameter in the call to xTaskCreate() used to create the task.
Do you mean last parameter “pxCreatedTask” for the handler?
How can I retrieve the handler when it hangs in function “vApplicationStackOverflowHook()”? (isn’t pxTask then 0x00?)
I create e.g. the 100ms task with following call:
res = xTaskCreate(OS_Task_100ms, "Task_100ms", configMINIMAL_STACK_SIZE_100MS, NULL_PTR, OS_PRIORITY_TASK_100ms, NULL_PTR);
where configMINIMAL_STACK_SIZE_100MS is
#define configMINIMAL_STACK_SIZE_100MS ( ( unsigned short ) 1024 )
In some other posts I read of a typical minimal stack size of 60, mine is 1024 although it seems to be too small.
Is “usStackDepth” only minimal stack size which could be much higher in run mode or is it the actual-fixed stack size?
Since you passed a NULL_PTR as the parameter pxCreatedTask, you program didn’t save the value of the handle. The overflow hook is passed two values, the handle for the task that was detected to have overflowed the stack, and a pointer to the name of the task (assuming that the overflow hasn’t damaged the Task Control Block so badly that it is still retreivable, in the earlier versions, the TCB was the first thing that an overflowing stack would overwrite). The stack size you provide is the actual size of the stack that the task will use, once created, you really can’t change it, as the memory you would need to expand it into is used. Using a name like MINIMAL_STACK_SIZE_TASKNAME is a misnomer. The define configMINIMAL_STACK_SIZE is intended to define the minimum amount of stack needed by a very simple task (like the idle task), and other tasks might have their stack requirements specified as this minimal size + the amount of additional stack needed by that task for its use. When looking at a task to figure this out, look at the task function (and everything that it calls) and count up how much space its variables will use, especially be aware of any arrays defined in the task, as they can take up a lot of room.
What can I derive from that?
Still seems it was called from interrupt…
Another question:
My freeRTOS runs with one 1ms timer tick. What happens if 100ms tasks needs more than 1ms and the 1ms task should start? Is the 100ms task interrupted?
What happens if 1ms task needs more than 1ms? Will it be interrupted by itself and will not (maybe never) run to the end of it?
Further topic:
I started to use uxTaskGetStackHighWaterMark() and at the beginning it seems to use 100-150 “words” in stack (my size is 1024, it returns e.g. 902). When I add a new function I get stack overflows and can’t call that function anymore, so that won’t help…
Another question:
My freeRTOS runs with one 1ms timer tick. What happens if 100ms tasks
needs more than 1ms and the 1ms task should start? Is the 100ms task
interrupted?
What happens if 1ms task needs more than 1ms? Will it be interrupted by
itself and will not (maybe never) run to the end of it?
These are fundamental questions you need to understand before using
[any] RTOS. I would recommend reading through at least the first few
chapters in the “Mastering the FreeRTOS Real Time Kernel” book - you
will find a link on the same page as the reference manual (see my post
of a few moments ago for the URL). It is quite a quick easy read and
will give you a good grounding. I don’t want to spend time typing in
answers here when the information is already provided in a few words
within the book.
Further topic:
I started to use uxTaskGetStackHighWaterMark() and at the beginning it
seems to use 100-150 “words” in stack (my size is 1024, it returns e.g.
902). When I add a new function I get stack overflows and can’t call
that function anymore, so that won’t help…
If you have 900 words free before you call the function, and calling the
function causes a stack overflow, then it would seem the problem is with
the function. If the stack has overflowed then you should not be trying
to call anything anymore as, unless you are using a port with memory
protection, a stack overflow is not a recoverable error.
What is the function doing to use so much stack? For example, is it
trying to allocate a large array on the stack?
Hi Daniel, without having read the entire text here above, please make sure that the (GCC) compiler doesn’t create code for stack checking. The reason that I ask this, is that users reported that GCC’s stack checking doesn’t work well in their embedded projects. Regards.
@Real Time Engineers ltd.:
Yes, I’ll read the documentation (our project is a bit in hurry and I thought to get some faster infos…)
I’ll examine the function, but there aren’t any big local variable arrays, nested calls etc. I had the behavior also with other “normal” functions.
Could you check my debugger screenshot with values of pxCurrentTCB?
What is the criteria for “stack overflow”? My pxTopOfStack is 0xfedfd208, what does it mean?
I see in StackMacros.h:
/* Is the currently saved stack pointer within the stack limit? */
if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack )
{
vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName );
}
@Hein Tibosch:
We don’t use GCC but Greenhills compiler for our Renesas RH850. Maybe it generates code for stack checking, too. I will check that, thanks for the hint.
Thinking about the values you are posting, one likely option is you have corrupted the FreeRTOS control variables, either with bad interrupt levels or a wild write. (pxTask = 0 is likely impossible otherwise).Perhaps also this might be the results of using the idle hook and blocking in it, which is a no-no (The Idle task must NEVER block, as something must always be able to run).
We don’t block idle hook, it’s running as far as I see normally:
I can’t imagine that we “wild write”. Our interrupt priority should be set correctly.
For every task I set a minimal stack size of 1024, is that really too less (we don’t have huge local arrays in the functions…)?
Futhermore I pass a task-handler variable at xTaskCreate(), but value pxTask has a value of e.g. 0xfedfd588
Which task handle should that be?
My task handler variable is listed in map file as:
.bss fedfa2d4+000004 _mgl_task_handle_100ms
I can’t find any variable in memory location 0xfedfd588.
We don’t use GCC but Greenhills compiler for our Renesas RH850
Ok - this is not code you have obtained from us. We can try to assist
the best we can, but have not seen the port, have no idea how good or
correct it is, and cannot say for certain whether you are doing anything
wrong of if the port is just bad. (Greenhills have never exactly been
‘co-operative’ with us)
[From Richard Damon] Thinking about the values you are posting, one
likely option is you have corrupted the FreeRTOS control
I concur with this. Your TCB is completely corrupted. That is
consistent with a stack overflow in FreeRTOS V6 (but not later versions
of FreeRTOS) where the first thing to be corrupted by a stack overflow
would be the TCB. That is not necessarily the only cause though.
Anything writing over the TCB is likely to also write over the end of
the stack, as they are next to each other (…in version 6) which could
be picked up as a stack overflow. I’m not sure how intelligent the
stack overflow detection is in FreeRTOS V6. Later versions use a couple
of methods and of overflow detection and make it easier to debug.
The port isn’t done from Greenhills, but the company which did says they don’t have a reason to update to version 9 because their version (6) runs stable (well, that’s really not my opinion ;-))
How do you recognize that my TCB is corrupt?
Do you think if TCB is corrupt there was a stack overflow? Or do both things don’t have to do with each other?
Currently I set my minimal stack sizes of my tasks to
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 2000 )
#define configMINIMAL_STACK_SIZE_1MS ( ( unsigned short ) 1024 )
#define configMINIMAL_STACK_SIZE_10MS ( ( unsigned short ) 150 )
#define configMINIMAL_STACK_SIZE_100MS ( ( unsigned short ) 300 )
#define configMINIMAL_STACK_SIZE_200MS ( ( unsigned short ) 150 )
#define configMINIMAL_STACK_SIZE_500MS ( ( unsigned short ) 150 )
#define configMINIMAL_STACK_SIZE_1S ( ( unsigned short ) 150 )
First, as has been mentioned before, calling these the ‘MINIMAL_STACK_SIZE’ is a misnomer. These are THE stack size of the task, it will NEVER get bigger. The entry configMINIMAL_STACK_SIZE is suppose to represent the minimum stack size that any task will need to just support minimal processing (which is what the idle task does, so it uses that define for its stack). I tend to define the stack size for other tasks as (configMINIMAL_STACK_SIZE+n) where n is an estimate of how much stack that task needs to do its work. The fact that you have all the stack having smaller stacks than configMINIMAL_STACK_SIZE is bothersome to me, and says either you have put something using a lot of stack into the idle hook, or the sizes are set wrong.
A corrupted TCB, at least for the earlier versions of FreeRTOS, was easily caused by a stack overrun for processors with descending stacks, as first the TCB was allocated, and then the stack so the TCB was just before the stack in memory. It isn’t the only way to corrupt it, but it is an easy way. Later version reversed the order of the allocations so a task would clobber something else instead, giving you a better chance to figure out what happened.
Independent of the FreeRTOS version you are using, I’m interested in the port - assembler files to save and restore context etc. - for the RH850 F1L. I tried to get it work with the V850 port, but that fails due to incompatibile things.
Can you provide the port you are using for the F1L?
@Richard: Yes, I understand the misnomer, let’s call it just “config_STACK_SIZE”. I don’t know why I need such a bick stack size in idle hook, but with smaller one I’m running into stackoverflow…
Now we updated to V9.0.0 but it seems that I can’t reduce the stack sizes since it’ll run into stackoverflow, too. But as you wrote the corrupted TCB problem shouldn’t exist now. I just run again into OS_ApplStackOverflowHook() and see these values: https://s22.postimg.org/a5gugzju9/image.png
Could you help me interpreting the values? Is it correct, that the stackoverflow occured in 500ms task? (That would be a great information :-))
@Martin: Which files do you mean?
I’m not sure if I may give you the files. Where can I find assembler files to save and restore context?
Since pxTask is an odd value (0x7007), and this should be word aligned, I suspect that you have corrupted the FreeRTOS conttrol store, and when walking the task list the system got into a bad state… This sort of problem can be hard to pin down. but it does say that the last task that was running was Task_500m, which well could be (but not neccisarily) the task that did tthe damage.
Yes, I understand the misnomer, let’s call it just “config_STACK_SIZE”.
I don’t know why I need such a bick stack size in idle hook, but with
smaller one I’m running into stackoverflow…
If you understand a bit of the assembler code, please try to debug and see what happens to the stack pointer when various routines are being called. I still get the impression that your compiler is doing stack- or other runtime-checking, and it uses the stack for that purpose.
The idle task never makes heavy use of the stack. tskIDLE_STACK_SIZE equals configMINIMAL_STACK_SIZE, which is usually 100 to 128 words, and that should be more than enough.