對于初次接觸無線MCU產(chǎn)品的人來說,拿到恩智浦的SDK后肯定需要一段時間適應,其實無線MCU也是MCU,只是在MCU的基礎上增加了一個稍顯復雜的射頻單元,另外圍繞這個射頻單元增加了一些輔助組件,比如framework,FreeRtos等,當然因為射頻部分具有最高的優(yōu)先級,所以用戶的應用必須附屬在無線系統(tǒng)之上。
恩智浦旗下的無線MCU采用了與普通MCU相同的SDK架構,對于芯片間的切換其實是很方便的。
下面是我總結的一些開發(fā)無線MCU的經(jīng)驗,希望能幫到剛開始使用NXP無線MCU的同學們。
本文由如下幾部分組成:
開發(fā)環(huán)境
如何開始
低功耗模式下的代碼調(diào)試
空中包時序分析
Controller enhanced notifications
Timer、Event及其它資源分配
發(fā)射功率調(diào)節(jié)
Panic分析
本文所有實例基于KW38芯片講解,但對于同一系列的其它KW3x芯片同樣適用,對于使用同一SDK架構的其它無線芯片(如QN9080,QN9090)大多數(shù)適用。
開發(fā)環(huán)境
SDK版本:SDK_2_6_13_FRDM-KW38
SDK下載地址:https://mcuxpresso.nxp.com
開發(fā)板:FRDM-KW38
IDE:IAR EmbeddedWorkbench for Arm version 8.50
演示代碼:https://github.com/N40E116/SDK_2_6_13_FRDM-KW38.git
如何開始
如果是第一次使用NXP的無線MCU,請先瀏覽SDK中的如下兩個文件:
Bluetooth Low Energy Quick Start Guide.pdf
Bluetooth Low Energy Demo ApplicationsUser's Guide.pdf
本文中的所有演示操作基于項目temp_sens/freertos,之所以選擇這個工程是因為它包含了低功耗和串口輸出等功能,方便演示。
SDK中所有項目都包含bm和freertos兩個版本,其中bm是不含RTOS的版本,F(xiàn)reeRtos是集成了RTOS的版本。
注意SDK中并非所有項目默認都是使能低功耗的,只有如下工程包含低功耗處理:
adv_ext_central /adv_ext_peripheral
beacon
ble_fscibb
hrs
temp_coll / temp_sens
建議在程序中增加打印復位源的功能,方便異常時的檢測,實例代碼如下:
void BleApp_Init(void)
{
…
(void)Serial_Print(gAppSerMgrIf, "rnReset source:", gNoBlock_d);
Serial_PrintDec(gAppSerMgrIf, PWR_GetSystemResetStatus());
(void)Serial_Print(gAppSerMgrIf, "rn", gNoBlock_d);
}
如果你已經(jīng)足夠熟悉SDK的框架,現(xiàn)在準備開始開發(fā)自己的產(chǎn)品,強烈建議你只修改項目所在工程目錄下的文件,因為其它文件是所有項目公用的,修改后可能導致其它項目的編譯或運行問題,另外這樣做的好處是,后續(xù)如果需要升級SDK,只需對比這些文件,進行移植即可,可大大節(jié)省升級時間。
如下是演示項目的工程目錄結構,可以在這里修改或增加文件:
SDK_2_6_13_FRDM-KW38boardsfrdmkw38wireless_examplesbluetoothtemp_sens

低功耗模式下的代碼調(diào)試
如果直接將未經(jīng)修改的temp_sens工程下載KW38中并開啟調(diào)試,很快你就會收到如下錯誤提示,這是因為KW38進入了低功耗模式, SWD引腳失去調(diào)試功能,J-Link和KW38失去了通訊,所以調(diào)試器斷開了。

要在低功耗的模式下調(diào)試代碼,我們需要定時喚醒KW38,讓debugger認為被調(diào)試芯片是一直在線的,我們可以讓KW38一直處于廣播或連接狀態(tài),這樣KW38為了處理藍牙事件會定時喚醒,從而保持住SWD連接。
另外KW38進入的低功耗模式也是有選擇的,需要進入Low Power mode 1。如下是對應的代碼修改:
#define gAppStartAfterReset_d 1 #define gAppDeepSleepMode_c 1 static void AdvertisingTimerCallback(void* pParam) { /* Stop advertising */ // if (mAdvState.advOn) // { // (void)Gap_StopAdvertising(); // } } BleApp_ConnectionCallback() -> case gConnEvtDisconnected_c: #if defined(cPWR_UsePowerDownMode) (cPWR_UsePowerDownMode) /* UI */ Led1Off(); /* Go to sleep */ SleepTimeoutSequence(); /* restart advertising*/ BleApp_Start(); #else
如果需要上電后或復位后馬上開啟廣播,可使能如下宏定義:
#define gAppStartAfterReset_d 1
對于各功耗模式的介紹可參考源碼文件PWR_Configuration.h。
為了快速掃描連接到設備,可以修改一下KW38的廣播間隔,實例代碼如下:
gapAdvertisingParameters_t gAdvParams = {
/* minInterval */ gGapAdvertisingIntervalRangeMinimum_c, //0x12C0,
/* maxInterval */ gGapAdvertisingIntervalRangeMinimum_c, //0x1900,
…
}
如果向已經(jīng)下載過使能低功耗程序的開發(fā)板再次下載代碼,有時會無法識別到芯片,此時需要按住開發(fā)板的SW3鍵以喚醒KW38,再點擊下載按鈕。
如果你現(xiàn)在沒有調(diào)試低功耗功能,為方便開發(fā)調(diào)試,建議先禁用低功耗模式,只需修改如下宏定義:
#define cPWR_UsePowerDownMode 0
如果你的產(chǎn)品最終選擇的功耗模式是需要MCU進入VLLSx模式的,比如low power mode:5/8/9,那么每次休眠喚醒后,需要重新初始化外設,因為從這些模式喚醒走的是reset流程,不過進入休眠后IO引腳的輸出電平狀態(tài)是可以保持的。
空中包時序分析
使用Ellisys的Bluetooth Tracker抓包工具,結合它的邏輯分析儀功能,我們可以抓取到藍牙空中包和IO的時序關系,以下是我們使用該功能分析KW38功耗狀態(tài)的一個實例。進入低功耗模式前拉低LED1引腳,退出低功耗模式后置高LED1。
#define gLEDSupported_d 1
#include "LED.h"
void BOARD_EnterLowPowerCb(void)
{
Led1Off();
…
}
void BOARD_ExitLowPowerCb(void)
{
Led1On();
…
}
抓取到的空中數(shù)據(jù)和LED1引腳數(shù)據(jù)如下:

聚焦到一個連接事件,我們看到KW38在空中包到來之前大約3ms喚醒了MCU,在處理完藍牙事件后大約304us進入低功耗模式。

Controller enhanced notifications
該特性可以產(chǎn)生額外的如下圖所示藍牙事件,但是默認只有wireless_uart使能了該功能,如果需要這些額外的event,請參考工程wireless_uart。

Timer、Event及其它資源分配
強烈建議用戶仔細瀏覽一遍app_preinclude.h文件,該文件中包含了大多數(shù)項目配置信息,如果用戶有增加的配置項的話,也建議放到這個文件中統(tǒng)一管理。
如用戶需要自己創(chuàng)建Timer或Event的話,則如下配置參數(shù)需要對應的增加。
/* Defines number of OS events used */ #define osNumberOfEvents 5 /* Defines number of timers needed by the application */ #define gTmrApplicationTimers_c (4 + gRepeatedAttemptsTimers_d + gAppAllowDeviceToSleepTimers_d)
app_config.c文件中包含了藍牙的配置信息,如廣播內(nèi)容,安全設置,如有需要可修改該文件。
gatt_db.h文件定義了藍牙的service,可以參考該文件增加或修改用戶自定義的service。
發(fā)射功率調(diào)節(jié)
KW36系列通過如下宏定義,配置藍牙的發(fā)射功率,但是該值對應的實際發(fā)射功率是如何計算的呢?
#define mAdvertisingDefaultTxPower_c 20 #define mConnectionDefaultTxPower_c 20 #define mDefaultTxPowerUsePaBump_c 0
在KW36的datasheet里有如下表格,有兩種方法計算實際發(fā)射功率:
第一種,設置值直接對應下面表格里的行數(shù)(從行0開始),如設置TxPower_c為3,則發(fā)射功率對應的PA_POWER[5:0]= 6,對應的25℃發(fā)射功率為-15.6。
第二種,設置值為0時,PA_POWER[5:0]=1, 設置值為其它值時,PA_POWER[5:0]為二倍的設置值,然后通過下表查詢對應的發(fā)射功率,如設置值為5,則PA_POWER[5:0] = 5*2=10,查詢下表對應的25℃發(fā)射功率為-11.2。

上表對應的是未使能最大+5dBm輸出時的配置,如果使能了+5dBm輸出,請參考如下表格,修改宏定義mDefaultTxPowerUsePaBump_c為1,可使能+5dBm輸出。

對于KW38系列,使用如下API配置發(fā)射功率,因為輸入?yún)?shù)即為發(fā)射功率值,所以不再需要任何轉換。
bleResult_t Controller_SetTxPowerLevelDbm(int8_t level_dbm, txChannelType_t channel);
Panic分析
這里的演示會使用到Segger的J-Link Commander,所以如果你的開發(fā)板的debugger固件呈現(xiàn)的不是J-Link的話,你需要按照如下鏈接里的說明更新debugger為Segger Jlink。或者使用一個外部的J-Link或J-Trace作為debugger。
OpenSDASerial and Debug Adapter | NXP Semiconductors
Panic是Framework下的一個十分有用的調(diào)試工具,在開發(fā)調(diào)試階段用于捕捉各種錯誤,SDK中默認已經(jīng)在很多異常處添加了Panic處理,但是該功能默認是關閉的,需要定義如下宏打開:
#define gUsePanic_c 1
Debugger在線調(diào)試分析
如果是連著Debugger的在線調(diào)試,我們只需暫停代碼即可看到panic的位置,通過panic_data中保存的數(shù)據(jù),我們能進一步定位到出問題時的更多信息,如下是我偽造的一個panic場景。
void BleApp_Start(void)
{
…
panic(0,(uint32_t)BleApp_Start,1,2);
}
運行代碼,程序卡死在panic里,暫停程序,并查看相關信息如下:

將location里的地址0x234b9輸入到匯編窗口的搜索欄,可以看到出問題的函數(shù)是BleApp_Start(),當然這個也可以通過Call Stack進行查看。另外我們可以看到出問題時的一些其它參數(shù)extra1和extra2。

離線分析
很多場景下,產(chǎn)品是在沒有連接debugger的情況下出現(xiàn)了異常,此時我們就需要Segger的J-Link Commander工具了,注意調(diào)試使用的debugger必須是J-Link或J-Trace等Segger公司的產(chǎn)品。
剛才相同的代碼,下載到開發(fā)板后,斷開debugger讓程序全速運行,此時程序應該也運行到了panic的位置,但是我們?nèi)绾尾榭茨兀?/p>
打開J-Link Commander,并連接到KW38芯片,輸入命令‘h’,此時可看到程序PC指針為0x19160。

通過addr2line工具我們可以定位到出問題的代碼文件為Panic.c,行數(shù)為65,addr2line的安裝十分簡單,大家可自行搜索下載安裝。

對于出問題時的其它數(shù)據(jù),我們可以通過變量panic_data查看,通過.map文件定位到panic_data的地址為0x2000421c。

結構體panic_data的定義如下:
typedef struct
{
panicId_t id;
uint32_t location;
uint32_t extra1;
uint32_t extra2;
uint32_t linkRegister;
uint32_t cpsr_contents; /* may not be used initially */
uint8_t stack_dump[4]; /* initially just contain the contents of the LR */
} panicData_t;
使用J-Link Commander的‘mem32’命令可以讀取到如下圖所示的panic_data數(shù)據(jù),通過這些數(shù)據(jù),查找出出問題的函數(shù)地址為0x234b9, extra1為1,extra2為2。

通過addr2line命令查詢到出問題的函數(shù)位于temperature_sensor.c文件的179行,即BleApp_Start()函數(shù),再結合當時保存的extra1和extra2參數(shù),我們大概就能分析出問題的原因了。


該方法用于panic后的代碼追蹤,當然也適用于程序跳入死循環(huán)、Hardfault及其它的一些debugger離線后的異常分析。
以上是我在使用無線MCU時總結的一點經(jīng)驗,希望能幫到剛剛入門無線產(chǎn)品的同學們。
來源:恩智浦MCU加油站
免責聲明:本文為轉載文章,轉載此文目的在于傳遞更多信息,版權歸原作者所有。本文所用視頻、圖片、文字如涉及作品版權問題,請聯(lián)系小編進行處理
審核編輯 黃宇
-
調(diào)試
+關注
關注
7文章
647瀏覽量
35692 -
無線MCU
+關注
關注
2文章
65瀏覽量
18271
發(fā)布評論請先 登錄
MCU51的串口調(diào)試工具
485調(diào)試助手_基于MM32 MCU的shell調(diào)試教程(一)
MCU的調(diào)試接口——怎么堵住這個后門?
STM32 MCU TrustZone開發(fā)調(diào)試技巧分享
MCU不復位調(diào)試的小技巧
無線MCU調(diào)試技巧匯總
評論