For Cortex M4 (and other MCUs) ISR’s run on a separate stack from FreeRTOS tasks (MSP).
To ensure bulletproof operation, its a good idea to verify all stacks have adequate space 😉
I suggest the following additions:
- In configuration, new #defines:
~~~
// DRN ISR (MSP) stack initialization and checking
define configISRSTACKSIZE_WORDS (0x100) // DRN in WORDS, must be valid constant for assembler
define configSUPPORTISRSTACK_CHECK 1 // DRN initialize and check ISR stack
~~~
2. Additional code in port.c (this is for the M4 GCC port). I’ve tried to keep this tight but my ARM-GCC-assembler isn’t super-strong…
~~~
define QUOTE(str) #str
define EXPANDANDQUOTE(str) QUOTE(str)
if defined(configSUPPORTISRSTACKCHECK) && configSUPPORTISRSTACKCHECK && !defined(configISRSTACKSIZE_WORDS)
#error “configISR
STACKSIZE_WORDS must be defined for ISR stack checking (WORDS to reserve for MSP stack)”
endif
static void prvPortStartFirstTask( void )
{
/* Start the first task. This also clears the bit that indicates the FPU is
in use in case the FPU was used before the scheduler was started – which
would otherwise result in the unnecessary leaving of space in the SVC stack
for lazy saving of FPU registers. */
__asm volatile(
” ldr r0, =0xE000ED08 n” /* Use the NVIC offset register to locate the initial stack. */
” ldr r0, [r0] n”
” ldr r0, [r0] n” /* r0 now has top of stack (actually, word above beginning of stack) */
” msr msp, r0 n” /* Set the MSP (*ISR* stack register) back to the start of the stack (top of RAM). */
#if defined(configSUPPORT_ISR_STACK_CHECK) && configSUPPORT_ISR_STACK_CHECK
// DRN code: Zero the MSP stack before use, to facilitate stack use check
" mov r1, #0 n" /* value to store into stack */
" ldr r2, pxMSRstackLenn" /* remaining words to clear in stack */
"FillZeroMSPstack: n"
" sub r0, r0, #4 n" /* next word to zero */
" str r1, [r0] n" /* store a zero */
" sub r2, r2, #1 n" /* decrement word count */
" cmp r2, #0 n" /* finished clearing stack? */
" bne FillZeroMSPstack n"
#endif // #if defined(configSUPPORT_ISR_STACK_CHECK) && configSUPPORT_ISR_STACK_CHECK
" mov r0, #0 n" /* Clear the bit that indicates the FPU is in use, see comment above. */
" msr control, r0 n"
" cpsie i n" /* Globally enable interrupts. */
" cpsie f n"
" dsb n"
" isb n"
" svc 0 n" /* System call to start first task. */
" nop n"
);
#if defined(configSUPPORT
ISRSTACK
CHECK) && configSUPPORTISR
STACKCHECK
__asm volatile (
” .align 4 n”
“pxMSRstackLen: .word ” EXPAND
ANDQUOTE(configISR
STACKSIZE
WORDS) “n”
);
#endif // #if defined(configUSEISR
STACKCHECK) && configUSE
ISRSTACK_CHECK
}
/*———————————————————–*/
if defined(configSUPPORTISRSTACKCHECK) && configSUPPORTISRSTACKCHECK
BaseType
t xUnusedISRstackWords( void ) {
register uint32t *pStackOrigin;
int unusedStackWords = 0;
__asm volatile(
” ldr r0, =0xE000ED08 n” /* Use the NVIC offset register to locate the initial stack. */
” ldr r0, [r0] n”
” ldr r0, [r0] n” /* r0 now has top of stack (actually, word above beginning of stack) */
” mov %[result], r0 n” : [result] “=r” (pStackOrigin) :: “r0”
);
uint32_t *pStackUseEnd = pStackOrigin – configISR_STACK_SIZE_WORDS; // start testing at stack limit
for(int lim=configISR_STACK_SIZE_WORDS; lim; lim–) {
if(*pStackUseEnd++) break; // break at first used word
unusedStackWords++;
}
return unusedStackWords;
}
endif // #if defined(configUSEISRSTACKCHECK) && configUSEISRSTACKCHECK
/
———————————————————–/
~~~
With this I’m able to verify ISR stack use in our application.
Thanks as always for your excellent work,
Best Regards, Dave
PS: I’ll update heap_useNewlib.c to match the above shortly, on http://www.nadler.com/embedded/newlibAndFreeRTOS.html
PS: I’ve created a pull-request for this change, hope its OK!