How to reduce minimal stack usage? - IDLE task stack overflow (again)

I have the IDLE task, not used for anything (managed by FreeRTOS only).

configMINIMAL_STACK_SIZE is set to 256 (which is in words, so, 1024 bytes). It overflows.

I changed it to 512 (2048) and I monitor the watermark, which gives me 1020bytes left, which means, it is using 1028bytes.

Since IDLE task is managed and owned only by FreeRTOS why does it uses so much stack?

What plays in the minimal stack size? How to reduce minimal stack usage?

1 Like

What Processor/port are you using.

Are you (or any framework you are using) using vApplicationIdleHook as that will be used in that system.

If your processor doesn’t have a separate ISR stack, then every task, especially the Idle task, needs enough space for a worse case ISR stack.

In addition to the points mentioned by @richard-damon, when IDLE task is swapped out, its context is also stored on the IDLE task stack.

I can not add much after the two great reactions/questions here above.

Just want to mention that configMINIMAL_STACK_SIZE is often used to set other stack sizes:

#define configMINIMAL_STACK_SIZE         ( 512U )
#define ipconfigIP_TASK_STACK_SIZE_WORDS ( 1024U )
#define niEMAC_TASK_STACK_SIZE           ( 4U * configMINIMAL_STACK_SIZE )

When I check the task list of my STM32F7 device:

            priority  stack   time    perc
IDLE            0      491  1282636   92.1 
EMAC            5      930      174    0.0 
IP-task         4      760      568    0.0 

So my idle task only uses 512 - 491 = 21 words.

PIC32MZ
void vApplicationIdleHook(void) { // function exists but has nothing }

ISR stack ? not sure, but it is defined as:
#define configISR_STACK_SIZE ( 512 )

21 words would be fine.. but mine fails with 256 words :\
For PIC32MZ I can see the port_asm.S code and it saves about 34 registers, 34*4=136bytes?
then I can see Idle task is doing some business management.. but..

Have you already tried to set configMINIMAL_STACK_SIZE much higher, like 10240 words? Would you see the same pattern?

@richard-damon do you know if a PIC32MZ has a dedicated stack for ISR handlers?

I changed configMINIMAL_STACK_SIZE from 256 to 512, that way I don’t have stack overflow on IDLE, which I measure and it uses 1028 bytes.

My main question is why 1028 is need ?

Also, I’m “water-monitoring” it and it starts increase over time until it reach the maximum (that I could replicate) and stays on that 1028.

can you set a hardware breakpoint to break at stack overflow time and inspect the stack then?

One thought is to see if you have tick-less idle enabled, and if so, look at the code it uses, as that is run in the idle task.

I am not familiar with this processor, but with a quick search, it sounds like the processor itself doesn’t implement in hardware a separate stack, but seems to be an expectation that a multi-tasking operating system will provide hooks to allow ISRs to switch to an ISR stack if needed, and uses a separate set of registers (“Shadow registers”), minimizing the stack needed to save the basic register set.

That would mean that an ISR that doesn’t implement this, but does use appreciable stack could up the stack requirements for all tasks in the system.

The size of context would be around portCONTEXT_SIZE + portFPU_CONTEXT_SIZE which comes out to be 424.

There is a separate stack for yield interrupt - FreeRTOS-Kernel/portable/MPLAB/PIC32MZ/port_asm.S at main · FreeRTOS/FreeRTOS-Kernel · GitHub.

Hi,

The idle task actually does stuff, like freeing memory (from anything that had been created from dynamic memory allocation:

“The idle task is responsible for freeing memory allocated by the RTOS to tasks that have since been deleted. It is therefore important in applications that make use of the vTaskDelete() function to ensure the idle task is not starved of processing time. The idle task has no other active functions so can legitimately be starved of microcontroller time under all other conditions.“ (FreeRTOS idle task - FreeRTOS™)

But it’s unusual that it takes so much memory though.

I did not understood the meaning of this swapped out, Could any one tell me what it means?

And So if RTOS needs to be run means the processor should have two stack pointer, one for tasks and other for ISRs, Is it correct?

“Swapped Out” Switched away from by the scheduler, which does this by saving all the processor context for the task onto its stack, and then storing the stack pointer into the TCB, and then getting the stack pointer for the next task to run, and restoring the context.

As to needing two stack pointers in the processor, that isn’t an absolute requirement. If the processor DOES have multiple stack pointers, and automatically switches, then the ISR automatically get their own stack (one they are setup).

Other processors only have a single stack pointer, and no software work around, will mean those processors need every task to have room for any ISR stack that might be needed.

Some, and I think the PIC32 falls into the category, are designed so that ISRs, with the proper preamble, can use just a minimal amount of the task stack, and then switch the stack pointer by code to use another one for the ISR. If the code wasn’t setup to do that, then they just run as processors without a separate stack and need more space on each tasks stack. This might be the case here, I don’t know if this processor has a common entry for ISRs, that then vectors out (in which case that common entry can have that code) or if every ISR needs some boiler plate to enable it.

1 Like

I think each ISR needs to do that. We do that here in the yield ISR.