Search code examples
carmstm32cortex-mstm32f4

How/When exactly does Cortex-M4 (STM32 F4) switch its R13 from MSP to PSP? Do i have to manually switch if using PSP in inline asm?


I'm writing my own RTOS and I'm implementing the context switch function, where I have to use PSP. The function is written in inline assembly

I was working on another project on STM32 F4 writing assembly and the R13 was apparently the MSP.

I'm wondering if I have to switch R13 from MSP to PSP for my purposes?

If we take a look at FreeRTOS's context switch function, it just uses psp and not r13. However i can only access r13 https://github.com/kylemanna/freertos/blob/master/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c#L481

Could anyone share some insight on how switching from MSP to PSP works?


Solution

  • As stated in the answer linked in the comments, r13 is not a physical register but instead always reflects the contents of either MSP or PSP. You cannot choose which of the two is available via r13, the switch is automatic and depends on whether the CPU is in thread mode or handler mode.

    By default, all code runs with privilege and all code uses the MSP so there is a single stack. Most operating system kernels will change this, by manipulating two bits in the CONTROL register. Setting bit 0 (nPriv) causes thread mode code to run without privilege, and setting bit 1 (SPSEL) chooses PSP as the active stack pointer (this bit reads as zero and ignores writes when in handler mode). Typically this will be done after establishing and initialising a small buffer to act as the idle task stack and writing the idle task stack pointer to PSP.

    In this configuration, context switching becomes quite easy. Provided the context switch runs in handler mode (the PendSV handler is an excellent choice in most cases) it will use the MSP for its own use, which means that it can manipulate the PSP without much difficulty. The CPU will automatically push r0-r3, r12, lr, pc and xPSR to the active stack before entering handler mode; so an integer-only context switch need only load the PSP into a register using MRS, push r4-r11, store the updated stack pointer value somewhere associated with the thread that had been running, load a new stack pointer from somewhere associated with the next thread to run, pop r4-r11, use MSR to update PSP, and return.