笔记
正在写固件工程, 程序框架差不多了, 在和设备通讯. 设备上改一个参数, 固件工程中看这个参数是否要保存, 如果是不同的值, 就写入文件.
发现只要一调用这个写参数的函数, 再运行几秒, 固件工程就会进HardFault_Handler.
如果不调用这个函数, 就正常.
开始检查这个函数, 能保证100%的正确. 而且从这个函数出来, 单步几下, 也不会HardFault.
最后想了一个笨招. 这个HardFault在调用写参数文件的函数后, 不是必现么? 好.
在和这个设备通讯的所有函数(大概50+个函数)的入口处都加了一个全局字符串指针赋值. 然后在HardFault_Handler处理中, 查看这个字符串指针, 这样, 是哪个函数出错, 就很清楚了.
char* gpsz_fun_entry = "unknown";
void my_wait_delay(void)
{
gpsz_fun_entry = "my_wait_delay";
OSTimeDlyHMSM(0, 0, 0, 100);
}
void cm_backtrace_fault(uint32_t fault_handler_lr, uint32_t fault_handler_sp) {
uint32_t stack_pointer = fault_handler_sp, saved_regs_addr = stack_pointer;
#ifdef CMB_USING_DUMP_STACK_INFO
uint32_t stack_start_addr = main_stack_start_addr;
size_t stack_size = main_stack_size;
#endif
if (NULL != gpsz_fun_entry)
{
gpsz_fun_entry = gpsz_fun_entry;
}
fn_debug_watch(e_debug_watch_event_for_hard_fault);
my_HardFault_Handler();
CMB_ASSERT(init_ok);
CMB_ASSERT(!on_fault);
重现了一下, 居然是调用my_wait_delay()时进了HardFault. my_wait_delay()中调用的都是OS的函数啊. 这时, 有点感觉了. 好像是任务栈开小了. 去看任务栈size的定义
#define EX_UART1_USER_Management_Task_stk_SIZE 127
#define EX_UART2_USER_Management_Task_stk_SIZE 127
#define EX_UART3_USER_Management_Task_stk_SIZE 127
#define EX_UART4_USER_Management_Task_stk_SIZE 127
#define EX_UART5_USER_Management_Task_stk_SIZE 127
都改成256试试.
#define EX_UART1_USER_Management_Task_stk_SIZE 256
#define EX_UART2_USER_Management_Task_stk_SIZE 256
#define EX_UART3_USER_Management_Task_stk_SIZE 256
#define EX_UART4_USER_Management_Task_stk_SIZE 256
#define EX_UART5_USER_Management_Task_stk_SIZE 256
将程序跑起来, 试试. 改了几次参数, 都是好好的. 那说明确实因为调用链比较深, 导致任务栈溢出引起的HardFault.
这个问题找了半天, 很耽误事. 这次靠感觉解决了问题, 先这样.
如果想彻底解决任务栈溢出的问题, 就要在每个函数调用前, 都检查任务栈. 或者在OS的任务栈操作中,设置一个任务栈将要溢出的断言. 这块没做试验呢, 以后有时间搞一下.
查资料, 有大佬说起了主任务栈MSP和任务栈PSP之间的区别和试验方法. 资料如下: Main Stack Pointer(MSP) vs Process Stack Pointer(PSP) RedKernel
|