Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Real time embedded FreeRTOS mailing list 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem TCP & FAT Training




Loading

Reusing main()'s stack: an ISR only stack?

Posted by aLUNZ on February 13, 2005
In the ongoing quest to scavenge yet another byte of useful memory one option is to recover the stack used by main() once the scheduler has been started. Effectively the main() routine is treated as a task that runs once and is then deleted, allowing its stack to be allocated to another task.

While trying to think of a way to do this on the MSP430 architecture have thought of an alternative that might make sense:

Reuse the main() stack as a stack exclusively for the use of ISR's.

The logic goes like this: Some ISRs are light-weight in their stack usage, but if the ISR calls other routine(s) and/or performs a lot of calculations then their use of the stack can blow out quite a lot. Threads need to have sufficient stack space to accommodate each ISR's requirements; which can occur at any time. So if an ISR requires 40 bytes of stack, then all threads need to have an extra 40 bytes added to their stack space. This gets worse if you have multiple ISRs in the application.

As a suggested alternative, ISRs that require a lot of stack could point the SP into an ISR only stack space (perhaps reuseing main()'s stack). If this works it would mean that:
- the stack used by main() gets to be reused
- the stack space allocated to each thread can be reduced.

Am not suggesting that this need to be done for all ISRs, just the memory hungry ones.

Implementation details would require handling of the case when one ISR interrupts another ISR, but that should be fairly easy?

Can anyone else spot anything else that can go wrong with this before aLUNZ launches into trying it? (For instance, will these SP shenanigans be compatable with cQueueSendFromISR() and cQueueReceiveFromISR()? aLUNZ thinks so, but has yet to walk through the code to make sure).

aLUNZ

RE: Reusing main()'s stack: an ISR only stack?

Posted by Marcel van Lieshout on February 13, 2005
Are you talking about a context-switch upon entering an isr? Or "just" changing stackpointers?

The default stack could also be used by the idletask. Perhaps for both the idletask and the isr's?

I like your thinking :-)

RE: Reusing main()'s stack: an ISR only stack?

Posted by aLUNZ on February 13, 2005
The idea is to just change the SP. The fact that we are servicing an interrupt effectively means that we have achieved a pre-emptive context switch.

For the MSP430 / GCC (other µs / compilers have the same basic approach, but the specifics may vary) this will require:
- declaring the ISR functions as "naked" which means that the compiler won't automatically save the registers. (The µ will save the PC and SR on the current threads stack - we cannot do anything about that).
- when called the ISR will test the current SP to determine if we are interrupting an ISR. If interrupting an ISR then we do not need to change the SP, if interrupting the application then the SP is saved (where?) then changed to use the ISR only stack space.
- all registers are saved to the stack
...
- the ISR does its thing
...
- on exit the ISR loads the registers, reloads the saved SP then calls IRET. (The µ will then pop the SR and PC from the interrupted threads stack and continue executing the interrupted thread).

There are dangers with this approach and FreeRTOS. For instance an ISR might call TaskYield() to force a context switch (if some action has been taken that might wake a suspended thread). Am pretty sure that calling TaskYield() inside this scheme will causes all sorts of mayhem.

There could be other problems, just haven't thought of any yet.

aLUNZ

RE: Reusing main()'s stack: an ISR only stack?

Posted by Richard on February 13, 2005
A bit of background before: I am currently working on an H8 port, when this is finished and released I would like to create another release that addresses a couple of issues. The first is this very point - how to use the main stack, the second is reorganizing the sTaskCreate() function call so that it does not require so much stack. Currently sTaskCreate() can be recursive (to one level only) when the idle task is automatically created. This uses more stack than is ideal. Reducing the necessary stack size of main() lessens the problem of not being able to recover it.

So far there are two suggestions for using the main() stack:

+ The first is giving it over to the idle task - but there is a big problem here as the idle task needs to configure itself which means creating it’s default stack used when it first runs. This means the idle task could only be created immediately before the scheduler was started otherwise main() would crash because it's stack was clobbered, or alternatively main() would clobber the idle stack before the task ran.

+ The second alternative (thus far) is to have a function that allows main() to be turned into a task. main() would then be two stage, the first would be sequential and create the tasks and start the scheduler as normal - the second would be an infinite loop that acted as a task. The problem with this is the extra complexity to the end user. They would have to understand the process - but it could be made optional.


aLUNZ has a third suggestion that is very attractive from the point of view of memory saved for the reasons he points out. There may be portability issues however as each processor on which FreeRTOS runs has different ways of handling interrupts.

For interrupts that do not cause a context switch I cannot see any problems.

For interrupts that do cause a context switch (for reasons already mentioned by aLUNZ) there are some difficulties. Each port uses the stack slightly differently. What has to be considered is the processor state when the task starts executing again. If the switch out is only performed once the stack is back at the task level (rather than the shared stack) then this should be ok. The idea with the queue and semaphore functions that are ISR safe (the ones with FromISR in their name) is that they return a value that indicates whether a yield is required or not rather than just performing the switch. This allows the application to then perform any tidy up necessary before making the switch – and the switch is only ever performed as the very last action in the ISR. Take a look at the ARM ports, where the processor forces the use of another stack anyway.

Regards.


[ Back to the top ]    [ About FreeRTOS ]    [ Sitemap ]    [ ]




Copyright (C) 2004-2010 Richard Barry. Copyright (C) 2010-2016 Real Time Engineers Ltd.
Any and all data, files, source code, html content and documentation included in the FreeRTOSTM distribution or available on this site are the exclusive property of Real Time Engineers Ltd.. See the files license.txt (included in the distribution) and this copyright notice for more information. FreeRTOSTM and FreeRTOS.orgTM are trade marks of Real Time Engineers Ltd.

Latest News:

FreeRTOS V9.0.0 is now available for download.


Free TCP/IP and file system demos for the RTOS


Sponsored Links

⇓ Now With No Code Size Limit! ⇓
⇑ Free Download Without Registering ⇑


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

Renesas Electronics Gold Alliance RTOS Partner.jpg

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

Atmel RTOS partner supporting ARM Cortex-M3 and AVR32 microcontrollers

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Xilinx Microblaze and Zynq partner

Silicon Labs low power RTOS partner

Altera RTOS partner for Nios II and Cortex-A9 SoC

Freescale Alliance RTOS Member supporting ARM and ColdFire microcontrollers

Infineon ARM Cortex-M microcontrollers

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

Cypress RTOS partner supporting ARM Cortex-M3

Fujitsu RTOS partner supporting ARM Cortex-M3 and FM3

Microsemi (previously Actel) RTOS partner supporting ARM Cortex-M3

Atollic Partner

IAR Partner

Keil ARM Partner

Embedded Artists