首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >分支到PendSV时数据被覆盖

分支到PendSV时数据被覆盖
EN

Stack Overflow用户
提问于 2019-03-09 20:40:24
回答 1查看 237关注 0票数 2

我有一个小的"os“的手臂皮层m4。我实现了一个等待函数。但从那时起,不知何故,上下文切换被破坏了。在逐步执行这些指令时,我注意到,无论出于什么原因,在进入PendSV中断时,current_task变量都会被覆盖。

这些是全局变量

代码语言:javascript
复制
volatile struct OS_task * current_task;
volatile struct OS_task * next_task;

属于以下类型:

代码语言:javascript
复制
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中断中调用的。

代码语言:javascript
复制
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寄存器,因为我不需要浮点运算。

代码语言:javascript
复制
.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_tasknext_task变量。只有在进入下面的PendSV中断时,current_task才会以某种方式被覆盖。这会导致两个任务被设置为相同的堆栈->不太好。

代码语言:javascript
复制
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。

编辑:我在等待函数执行期间禁用中断,以避免Systick调用Scheduler并将事情搞得一团糟。

EN

回答 1

Stack Overflow用户

发布于 2019-03-11 05:08:21

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

如果可以的话,我想把这个答案的大部分时间花在解决你的上下文切换和调度程序中的一些奇怪的问题上。也许你会在这些文章中找到你最初问题的答案!

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

上下文切换中类似于以下内容:

LDR r0,=OS_Scheduler BLX r0 /*指向下一个任务的指针现在在r0 */中

显然,您还必须重写您的调度器,以便它返回一个指向任务structure.

  • Your的指针,保存和加载r4-r11有点奇怪。为什么要使用STMIA和指针算法,而不是STMDBSTMFDPUSH (都是同义词)?为什么一次推入四个寄存器?例如,我已经做到了

r1女士

然后,您可以简单地编写

STMFD r1!,{r4-r11}

来推送整个批次,pop也是如此(使用LDMFDPOP).

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

BX lr

这就是你所需要的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55077452

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档