本文將講述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瀏覽量
2113
發布評論請先 登錄
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
評論