1、前言
阅读本文请需要先了解一下技术原理,请阅读一下这篇文章:https://blog.csdn.net/fhqlongteng/article/details/112756689。
2、故障时的寄存器信息
程序在运行中串口打印出如下信息,程序进入hard fault中断并打印出异常点的寄存器数据。
[E/NET_SW] Invalid low power sensor data on the uart2 channel
psr: 0x21000200
r00: 0x000000f6
r01: 0x000000f5
r02: 0x0000006a
r03: 0x20030000
r04: 0x000000a3
r05: 0x00000085
r06: 0x00000085
r07: 0x00000250
r08: 0x00000250
r09: 0x00000018
r10: 0x200200f7
r11: 0x00000000
r12: 0x0000e8bc
lr: 0x0800df1b
pc: 0x0800dbcc
hard fault on thread: mlp_cln
thread pri status sp stack size max used left tick error
-------- --- ------- ---------- ---------- ------ ---------- ---
mlp_cln 7 suspend 0x000000a0 0x00000600 56% 0x00000012 000
mlp_cln 7 suspend 0x000000a4 0x00000600 24% 0x0000000e 000
mlp_cln 7 suspend 0x000000a0 0x00000600 22% 0x00000013 000
mlp_cln 7 ready 0x000000a4 0x00000600 27% 0x00000004 000
Dw_send 9 suspend 0x000000ac 0x00000800 08% 0x0000000a 000
Up_send 8 suspend 0x000000ac 0x00000800 14% 0x00000007 000
tshell 20 suspend 0x0000013c 0x00000800 20% 0x00000003 000
ntp_sync 26 suspend 0x00000078 0x00000600 41% 0x00000002 000
sys_work 23 suspend 0x00000070 0x00000800 05% 0x0000000a 000
tcpip 6 suspend 0x000000c0 0x00000400 50% 0x00000014 000
etx 7 suspend 0x00000094 0x00000400 14% 0x0000000f 000
erx 7 suspend 0x0000009c 0x00000400 51% 0x00000010 000
tidle 31 ready 0x00000050 0x00000400 09% 0x00000005 000
timer 8 suspend 0x00000084 0x00000400 42% 0x00000006 000
main 10 suspend 0x000000a8 0x00000800 33% 0x00000013 000
bus fault:
SCB_CFSR_BFSR:0x82 PRECISERR SCB->BFAR:20030000
通过打印信息可以看出,程序发生异常的点是PC=0x0800dbcc, 返回寄存器LR= 0x0800DF1B,打开程序的源码,查看汇编程序的位置来确认一下出现源代码的位置。总线异常0x0800dbcc发生在函数 sensor_crc16 中iIndex = ucCRCLo ^ *( pucFrame++ )语句中。
根据返回寄存器LR= 0x0800DF1B,程序在执行完成当前函数 sensor_crc16会返回到0x0800DF1B的位置,就是 函数sensor_data_is_valid中,如下图,通过分析sensor_data_is_valid的代码,可以看到当给这个函数你传入len=1时, 调用sensor_crc16函数传入的第二个参数就是0xFFFFFFFF,这会导致sensor_crc16程序访问到非法的内存,导致出现总线错误引发硬件错误。这种故障通过程序执行这个函数时,人为修改len=1,即可复现这样子的寄存器打印信息。
3、解决办法
找到异常代码的问题,解决起来就很简单了,在sensor_data_is_valid入口增加对输入长度len的判断,即当len < 3时返回,代码更改如下:
int sensor_data_is_valid(rt_uint8_t *data, rt_uint32_t len)
{
rt_uint16_t crc = 0;
RT_ASSERT(data);
/*if len == 1, the programe will enter the hardfault interrupt by bus fault 20210120*/
if(len < 3)
{
return RT_FALSE;
}
crc = (data[len - 2] << 8) | data[len - 1];
if(crc != sensor_crc16(data, len - 2))
{
return RT_FALSE;
}
else
{
return RT_TRUE;
}
}