【问题标题】:Finding the source of a Hard Fault - C embedded ARM Cortex-M4 32b查找硬故障的根源 - C 嵌入式 ARM Cortex-M4 32b
【发布时间】:2019-09-22 05:49:45
【问题描述】:

我是嵌入式 C 的新手。调试用于图像相机跟踪的嵌入式系统我得到以下 HardFaultHandler:

Atollic Debug 在此时停止它,而没有明显的特定错误迹象。

__weak void DefaultHardFaultHandle ( void ){
asm volatile(
 " tst lr,#4 \n"
 " ite eq \n"
 " mrseq r0,msp \n"
 " mrsne r0,psp \n"
 " mov r1,lr \n"
 " ldr r2,=HardwareFaultHandler_GetSP \n"
 " bx r2"
 );

我没有一堆内存位置,但是,我如何根据这些位置得出是哪一行代码导致问题的结论? 这是代码的一部分,请帮助我:

uint8_t CameraImageTracker(uint8_t **edgeImage){
    ......

for (y = xRight.yStart; (y < height) && (exit == false); y++)
{
    xRight.yStart = y;

    int x = 0;
    for (x = 0; (x < width) && (exit == false); x++)
    {
        if (edgeImage[y][x] == grayScale)
        {
            xRight.xStart = x;
            xRight.yStart = y;

            CountPixelX(width, height, &xRight, edgeImage, grayScale);

            if (xRight.count > WhiteLinesPixMin)
            {
                exit = true;
            }
        }
    }

    WhiteLinesPixMin = xRight.count;
    WhiteLinesPixMax = (WhiteLinesPixMin + 5);

    if (exit == true)
    {
        exit = false;

        xLeft.xStart = xRight.xStart;
        xLeft.yStart = xRight.yStart;

        CountPixelXleft(width, height, &xLeft, edgeImage, WhiteLinesPixMax, grayScale);

        yLeft.xStart = xLeft.xEnd;
        yLeft.yStart = xLeft.yEnd;

        CountPixelY(width, height, &yLeft, edgeImage, grayScale);

        yRight.xStart = xRight.xEnd;
        yRight.yStart = xRight.yEnd;

        CountPixelY(width, height, &yRight, edgeImage, grayScale);

        ellipseCenter(&xRight, &yRight, &xLeft, &yLeft);

        exit = true;
    }
}
return 0;

【问题讨论】:

  • 为什么要标记eclipse?
  • 可能是 OP 正在使用的 IDE。
  • 所以当您注释掉这段代码或使用其他调试技术来缩小违规行时,您看到了什么?这段代码减少了多少,仍然会中断?

标签: c eclipse arm embedded cortex-m


【解决方案1】:

通过您发布的代码,我看不到您的硬故障的来源。但是通过检查堆栈可以找到硬故障的来源。当进入硬故障时,Cortex-M4 应该将旧的寄存器值压入堆栈。在堆栈上它应该是这样的:

sp + 0x00 =  R0
sp + 0x04 =  R1
sp + 0x08 =  R2
sp + 0x0C =  R3
sp + 0x10 =  R12
sp + 0x14 =  LR
sp + 0x18 =  PC <- That is the one you need
sp + 0x1C =  xPSR 
sp + 0x20 =  end of the stack before hard fault 

但是请注意,如果您做了一些有趣的事情,PC 可能会指向错误的位置或什么都没有,特别是如果您的硬故障不是由您的程序引起的,而是由 DMA、MPU 或类似的东西引起的。

编辑:忘记提及:您应该首先查看 SCB->CSFR 以了解发生了什么。在手册中查看这些位的含义。

【讨论】:

  • 你打错了,堆栈的前四个寄存器是 R0 到 R3,而不是 R1 到 R4。
  • @RichardatImageCraft 你是对的。不要在做不同的事情时发帖......
  • 还有一个错字,抱歉 :-) PC 的偏移量是 0x18,而不是 0x08
【解决方案2】:

第一步是确定发生故障时的 PC 值是多少。在您的“DefaultHardFaultHandle”中,注意:

" mrseq r0,msp \n" " mrsne r0,psp \n" " mov r1,lr \n" " ldr ,=HardwareFaultHandler_GetSP \n" " bx r2"

前两条指令将正确的 SP(堆栈指针)指向 R0。有两个 SP,使用的一个取决于 CPU 出现故障时所处的 CPU 模式(线程或处理程序模式)。最后两条指令跳转到一个新的例程 HardwareFaultHandler_GetSP。换句话说,如果您要为 HardwareFaultHandler_GetSP 编写 C 签名,它将如下所示:

void HardwareFaultHandler_GetSP(uint32_t *sp);

您应该能够使用调试器向下钻取以找到有故障的 PC。例如单步执行DefaultHardFaultHandle,一旦获得SP进入R0,再查看R0的值。假设它是 0x20004000。然后使用内存窗口,查看地址0x20004000+0x18,也就是0x20004018。其中包含出现故障的 PC。

如果你经常这样做,使用我写的函数签名,你可以修改 HardwareFaultHandler_GetSP 显示“SP[6]”来获取 PC。

注意由于缓存,PC 可能会被一两条指令关闭。 BusFault 状态寄存器(或 BFSR,可在地址 0xE000ED29 处进行字节访问)中的 IMPRECISERR 位(位 2)控制此行为。如果它打开,您可以在调试器中将其关闭(例如,当您在 main() 处中断时)或以编程方式关闭它。这会使您的程序运行速度变慢,但会在出现故障时显示确切的 PC。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-23
    • 2016-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-29
    相关资源
    最近更新 更多