在nrf52832低功耗睡眠唤醒调试的过程中,会出现睡眠后芯片直接自重启,在使用网上大牛博文的关闭外设easyDMA的解决办法之后仍然会自动重启,最终经过自己反复调试代码终于找到了问题所在,最终成功解决了自重启的问题,希望本博文提供的解决方案能对您有所帮助
问题描述设备开机进行快速广播,3分钟后若超时未连接则进入睡眠,设备唤醒方式是通过io的detect进行唤醒。官方sdk11的代码如下:
#define APP_ADV_TIMEOUT_IN_SECONDS 180 //3 分钟
static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
{
uint32_t err_code;
switch (ble_adv_evt)
{
case BLE_ADV_EVT_FAST:
err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
APP_ERROR_CHECK(err_code);
break;
case BLE_ADV_EVT_IDLE:
sleep_mode_enter();//==1、广播超时进入睡眠==
break;
default:
break;
}
}
static void sleep_mode_enter(void)
{
uint32_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
APP_ERROR_CHECK(err_code);
// Prepare wakeup buttons.
err_code = bsp_btn_ble_sleep_mode_prepare();//==2、唤醒IO设置==
APP_ERROR_CHECK(err_code);
// Go to system-off mode (this function will not return; wakeup will cause a reset).
err_code = sd_power_system_off();//==3、进入睡眠==
APP_ERROR_CHECK(err_code);
}
结果设备进入睡眠之后,就会很快重启,解决方法如下:
网上的解决方法网上解决方法主要在睡眠之前设备要关闭所有外设的easyDMA,如手册上圈出部分所描述:
手册上提到的关闭easyDMA是很重要的,如果您开启了相关的外设DMA请睡眠前关闭,但我的设备里没有使用任何外设的easyDMA,所以该方法对我来说无效,如果您也遇到了关闭了所有外设的easyDMA仍然重启,那不妨试试下面的解决方式。
问题分析官方提供的代码mian函数如下:
int main(void)
{
uint32_t err_code;
bool erase_bonds;
// Initialize.
timers_init();//定时器初始化
buttons_leds_init(&erase_bonds);//按键和LED灯初始化
ble_stack_init();//蓝牙协议栈初始化
device_manager_init(erase_bonds);//设备管理初始化
gap_params_init();//GAP参数初始化
advertising_init();//广播初始化
services_init();//服务初始化
conn_params_init();//更新过程初始化
// Start execution.
application_timers_start();//定时器开始计时
err_code = ble_advertising_start(BLE_ADV_MODE_FAST);//开始广播
APP_ERROR_CHECK(err_code);
// Enter main loop.
for (;;)
{
power_manage();
}
}
由于在协议栈初始化函数ble_stack_init中调用了softdevice_enable函数对协议栈进行了使能,此处也会导致系统睡眠后会重启,解决办法就是睡眠前调用softdevice_handler_sd_disable失能协议栈。
问题解决主要程序代码如下:(请仔细阅读代码注释)
static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
{
uint32_t err_code;
switch (ble_adv_evt)
{
case BLE_ADV_EVT_FAST:
break;
case BLE_ADV_EVT_IDLE:
sleep_flg = 1;//==1、超时未连接后置位睡眠标志位,在main函数主循环里根据该位判断是否睡眠==
break;
default:
break;
}
}
int main(void)
{
uint32_t err_code;
bool erase_bonds;
// Initialize.
timers_init();//定时器初始化
buttons_leds_init(&erase_bonds);//按键和LED灯初始化
ble_stack_init();//蓝牙协议栈初始化
device_manager_init(erase_bonds);//设备管理初始化
gap_params_init();//GAP参数初始化
advertising_init();//广播初始化
services_init();//服务初始化
conn_params_init();//更新过程初始化
// Start execution.
application_timers_start();//定时器开始计时
err_code = ble_advertising_start(BLE_ADV_MODE_FAST);//开始广播
APP_ERROR_CHECK(err_code);
// Enter main loop.
for (;;)
{
power_manage();//==2、电源管理里根据睡眠标志进行睡眠判断==
}
}
static void power_manage(void)
{
if(sleep_flg == 1)//==3、睡眠标志置位则睡眠==
{
sleep_mode_enter();//==4、进入睡眠==
}
else
{
uint32_t err_code = sd_app_evt_wait();//==5此处很重要,睡眠之前不能再次调用sd_app_evt_wait进入待机魔术==
APP_ERROR_CHECK(err_code);
}
}
static void sleep_mode_enter(void)
{
uint32_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
APP_ERROR_CHECK(err_code);
// Prepare wakeup buttons.
err_code = bsp_btn_ble_sleep_mode_prepare();//==6、唤醒设置==
APP_ERROR_CHECK(err_code);
//==7、如果开启了easyDMA则关闭==
softdevice_handler_sd_disable();//==8、关闭协议栈==
// Go to system-off mode (this function will not return; wakeup will cause a reset).
err_code = sd_power_system_off();//==9、进入睡眠,此语句改成 NRF_POWER->SYSTEMOFF = 1;原因是softdevice_handler_sd_disable已经关闭了协议栈,如果再次调用协议栈函数sd_power_system_off会导致异常问题
APP_ERROR_CHECK(err_code);
}
按如上修改成功解决了睡眠重启的问题!读者重点关注注释中的步骤5、8、9。
查看专栏详情 立即解锁全部专栏