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

ISR only stack - POC stage 1

Posted by aLUNZ on February 15, 2005
Following is some code that is offered as a Proof of Concept of a ISR only stack. (The code includes a sample ISR which demonstrates how to use it.) The code is targeted for a MSP430F149 and is obviously not portable in the slightest; it is offered with the usual disclaimers (if it breaks your application/computer - you get to keep the pieces).

Having said that, it does seem to work, but has not been tested thoroughly. Specifically; whether it works with nested interrupts has yet to be tested.

The other limitations of this are:
- It is NOT suitable for wrapping the timer ISR for pre-emptive scheduling (the reason why is left as an exercise for the reader). Some different code will have to be produced to support that.
- Not sure if the approach is all that portable.
- The wrapper macro is does not qualify as elegant at all. There are probably smart ways to determine main's top of stack, and the address range for allocated stack space. But have yet to figure out how to do that.
- The whole wrapper macro approach was adopted as there does not seem to be a generic way to determine a functions register / stack usage. This approach work, but does have the overhead of an extra function call (5 cycles).

Next up is to figure out a version which will support the timer tick for pre-emptive scheduling. Am open to any comments / suggestions?

aLUNZ

/*-----------------------------------------------------------*/

/*
* ISR stack shenanigan routines
*/
volatile unsigned portSHORT usIsrToYield = 0;

// The maximum value for SP when in normal application space:
// 0x09c0 == 2496
#define MAX_STACK_ADDR "2496"

// The top of the ISR stack:
// 0x0a00 == 2560
#define ISR_STACK_SAVED "2560"

#define INTERRUPT_FUNCTION(irq, fcn) \
interrupt ( (irq) ) fcn ## _wrapper ( void ) __attribute__ ( ( naked ) ); \
interrupt ( (irq) ) fcn ## _wrapper ( void ) \
{ \
asm volatile ( \
"cmp #" MAX_STACK_ADDR ", r1 \n\t" \
"jc $+10 \n\t" \
"push r15 \n\t" \
"mov.w r1, r15 \n\t" \
"mov.w #" ISR_STACK_SAVED ", r1 \n\t" \
"push r15 \n\t" \
"push r14 \n\t" \
"push r13 \n\t" \
"push r12 \n\t" \
"call #" #fcn " \n\t" \
"pop r12 \n\t" \
"pop r13 \n\t" \
"pop r14 \n\t" \
"pop r15 \n\t" \
"cmp #" ISR_STACK_SAVED ", r1 \n\t" \
"jnc $+16 \n\t" \
"mov.w r15, r1 \n\t" \
"pop r15 \n\t" \
"cmp #0, &usIsrToYield \n\t" \
"jz $+6 \n\t" \
"call #vPortYield \n\t" \
"reti \n\t" \
); \
}

#define INTERRUPT_TASK_YIELD ( usIsrToYield = 1 )

/*-----------------------------------------------------------*/

/* declare the routines that service the interrupt, wrapping them
* in the ISR stack handler.
*/
static void vRxIsr( void );
static void vRxIsr( void );

INTERRUPT_FUNCTION(UART0RX_VECTOR, vRxISR);
INTERRUPT_FUNCTION(UART0TX_VECTOR, vTxISR);

/*-----------------------------------------------------------*/

/*
* UART RX interrupt service routine.
*/
static void vRxISR( void )
{
signed portCHAR cChar;

/* Get the character from the UART and post it on the queue of Rxed
characters. */
cChar = U0RXBUF;

if( cQueueSendFromISR( xRxedChars, &cChar, pdFALSE ) )
{
/*If the post causes a task to wake force a context switch
as the woken task may have a higher priority than the task we have
interrupted. */
INTERRUPT_TASK_YIELD;
}
}

RE: ISR only stack - POC stage 1

Posted by aLUNZ on February 15, 2005
*sigh* why is it that the the obvious solutions are only spotted after posting something to the world? The obvious way to use this new approach with the timer ISR is:

static void prvTickISR( void )
{
/* Increment the tick count then switch to the highest priority task
that is ready to run. */
vTaskIncrementTick();
INTERRUPT_TASK_YIELD;
}

Think that this could be optimised even further to save a byte or two off each tasks stack.

Oh, the INTERRUPT_FUNCTION macro has a "deliberate" mistake in it. The last `jz' line should be replaced with:
"jz $+10 \n\t" \
"mov #0, &usIsrToYield \n\t" \

Using this approach have managed to save about 26 bytes per task. In the EW2 demo this means that after reducing the min. stack size there is now enough memory to add the integer test tasks (another 2 tasks).

So far so good. Now what to do...?

aLUNZ




RE: ISR only stack - POC stage 1

Posted by Richard on February 15, 2005
I will have to have a closer look at these to understand their operation properly.

RE: ISR only stack - POC stage 1

Posted by aLUNZ on February 15, 2005
Sorry for the lack of comments. After thinking about this for so long that the brain hurts aLUNZ forgot that anyone else may not be able to quickly spot what the code is meant to do. Of course, aLUNZ knows better than this, but just wanted to get the thing out the door; which is no excuse really.

A quick explanation:
The macro defines a "naked" function that wraps the routine that actualy does the work of the ISR. The purpose of the wrapper function is to replace the normal (compiler provided) preamble and postamble with routines that switch the stack.

The wrapper function only has to save/recover the "call destroyed" (r15 to r12) registers as the worker routine pre/postamble will preserve any other registers and stack space used.

- On entry the routine tests the SP to see if we are already using the ISR stack space, if not the current SP is saved and then set to the top of what used to be main's stack.
- Registers 15 to 12 are then pushed onto the stack.
- The `worker' function is then called. The worker function can choose to initiate a task switch by calling INTERRUPT_TASK_YIELD which sets a flag to indicate that a task switch is requested.
- When the worker routine returns, registers 12 to 15 are popped off the stack.
- If the SP is at the top of the stack area, the original SP (pointing into a tasks stack space) is loaded. At this point the registers (with the exception of the PC and SR) are as they were at ISR entry; reti can now be called safely.
- If the usIsrToYield is non-0 the routine will call TaskYIELD().
- The routine then calls reti to return.


[ 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