本文将讲述nordicnrf5sdk的主要调试手段,以帮助大家快速定位问题,并解决问题。一般来说,你可以通过打log方式,ide的debug模式,sdk自带的app_error_check函数,以及命令行方式等多种手段来调试你的代码。
1. 通过打log方式进行调试
nrf5sdk支持uart和swdj-link(rtt)两种底层通信方式来打印日志,sdk14之后日志也可以通过蓝牙或者flash进行输出和存储打印,一般来说,uart和swd用得比较多,其中uart使用串口助手来查看日志,swd使用j-linkrttviewer(仅适用windows)或者j-linkrttclient(windows/mac/linux系统)来查看打印日志。由于uart日志打印方式会占用一个uart口,而大部分nrf5芯片都只有一个uart口,从而导致资源冲突,为此推荐大家使用rtt方式来打印日志,从而可以将uart口留给正常应用,更重要的是rtt打印方式功耗非常低(几乎可以忽略不计),大家可以在正式release的产品中也使能它,从而发现产品部署后有可能会出现的问题(uart打印方式功耗非常高,在正式release产品中必须关掉它)。
如果使用swd接口进行日志打印,那么你可以使用j-linkrttviewer或者rttclient来显示日志,二者选其一即可。在windows平台推荐使用rttviewer,否则使用rttclient。
1.1 j-link rtt viewer
rttviewer配置方式如下所示:
rttviewer日志打印窗口如下所示:(使用的是sdk15.3中的ble_app_hrs例子,下同)
1.2 j-link rttclient
rttclient配置方式如下所示(直接使用jlink命令进行配置):
rttclient打印窗口如下所示:
1.3 uart串口助手
串口助手配置方式如下所示:
baudrate:115200
8 data bits
1 stop bit
no parity
hwflowcontrol:none
随便选择一款你熟悉的串口助手,比如putty或者termite,termite打印窗口如下所示:
putty打印窗口如下所示:
1.4 日志打印模块nrf_log
nrf5sdk日志打印功能是通过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_59ac345examplesle_peripheralle_app_hrspca10040s132arm5_no_packs为例,nrf_log的配置选项如下所示:
注意:nrf5sdkv11.0.0及以前版本是没有sdk_config.h文件的,此时你需要到optionsfortarget->c/c++->define里面定义一个宏(keil工程),如果定义“nrf_log_uses_uart=1”选择uart日志打印;如果定义”nrf_log_uses_rtt=1”则选择rtt日志打印,如下:
还是以nrf5_sdk_15.3.0_59ac345examplesle_peripheralle_app_hrspca10040s132arm5_no_packs为例,当nrf_log配置为info级别,无timestamp,打印信息如下(与前面配置一样)
当nrf_log配置为debug级别,打开timestamp,打印信息如下所示:
2. 使用ide调试界面进行调试
nordic产品支持单步,断点,寄存器查看,内存查看,callstack查看等所有常规调试手段。需要注意的是,由于softdevice在底层要维持一定的时钟以及处理很多中断事件,一旦蓝牙跑起来后,只能用一个断点进行全速跑,也就是说,执行完一个断点后,程序内部逻辑和时序已经紊乱,此时不能再继续全速跑第二个断点。如果要看第二个断点的内容,只能删掉第一个断点,重新开始执行。
keil ide
通过以下方式打开nrf5soc内部寄存器查看窗口:
用得比较多的几个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是nrf5sdk定义的一个用来检查api返回值是否正确的函数,在nrf5sdk中,nrf_success(0)为正确返回值,其它返回值皆为错误值。nrf5sdk所有协议栈api调用,以及sdk库函数调用,都会用app_error_check去检查调用的返回值。当出现非法调用时,比如传入的实参不对,api返回值就不会为nrf_success,此时app_error_check就会派上大用场。通过查看app_error_check函数定义,如下所示:
你会发现app_error_check行为受宏debug和有没有挂仿真器两个因素的影响,当没有定义debug宏时,系统将直接产生软复位;当定义了debug宏并且没有挂仿真器时,系统将把错误信息保存在callstack中。不管怎么配置,app_error_check都会把相应的错误信息打印出来,以方便你去排查问题,如下所示。通过打印出来的错误信息,你就可以知道是哪个文件哪一行代码出了什么类型的错误。
注意在sdk14以前,app_error_check不会主动把错误信息打印出来,而是把错误信息存在ram中,然后通过debug模式可以直接查看相关错误信息,如下所示:
默认情况下,nrf5sdk是没有定义debug宏的,所以一旦函数返回值不对,系统就会复位。这里要特别指出的是,在你开发调试过程中,经常会碰到复位的情况,这其中大部分都是由app_error_check引起的。针对这种情况的复位,你只需要在optionsfortarget->c/c++->define里面定义一个宏:debug,就可以快速找出是哪一个文件哪一行代码引出的复位,以及复位原因是什么,如下所示:
4.使用命令行(cli)方式进行调试
打log方式只能单方面输出,而不能接受终端的输入,在很多情况下,我们需要动态调整log信息,比如动态更改log的级别,动态更改log的颜色等等,这个时候就需要用到nrf_cli模块,跟nrf_log相似,nrf_cli同时支持5种后端接口:uart,rtt,ble,flash和usbcdc。由于nrf_cli也有log输出功能,因此nrf_log模块可以直接选择nrf_cli为其后端接口。这里再次强调一下,nrf_log和nrf_cli是两个完全独立的模块,但是nrf_log可以选用nrf_cli为其后端接口,由nrf_cli完成后端打印功能。sdk中提供了三个cli的例子,分别为:
examplesperipheralclipca10040lankarm5_no_packs
examplesle_peripheralexperimentalle_app_clipca10040s132arm5_no_packs
examplesle_central_and_peripheralexperimentalle_app_interactivepca10040s132arm5_no_packs
如果大家的应用需要命令行交互方式,可以参考上面3个例子,以examplesperipheralclipca10040lankarm5_no_packs为例,交互成功后的界面如下所示:
iGameZ390VulcanX评测 期待继续优化和完善BIOS功能
新型能源传感器的地热供暖作用
印尼VR线下体验馆市场大揭秘,如何才能进入印尼市场?
电池指示电路图解
钠离子电池制备上面临哪些挑战
讲述Nordic nRF5 SDK的主要调试手段,以帮助大家快速定位问题
3种常用的单片机晶振电路原理和作用图解
工信部:我国将加快无线通信网络业务创新应用
直流电机的功率如何增大
中国最优秀的IC设计企业TOP100最新名单出炉!(含传感器10强企业)
极点全面屏+全息幻彩设计,华为畅享10首销惊艳众人
5G网络可持续供电方案标准解析
重新定义零售体验——RF技术的四大机遇
基于LM380的音频放大器电路图
随着物联网部署的快速增长,迎来挖掘数据湖
数据/业务中台系统建设解答
伏安法测电阻的原理是什么?
Zigbee模组选型方法
GDT放电管的型号及陶瓷气体放电管在开关电源上的应用
星三角启动电路的电气原理图解析