本文将讲述Nordic nRF5 SDK的主要调试手段,以帮助大家快速定位问题,并解决问题。一般来说,你可以通过打log方式,IDE的debug模式,SDK自带的app_error_check函数,以及命令行方式等多种手段来调试你的代码。
1. 通过打log方式进行调试
nRF5 SDK支持UART和SWD J-Link(RTT)两种底层通信方式来打印日志,SDK14之后日志也可以通过蓝牙或者Flash进行输出和存储打印,一般来说,UART和SWD用得比较多,其中UART使用串口助手来查看日志,SWD使用J-Link RTT Viewer(仅适用Windows)或者J-Link RTT Client(Windows/Mac/Linux系统)来查看打印日志。由于UART日志打印方式会占用一个UART口,而大部分nRF5芯片都只有一个UART口,从而导致资源冲突,为此推荐大家使用RTT方式来打印日志,从而可以将UART口留给正常应用,更重要的是RTT打印方式功耗非常低(几乎可以忽略不计),大家可以在正式release的产品中也使能它,从而发现产品部署后有可能会出现的问题(UART打印方式功耗非常高,在正式release产品中必须关掉它)。
如果使用SWD接口进行日志打印,那么你可以使用J-Link RTT Viewer或者RTTClient来显示日志,二者选其一即可。在Windows平台推荐使用RTT viewer,否则使用RTT Client。
1.1 J-Link RTT Viewer
RTT viewer配置方式如下所示:

RTT viewer日志打印窗口如下所示:(使用的是SDK15.3中的ble_app_hrs例子,下同)

1.2 J-Link RTTClient
RTT client配置方式如下所示(直接使用jlink命令进行配置):

RTT client打印窗口如下所示:

1.3 UART串口助手
串口助手配置方式如下所示:
Baud rate: 115200
8 data bits
1 stop bit
No parity
HW flow control: None
随便选择一款你熟悉的串口助手,比如Putty或者Termite,Termite打印窗口如下所示:

Putty打印窗口如下所示:

1.4 日志打印模块nRF_Log
nRF5 SDK日志打印功能是通过nRF_Log模块实现的(上面展示的日志都是通过nRF_Log打印出来的),SDK包含的大部分例子都自带打印功能,也就是说包含了nRF_Log模块。一般来说,例子都是默认使用UART进行打印的,如果需要改为RTT进行打印,需要对nRF_Log模块进行配置。在具体讲述nRF_Log模块的配置选项之前,先大概讲述一下nRF_Log的工作原理。
nRF_Log工作原理
nRF_Log模块包含前端和后端两部分代码。前端是面向用户的打印接口,比如NRF_LOG_INFO,它把用户要打印的数据放在一块RAM中。后端用来具体实现打印功能,即把前端RAM中的数据通过不同的后端接口打印出去。目前nRF_Log支持的后端接口有:UART,RTT,Flash和蓝牙。不管采用哪一种后端接口,对用户来说,其调用的前端API是一样的,nRF_Log模块会根据用户的配置自动适配相应后端接口,而且用户可以同时使能多个后端接口,即把日志同时打印到多个后端端口上。nRF_Log模块可以单独使能或禁止某一个模块的打印功能,比如advertising模块,当你调试advertising模块的时候,可以把log打开,调试完毕,把log关闭以让log界面变得更清爽。nRF_Log模块还可以设置打印的级别(Level),如果不分级别的话,打印界面会包含很多打印信息,让我们每次调试都要花费很多时间去寻找自己想要的日志上。设定级别后,我们可以有选择的打印需要的日志信息,没问题时,我们只打印info级别的日志;有问题时,我们就可以把所有debug级别的日志都打印出来。nRF_Log还有一个功能:Deferred,如果不使能Deferred,那么调用NRF_LOG_INFO等API的时候,立马就Flush,即把日志打印出去;如果使能了Deferred,那么调用NRF_LOG_INFO等API的时候,只是把打印数据放在RAM中,真正的打印由main函数中的NRF_LOG_PROCESS完成,这样可以最大程度降低打印对应用本身的影响,尤其在执行一些时序很关键的操作的时候。nRF_Log还支持时间戳打印,即在每条日志之前加上时间戳信息。
nRF_Log配置
从SDK12以后,nRF_Log模块的配置主要放在sdk_config.h文件中,以工程nRF5_SDK_15.3.0_59ac345examplesble_peripheralble_app_hrspca10040s132arm5_no_packs为例,nRF_Log的配置选项如下所示:

注意:nRF5 SDK v11.0.0及以前版本是没有sdk_config.h文件的,此时你需要到options for target->C/C++->define里面定义一个宏(Keil工程),如果定义“NRF_LOG_USES_UART=1”选择UART日志打印;如果定义”NRF_LOG_USES_RTT=1” 则选择RTT日志打印,如下:

还是以nRF5_SDK_15.3.0_59ac345examplesble_peripheralble_app_hrspca10040s132arm5_no_packs为例,当nRF_Log配置为info级别,无timestamp,打印信息如下(与前面配置一样)

当nRF_Log配置为debug级别,打开timestamp,打印信息如下所示:


2. 使用IDE调试界面进行调试
Nordic产品支持单步,断点,寄存器查看,内存查看,call stack查看等所有常规调试手段。需要注意的是,由于softdevice在底层要维持一定的时钟以及处理很多中断事件,一旦蓝牙跑起来后,只能用一个断点进行全速跑,也就是说,执行完一个断点后,程序内部逻辑和时序已经紊乱,此时不能再继续全速跑第二个断点。如果要看第二个断点的内容,只能删掉第一个断点,重新开始执行。
Keil IDE
通过以下方式打开nRF5 SoC内部寄存器查看窗口:

用得比较多的几个Keil窗口:

Segger embedded studio IDE
SES的调试界面如下所示(跟Keil很像):

这里要特别强调一下,所有SES工程都包含2个版本:Release版和Debug版,Release是没有包含debug信息以节省代码空间,所以如果你要debug一个工程,请先选择debug版本,然后再进行debug,如下所示:

3. nRF5 SDK自带的APP_ERROR_CHECK函数
APP_ERROR_CHECK是nRF5 SDK定义的一个用来检查API返回值是否正确的函数,在nRF5 SDK中,NRF_SUCCESS(0)为正确返回值,其它返回值皆为错误值。nRF5 SDK所有协议栈API调用,以及SDK库函数调用,都会用APP_ERROR_CHECK去检查调用的返回值。当出现非法调用时,比如传入的实参不对,API返回值就不会为NRF_SUCCESS,此时APP_ERROR_CHECK就会派上大用场。通过查看APP_ERROR_CHECK函数定义,如下所示:
NRF_BREAKPOINT_COND; // On assert, the system can only recover with a reset. #ifndef DEBUG NRF_LOG_WARNING("System reset"); NVIC_SystemReset(); #else app_error_save_and_stop(id, pc, info); #endif // DEBUG
你会发现APP_ERROR_CHECK行为受宏DEBUG和有没有挂仿真器两个因素的影响,当没有定义DEBUG宏时,系统将直接产生软复位;当定义了DEBUG宏并且没有挂仿真器时,系统将把错误信息保存在call stack中。不管怎么配置,APP_ERROR_CHECK都会把相应的错误信息打印出来,以方便你去排查问题,如下所示。通过打印出来的错误信息,你就可以知道是哪个文件哪一行代码出了什么类型的错误。

注意在SDK14以前,app_error_check不会主动把错误信息打印出来,而是把错误信息存在RAM中,然后通过debug模式可以直接查看相关错误信息,如下所示:

默认情况下,nRF5 SDK是没有定义DEBUG宏的,所以一旦函数返回值不对,系统就会复位。这里要特别指出的是,在你开发调试过程中,经常会碰到复位的情况,这其中大部分都是由APP_ERROR_CHECK引起的。针对这种情况的复位,你只需要在options for target->C/C++->define里面定义一个宏:DEBUG,就可以快速找出是哪一个文件哪一行代码引出的复位,以及复位原因是什么,如下所示:

4.使用命令行(CLI)方式进行调试
打log方式只能单方面输出,而不能接受终端的输入,在很多情况下,我们需要动态调整log信息,比如动态更改log的级别,动态更改log的颜色等等,这个时候就需要用到nrf_cli模块,跟nRF_Log相似,nrf_cli同时支持5种后端接口:UART,RTT,BLE,Flash和USB CDC。由于nrf_cli也有log输出功能,因此nRF_Log模块可以直接选择nrf_cli为其后端接口。这里再次强调一下,nrf_log和nrf_cli是两个完全独立的模块,但是nrf_log可以选用nrf_cli为其后端接口,由nrf_cli完成后端打印功能。SDK中提供了三个cli的例子,分别为:
examplesperipheralclipca10040blankarm5_no_packs
examplesble_peripheralexperimentalble_app_clipca10040s132arm5_no_packs
examplesble_central_and_peripheralexperimentalble_app_interactivepca10040s132arm5_no_packs
如果大家的应用需要命令行交互方式,可以参考上面3个例子,以examplesperipheralclipca10040blankarm5_no_packs为例,交互成功后的界面如下所示:

审核编辑 黄宇
-
nRF5 SDK
+关注
关注
0文章
3浏览量
2110
发布评论请先 登录
Nordic Semiconductor批量生产nRF52840 SoC可全面支持蓝牙5以及蓝牙Mesh和Thread,为市场带来量产级的最先进多协议无线
nRF Connect SDK(NCS)/Zephyr固件升级详解 – 重点讲述MCUboot和蓝牙空中升级
Nordic nRF5 SDK和softdevice介绍
如何调试nRF5 SDK
深度技术解析低功耗蓝牙厂商nordic的nRF Connect SDK裸机选项方案
使用nRF52840芯片的USB Host 功能参考例程
深度技术解析nRF Connect SDK裸机选项方案
nRF5芯片外设GPIO和GPIOTE介绍
nRF5 SDK软件架构和softdevice工作原理
Nordic Semiconductor最新nRF5 SDK推出安全的签名空中固件升级功能
讲述Nordic nRF5 SDK的主要调试手段,以帮助大家快速定位问题
nRF52开发工具包用户指南免费下载
nRF5 SDK软件架构及softdevice工作原理
nRF Connect SDK Basic

如何调试nRF5 SDK
评论