打印

上传个文档:《HardFault的诊断》 自问自答

[复制链接]
29675|35
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
aozima|  楼主 | 2012-11-30 00:23 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 aozima 于 2012-11-30 00:26 编辑

上次ST研究中,有位ST的漂亮女工程师讲了关于hardfault的排查,讲得非常好。
以为光盘中会有PPT,今天搜索光盘结果发现没有。
不知道这个文档是否可以提供?
沙发
aozima|  楼主 | 2012-11-30 00:25 | 只看该作者
刚网上搜了一番,在http://st.**.com/down/index.php?id=120找到了。
上传之。
HardFault的诊断.pdf (226.79 KB)

使用特权

评论回复
板凳
acgean| | 2012-11-30 08:57 | 只看该作者
嗯, 好东西, 要进一步写好 Cortrx M3 的程序, 这一块东西必须得学习掌握. 感谢楼主

使用特权

评论回复
地板
aozima|  楼主 | 2012-12-2 21:58 | 只看该作者
本帖最后由 aozima 于 2012-12-2 22:07 编辑

项目中加了一些代码,Fault 后可以打印出更多的信息。
#define SCB_CFSR        (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */
#define SCB_HFSR        (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */
#define SCB_MMAR        (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */
#define SCB_BFAR        (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */

#define SCB_CFSR_MFSR   (*(volatile const unsigned char*)0xE000ED28)  /* Memory-management Fault Status Register */
#define SCB_CFSR_BFSR   (*(volatile const unsigned char*)0xE000ED29)  /* Bus Fault Status Register */
#define SCB_CFSR_UFSR   (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */

static void usage_fault_track(void)
{
    rt_kprintf("usage fault:\n");
    rt_kprintf("SCB_CFSR_UFSR:0x%02X ", SCB_CFSR_UFSR);

    if(SCB_CFSR_UFSR & (1<<0))
    {
        /* [0]:UNDEFINSTR */
        rt_kprintf("UNDEFINSTR ");
    }

    if(SCB_CFSR_UFSR & (1<<1))
    {
        /* [1]:INVSTATE */
        rt_kprintf("INVSTATE ");
    }

    if(SCB_CFSR_UFSR & (1<<2))
    {
        /* [2]:INVPC */
        rt_kprintf("INVPC ");
    }

    if(SCB_CFSR_UFSR & (1<<3))
    {
        /* [3]:NOCP */
        rt_kprintf("NOCP ");
    }

    if(SCB_CFSR_UFSR & (1<<8))
    {
        /* [8]:UNALIGNED */
        rt_kprintf("UNALIGNED ");
    }

    if(SCB_CFSR_UFSR & (1<<9))
    {
        /* [9]:DIVBYZERO */
        rt_kprintf("DIVBYZERO ");
    }

    rt_kprintf("\n");
}

static void bus_fault_track(void)
{
    rt_kprintf("bus fault:\n");
    rt_kprintf("SCB_CFSR_BFSR:0x%02X ", SCB_CFSR_BFSR);

    if(SCB_CFSR_BFSR & (1<<0))
    {
        /* [0]:IBUSERR */
        rt_kprintf("IBUSERR ");
    }

    if(SCB_CFSR_BFSR & (1<<1))
    {
        /* [1]:PRECISERR */
        rt_kprintf("PRECISERR ");
    }

    if(SCB_CFSR_BFSR & (1<<2))
    {
        /* [2]:IMPRECISERR */
        rt_kprintf("IMPRECISERR ");
    }

    if(SCB_CFSR_BFSR & (1<<3))
    {
        /* [3]:UNSTKERR */
        rt_kprintf("UNSTKERR ");
    }

    if(SCB_CFSR_BFSR & (1<<4))
    {
        /* [4]:STKERR */
        rt_kprintf("STKERR ");
    }

    if(SCB_CFSR_BFSR & (1<<7))
    {
        rt_kprintf("SCB->BFAR:%08X\n", SCB_BFAR);
    }
    else
    {
        rt_kprintf("\n");
    }
}

static void mem_manage_fault_track(void)
{
    rt_kprintf("mem manage fault:\n");
    rt_kprintf("SCB_CFSR_MFSR:0x%02X ", SCB_CFSR_MFSR);

    if(SCB_CFSR_MFSR & (1<<0))
    {
        /* [0]:IACCVIOL */
        rt_kprintf("IACCVIOL ");
    }

    if(SCB_CFSR_MFSR & (1<<1))
    {
        /* [1]:DACCVIOL */
        rt_kprintf("DACCVIOL ");
    }

    if(SCB_CFSR_MFSR & (1<<3))
    {
        /* [3]:MUNSTKERR */
        rt_kprintf("MUNSTKERR ");
    }

    if(SCB_CFSR_MFSR & (1<<4))
    {
        /* [4]:MSTKERR */
        rt_kprintf("MSTKERR ");
    }

    if(SCB_CFSR_MFSR & (1<<7))
    {
        /* [7]:MMARVALID */
        rt_kprintf("SCB->MMAR:%08X\n", SCB_MMAR);
    }
    else
    {
        rt_kprintf("\n");
    }
}

static void hard_fault_track(void)
{
    if(SCB_HFSR & (1UL<<1))
    {
        /* [1]:VECTBL, Indicates hard fault is caused by failed vector fetch. */
        rt_kprintf("failed vector fetch\n");
    }

    if(SCB_HFSR & (1UL<<30))
    {
        /* [30]:FORCED, Indicates hard fault is taken because of bus fault,
                        memory management fault, or usage fault. */
        if(SCB_CFSR_BFSR)
        {
            bus_fault_track();
        }

        if(SCB_CFSR_MFSR)
        {
            mem_manage_fault_track();
        }

        if(SCB_CFSR_UFSR)
        {
            usage_fault_track();
        }
    }

    if(SCB_HFSR & (1UL<<31))
    {
        /* [31]:DEBUGEVT, Indicates hard fault is triggered by debug event. */
        rt_kprintf("debug event\n");
    }
}

/**
* fault exception handling
*/
void rt_hw_hard_fault_exception(struct stack_context* contex)
{
   rt_kprintf("psr: 0x%08x\n", contex->psr);
   rt_kprintf(" pc: 0x%08x\n", contex->pc);
   rt_kprintf(" lr: 0x%08x\n", contex->lr);
   rt_kprintf("r12: 0x%08x\n", contex->r12);
   rt_kprintf("r03: 0x%08x\n", contex->r3);
   rt_kprintf("r02: 0x%08x\n", contex->r2);
   rt_kprintf("r01: 0x%08x\n", contex->r1);
   rt_kprintf("r00: 0x%08x\n", contex->r0);

   hard_fault_track();

    rt_kprintf("hard fault on thread: %s\n", rt_current_thread->name);
#ifdef RT_USING_FINSH
   list_thread();
#endif
   while (1);
}
再写了两个测试代码,以手动触发fault。
#include <finsh.h>
static void div0_test(void)
{
    int x,y,z;
    x = 10;
    y = 0;
    z = x / y;
    rt_kprintf("z:%d\n", z);
}
FINSH_FUNCTION_EXPORT(div0_test, div0_test)

static void unalign_test(void)
{
    int * p;
    p = (int *)0x00;
    rt_kprintf("00:0x%08X\n", *p);
    p = (int *)0x04;
    rt_kprintf("04:0x%08X\n", *p);
    p = (int *)0x03;
    rt_kprintf("03:0x%08X\n", *p);
}
FINSH_FUNCTION_EXPORT(unalign_test, unalign_test)
测试时可以使用finsh强大的功能来配置CPU的状态:

1. 访问末授权区域
finsh>>int * p //声明一个指针变量
        0, 0x00000000
finsh>>p = 0xDFFFFFF0 // 指向片上外设区结束处,一般不可能用完,所以此处一般不可访问。
        -536870928, 0xdffffff0
finsh>>*p // 读取指针处数据
psr: 0x01000000
pc: 0x00000e3e
lr: 0x0000451d
r12: 0x00000000
r03: 0x00000000
r02: 0x1fff0180
r01: 0x1fff0814
r00: 0xdffffff0
bus fault:
SCB_CFSR_BFSR:0x82 PRECISERR SCB->BFAR:DFFFFFF0
hard fault on thread: tshell
thread  pri  status      sp     stack size max used   left tick  error
-------- ---- ------- ---------- ---------- ---------- ---------- ---
tidle    0x1f ready   0x00000040 0x00000100 0x00000060 0x00000015 000
tshell   0x14 ready   0x00000088 0x00000400 0x00000218 0x00000009 000
2. 非对齐访问测试
finsh>>int * p //声明一个指针变量
        0, 0x00000000
finsh>>p = 0xE000ED14 // 指向SCB->CCR
        -536810220, 0xe000ed14
finsh>>*p = 0x00000208 // 打开非对齐异常
        520, 0x00000208
finsh>>unalign_test() // 非对齐访问测试
psr: 0x21000000
pc: 0x00000430
lr: 0x00003cbd
r12: 0x0000006e
r03: 0x00000002
r02: 0x00000004
r01: 0x1fff1b6a
r00: 0x1fff1a2c
usage fault:
SCB_CFSR_UFSR:0x100 UNALIGNED
hard fault on thread: tshell
thread  pri  status      sp     stack size max used   left tick  error
-------- ---- ------- ---------- ---------- ---------- ---------- ---
tidle    0x1f ready   0x00000058 0x00000100 0x00000060 0x00000001 000
tshell   0x14 ready   0x00000088 0x00000400 0x00000218 0x00000008 000
3. 除零异常测试
finsh>>int * p //声明一个指针变量
        0, 0x00000000
finsh>>p = 0xE000ED14 // 指向SCB->CCR
        -536810220, 0xe000ed14
finsh>>*p = 0x00000210 // 打开除零异常
        528, 0x00000210
finsh>>div0_test() // 除零异常测试
psr: 0x41000000
pc: 0x00001efe
lr: 0x0000096d
r12: 0x00000000
r03: 0x1fff012c
r02: 0x1fff0917
r01: 0x00001ef9
r00: 0x00000000
usage fault:
SCB_CFSR_UFSR:0x200 DIVBYZERO
hard fault on thread: tshell
thread  pri  status      sp     stack size max used   left tick  error
-------- ---- ------- ---------- ---------- ---------- ---------- ---
tidle    0x1f ready   0x00000040 0x00000100 0x00000060 0x0000000b 000
tshell   0x14 ready   0x00000088 0x00000400 0x00000218 0x00000009 000

使用特权

评论回复
5
LDTEST| | 2012-12-3 21:18 | 只看该作者
  感谢

使用特权

评论回复
6
Xflyan| | 2012-12-3 23:37 | 只看该作者
谢谢分享!其实发现HARTFAULT大部分原因并不是难题 而是自己没有注意到的细节问题

使用特权

评论回复
7
Lyc1992| | 2012-12-4 09:06 | 只看该作者

使用特权

评论回复
8
拿起书本| | 2012-12-4 14:13 | 只看该作者
不错,资料挺详细又全面,学习中,感谢楼主的分享,顶了

使用特权

评论回复
9
aozima|  楼主 | 2013-7-1 12:06 | 只看该作者
本帖最后由 aozima 于 2013-7-1 12:09 编辑

更新一下出现hard fault后如何反查。

问题追踪

上面测试出了问题,是我们人为设置的故障,但在平时调试中出了问题如何追综呢?
以非对齐访问为例,开发环境使用MDK。

1. 进入JTAG仿真状态,并触发非对齐异常。
此时串口会打印出异常时的寄存器值,此时停止仿真器发现程序停在rt_hw_hard_fault_exception中。
finsh>>unalign_test()
addr:0x00 value:0x20001B80
addr:0x04 value:0x0800DE81
psr: 0x21000000
r00: 0x00000000
r01: 0x40013800
r02: 0x20000690
r03: 0x00000000
r04: 0x00000003
r05: 0xe000ed14
r06: 0xdeadbeef
r07: 0x20002678
r08: 0xdeadbeef
r09: 0xdeadbeef
r10: 0xdeadbeef
r11: 0xdeadbeef
r12: 0x08000a95
lr: 0x08002eb5
pc: 0x08000386
usage fault:
SCB_CFSR_UFSR:0x100 UNALIGNED
hard fault on thread: tshell
thread  pri  status      sp     stack size max used   left tick  error
-------- ---- ------- ---------- ---------- ---------- ---------- ---
tidle    0x1f ready   0x00000040 0x00000100 0x0000005c 0x00000009 000
tshell   0x14 ready   0x00000088 0x00000800 0x000001b0 0x0000000a 000
led      0x14 suspend 0x00000078 0x00000200 0x00000078 0x00000005 000
2. 根据上面打印出来的寄存器,提取出关键值是 pc: 0x08000386
我们在MDK的command窗口中输入 pc = 0x08000386


可以把PC指针临时设回问题发生时的场景,我们看到出现问题的指令是
   239:     p = (int *)0x03; 
0x08000384 2403      MOVS     r4,#0x03
   240:     value = *p;
0x08000386 6820      LDR      r0,[r4,#0x00]
0x08000388 9000      STR      r0,[sp,#0x00]


分析 #386 这条指令从 R4+0 的问题读取4字节到R0中,
先前打印出的R4的值为 r04: 0x00000003
因此可以确定为这是因为地址不对齐造成的。

当然,具体情况要具体分析,有时候某个步骤出现问题并不会马上崩溃,
而是过一段时间以后才出问题,因此要结合上下文综合分析。
比如上面这个案例真正有问题的指令是 0x08000384。

根据以上的案例,并结合实际调试经验,相信大家可以更快地找出问题。


使用特权

评论回复
10
aozima|  楼主 | 2013-7-1 12:08 | 只看该作者
再更新一下测试代码,以手动触发fault。
void div0_test(void)
{
    volatile int * SCB_CCR = (volatile int *)0xE000ED14; // SCB->CCR
    int x,y,z;

    *SCB_CCR |= (1 << 4); /* bit4: DIV_0_TRP. */

    x = 10;
    y = 0;
    z = x / y;
    rt_kprintf("z:%d\n", z);
}

void unalign_test(void)
{
    volatile int * SCB_CCR = (volatile int *)0xE000ED14; // SCB->CCR
    volatile int * p;
    volatile int value;

    *SCB_CCR |= (1 << 3); /* bit3: UNALIGN_TRP. */

    p = (int *)0x00;
    value = *p;
    rt_kprintf("addr:0x%02X value:0x%08X\n", (int)p, value);

    p = (int *)0x04;
    value = *p;
    rt_kprintf("addr:0x%02X value:0x%08X\n", (int)p, value);

    p = (int *)0x03;
    value = *p;
    rt_kprintf("addr:0x%02X value:0x%08X\n", (int)p, value);
}

#ifdef  RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(div0_test, div0_test)
FINSH_FUNCTION_EXPORT(unalign_test, unalign_test)
#endif /* RT_USING_FINSH */

使用特权

评论回复
11
SwPwr| | 2013-7-4 21:55 | 只看该作者
aozima 发表于 2012-11-30 00:25
刚网上搜了一番,在http://st.**.com/down/index.php?id=120找到了。
上传之。

谢谢共享

使用特权

评论回复
12
freezz| | 2013-12-10 20:44 | 只看该作者
,mark,慢慢消化。

使用特权

评论回复
13
outstanding| | 2013-12-10 21:08 | 只看该作者
不错。。。。。。。。。。。

使用特权

评论回复
14
hjl2832| | 2014-7-10 11:19 | 只看该作者
不错,查异常的方法。

使用特权

评论回复
15
fvcvxvcv| | 2014-7-11 14:24 | 只看该作者
学习

使用特权

评论回复
16
xzezhen| | 2014-10-25 12:24 | 只看该作者
很赞的分析:lol

使用特权

评论回复
17
zook0k| | 2014-10-27 10:00 | 只看该作者
多谢

使用特权

评论回复
18
xlsf1048| | 2014-12-16 14:17 | 只看该作者
mark

使用特权

评论回复
19
jemy00| | 2014-12-17 11:48 | 只看该作者

mark

使用特权

评论回复
20
FAQ| | 2014-12-17 12:01 | 只看该作者
表示出现过一次hardfault

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:RTOS RT-Thread

55

主题

2015

帖子

23

粉丝