分支到PendSV时覆盖数据

时间:2019-03-09 12:40:24

标签: c arm cortex-m

我的手臂皮质m4有一点“ os”。我实现了一个等待功能。但是自那时以来,上下文切换已损坏。当我逐步执行说明时,无论出于何种原因,进入PendSV中断时,apt-get clean && apt-get update apt-get install locales locale-gen en_US.UTF-8 Generating locales (this might take a while)... en_US.UTF-8... done Generation complete 变量都会被覆盖。

这些是全局变量

current_task

具有以下类型:

volatile struct OS_task * current_task;
volatile struct OS_task * next_task;

这是调度程序功能。它也从Systick中断中调用。

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;
};

这是PendSV处理程序。尽管我正在使用Cortex-M4F,但是我并没有保存FPU寄存器,只是因为我不需要浮点运算。

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;
}

这是等待功能。通过SVC中断调用。执行此操作后,将正确设置.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 current_task变量。仅在进入以下PendSV中断时,next_task才会被覆盖。这导致两个任务都设置为同一堆栈->不好。

current_task

如果有帮助,请使用精确的恩智浦S32K146EVB。

编辑:我在等待函数执行期间禁用了中断,以避免Systick调用Scheduler并使事情混乱。

1 个答案:

答案 0 :(得分:1)

您观察到的行为可能有多种原因。其一是它并没有真正发生。在中断边界上进行调试非常棘手,因为暂停和步进会禁用中断,因此很难跟踪事件发生的顺序。考虑到该变量是静态分配的,它不太可能是堆栈损坏,从而缩小了范围。但是从您提供的代码来看,原因并不明显。

如果我想将大部分答案用于解决上下文切换和调度程序中的一些奇怪问题。也许通过查看这些内容,您将找到原始问题的答案!

  1. 我建议您从上下文切换调用调度程序。这有几个好处:它简化了上下文切换的调用(您只需要设置PENDSV位,无需先调用调度程序即可;您不再需要全局next_task变量,因为调度程序返回了指向的指针。下一个任务直接传递给上下文切换;您不再需要在上下文切换期间禁用中断(如果ISR在另一个正在进行的情况下触发上下文切换,则可能发生的最坏情况是您连续获得两个);并且您没有任务进入等待状态时,不再需要调用调度程序(尽管您将需要设置PENDSV位,最简单的方法是使用SVC处理程序)。

    在上下文切换中是这样的:

    LDR r0, =OS_Scheduler
    BLX r0
    /* Pointer to next task is now in r0 */
    

    显然,您还必须重写调度程序,以便它返回指向任务结构的指针。

  2. 您保存和加载的r4-r11有点奇怪。为什么使用STMIA和指针算法,而不是STMDBSTMFDPUSH(所有同义词)?为什么每次一次将寄存器推四?例如完成

    MRS r1, PSP
    

    然后您可以简单地编写

    STMFD r1!, {r4-r11}
    

    推送全部内容,弹出按钮也一样(使用LDMFDPOP)。

  3. 我不清楚您为什么要创建和使用特定的异常返回代码。在进入PendSV处理程序时,正确的代码应该已经加载到LR中。一个简单的

    BX lr
    

    是您所需要的。