掌握中断对于使嵌入式应用程序可重入至关重要。重入的挑战在于事情可能会以错误的方式实现,并且问题可能只是偶尔出现(请参阅“ EnterCritical() 和 ExitCritical():为什么事情会严重失败 ”)。 ARM Cortex 中断控制器被命名为 NVIC(嵌套向量中断控制器)。
正如 NVIC 中的“嵌套”所示,该控制器支持嵌套中断,从中断延迟和灵活性的角度来看,这是一件好事。我可以使用 NVIC 有选择地禁用/启用中断。如果操作得当,我不必在整个系统范围内禁用中断:我可以将中断锁定的范围缩小到最少的中断。
NVIC 具有以下用于启用/禁用中断的寄存器(每个向量号对应一位):
- NVIC_ISER :中断设置启用寄存器以启用中断源
- NVIC_ICER :中断清除启用寄存器以禁用中断源
- NVIC_ISPR :中断设置挂起寄存器以引发中断
- NVIC_ISCR : Interrupt Clear Pending Register 清除挂起的中断
下面显示了在 Freescale KL25Z 设备上启用 DMA 中断的位:
要禁用中断源,我可以通过以下 CMSIS 方式执行此操作:
NVIC_DisableIRQ(device_IRQn); // Disable interrupt
使用正确的 IRQ 号。但是,体系结构可能存在问题。
:idea: 使用这些现代处理器,事情将“立即完成”是一种错误的想法:由于内部流水线、缓存、总线和传播延迟设置不会立即产生影响。相反,可能会有一些延迟。
因此,如果在禁用指令之前发生中断,则在我禁用中断后它可能仍会发生:
这对我的设计来说可能是也可能不是问题。但是如果我想创建一个关键部分来防止中断以这种方式发生,我需要添加“内存屏障”指令(参见 http://infocenter.arm.com/help/index.jsp?topic=/com .arm.doc.dai0321a/BIHEBHFF.html ):
-
DSB
:数据同步屏障。确保在执行
DSB
之后的任何指令之前完成DSB
之前的所有显式数据存储器传输。 -
ISB
:指令同步屏障。确保在
ISB
之前所有上下文更改操作的影响被后续指令识别。这导致指令流水线的刷新,ISB
之后的指令被重新获取。
ARM 建议首先使用 DSB,然后再使用 ISB:
NVIC_DisableIRQ(device_IRQn); // Disable interrupt
如果我不想触发挂起的中断,或者如果需要访问与中断源相关的外围空间中的某些内容,例如更改中断向量或外围设置,例如将更改矢量位置。或者换句话说,该外设的任何中断活动都会成为问题。
概括
不考虑 ARM Cortex M0/M4 架构中存在传播延迟这一事实可能会导致有缺陷的中断处理。令人讨厌的是,该问题很少发生,而且很难追踪。添加内存屏障也可能是解决您的问题的金弹 :-) 。
快乐打扰 :-)