SylixOS ArmV7m 支持

SylixOS ArmV7m 支持

问题分析

Cortex-M系列与Cortex-A系列不同,在中断处理函数中,会产生如下情况:
问题一
Cortex-A系列进入中断后,会切换到IRQ模式,同时硬件上自动关闭IRQ,而Cortex-M系列进入中断后,硬件不会自动关闭中断。即使中断处理中,第一条指令执行CPSID I关闭中断,如果有高优先级中断产生,仍然有可能还没有来的及关中断,就被高优先级中断抢占(晚到中断)。这种情况属于中断嵌套,但是此时系统的CPU_ulInterNesting次数仍然是1,这里需要额外处理

问题二
在任务切换时,Cortex-A可以将LR赋值给PC值时,同时将保存的SPSR的值赋给CPSR,即赋值PC的时候同时打开中断,这里可以理解为原子操作。而Cortex-M系列的开中断操作需要额外的指令,且硬件上无法保证开中断和BX LR的原子性,有可能在执行中断服务程序时,由于此时是关中断的,已经有高优先级中断处于Pending状态,一旦我打开中断,没有来得及执行BX LR,就被高优先级中断抢占,此时仍然属于中断嵌套,但是CPU_ulInterNesting次数仍然是1,所以也需要做特殊处理


解决方法分析

无论是问题一还是问题二,在硬件上都属于中断嵌套,但是由于发生这两种情况时,CPU_ulInterNesting为1,所以系统看来,都不属于中断嵌套,这样会产生问题。

1.针对问题二,当执行BX LR时,如果被抢占,之前考虑的解决方法是对于此时的现场不做保护,因为我们只需要保证返回到任务被中断现场即可,这里涉及到一个问题,即嵌套的两级中断并没有按层次返回,而是直接从嵌套中断返回到任务,这种做法对于Cortex-M系列是不允许的,会产生Usage fault,如下图(图片来源于The definitive guide to the ARM Cortex-M3):
SylixOS ArmV7m 支持_第1张图片
图片内容解释如下,当Task A运行时被外设IRQ打断,在执行IRQ服务程序时,产生更高优先级中断(SysTick),在SysTick中,如果发生了上下文切换,那么CPU会直接切换到Task B去运行,而没有回到IRQ服务程序,这样会产生Usage fault异常。这样设计是合理地,中断服务程序应该优先处理。为了避免产生Usage fault,这里可以手动执行一次BX LR操作,且要保证MSP中内容与中断嵌套时硬件自动压栈内容一致(否则仍然产生Usage fault),这种方法虽然可以解决Usage fault,但是欺骗了处理器,可能存在一定风险,所以不采用这种方法。

2.针对问题一和二,在执行服务程序后,进行API_InterExit时,都不应该进行任务调度,否则如果有高优先级任务产生,会切换到高优先级运行,而此时处于中断嵌套,这样就会产生Usage fault。所以要保证当问题一和二的情况发生时,不能发生调度。对于问题一发生时,即使不进行调度,在其返回后,仍热会执行API_InterExit,进行调度,所以不存在问题。如果在问题二发生时,由于我任务现场已经恢复了,如果调度时发现有高优先级任务产生,会导致pcpuCur->CPU_ptcbTCBCur与当前上下文不对应,如果不调度的话,虽然可以继续正常运行,但是如果此刻已经有高优先级任务就绪,由于这里没有调度会导致调度延迟,最坏情况会导致一个tick,这是不允许的,所以这里使用了PendSV来避免该情况。如果此时情况一和情况二发生,此时虽然不执行调度程序,但是会置位PendSV,由于PendSV优先级最低,当完成任务切换时,会立即执行PendSV服务程序,并执行一次调度,选取最高优先级任务运行。目前的中断处理流程如下图:
SylixOS ArmV7m 支持_第2张图片
目前在问题一和二发生时没有执行调度,而是发送PendSV,最佳的方法是执行调度程序,但是不会修改pcpuCur->CPU_ptcbTCBCur,仅仅判断是否有高优先级任务,如果有高优先级任务需要执行,再发送PendSV,否则不会发送PendSV,这样不会导致pcpuCur->CPU_ptcbTCBCur和任务上下文不一致。目前的方法不是最好的,有可能在发送PendSV时,并不需要调度。对于蓝色的允许抢占的中断服务程序,这里面是不会发送PendSV的,只会在最外层中断执行调度。

你可能感兴趣的:(ARCH,cortex-m)