У меня есть маленькая "ОС" для руки Кора 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;
}
Если это поможет: я использую S32K146EVB от NXP, если быть точным.
РЕДАКТИРОВАТЬ: я отключаю прерывания во время выполнения функции ожидания, чтобы избежать Systick, вызывающего планировщик и путаницы.