Operating system IRQ后Cortext-M3上的任务切换崩溃

Operating system IRQ后Cortext-M3上的任务切换崩溃,operating-system,arm,interrupt,cortex-m3,task-switching,Operating System,Arm,Interrupt,Cortex M3,Task Switching,我已经为我的ARM Cortex-M3操作系统使用了一个外内核模型。当任务想要从UART读取数据时,它会调用一个库函数,如果没有数据,它会发出一个SVC调用来阻止任务(这会导致内核将任务放入该IRQ的等待队列并启用IRQ)。当中断发生时,等待它的所有任务都被移动到可运行队列,并且中断再次被禁用 当我有一个固定的任务数组时,这个模型工作得很好,但现在我移动到了链表,以允许更多类型的等待队列(例如IPC消息)。变化中的某些东西正在导致崩溃。以下是调试输出: Creating task 0 (idle

我已经为我的ARM Cortex-M3操作系统使用了一个外内核模型。当任务想要从UART读取数据时,它会调用一个库函数,如果没有数据,它会发出一个SVC调用来阻止任务(这会导致内核将任务放入该IRQ的等待队列并启用IRQ)。当中断发生时,等待它的所有任务都被移动到可运行队列,并且中断再次被禁用

当我有一个固定的任务数组时,这个模型工作得很好,但现在我移动到了链表,以允许更多类型的等待队列(例如IPC消息)。变化中的某些东西正在导致崩溃。以下是调试输出:

Creating task 0 (idle task)
task0 stack top is 2007cd20
Starting SysTick @ 100Hz
Becoming task 0
Switching to task gsm@2007c008 with SP 2007c3e8
GSM task starting
Switching to task rfid@2007c430 with SP 2007c810
Monitoring RFID reader
Blocking task rfid on IRQ 7
Switching to task gps@2007c858 with SP 2007cc38
Switching to task task0@2007cc80 with SP 2007ccd8
Switching to task gsm@2007c008 with SP 2007c390
Blocking task gsm on IRQ 8
Switching to task gps@2007c858 with SP 2007cc38
Switching to task task0@2007cc80 with SP 2007ccd8
Switching to task gps@2007c858 with SP 2007cc38
Starting GPS tracking
Blocking task gps on IRQ 6
Switching to task task0@2007cc80 with SP 2007ccd8
[... repeats...]
Switching to task task0@2007cc80 with SP 2007ccd8
Unblocking tasks waiting on IRQ 8
Switching to task gsm@2007c008 with SP 2007c3a0
Switching to task task0@2007cc80 with SP 2007ccd8
Switching to task gsm@2007c008 with SP 2007c3a0
Fault: Usage fault
   r0 = 2007c3a0
   r1 = 10007fb8
   r2 = 2007ccd8
   r3 = 10007fb8
  r12 = 00000008
   lr = fffffffd
   pc = 0070c858
  psr = 00000003
 BFAR = e000ed38
 CFSR = 00040000
 DFSR = 00000000
 AFSR = 00000000
SHCSR = 00070008
所以在中断之前一切都很好。实际输出根据哪个UART先有数据而有所不同,但模式是相同的:当发生中断时,当未阻塞的任务切换到第二次时,就会发生故障

下面是相关的代码位。装配垫片:

zeptos_pendsv_isr:
    push {lr}
    mrs r0, psp
    stmfd r0!, {r4-r11}
    bl zeptos_schedule
    ldmfd r0!, {r4-r11}
    msr psp, r0
    pop {pc}
和C函数:

static void pendsv(void){
SCB->ICSR |=1 sp=sp;
DL_追加(可运行_任务、当前_任务);
}
当前任务=可运行任务;
DL_DELETE(可运行_任务、当前_任务);
zeptos_printf(“切换到任务%s@%p,SP为%p\n”,当前_任务->名称,当前_任务,当前_任务->SP);
返回当前任务->sp;
}
静态空隙块(空隙*sp,uint8_t irq){
zeptos_printf(“在IRQ%i\n上阻止任务%s”,当前任务->名称,IRQ);
当前任务->sp=sp;
DL_追加(irq_阻塞的_任务[irq],当前_任务);
当前_任务=0;
NVIC_启用irq(irq);
pendsv();
}
void属性(中断)zeptos isr(void){
int irq=(SCB->ICSR&0xff)-16;
zeptos_printf(“解除阻止等待IRQ%i\n”的任务,IRQ);
NVIC_禁用irq(irq);
//NVIC_ClearPendingIRQ(irq);
DL_CONCAT(可运行任务、irq_阻塞任务[irq]);
irq_阻塞的_任务[irq]=0;
pendsv();
}
void属性(中断)zeptos svc isr(void){
__禁用_irq();
uint32_t*sp=(uint32_t*)\uu get_PSP();
uint32_t pc=sp[6];
uint8_t svc_type=*((uint8_t*)pc-2);
开关(svc_型){
案例0:
睡眠(sp[0]);
打破
案例1:
块(sp,sp[0]);
打破
违约:
zeptos_puts(“坏SVC类型\n”);
}
__启用_irq();
}
无效Zeptos_BlockOnIrq(uint8_t irq){
asm(“svc 1”);
}
SVC、SysTick和PendSV的优先级分别为29、30和31

该故障是INVPC类型的使用故障,这意味着使用了错误类型的EXC_返回值。我检查过了,每次都是0xFFFFFD


有什么建议吗?我应该在哪里查看?

任务的处理器状态是如何保持的? 如果我没记错的话,切换时还需要保存CPSR。 您可能需要将其更改为:

mrs r12, epsr
stmfd r0!, { r4 - r11, r12 }
...
ldmfd r0!, { r4 - r11, r12 }
msr r12, epsr
EPSR将包含诸如处理器条件标志和任何IT块状态信息之类的内容。

我终于找到了问题所在。当我的SVC处理程序调用
block
将任务放入阻止列表时,该任务的堆栈中只有硬件堆叠的寄存器,而不是调度器稍后再次运行时所期望的
{r4-r11}


快速修复方法是为SVC ISR提供一个组装垫片,用于堆叠和取消堆叠额外寄存器,并让C
zeptos_SVC_ISR
函数像
zeptos_schedule
一样返回堆栈指针。它可以工作,但现在需要进行一些重构。

一旦中断发生,硬件就会在PSP上堆叠PSR和{r0-r3,lr,pc}。在中,它表示为异常返回堆叠的pc值(您已标识为0x0070c858)指向有问题的指令。你能在你的C代码中给我们指出这个指令吗<代码>//