Finding Max possible Task stack size

The application uses TI Stellaris ARM M3 processor (obsolete processor with obsolete Code Red IDE). Free RTOS 8.2.1. RTOS is used as a simple round robin scheduler, with each task getting a 1 ms time splice, all the same priority.

One of these tasks is highly interrupt intensive, with PWM, timers, sensors etc. This task needs more stack size. Initially, all tasks had a size of 1000. Application did better when this task size increased to 1800. Things got worse when a size of 3000 was tried. Is there a way to find out how large the stack can be made other than by long runs of testing?

While I do have access to a Segger debugger and ozone IDE, while I have not set these tools up yet. I will have to learn how to find the real time stack usage using these tools. Unless, this can be found out from RTOS some way?

Thanks,
Priya

FreeRTOS does have some optional stack checking code. See


and

(The stack high water mark)

I think everything these goes back that far.

Just for completeness https://www.freertos.org/uxTaskGetStackHighWaterMark.html

Thank you for your replies. I put in print statements to show stack usage if it dips below 100 bytes. My concern is there are several interrupts happening closely spaced in time. Some ISRs have added processing in them because there is so little time. The RTOS scheduler must be getting pre-empted constantly. In this case, if there is a stack over flow, will this API catch it?
Thanks,
Priya

The stack checking functionality tests the task at the time it is switched out. Level 1 just checks the stack pointer (so is quick) but only catch if you have exceeded NOW, Level 2 check for the profiled pattern at the end of the stack (so is a bit slower), but will catch most of the time if you have exceeded in the past (but any damage caused is still done). The High water mark tells you what you all time peak has been.

Note, lots of interrupts in sequence aren’t an issue, it is nesting of interrupts, and for an M3, the interrupts don’t even use the task stack. Thinking about it, I am not sure if FreeRTOS checks for the ISR stack overflowing, but it wouldn’t be that hard to put a check pattern between the ISR stack and the heap and check it periodically.

So when stack size is allotted for a task, which part of the processor memory does this come from? What all task functions will be covered by this stack size?

I see this line in the map file. Is this the start address of the heap memory, heap size being 0x7530?

.bss.ucHeap 0x20000554 0x7530 ./FreeRTOS_MemMang/heap_4.o

Thanks,
Priya

It depends which memory allocation scheme you are using. In the case of schemes such as heap_4.c the memory comes from a statically allocated array. By default that will be placed in memory by the linker like any other array - but it is possible to override the default behaviour to place it where you like.

Another distinction is tasks created with xTaskCreate will have their task allocated from whatever heap FreeRTOS is using, but if you use xTaskCreateStatic, you explicitly provide the memory for the stack, which will normally be some file static memory allocation.

I still need a lay person’s understanding of stack and heap usage. I need to use the ozone IDE with the free RTOS plug in. The first time I used ozone (6 months back), I had trouble installing this plugin. Would you happen to know why? Seeing the stack/heap usage may shed more light.

Segger maintain the plug-in, so best ask them.

Do you specific to how FreeRTOS users them? Or how C uses them?

Both. The application has a section where nested interrupts happen. One of these 6 interrupts is to transition to a different task, 5 others are from the main task. I am guessing this is what ends the test in an error. Are there RTOS features to help here without too much upheaval to the round robin scheduling. I can certainly get the Segger debugger and IDE in place.

First, interrupts are not inherently tied to any task (particularly as far as using stack), so no interrupt is ‘from’ a task, it may communicate to a particular task, but it isn’t from a task, if anything, it is from some device in the system.

On a M3, interrupt are allowed to nest if and only if they are of different priorities, and a higher priority interrupt can interrupt a lower priority interrupt (and confusingly, lower values of the interrupt priority number are higher a priority for nesting). If the interrupt causes a task switch, it does so by trigger a special interrupt that will happen when all the currently pending ISRs return.

All interrupt will use a special ISR stack, which will use the memory initially allocated to the main program, and each task will have its own stack that was assigned to it, either from the heap or from static memory given to xTaskCreateStatic.

Actually, there is a seventh interrupt also. First 5 happen, then a sixth and then seventh. When seventh happens, there is transition to a different task. Yes, I found some interrupt tail chaining resources about the M3 processor when there are multiple pending interrupts.

There is probably nothing that can be done with free rtos to improve this situation. Handshaking with external processor works seamlessly if RTOS is there, especially for forward compatibility. The application as such doesn’t need RTOS. The hardware is such the interrupts happen this way.

If your concerned about ISR stack requirements, making all the interrupts the same priority will eliminate nesting, and minimize stack usage (and if you can’t make them all the same due to latency requirements, minimizing the number of different priorities will reduce the requirements). This will cause more chaining and less nesting, which reduces stack requirements.

Each task needs enough stack space to cover that tasks operational requirements (which doesn’t include interrupts logically connected to it).

Richard,
Thank you again for your reply. The application as I inherited it has trouble maintaining performance stability after free RTOS was added. The version prior to RTOS performs much better, though it does not support current external processor compatibility.

The RTOS added application has all interrupts same priority, all stack sizes the same as you recommend. However, the application test does better with different hardware when two levels of priority are used.

I don’t fully understand why task operational requirements are higher for the main task, but when I increased its size by 500 bytes, results were better.

There is one nested interrupt sequence that happens when printing – timer, PWM, I2C, two more timers. When printing is done, the main task enables the sensor timer and interrupt. When it is time to send a handshaking response, the task dedicated to the external processor takes over. Here is where the error happens during prolonged testing.

Will a mutex between the main task and handshaking task be of any help? How will this work with round robin scheduling?

Thanks,
Priya

First, to clarify, I never said that using just a single interrupt priority was the best, I said that if you were very concerned about ISR Stack usage, that avoiding nesting reduced it. Normally, latency requirements dominate, which imply using multiple ISR priorities.

I NEVER said all tasks should have the same size stack, which is a very wrong concept, the stack for a task should be tailored to the needs for that task.

I am puzzled a bit by your comments that things work ‘better’, with stack sizes things tend to either work or not, and if they don’t it is because your stack size was insufficient, and thus the clear solution is to either give more stack or reduce the stack usage of that task.

I do hope you have stack checking turned on and configASSERT defined to let you know of a failure.

As to a mutex, if they share a resource that needs exclusion, you need a mutex, if not then what you are thinking about? As for how that affect scheduling, if a task is waiting to take a mutex, it isn’t ready to run and thus won’t be scheduled.

One note, I generally find that most of my tasks at any given time are blocked on some signal waiting for work to do, so the round robin aspects aren’t that important.

I think we need to take a step back a bit in this thread in case we are missing the big picture. You are asking specific questions about stack sizes without saying why you think there is a problem with the stack size, and saying the pre-RTOS version worked better without saying by which measure. Perhaps if you could explain the problem you are seeing, we could then ask questions about your architecture, and may be able to spot something that is causing your issues.

With firmware changes made to the version with RTOS, the error happens 1 in a 1000. The firmware without RTOS showed no errors in 5000 trials. The firmware version with RTOS gives an error within 50-500 trials, but this error is a firmware reset, different than the error that I am currently getting.

I don’t understand why increasing task stack size helped. I don’t have an IDE that shows me real time stack usage. Possibly the mail messages that gets sent between tasks.

As far as the error scenario:
Ticket moves as the thermal printhead prints each row of a barcode. The rotary motor moves the ticket. A timer for the rotary motor (500 us) generates PWM interrupt. An I2C interrupt goes off to communicate the PWM to the driver IC for the rotary motor. During the rotary motor PWM ISR, the printing begins. The printhead uses two timer interrupts to generate control signals for the printhead (these timers period varies). One row of the barcode gets printed.

When printing is finished, sensor timer starts (100 us). This will trigger an ADC ISR. When the entire barcode is printed, the handshaking interrupt goes off, processed in the external processor task.

During the error, at the end of the barcode being printed, the ticket overshoots all the way forward and the mechanism has lost control of the ticket which is now under an unexpected sensor and is unable to come back to print ready position.

First big question, have you enable the Stack Checking in FreeRTOS and enable configASSERT in a way that you CAN tell if you have hit an assert. If not, then you are really flying blind and there isn’t much we can help you with.

Second, with the sequencing you are describing, I trust that most of the work is actually being done in the ISRs, and you didn’t decide that just because you added FreeRTOS, that all the ISR need to just field the interrupt and pass the results to a task. Also, it does sound like not all your interrupts should have the same priority, some seem to be much more sensitive to time delays, and in fact some of them may want to be above the FreeRTOS interaction priority (like those timer interrupt that control the printhead).

You may want to add a background task that periodically polls FreeRTOS and checks the stack usage of your major task and either sends them to you or stores them where you can check with the debugger (I presume you have SOME debugger, even if it isn’t ‘FreeRTOS aware’).

The last time I tried enabling configASSERT, I found out I needed to upgrade the RTOS version. I did not do this. Yes, the firmware came with a lot of processing happening in the ISR. I tried offsetting this to a task and found out processing during PWM is so fast, RTOS delays are too much. I don’t have a working debugger. I video taped the error and try things based on how the mechanical components work together.