[ARM Cortex-M3/Thumb-2] - Exit proc must pop from stack before shifting stack pointer
Original Reporter info from Mantis: alrieckert
-
Reporter name: Anton Rieckert
Original Reporter info from Mantis: alrieckert
- Reporter name: Anton Rieckert
Description:
I got the interrupts working on the STM32F controller making use of the patches in this topic
http://www.mail-archive.com/fpc-devel@lists.freepascal.org/msg22728.html
Now the compiler generates the NVIT for me and links in the correct procedure addresses at the beginning of the code. The problem however came in that running multiple interrupts, (SysTick, USART1, USART2, EXTI and a few Timers) the program started to give me a HardFault interrupt.
I figured out that the problem lies in the way the compiler generates the procedure exit code. When entering a procedure, the compiler stores the current SP, then pushes the working registers onto the stack while adjusting the SP. Now when the procedure exits, instead of restoring the working registers while incrementing the SP, the compilers loads the SP with the saved SP and then just pops the working registers. This is all fine if your not using interrupts, but when an interrupt fires between loading the saved SP to the SP and then poping the working registers, the interrupt procedure will override the variables that is on the stack since the SP is already adjusted.
In other words, the restoring of the SP and the poping of the working registers should be atomic.
For example (currently):
Entering a procedure
mov ip, sp
stmdb sp!, {r4, r5, fp, lr}
sub.w fp, ip, #4
sub sp, #44 ; 0x2c
Exiting the procedure
mov sp, fp
add sp, #4
ldmdb sp, {r4, r5, fp, pc}
Proposed solution:
Entering a procedure can stay the same:
mov ip, sp
stmdb sp!, {r4, r5, fp, lr}
sub.w fp, ip, #4
sub sp, #44 ; 0x2c
Exiting a procedure we make use of ldmdb sp!
add sp, #44 ; 0x2c
ldmia.w sp!, {r4, r5, fp, pc}
Additional information:
I've added a patch to generate output as explained in this report. The patch seems to work fine. Currently I'm running a STM32F103RB and my code is already
11911 lines compiled, 1.7 sec, 73792 bytes code, 14874 bytes data
in size with no HardFauls or any other problems.
An interrupt procedure will look something like the following
//==============================================================================
procedure InterruptUART2; interrupt 53;
var
data : byte;
begin
if (USART2.SR AND USART_Flag_RXNE) > 0 then
begin
data := USART_ReceiveData(Usart2);
// Do something with your data
end
else
data := USART_ReceiveData(Usart2);
end;
Mantis conversion info:
- Mantis ID: 22146
- OS: Embedded
- Build: SVN
- Platform: ARM Cortex M3
- Version: 2.7.1
- Monitored by: » alrieckert (Anton Rieckert)