stm32f103 the function code in the UCOS-II code in the Os_cpu_pendsvhandler.
Ucos-ii is a non-stripped operating system, task switching occurs only in the following situations:
1> external interrupts cause changes that cause high priority tasks to be ready.
For example, the serial port interrupt received data, after receiving the data in the interrupt routine call Ossempost (), the mutex post so that ucos-ii know the corresponding serial receive task to transition to ready state.
2> Systick A timed interrupt, leading to a high-priority task that was previously in ostimedly pending.
3> The current task execution, such as Ossempend, ostimedly, causes the current task to hang and needs to switch to another sub-priority task.
The first two are the task transitions that are caused after an interrupt exits.
An external interrupt exits when the Osintexit function is invoked to activate the PENDSV interrupt, and the real task switch is implemented in the PENDSV interrupt routine.
The Systick interrupt priority is higher, does not directly do the task switch, it also calls the Osintexit function to activate the PENDSV interrupt when the interrupt exits, and the real task switch is implemented in the PENDSV interrupt routine.
The 3rd is to call Os_sched when a task switch is required, which calls OSCTXSW, while OSCTXSW activates the PENDSV interrupt, and the PENDSV interrupt routine completes the real task switch.
So all the task transitions are ultimately done by the PENDSV interrupt routine.
The interrupt priority of the PENDSV must be the lowest of all interrupts in the system.
PENDSV interrupts are handled by the Os_cpu_pendsvhandler function.
Code for the Os_cpu_pendsvhandler function:
Os_cpu_pendsvhandler Cpsid I; Prevent interruption during context switch MRS R0, PSP; PSP is process stack pointer CBZ R0, Os_cpu_pendsvhandler_nosave; Skip Register Save the first time SUBS R0, R0, #0x20; Save remaining regs r4-11 on process stack STM R0, {r4-r11} LDR R1, =ostcbcur ;
Ostcbcur->ostcbstkptr = SP; LDR R1, [R1] STR R0, [R1]; R0 is SP of process being switched out; At this point, entire context of the process has been saved Os_cpu_pendsvhandler_nosave PUSH {R14} ; Save LR Exc_return value LDR R0, =ostaskswhook; OstaskswHook (); BLX R0 POP {R14} LDR R0, =ospriocur;
Ospriocur = Ospriohighrdy; Ldr R1, =ospriohighrdy ldrb R2, [R1] STRB R2, [R0] Ldr R0, =ostcbcur ;
Ostcbcur = Ostcbhighrdy; Ldr R1, =ostcbhighrdy ldr R2, [R1] STR R2, [R0] Ldr R0, [R2] ; R0 is new process SP;
SP = ostcbhighrdy->ostcbstkptr; LDM R0, {r4-r11}; Restore r4-11 from New process stack ADDS R0, R0, #0x20 MSR PSP, R0 ; Load PSP with new process SP ORR LR, LR, #0x04; Ensure exception return uses process stack Cpsie I BX LR;
Exception return to restore remaining context
1) Status before the task switch
Assuming that there are two tasks in the system, TASK1 and Task2,task1 are currently running tasks (indicated by ostcbcur) and Task2 are in a suspended state.
Before entering the Os_cpu_pendsvhandler interrupt, the stack state is shown in the following figure.
The CPU is in thread state, working with the PSP stack, and the PSP points to the TASK1 stack.
Each register in the CPU is the register value of the Task1 current task.
The TASK2 is in a suspended state, and the TASK2 stack pointer is saved by the TCB2 SP variable. At the bottom of the Task2 stack, two pieces of data are saved, part of the register variable (including XPSR,PC,LR,R12,R0~R3) that is automatically saved to the stack when the CPU breaks, and the other is Ucos the extra saved register variable (R4~R11). These registers hold all the data before the Task2 hangs.
2) The state of the interrupt routine when the task is switched
TCB2 interrupts are fired when a conditional change causes Task1 to switch to Task2 (Ostcbhighrdy points to Task2 PENDSV).
When entering a os_cpu_pendsvhandler interrupt, a portion of the action is automatically performed by the CPU according to the CORTEX-M3 interrupt process:
The CPU automatically saves XPSR,PC,LR,R12,R0~R3 to the current stack, because the PSP is a stack that points to the Task1, so these registers are automatically saved to the Task1 stack. The CPU switches to handler mode, using the MSP as the work stack for the interrupt routine. The PC points to the interrupt routine and executes the interrupt routine.
When entering a os_cpu_pendsvhandler interrupt, the stack status is shown in the following figure:
3) Ucos the status after saving the current task site
After entering the Os_cpu_pendsvhandler, since the CPU only automatically saves the partial register value, Ucos needs to save the remaining registers so that the field can be fully restored when the task is cut back.
The Os_cpu_pendsvhandler will be based on the PSP's worth to the bottom of the Task1 stack, and then save the extra register r4~r11 to the bottom of the Task1 stack.
and save the updated stack value of the Task1 to the SP variable of the TCB1.
Os_cpu_pendsvhandler the stack state after saving the current task data is shown in the following figure:
4) Ucos the status after recovering the target task data
After that Os_cpu_pendsvhandler need to restore the field data of the TASK2 task.
Os_cpu_pendsvhandler Gets the task block (at which it equals TCB2) that needs to be switched from Ostcbhighrdy, and then gets the stack pointer for the task from the TCB2 SP variable.
After getting the TASK2 stack pointer, Os_cpu_pendsvhandler restores the value of the R4~R11 register from the bottom of its stack (which was previously saved by Ucos), and then adjusts the CPU's PSP pointer to the TASK2 stack where the previous CPU automatically saved data. As shown in the following figure.
At this point the CPU's R4~R11 register has reverted to the value before Task2 pending, but R0~r3, R12, LR, PC, XPSR these have not yet been restored, and these registers will be automatically recovered by the CPU when the interrupt returns.
Finally Os_cpu_pendsvhandler calls BX LR to perform an interrupt return (the value in LR is the Exc_return value to inform the CPU to do an interrupt return action).
Os_cpu_pendsvhandler the stack state before the interrupt return is as follows:
5) Ucos return from interrupt, complete the status after the task switch After the Os_cpu_pendsvhandler invokes BX LR, the rest of the onsite recovery is done by the CPU:
The CPU recovers the values of these registers from the PSP stack, and since the PSP has pointed to the Task2 stack, the value of these registers is reverted to the value in the Task2 stack, which is the register value XPSR,PC,LR,R12,R0~R3 the TASK2 task hangs. The PC value of the CPU is also restored from the stack to the PC value when the Task2 task is interrupted. The CPU exits the handler mode, switches to threading mode, re-uses the PSP stack as the work stack (at this point the PSP has pointed to the Task2 stack), and uses the TASK2 stack as the work stack. The CPU has been restored to the scene before the Task2 hangs and continues to run from the Task2 disconnected pc. Compared to the state before the task switch, the state of Task1 and Task2 is completely swapped, so the switch between Task1 and Task2 is completed. After the interrupt is returned, the stack status of completing the TASK2 task switch is shown in the following figure: