如何调试nRF5 SDK

本文将讲述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。app

1.1 J-Link RTT Viewer

RTT viewer配置方式以下所示:函数

 

 

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

 

 

1.2 J-Link RTTClient

RTT client配置方式以下所示(直接使用jlink命令进行配置):命令行

 

 

RTT client打印窗口以下所示:debug

 

 

 

1.3 UART串口助手

 

串口助手配置方式以下所示:3d

  • 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_59ac345\examples\ble_peripheral\ble_app_hrs\pca10040\s132\arm5_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_59ac345\examples\ble_peripheral\ble_app_hrs\pca10040\s132\arm5_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的例子,分别为:

  • \examples\peripheral\cli\pca10040\blank\arm5_no_packs
  • \examples\ble_peripheral\experimental\ble_app_cli\pca10040\s132\arm5_no_packs
  • \examples\ble_central_and_peripheral\experimental\ble_app_interactive\pca10040\s132\arm5_no_packs

若是你们的应用须要命令行交互方式,能够参考上面3个例子,以examples\peripheral\cli\pca10040\blank\arm5_no_packs为例,交互成功后的界面以下所示:

 

相关文章
相关标签/搜索