对于初次接触无线MCU产品的人来说,拿到恩智浦的SDK后肯定需要一段时间适应,其实无线MCU也是MCU,只是在MCU的基础上增加了一个稍显复杂的射频单元,另外围绕这个射频单元增加了一些辅助组件,比如framework,FreeRtos等,当然因为射频部分具有最高的优先级,所以用户的应用必须附属在无线系统之上。
本文由如下几部分组成:
开发环境
如何开始
低功耗模式下的代码调试
空中包时序分析
Controller enhanced notifications
Timer、Event及其它资源分配
发射功率调节
Panic分析
本文所有实例基于KW38芯片讲解,但对于同一系列的其它KW3x芯片同样适用,对于使用同一SDK架构的其它无线芯片(如QN9080,QN9090)大多数适用。
开发环境
SDK版本:SDK_2_6_13_FRDM-KW38
SDK下载地址:https://mcuxpresso.nxp.com
开发板: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,之所以选择这个工程是因为它包含了低功耗和串口输出等功能,方便演示。
adv_ext_central /adv_ext_peripheral
beacon
ble_fscibb
hrs
temp_coll / temp_sens
建议在程序中增加打印复位源的功能,方便异常时的检测,实例代码如下:
void BleApp_Init(void)
{
…
(void)Serial_Print(gAppSerMgrIf, "\r\nReset source:", gNoBlock_d);
Serial_PrintDec(gAppSerMgrIf, PWR_GetSystemResetStatus());
(void)Serial_Print(gAppSerMgrIf, "\r\n", gNoBlock_d);
}
如下是演示项目的工程目录结构,可以在这里修改或增加文件:
SDK_2_6_13_FRDM-KW38\boards\frdmkw38\wireless_examples\bluetooth\temp_sens
低功耗模式下的代码调试
如果直接将未经修改的temp_sens工程下载KW38中并开启调试,很快你就会收到如下错误提示,这是因为KW38进入了低功耗模式, SWD引脚失去调试功能,J-Link和KW38失去了通讯,所以调试器断开了。
要在低功耗的模式下调试代码,我们需要定时唤醒KW38,让debugger认为被调试芯片是一直在线的,我们可以让KW38一直处于广播或连接状态,这样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。
gapAdvertisingParameters_t gAdvParams = {
* minInterval */ gGapAdvertisingIntervalRangeMinimum_c, //0x12C0,
* maxInterval */ gGapAdvertisingIntervalRangeMinimum_c, //0x1900,
…
}
如果向已经下载过使能低功耗程序的开发板再次下载代码,有时会无法识别到芯片,此时需要按住开发板的SW3键以唤醒KW38,再点击下载按钮。
如果你现在没有调试低功耗功能,为方便开发调试,建议先禁用低功耗模式,只需修改如下宏定义:
#define cPWR_UsePowerDownMode 0
空中包时序分析
#define gLEDSupported_d 1
#include "LED.h"
void BOARD_EnterLowPowerCb(void)
{
Led1Off();
…
}
void BOARD_ExitLowPowerCb(void)
{
Led1On();
…
}
聚焦到一个连接事件,我们看到KW38在空中包到来之前大约3ms唤醒了MCU,在处理完蓝牙事件后大约304us进入低功耗模式。
Controller enhanced notifications
该特性可以产生额外的如下图所示蓝牙事件,但是默认只有wireless_uart使能了该功能,如果需要这些额外的event,请参考工程wireless_uart。
Timer、Event及其它资源分配
强烈建议用户仔细浏览一遍app_preinclude.h文件,该文件中包含了大多数项目配置信息,如果用户有增加的配置项的话,也建议放到这个文件中统一管理。
* 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文件中包含了蓝牙的配置信息,如广播内容,安全设置,如有需要可修改该文件。
gatt_db.h文件定义了蓝牙的service,可以参考该文件增加或修改用户自定义的service。
发射功率调节
#define mAdvertisingDefaultTxPower_c 20
#define mConnectionDefaultTxPower_c 20
#define mDefaultTxPowerUsePaBump_c 0
在KW36的datasheet里有如下表格,有两种方法计算实际发射功率:
第一种,设置值直接对应下面表格里的行数(从行0开始),如设置TxPower_c为3,则发射功率对应的PA_POWER[5:0]= 6,对应的25℃发射功率为-15.6。
第二种,设置值为0时,PA_POWER[5:0]=1, 设置值为其它值时,PA_POWER[5:0]为二倍的设置值,然后通过下表查询对应的发射功率,如设置值为5,则PA_POWER[5:0] = 5*2=10,查询下表对应的25℃发射功率为-11.2。
上表对应的是未使能最大+5dBm输出时的配置,如果使能了+5dBm输出,请参考如下表格,修改宏定义mDefaultTxPowerUsePaBump_c为1,可使能+5dBm输出。
bleResult_t Controller_SetTxPowerLevelDbm(int8_t level_dbm, txChannelType_t channel);
Panic分析
Panic是Framework下的一个十分有用的调试工具,在开发调试阶段用于捕捉各种错误,SDK中默认已经在很多异常处添加了Panic处理,但是该功能默认是关闭的,需要定义如下宏打开:
#define gUsePanic_c 1
Debugger在线调试分析
如果是连着Debugger的在线调试,我们只需暂停代码即可看到panic的位置,通过panic_data中保存的数据,我们能进一步定位到出问题时的更多信息,如下是我伪造的一个panic场景。
void BleApp_Start(void)
{
…
panic(0,(uint32_t)BleApp_Start,1,2);
}
将location里的地址0x234b9输入到汇编窗口的搜索栏,可以看到出问题的函数是BleApp_Start(),当然这个也可以通过Call Stack进行查看。另外我们可以看到出问题时的一些其它参数extra1和extra2。
离线分析
很多场景下,产品是在没有连接debugger的情况下出现了异常,此时我们就需要Segger的J-Link Commander工具了,注意调试使用的debugger必须是J-Link或J-Trace等Segger公司的产品。
刚才相同的代码,下载到开发板后,断开debugger让程序全速运行,此时程序应该也运行到了panic的位置,但是我们如何查看呢?
打开J-Link Commander,并连接到KW38芯片,输入命令‘h’,此时可看到程序PC指针为0x19160。
通过addr2line工具我们可以定位到出问题的代码文件为Panic.c,行数为65,addr2line的安装十分简单,大家可自行搜索下载安装。
结构体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数据,通过这些数据,查找出出问题的函数地址为0x234b9, extra1为1,extra2为2。
通过addr2line命令查询到出问题的函数位于temperature_sensor.c文件的179行,即BleApp_Start()函数,再结合当时保存的extra1和extra2参数,我们大概就能分析出问题的原因了。
该方法用于panic后的代码追踪,当然也适用于程序跳入死循环、Hardfault及其它的一些debugger离线后的异常分析。
以上是我在使用无线MCU时总结的一点经验,希望能帮到刚刚入门无线产品的同学们。
暂无评论哦,快来评论一下吧!