Using end of memory address as process stack pointer value causing INVPC hard fault

69 views Asked by At

In STM32L432KC(arm cortex-m4+FPU) there are two ram memory blocks. Following is a snippet from the linker script I use.

_e_ram2_stack  = ORIGIN(RAM2) + LENGTH(RAM2);
_e_ram_stack   = ORIGIN(RAM ) + LENGTH(RAM );
...

RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 64K
RAM2   (xrw)    : ORIGIN = 0x10000000,   LENGTH = 16K

I can set main stack pointer(MSP) to use _e_ram_stack or _e_ram2_stack without problem. However when I try to set thread mode to use process stack pointer(PSP) I start to get INVPC hard fault on SysTick interrupt return pop {r7, pc} instruction.

If I subtract 112 from _e_ram_stack or _e_ram2_stack, only then I can start using PSP without problem. Something is preventing the use of end of memory address as top of the stack for PSP, but I couldn't find anything related to that in ARMv7-m architecture manual.

Following is the only change I did in the project code of STM32CubeIDE. Main program is just a dummy while(1) loop and only SysTick interrupt is enabled.

Reset_Handler:
  ldr   sp, =_e_ram_stack

  ldr r0, =_e_ram2_stack
  msr psp, r0

  ldr r1, =2
  msr control, r1

  isb

Disassembly and register values are as following:

On SysTick interrupt handler entry: enter image description here

On SysTick interrupt handler exit(pop {r7,pc} causes hardfault): enter image description here

On Hard Fault exception entry: enter image description here

1

There are 1 answers

0
zenprogrammer On BEST ANSWER

In STM32L432KC data sheet in section 3.5 Embedded SRAM.

STM32L432xx devices feature 64 Kbyte of embedded SRAM. This SRAM is split into two blocks:

48 Kbyte mapped at address 0x2000 0000 (SRAM1)

16 Kbyte located at address 0x1000 0000 with hardware parity check (SRAM2). This memory is also mapped at address 0x2000 C000, offering a contiguous address space with the SRAM1

So the problem is in the linker script RAM length is given as the total of RAM1 and RAM2. And RAM2 is also mapped to be accessible after RAM1.

Linker script in the original post leads to _e_ram2_stack being equal to _e_ram_stack after mapping. So MSP and PSP is using same memory location.

The fix:

_e_ram1_stack  = ORIGIN(RAM1) + LENGTH(RAM1);
_e_ram2_stack  = ORIGIN(RAM2) + LENGTH(RAM2);
...   
RAM1    (xrw)   : ORIGIN = 0x20000000,   LENGTH = 48K # was 64K in original script
RAM2   (xrw)    : ORIGIN = 0x10000000,   LENGTH = 16K