我有这个代码在KEIL下工作但不在GCC下工作,我不知道为什么会这样。它测试了一些RTX OS功能。
处理程序:
void GenWait_IRQHandler (void) {
switch (ISR_ExNum) {
case 0: Stat_Isr = osDelay (10); break;
#if (osFeatureWait)
case 1: Stat_Isr = osWait (10); break;
#endif
}
}
通过从main设置挂起的IRQ来输入上述代码:
...
ISR_ExNum = 0; /* Test: osDelay */
NVIC_SetPendingIRQ((IRQn_Type)SWI_HANDLER);
ASSERT_TRUE (Stat_Isr == osErrorISR);
...
问题是此ASSERT_TRUE()
失败,因为Stat_Isr
不等于osErrorISR
它应该是,因为不允许从处理程序模式调用osDelay()
:
osStatus osDelay (uint32_t millisec) {
if (__get_IPSR() != 0U) {
return osErrorISR; // Not allowed in ISR
}
return __svcDelay(millisec);
}
正如我所说,在KEIL下编译它可以正常工作,但是在GCC下编译它失败了。输入处理程序时看起来IPSR没有更新,osDelay()
不知道它应该返回错误。知道为什么会这样吗?
SWI_Handler
是软件处理程序,我在其中调用GenWait_IRQHandler()
。
编辑:
这是可以从KEIL Packs获得的实现作为RTX验证,我只是尝试使其在我正在使用的芯片上工作。所以即使我从ISR调用函数它也应该工作。
此外,正如我在评论中写道:
(来自www.keil.com):
中断服务程序(ISR)可以调用某些CMSIS-RTOS功能。当无法从ISR上下文调用CMSIS-RTOS函数时,它拒绝调用。
然后:
无法从ISR调用的函数正在验证中断状态,并在从ISR上下文调用状态代码
osErrorISR
时返回。在某些实现中,可能使用HARD FAULT向量捕获此条件。
EDIT2:
将-O3中的优化从-O1减少到-O1但是我仍然不知道为什么它会像这样进行优化以及如何轻松阻止编译器执行此操作。我知道最简单的答案是添加几个" volatile"但在这种情况下,我认为这不是那么简单。
答案 0 :(得分:1)
感谢@kkrambo正确的追踪。问题在于指令顺序。将挥发物添加到Stat_Isr
是不够的,但增加记忆障碍使这对我有用:
...
ISR_ExNum = 0; /* Test: osDelay */
NVIC_SetPendingIRQ((IRQn_Type)SWI_HANDLER);
__DMB();
ASSERT_TRUE (Stat_Isr == osErrorISR);
...
之所以发生,是因为代码优化使得在ASSERT_TRUE (Stat_Isr == osErrorISR);
之后调用ISR。我认为现在很清楚。