Minimum bound for stack sizes
Greetings.
I’ve been working with FreeRTOS on the SAM7S32.
I ended up chasing down a nasty funny, in that, I had an application which was calling vTaskDelay(10); but was never being re-scheduled.
I ended up instruction stepping
xTaskDelay(); To cut a long story short – FreeRTOS’ practice of saving context on the user’s stack in portSAVE_CONTEXT(); – rather than on the ISR’s stack – I believe – with respect – is a bit backwards.
Reason being the following – the pvOwner – which is a pointer to the TCB of the task that did the xTaskDelay(); is at 0x2006c0.
At this point in time the task calling xTaskDelay(); has been configured with a stack of 0x18 * 4 words – or 96 bytes, which I was thinking was generous on 8k of SRAM.
However at vPortYieldProcessor+44 – you’ll see that the ARM assembler is subtracting 60 bytes from the link register.
The link registers is in fact the stack pointer – plus or minus a few words of the CALLING task – not the ISR context we are in a this point.
Hence : if the stack size of the calling task is below a certain size ~ 1xx bytes the context switching code of the ISR will overflow the tasks stack.
I was loathe to go changing the context switching code – without a full understanding of all aspects of it – however – I think it would be a good idea to have at the very least an
#if configMINIMAL_STACK_SIZE < SOME_MINIMUM_SIZE_FOR_CONTEXT_SWITCHING
#error "Your stack will overflow me auld flower"
#endif
just to ATTEMPT to idot proof – even against sufficiently talented idots such as myself !
Cheers,
Bryan
[code]
$7 = (volatile struct xLIST_ITEM *) 0x2006c0
(gdb) print &pxDelayedTaskList->xListEnd->pxNext->pvOwner
$8 = (void **) 0x2006cc
(gdb) disass
Dump of assembler code for function vPortYieldProcessor:
0x0010432c <vPortYieldProcessor+0>: add lr, lr, #4 ; 0x4
0x00104330 <vPortYieldProcessor+4>: push {r0}
0x00104334 <vPortYieldProcessor+8>: stmdb sp, {sp}^
0x00104338 <vPortYieldProcessor+12>: nop (mov r0,r0)
0x0010433c <vPortYieldProcessor+16>: sub sp, sp, #4 ; 0x4
0x00104340 <vPortYieldProcessor+20>: pop {r0}
0x00104344 <vPortYieldProcessor+24>: stmdb r0!, {lr}
0x00104348 <vPortYieldProcessor+28>: mov lr, r0
0x0010434c <vPortYieldProcessor+32>: pop {r0}
0x00104350 <vPortYieldProcessor+36>: stmdb lr, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r1
1, r12, sp, lr}^
0x00104354 <vPortYieldProcessor+40>: nop (mov r0,r0)
0x00104358 <vPortYieldProcessor+44>: sub lr, lr, #60 ; 0x3c
0x0010435c <vPortYieldProcessor+48>: mrs r0, SPSR
0x00104360 <vPortYieldProcessor+52>: stmdb lr!, {r0}
0x00104364 <vPortYieldProcessor+56>: ldr r0, [pc, #404] ; 0x104500
0x00104368 <vPortYieldProcessor+60>: ldr r0, [r0]
0x0010436c <vPortYieldProcessor+64>: stmdb lr!, {r0}
0x00104370 <vPortYieldProcessor+68>: ldr r0, [pc, #388] ; 0x1044fc
0x00104374 <vPortYieldProcessor+72>: ldr r0, [r0]
0x00104378 <vPortYieldProcessor+76>: str lr, [r0]
0x0010437c <vPortYieldProcessor+80>: ldr r3, [pc, #76] ; 0x1043d0 <vPortYieldProcessor+164>
0x00104380 <vPortYieldProcessor+84>: ldr r3, [r3]
0x00104384 <vPortYieldProcessor+88>: ldr r3, [pc, #72] ; 0x1043d4 <vPortYieldProcessor+168>
0x00104388 <vPortYieldProcessor+92>: ldr r3, [r3]
0x0010438c <vPortYieldProcessor+96>: bl 0x102d9c <vTaskSwitchContext>
0x00104390 <vPortYieldProcessor+100>: ldr r0, [pc, #356] ; 0x1044fc
0x00104394 <vPortYieldProcessor+104>: ldr r0, [r0]
0x00104398 <vPortYieldProcessor+108>: ldr lr, [r0]
0x0010439c <vPortYieldProcessor+112>: ldr r0, [pc, #348] ; 0x104500
0x001043a0 <vPortYieldProcessor+116>: ldm lr!, {r1}
0x001043a4 <vPortYieldProcessor+120>: str r1, [r0]
0x001043a8 <vPortYieldProcessor+124>: ldm lr!, {r0}
0x001043ac <vPortYieldProcessor+128>: msr SPSR_fc, r0
0x001043b0 <vPortYieldProcessor+132>: ldm lr, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r1
1, r12, sp, lr}^
0x001043b4 <vPortYieldProcessor+136>: nop (mov r0,r0)
0x001043b8 <vPortYieldProcessor+140>: ldr lr, [lr, #60]
0x001043bc <vPortYieldProcessor+144>: subs pc, lr, #4 ; 0x4
0x001043c0 <vPortYieldProcessor+148>: ldr r3, [pc, #8] ; 0x1043d0 <vPortYieldProcessor+164>
0x001043c4 <vPortYieldProcessor+152>: ldr r3, [r3]
0x001043c8 <vPortYieldProcessor+156>: ldr r3, [pc, #4] ; 0x1043d4 <vPortYieldProcessor+168>
0x001043cc <vPortYieldProcessor+160>: ldr r3, [r3]
0x001043d0 <vPortYieldProcessor+164>: eoreq r0, r0, r4
0x001043d4 <vPortYieldProcessor+168>: eoreq r0, r0, r0, asr r4
End of assembler dump.
(gdb) info registers
r0 0x0 0
r1 0x0 0
r2 0x0 0
r3 0x0 0
r4 0x4040404 67372036
r5 0x5050505 84215045
r6 0x6060606 101058054
r7 0x7070707 117901063
r8 0x8080808 134744072
r9 0x9090909 151587081
r10 0x10101010 269488144
r11 0x11111111 286331153
r12 0x12121212 303174162
sp 0x200ed8 0x200ed8
lr 0x2006d0 2098896
pc 0x10436c 0x10436c <vPortYieldProcessor+64>
fps 0x0 0
cpsr 0x60000093 1610612883
(gdb) print &pxDelayedTaskList->xListEnd->pxNext->pvOwner
$9 = (void **) 0x2006cc
(gdb) print pxDelayedTaskList->xListEnd->pxNext->pvOwner
$10 = (void *) 0x2006bc
(gdb) stepi
0x00104370 186 portSAVE_CONTEXT();
(gdb) print pxDelayedTaskList->xListEnd->pxNext->pvOwner
$11 = (void *) 0x0
(gdb) print &pxDelayedTaskList->xListEnd->pxNext->pvOwner
$12 = (void **) 0x2006cc
(gdb) q
The program is running. Exit anyway? (y or n) y
[/code]
Minimum bound for stack sizes
The context cannot be saved on the IRQ stack because the stack frame has to exist until the task next runs, the IRQ stack frame will be clobbered the next time a task runs.
Take a look at number 1 on this page, including the links. These should help.
http://www.freertos.org/FAQHelp.html