1

I m trying to follow a tutorial implementinng task schedular in stm32f407 discovery board.

There are four functions which will be executed one at time for 1ms each and then switch to next function.

Tutorial defined the whole flow like, we will save each stack register of each function, namely these register xpsr,pc,lr,R0...R13 and then loading this value of the next function to PSP (processor stack pointer) at time of context switching (this is will happen inside systick_handler which will get trigger at 1ms interval).

What I dont understand is, I thought the registers are global and not private like variables inside a function.So how is he saving these register value for each function. This is the given code https://github.com/niekiran/CortexMxProgramming/blob/master/Source_code/015_task_scheduler/Src/main.c if anyone can brief me about the context switching part only a bit then I will be very much confident about what I m doing

Thank You

Abhinav Singh
  • 302
  • 3
  • 15

1 Answers1

6

Imagine you could take a photograph of the CPU at some point in time, and that the photograph could show you the individual 1s and 0s in the CPU at that instant. If you had a way to restore the 1s and 0s from your photograph back into the CPU at some point in the future, and you could then let the CPU run, then assuming RAM and ROM contents were unaltered it would continue doing what it had been doing at the point the photograph was taken.

This is essentially what the context switch is doing. It is saving all of the "volatile context" of the CPU: the contents of all of the general purpose registers (including the program counter which tells it which instruction it was executing, roughly speaking, and the stack pointer) as well as the processor status register (PSR). This is sufficient information to allow the CPU to resume again from this exact point at some future time.

On the Cortex-M, there are two stack pointers, and these exist to make this process easier. One or the other of them is always accessible as sp (r13). The way this example is configured, handler-mode code uses the MSP (main stack pointer) and thread-mode code uses the PSP (process stack pointer). The registers r0-r3, r12, lr (r14), pc (r15) and the PSR are pushed to the active stack on entry to handler mode. That just leaves r4-r11 and the stack pointer (r13 in thread mode, but now accessed via the special-purpose PSP register because the handler is using the MSP).

So the context switch grabs the value of PSP, and then pushes r4-r11 to the task's own stack before saving the updated value of the task's stack pointer in its task control block. Now the entire volatile context of the CPU at the point where it entered handler mode has been saved to the stack of the task that was running, and the stack pointer has been saved in the TCB. All that remains is to find a new task to run, get its stack pointer out of its TCB, use it to pop r4-r11, and then update PSP before returning. On exit from handler mode, r0-r3, r12, lr, pc and the PSR will all be popped automatically by the hardware.

So yes, the registers are 'global', kind of, in that the same registers are used by every task. But when a task isn't running, the contents of those registers are stored on its stack, and restored back into the registers when it is next ready to run. That's the purpose of a context switch.

cooperised
  • 2,404
  • 1
  • 15
  • 18
  • When we enter handler mode i.e in pendSv handler, that means our register value must have changed specifically `LR` and `PC`, so now if I save these values then it would be incorrect right? – Abhinav Singh Dec 31 '20 at 00:22
  • I'd recommend you to read the "exception entry and return" section of the generic manual for the core you're using ([here](https://developer.arm.com/documentation/dui0552/a/the-cortex-m3-processor/exception-model/exception-entry-and-return) is the one for the M3, for example). As I said in my answer, LR and PC are pushed along with some other registers _on entry to handler mode_, so yes they'll have changed, but they'll already have been pushed so it's no problem. LR in particular changes in an interesting way; it contains a code that triggers unstacking everything at the end of the handler. – cooperised Jan 01 '21 at 13:26
  • I have one doubt, is it necessary to use processor stack pointer for handler (task and exception). I have read that processor stack pointer is generally used to avoid corruption of main stack pointer – Abhinav Singh Jan 02 '21 at 13:12
  • The **process** stack pointer (PSP) is used, in your example, for the _task_ stacks. This is selected by the `switch_sp_to_psp()` function. The main stack pointer (MSP) is used by handlers, and this cannot be changed. The context switch accesses the PSP in order to interact with the task stacks to stack and unstack `r4-r11` during the switch. – cooperised Jan 03 '21 at 15:39