NRF52832调试方法1——HardFault_Handler问题定位

一、遇到问题

在运行官方SDK(V17.0.2)的examples: bsp例程时,此例程时钟使用了32.768kHz的低速时钟。我碰到了硬件错误,下面随我一起来找一下原因。

在keil的debug模式下,直接点击全速运行(Run)发生程序卡死,debug显示停到了HardFault_Handler位置,如下图所示。

NRF52832调试方法1——HardFault_Handler问题定位_第1张图片

此时使用navigate backwards(蓝色左箭头)是找不到C代码卡在了何处,毕竟让keil记住整个代码的执行过程,太过于为难它了。

二、解决办法

1.此时首先观察register窗口,观察Stack是否为MSP.

NRF52832调试方法1——HardFault_Handler问题定位_第2张图片

2.栈中定位函数

若Stack为MSP,则复制R13(SP)的值到memory观察窗的地址搜索栏。在我的keil中,每一行显示连续的28个地址上的存储信息,每个地址上存有一个字节的数据。

NRF52832调试方法1——HardFault_Handler问题定位_第3张图片

从第21个位置起的连续四个字节是LR的值,LR( link register)是用于保存函数调用的返回地址. 如上图所示:LR = 0x00001A37. 有了这条地址我们基本上可以找到导致程序卡死的函数。

3.反汇编中找到确切语句

在Disassembly栏中空白处点击右键,选择show disassembly at address,输入LR的值,此时C代码栏已经可以定位到该语句处(蓝色箭头所指的430行处)。

NRF52832调试方法1——HardFault_Handler问题定位_第4张图片

三、问题解决

  既然已经定位到了错误代码,那就去go to definition看一下。找到上图中timestamp_func()的函数定义,该函数的作用是:timestamp_func Function for getting a 32-bit timestamp,即debug时用于输出调试信息的时间。

经过查找发现:timestamp_func函数是通过函数指针传入nrf_log_init函数。nrf_log_init的第一个形参是timestamp_func,而该函数的第二个形参为timestamp_freq(时间戳的频率)。而恰恰是因为log初始化函数的第二个参数与实时性有关,导致log函数无法完成初始化,这又是为什么呢?

答案是:我的板子上52832并没有32.768kHz的晶振,因此log函数无法进行时间戳的操作,请看下图。

NRF52832调试方法1——HardFault_Handler问题定位_第5张图片

这段代码是在nrf_log_ctrl_internal.h头文件中的起始处。定义了宏:#define NRF_LOG_LFCLK_FREQ 32768,从图中的几行宏中我们可以发现:NRF_LOG_LFCLK_FREQ 和时间戳的操作紧密相关,因此可以得出结论:如果debug时需要打印时间戳,一定要让32.768kHz的晶振起振。

解决办法:在sdk_config.h头文件中将时间戳的宏不使能后,并注释掉main函数的clock_initialization函数后,J-Link RTT Viewer可以成功打印出调试信息。

NRF52832调试方法1——HardFault_Handler问题定位_第6张图片

NRF52832调试方法1——HardFault_Handler问题定位_第7张图片

 

四、总结

此篇blog记录了一次hardfault的调试过程,此次造成hardfault的根本原因是:缺少低速晶振,纯硬件问题。但在调试中得出了一个结论:timestamp_func函数(log的时间输出)需要配合32.768kHz晶振一起使用,也算是收获了一个NRF52832的调试经验。

 

 

 

 

你可能感兴趣的:(Nordic,&,BLE,单片机,debug,c语言)