In this article let me explain, line by line, the PendSV handler which carry out the Context switch form one task to another task. That is nothing but saving the context of current task (Context is nothing but few processor registers, that’s it) and retrieving the context of the next potential task.

So, here is the handler code, I copied from the port.c file of ARM Cortex M3

If you want to locate this file then, you have to go to,

<FreeRTOs installation path>\FreeRTOS\FreeRTOSv9.0.0\FreeRTOS\Source\portable\GCC\ARM_CM3\

you can download and install the FreeRTOS from here : https://sourceforge.net/projects/freertos/

Now let’s explore this line by line
First i will write the code and below that i will give the explanation !

 

Here, they are just saving the PSP value in to R0. Why? Let’s see.

 

Now, in this line, the address of the global variable “pxCurrentTCB” is stored in R3 register.
“pxCurrentTCB” is a global variable defined in tasks.c(go ahead and check tasks.c) which holds the address of the Currently executing task’s TCB.

Now, let’s just assume that the address of the pxCurrentTCB is 0x20000000. And it is holding the address 0x20001108 as shown below.


So, now R3 = 0x20000000

 

(De-reference 0x20000000 and store the value into R2)
So, R2 = 0x20001108 (Address of the Current TCB)

 

Now , R0 has PSP value right ??, so , using that PSP, we are saving the registers contents R4 to R11 on to the tasks stack memory. So, currently R4 to R11 are safe

\

 

 

(De-reference 0x20001108 and store the value in to R0)
What is 0x20001108? It’s the address of the current TCB stored in pxCurrentTCB pointer.

That is, pxCurrentTCB is nothing but a pointer of type “tskTCB”.
tskTCB is the TCB structure which is defined in tasks.c. Go Go Go check tasks.c !!! . You will find the below structure.

In this structure take look in to the first member. What’s that??
It’s another pointer isn’t? Or you can say a place holder, which holds address of the stack where the last item is placed by this task and remember that every task will have its own stack space.

So, the first member just holds the address of the last item present in the stack.

After stmdb R0!, {R4-R11} , R0″ will be pointing to the new top of the stack isn’t it ??

So, save that new top of the stack in to the first member of the TCB.
Now, the first member of the TCB is updated with new top of the stack. I.e. value in the register R0.

This value will be used to restore the stack pointer, when this task switches in later point in time.

Ok let’s move ahead.

 

We are going to branch out after this, that’s why save R3 and R14 for a time being.
R0 is already saved, no worries!
R1 is not required because we didn’t used it so far,
R2 was just a place holder, now it’s not required, so only save R3 and R14.
Note that here SP being used, since we are in the handler mode of the processor, SP is nothing but MSP (Main Stack Pointer).
So, we just pushed to kernels stack memory.

 

/* disable the interrupts, */

 

branch out to vTaskSwitchContext
vTaskSwitchContext is defined in tasks.c , which selects the next potential task based on priority .

So, the below figure explains what happens when call is made to vTaskSwitchContext

  1. Initially the global pointer pxCurrentTCB was holding the address of the Current TCB .i.e 0x20001108
  2. After that call is made to vTaskSwitchContext
  3. Inside vTaskSwitchContext , there is a call to taskSELECT_HIGHEST_PRIORITY_TASK()
  4. Which changes the pxCurrentTCB value to the address of the next potential TCB.

 

Disables the interrupt again, who knows what happened to basepri when we branched out above */

 

POP R3 , R14.
Remember that R3 = 0X20000000

 

Dereference R3, and store the value in to R1.


So, R1 = 0x20000580 (address of the new Task’s TCB, which is going to switch in next)

 

Dereference 0x20000580 and store the value in to R0 .

That means, store the value of the first member of the new TCB.
As you already know, first member is nothing but top of the stack.

So,R0 = Top of the stack of new Task, which is selected for switching in.

 

So, we know the top of the stack;
Let’s use that to retrieve the context of new Task.

This is the Current Stack state of the New Task which is about to switch in!

This is the Current Stack state of the New Task after ldmia R0!, {R4-R11}”

So, context of the new task is retrieved to register R4 to R11.

 

Now, let’s initialize the PSP with the R0 value

 

Return from the handler!

Before executing “bx R14”

 

After executing bx R14

So, the task will resume to the instruction during which it was switched out of the running state.

Note: I have omitted explaining of “ISB” instruction. Please read from here

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/CHDEBIEG.html

Get the Full Course on FreeRTOS Porting and programming  Here

If you like this article, please consider sharing it in linkedin by clicking below.

Thanks