OSCtxSwCtr++; /* Increment context switch counter */
OS_TASK_SW(); /* Perform a context switch */
}
}
}
OS_EXIT_CRITICAL();
}
OS_TASK_SW(); 之后什么时候恢复 PC 寄存器?如果马上恢复,那就跳转到别的任务了,
OS_EXIT_CRITICAL 不就被忽略了吗?
用的的函数有下面这些
#define OS_TASK_SW() OSCtxSw()
OSCtxSw
PUSH {R4, R5}
LDR R4, =NVIC_INT_CTRL ;触发PendSV异常 (causes context switch)
LDR R5, =NVIC_PENDSVSET
STR R5, [R4]
POP {R4, R5}
BX LR
#define OS_CRITICAL_METHOD 3 //进入临界段的方法
#if OS_CRITICAL_METHOD == 3
#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}
#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}
#endif
OS_CPU_SR_Restore
MSR PRIMASK, R0 ;读取R0到PRIMASK中,R0为参数
BX LR ;返回
在 PendSV_Handler 结尾有
CPSIE I ;开中断
还有,OSCtxSw 里面 POP {R4, R5},不是把刚刚 PendSV_Handler 对 R4-R11 的操作覆盖了吗?
谢谢~
在 ARM Cortex-M 架构中,当发生 PendSV 异常时,CPU 会自动将当前任务的寄存器内容保存到任务栈中,并切换到另一个任务的堆栈。在切换到另一个任务之前,CPU 会将任务栈指针保存到 PSP 寄存器中,以便切换回该任务时使用。
在上述代码中,OS_TASK_SW() 宏会调用 OSCtxSw() 函数,在该函数中会触发 PendSV 异常,从而进行任务切换。在 PendSV_Handler 函数中,由于 CPU 已经自动保存了当前任务的寄存器内容,因此可以进行上下文切换操作。在上下文切换完成后,CPU 会自动从 PSP 寄存器中读取新任务的堆栈指针,并更新相关寄存器。
在 PendSV_Handler 函数结尾处开中断是为了允许新任务在退出临界区后能够响应中断。因为在进入临界区时,CPU 会将 PRIMASK 寄存器中断开关位(第0位)设置为 1,从而禁止所有中断的响应。在退出临界区时,需要将 PRIMASK 寄存器恢复为先前的值,以便中断可以继续响应。
至于 OSCtxSw() 函数中的 POP {R4, R5} 操作,其目的是为了恢复任务切换之前的堆栈指针和程序计数器(PC)的值。在触发 PendSV 异常后,CPU 会将 R0-R3、R12、LR 和 PSR 寄存器的值自动保存到当前任务的堆栈中,而 R4-R11 寄存器的值则会被保存到 PSP 寄存器指向的堆栈中。因此,在切换回原任务时,需要将 R4-R11 寄存器的值从任务栈中恢复回来。另外,由于 PC 寄存器的值也需要在任务切换时进行保存和恢复,因此 POP {R4, R5} 操作不会覆盖 PendSV_Handler 对 R4-R11 的操作。
不知道你这个问题是否已经解决, 如果还没有解决的话:;********************************************************************************************************
; HANDLE PendSV EXCEPTION
; void OS_CPU_PendSVHandler(void)
;
; Note(s) : 1) PendSV is used to cause a context switch. This is a recommended method for performing
; context switches with Cortex-M. This is because the Cortex-M auto-saves half of the
; processor context on any exception, and restores same on return from exception. So only
; saving of R4-R11 & R14 is required and fixing up the stack pointers. Using the PendSV exception
; this way means that context saving and restoring is identical whether it is initiated from
; a thread or occurs due to an interrupt or exception.
;
; 2) Pseudo-code is:
; a) Get the process SP
; b) Save remaining regs r4-r11 & r14 on process stack;
; c) Save the process SP in its TCB, OSTCBCur->OSTCBStkPtr = SP;
; d) Call OSTaskSwHook();
; e) Get current high priority, OSPrioCur = OSPrioHighRdy;
; f) Get current ready thread TCB, OSTCBCur = OSTCBHighRdy;
; g) Get new process SP from TCB, SP = OSTCBHighRdy->OSTCBStkPtr;
; h) Restore R4-R11 and R14 from new process stack;
; i) Perform exception return which will restore remaining context.
;
; 3) On entry into PendSV handler:
; a) The following have been saved on the process stack (by processor):
; xPSR, PC, LR, R12, R0-R3
; b) Processor mode is switched to Handler mode (from Thread mode)
; c) Stack is Main stack (switched from Process stack)
; d) OSTCBCur points to the OS_TCB of the task to suspend
; OSTCBHighRdy points to the OS_TCB of the task to resume
;
; 4) Since PendSV is set to lowest priority in the system (by OSStartHighRdy() above), we
; know that it will only be run when no other exception or interrupt is active, and
; therefore safe to assume that context being switched out was using the process stack (PSP).
;
; 5) Increasing priority using a write to BASEPRI does not take effect immediately.
; (a) IMPLICATION This erratum means that the instruction after an MSR to boost BASEPRI
; might incorrectly be preempted by an insufficient high priority exception.
;
; (b) WORKAROUND The MSR to boost BASEPRI can be replaced by the following code sequence:
;
; CPSID i
; MSR to BASEPRI
; DSB
; ISB
; CPSIE i
;********************************************************************************************************