我有一个小的"os“的手臂皮层m4。我实现了一个等待函数。但从那时起,不知何故,上下文切换被破坏了。在逐步执行这些指令时,我注意到,无论出于什么原因,在进入PendSV中断时,current_task变量都会被覆盖。
这些是全局变量
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。
编辑:我在等待函数执行期间禁用中断,以避免Systick调用Scheduler并将事情搞得一团糟。
发布于 2019-03-11 05:08:21
你观察到的行为可能有很多原因。其一是它并没有真正发生;跨中断边界进行调试是很棘手的,因为暂停和单步执行会禁用中断,因此很难跟踪事情发生的顺序。考虑到变量是静态分配的,它不太可能是堆栈损坏,这会缩小它的范围。但从您提供的代码来看,原因并不明显。
如果可以的话,我想把这个答案的大部分时间花在解决你的上下文切换和调度程序中的一些奇怪的问题上。也许你会在这些文章中找到你最初问题的答案!
next_task变量,因为调度器直接将指向下一个任务的指针返回给上下文切换;你不再需要在上下文切换期间禁用中断(如果一个ISR触发了一个上下文切换,而另一个正在进行,最糟糕的情况是你只连续得到两个);当任务进入等待状态时,您不再需要调用调度器(尽管您将需要设置PENDSV位,最简单的方法是使用SVC处理程序)。上下文切换中类似于以下内容:
LDR r0,=OS_Scheduler BLX r0 /*指向下一个任务的指针现在在r0 */中
显然,您还必须重写您的调度器,以便它返回一个指向任务structure.
r4-r11有点奇怪。为什么要使用STMIA和指针算法,而不是STMDB、STMFD或PUSH (都是同义词)?为什么一次推入四个寄存器?例如,我已经做到了r1女士
然后,您可以简单地编写
STMFD r1!,{r4-r11}
来推送整个批次,pop也是如此(使用LDMFD或POP).
LR中。一个简单的BX lr
这就是你所需要的。
https://stackoverflow.com/questions/55077452
复制相似问题