【发布时间】:2023-03-13 03:55:01
【问题描述】:
我有一个手臂皮质 m4 的小“操作系统”。我实现了一个等待功能。但从那以后,不知何故,上下文切换被破坏了。在逐步执行我注意到的指令时,无论出于何种原因,current_task 变量在进入 PendSV 中断时都会被覆盖。
这些是全局变量
volatile struct OS_task * current_task;
volatile struct OS_task * next_task;
属于以下类型:
struct OS_task{
volatile unsigned int *sp;
void (*handler)(void * params);
void * params;
volatile enum task_state state;
volatile unsigned char number;
volatile unsigned int delay;
};
这是调度程序功能。它也是从 Systick 中断调用的。
void OS_Scheduler(void)
{
current_task = &OS_tasktable.task_list[OS_tasktable.current_task];
current_task->state = OS_TASK_STATE_IDLE;
int next = OS_GetNextTask(OS_tasktable.current_task);
while (1)
{
if (OS_tasktable.task_list[next].delay == 0)
break;
OS_tasktable.task_list[next].delay--;
next = OS_GetNextTask(next);
}
OS_tasktable.current_task = next;
next_task = &OS_tasktable.task_list[OS_tasktable.current_task];
next_task->state = OS_TASK_STATE_ACTIVE;
S32_SCB->ICSR |= S32_SCB_ICSR_PENDSVSET_MASK;
}
这是 PendSV 处理程序。虽然我正在使用 Cortex-M4F,但我并没有保存 FPU 寄存器,因为我不需要浮点运算。
.syntax unified
.thumb
.global PendSV_Handler
.type PendSV_Handler, %function
PendSV_Handler:
/* Disable interrupts: */
cpsid i
/* Save registers R4-R11 (32 bytes) onto current PSP (process stack
pointer) and make the PSP point to the last stacked register (R8).*/
mrs r0, psp
subs r0, #16
stmia r0!,{r4-r7}
mov r4, r8
mov r5, r9
mov r6, r10
mov r7, r11
subs r0, #32
stmia r0!,{r4-r7}
subs r0, #16
/* Save current task's SP: */
ldr r2, =current_task
ldr r1, [r2]
str r0, [r1]
/* Load next task's SP: */
ldr r2, =next_task
ldr r1, [r2]
ldr r0, [r1]
/* Load registers R4-R11 (32 bytes) from the new PSP and make the PSP
point to the end of the exception stack frame. */
ldmia r0!,{r4-r7}
mov r8, r4
mov r9, r5
mov r10, r6
mov r11, r7
ldmia r0!,{r4-r7}
msr psp, r0
/* EXC_RETURN - Thread mode with PSP: */
ldr r0, =0xFFFFFFFD
/* Enable interrupts: */
cpsie i
bx r0
.size PendSV_Handler, .-PendSV_Handler
这是等待功能。它通过 SVC 中断调用。执行此操作后,current_task 和 next_task 变量设置正确。只有在进入以下 PendSV 中断时,current_task 才会以某种方式被覆盖。这导致两个任务都设置到同一个堆栈 -> 不好。
void __os_wait_ms(unsigned int ms)
{
struct OS_task * current;
current = &OS_tasktable.task_list[OS_tasktable.current_task];
current->delay = ms * OS_tasktable.delay_factor;
OS_Scheduler();
return;
}
如果有帮助:准确地说,我使用的是 NXP 的 S32K146EVB。
编辑:我在等待函数执行期间禁用中断,以避免 Systick 调用调度程序并将事情搞砸。
【问题讨论】: