我在 ATSAME54 (ARM Cortex-M4) 上运行的 FreeRTOS 应用程序出现硬故障。
我只使用静态分配的内存。当我以非常高的速率向其发送 CAN 消息时,会发生硬故障。我需要运行它几秒钟到一分钟。
硬故障类型是精确的 BusFault 错误(
CFSR.PRECISERR
和 CFSR.BFARVALID
位设置),BFAR
为 5a5a5a5a
。
我使用来自 https://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html.
的代码解码了堆栈帧。这给出:
r0 = 200030e8 <= part of a task stack
r1 = 200030a4
r2 = 5a5a5a5a <= same as BFAR
r3 = 20003934
r12 = 2000317c <= pxCurrentTCB
lr = a5a5a5a5 <= ????? could this be the reason?
pc = 00000955 <= in the middle of xPortPendSVHandler
psr = 00000960
随着内存任务堆栈
r0
指向,FreeRTOS内存启动。作为我的测试之一,我在两者之间放置了一个内存屏障,但这保持不变,因此如果堆栈损坏,则不是因为从 FreeRTOS 内存写入任务堆栈而导致的。
5a5a5a5a
值恰好是FreeRTOS添加到其结构中的完整性检查值。 a5a5a5a5
是堆栈内存的正常填充值。
我还可以尝试什么来找出导致此问题的原因?
最终没找到问题所在。我完全删除了 FreeRTOS,并用一些裸机代码替换了它。这工作完美无缺。然而,这并不是一个令人满意的解决方案,也不是 FreeRTOS.f 出现问题时的通用解决方案。
在我的研究过程中,我发现ARM程序代码应该是字对齐或半字对齐(16位或32位宽指令),因此0x955
对于程序计数器来说是一个奇怪的值。它也非常接近 PSR 的值,所以这让我想知道堆栈解码是否正确发生,以及硬故障时的 PC 是否实际上没有指向其他地方。
xPortPendSVHandler
是
FreeRTOS
的上下文切换器。如果总线故障发生在那里,除了损坏的堆栈帧之外,由于 SRAM 中的任务控制块损坏,您可能还会有一个损坏的进程堆栈指针。您可能需要使用静态分析器来检查代码中是否存在常见错误,例如 NULL 指针取消引用、数组索引越界等。此外,它仅在高速发送消息时发生,这一事实使其看起来像是与赛车相关的问题。
在我的例子中,我使用特定 GPIO 引脚中的上升沿/下降沿中断来解码温度传感器 (DHT22)。我将边缘之间的间隔存储在缓冲区数组中,并在每个中断事件中递增它。
事实是,由于一些电气间歇性,我的缓冲区变得异常高,并且堆栈边界被侵犯。 就我而言,我通过限制缓冲区大小的单个条件解决了这个问题,即,我为其设置了“增长限制”!