DA14580睡眠配置

我们使用官方的ble_app_profile工程配置睡眠模式,睡眠模式使用扩展睡眠。

项目功能:上电广播10s,然后进入睡眠。按下按键唤醒,广播10s,然后进入睡眠,以此循环。

 

1、打开文件 user_config.h,将app_default_sleep_mode 赋值为 ARCH_EXT_SLEEP_ON

    const static sleep_state_t app_default_sleep_mode = ARCH_EXT_SLEEP_ON;

 

2、为了方便管理,我们新建1个.c文件,把用户配置睡眠相关的代码放在里面。该文件命名为user_sleepmode_task.c,然后把这个文件加入到工程的user_app目录下。

 

user_sleepmode_task.c的内容如下:

#include "user_sleepmode_task.h"
#include "wkupct_quadec.h"
#include "gpio.h"
#include "custs1_task.h"
#include "user_periph_setup.h"

#include "rwip_config.h"
#include "app_api.h"
#include "user_callback_config.h"
#include "app_default_handlers.h"
#include "custs1_task.h"

#include "wkupct_quadec.h"


/**
 ****************************************************************************************
 * @brief Sets button as wakeup trigger
 * @return void
 ****************************************************************************************
*/
void app_button_enable(void)
{
    app_easy_wakeup_set(app_wakeup_cb);				
    wkupct_register_callback(app_button_press_cb);
	
    wkupct_enable_irq(WKUPCT_PIN_SELECT(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN), 
                      WKUPCT_PIN_POLARITY(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN, WKUPCT_PIN_POLARITY_LOW),
                                          1, 
                                          40); 
}



/**
 ****************************************************************************************
 * @brief Button press callback function. Registered in WKUPCT driver.
 * @return void
 ****************************************************************************************
 */
void app_button_press_cb(void)
{
    if (GetBits16(SYS_STAT_REG, PER_IS_DOWN))
    {
        periph_init();
    }

    if (arch_ble_ext_wakeup_get())
    {
        arch_set_sleep_mode(app_default_sleep_mode);	//给出默认睡眠模式
        arch_ble_force_wakeup();			//强制唤醒BLE				
        arch_ble_ext_wakeup_off();			//退出外部唤醒		
        app_easy_wakeup();				//发送消息给内核,内核回调app_wakeup_cb			
    }
}



/**
 ****************************************************************************************
 * @brief Application wakeup callback function. Registerd in API message utility.
 * @return void
 ****************************************************************************************
*/
void app_wakeup_cb(void)
{
    // If state is not idle, ignore the message
    if (ke_state_get(TASK_APP) == APP_CONNECTABLE)
    {
        user_app_adv_start();
    }
}


 

头文件user_sleepmode_task.h,声明函数。

 

#ifndef _USER_SLEEPMODE_TASK_H_
#define _USER_SLEEPMODE_TASK_H_

#include "custs1_task.h"
#include "ke_msg.h"
#include <stdint.h>

void app_button_enable(void);
void app_button_press_cb(void);
void app_wakeup_cb(void);

#endif // _USER_SLEEPMODE_TASK_H_

解析函数:

a、app_button_enable函数主要用来使能按键中断,注册回调函数,睡眠前用户调用。

void app_button_enable(void)
{
    app_easy_wakeup_set(app_wakeup_cb);							
    wkupct_register_callback(app_button_press_cb);	
	
    wkupct_enable_irq(WKUPCT_PIN_SELECT(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN), 
           WKUPCT_PIN_POLARITY(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN, WKUPCT_PIN_POLARITY_LOW), 
           1, 40); 
}	
app_easy_wakeup_set(app_wakeup_cb);
设置唤醒回调函数,当内核从睡眠中唤醒时会调用app_wakeup_cb函数

wkupct_register_callback(app_button_press_cb);
注册按键中断函数,按键中断时会调用app_button_press_cb
 
wkupct_enable_irq( );        配置唤醒管脚中断
参数1:WKUPCT_PIN_SELECT(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN) 需要唤醒的管脚,如果需要多个管脚唤醒,则可以使用 | 来配置。
( WKUPCT_PIN_SELECT(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN)  | WKUPCT_PIN_SELECT(GPIO_BUTTON2_PORT, GPIO_BUTTON2_PIN) )
 

参数2:WKUPCT_PIN_POLARITY(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN, WKUPCT_PIN_POLARITY_LOW)        选择中断的极性(即上升沿/下降沿中断),如果需要多个管脚唤醒,则同样可以使用 | 来配置。

WKUPCT_PIN_POLARITY(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN, WKUPCT_PIN_POLARITY_LOW)  |

WKUPCT_PIN_POLARITY(GPIO_BUTTON2_PORT, GPIO_BUTTON2_PIN, WKUPCT_PIN_POLARITY_LOW)

参数3:事件数,即按键按下多少次才触发中断。按下一次就中断,则填1即可。

参数4:消抖时间,消除按键抖动,防止误唤醒。最大可以设置63ms。

 

由于我们使用按键唤醒,所以要定义按键管脚和配置按键的工作模式。

在user_periph_setup.h中定义按键的管脚

    #define GPIO_BUTTON_PORT  GPIO_PORT_2
    #define GPIO_BUTTON_PIN   GPIO_PIN_4

然后在 user_periph_setup.c文件的GPIO_reservations和set_pad_functions中配置按键管脚。

void GPIO_reservations(void)
{
    RESERVE_GPIO(PUSH_BUTTON, GPIO_BUTTON_PORT, GPIO_BUTTON_PIN, PID_GPIO);		
}
void set_pad_functions(void)       
{
    GPIO_ConfigurePin(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN, INPUT_PULLUP, PID_GPIO, false);
}

 

b、app_button_press_cb 该函数是按键中断唤醒时由系统回调的。

 

 如果外设已经掉电了,则调用periph_init()初始化外设

    if (GetBits16(SYS_STAT_REG, PER_IS_DOWN))
    {
        periph_init();
    }

 

如果是外部唤醒,则执行里面的内容。

    if (arch_ble_ext_wakeup_get())
    {
        arch_set_sleep_mode(app_default_sleep_mode);
        arch_ble_force_wakeup();													
        arch_ble_ext_wakeup_off();									
        app_easy_wakeup();															
    }

arch_set_sleep_mode(app_default_sleep_mode)    给出下次要进入哪种睡眠模式,这里我们使用默认的睡眠模式,也就是我们之前定义为ARCH_EXT_SLEEP_ON。如果唤醒后广播期间不想进入睡眠,只有在广播结束后才进入睡眠,则这里可以先把它关闭arch_set_sleep_mode(ARCH_SLEEP_OFF)。然后在广播完成后再调用arch_set_sleep_mode(app_default_sleep_mode)即可。

arch_ble_force_wakeup();    强制唤醒BLE内核。DA14580是由 Cortex M0和BLE内核组成,所以按键唤醒时只是Cortex M0唤醒,而BLE内核则需要Cortex M0去唤醒。

arch_ble_ext_wakeup_off(); 退出外部唤醒,下次进入睡眠再使能外部唤醒。

app_easy_wakeup(); 发送消息给BLE内核,然后回调我们之前注册的函数app_wakeup_cb

 

c、app_wakeup_cb    BLE内核唤醒回调函数

void app_wakeup_cb(void)
{
    if (ke_state_get(TASK_APP) == APP_CONNECTABLE)
    {
        user_app_adv_start();
    }
}

唤醒后就可以调用user_app_adv_start()开始广播了。这里需要注意要在 user_modules_config.h文件中将EXCLUDE_DLG_MSG配置为0,否则不会调用app_wakeup_cb 函数。

 #define EXCLUDE_DLG_MSG             (0)

到这里这3个函数就介绍完了,接下来就配置如何进入睡眠。

 

void user_app_adv_start(void)
{
    app_adv_data_update_timer_used = app_easy_timer(APP_ADV_DATA_UPDATE_TO, adv_data_update_timer_cb);

    struct gapm_start_advertise_cmd* cmd;
    cmd = app_easy_gap_undirected_advertise_get_active();

    mnf_data_update();
    app_add_ad_struct(cmd, &mnf_data, sizeof(struct mnf_specific_data_ad_structure));

    app_easy_gap_undirected_advertise_start();
}

来到我们的user_app_adv_start()函数可以看到这里创建1个广播定时器app_adv_data_update_timer_used,它的定时时间为APP_ADV_DATA_UPDATE_TO ,我们设置它的值为1000,由于内核定时器的时基为10ms,所以它的定时时间为1000 * 10ms = 10s。

#define APP_ADV_DATA_UPDATE_TO              (1000) 

它的回调函数是adv_data_update_timer_cb,找到该函数原型,可以看到,它是停止广播。因此我们可以清楚的明白广播的工作流程是:开始广播10S后,如果没有连接设备,则停止广播。

static void adv_data_update_timer_cb()
{
    app_easy_gap_advertise_stop();
}

 

停止广播后系统会回调user_app_adv_undirect_complete函数。

void user_app_adv_undirect_complete(uint8_t status)
{
    if (status == GAP_ERR_CANCELED)
    {			
	arch_set_sleep_mode(app_default_sleep_mode);	
        arch_ble_ext_wakeup_on();									
        app_button_enable();													
    }
}

arch_set_sleep_mode(app_default_sleep_mode);        给出需要进入哪种睡眠模式

arch_ble_ext_wakeup_on();                                        使能外部唤醒

app_button_enable();                                                使能按键唤醒

 

好了,到这里整个睡眠相关的就配置完成了,可以运行程序看看效果。

 

注意:

1、如果你没有外接32.768k的晶振,则要配置为内部32.768k的RC,在da1458x_config_advanced.h中更改CFG_LP_CLK的值定义为LP_CLK_RCX20,如果使用外部晶振则定义为LP_CLK_XTAL32。

#define CFG_LP_CLK              LP_CLK_RCX20

2、如果使用外部Flash,则睡眠前要让它进入低功耗模式。

    在periph_init函数中调用3个函数,即最下面3个函数,使Flash进入低功耗模式。

void periph_init(void)
{
    SetBits16(PMU_CTRL_REG, PERIPH_SLEEP, 0);
    while (!(GetWord16(SYS_STAT_REG) & PER_IS_UP));
    SetBits16(CLK_16M_REG, XTAL16_BIAS_SH_ENABLE, 1);
    patch_func();
    set_pad_functions();
    SetBits16(SYS_CTRL_REG, PAD_LATCH_EN, 1);
		
    spi_flash_enable(SPI_EN_GPIO_PORT,  SPI_EN_GPIO_PIN);
    spi_flash_power_down();
    spi_release();				
}
void set_pad_functions(void)       
{
    GPIO_ConfigurePin(SPI_EN_GPIO_PORT,  SPI_EN_GPIO_PIN,  OUTPUT, PID_SPI_EN,  true);
    GPIO_ConfigurePin(SPI_CLK_GPIO_PORT, SPI_CLK_GPIO_PIN, OUTPUT, PID_SPI_CLK, false);
    GPIO_ConfigurePin(SPI_DO_GPIO_PORT,  SPI_DO_GPIO_PIN,  OUTPUT, PID_SPI_DO,  false);
    GPIO_ConfigurePin(SPI_DI_GPIO_PORT,  SPI_DI_GPIO_PIN,  INPUT,  PID_SPI_DI,  false);

    GPIO_ConfigurePin(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN, INPUT_PULLUP, PID_GPIO, false);
}
void GPIO_reservations(void)
{
    RESERVE_GPIO(PUSH_BUTTON, GPIO_BUTTON_PORT, GPIO_BUTTON_PIN, PID_GPIO);
	
    RESERVE_GPIO(SPI_EN,  SPI_EN_GPIO_PORT,  SPI_EN_GPIO_PIN,  PID_SPI_EN);
    RESERVE_GPIO(SPI_CLK, SPI_CLK_GPIO_PORT, SPI_CLK_GPIO_PIN, PID_SPI_CLK);
    RESERVE_GPIO(SPI_DO,  SPI_DO_GPIO_PORT,  SPI_DO_GPIO_PIN,  PID_SPI_DO);
    RESERVE_GPIO(SPI_DI,  SPI_DI_GPIO_PORT,  SPI_DI_GPIO_PIN,  PID_SPI_DI);	

 

由于我的工程在运行时没有用到Falsh,所以我在periph_init中就把它关闭了。如果你的工程需要在工作时使用Flash则可以在进入睡眠前才调用这3个函数即可。

 

 

3、内核定时器唤醒

  在user_app_adv_undirect_complete函数中添加唤醒定时器

void user_app_adv_undirect_complete(uint8_t status)
{	
    // If advertising was canceled then update advertising data and start advertising again
    if (status == GAP_ERR_CANCELED)
    {			
	arch_set_sleep_mode(app_default_sleep_mode);	//给出睡眠模式
        arch_ble_ext_wakeup_on();			//使能外部唤醒
        app_button_enable();                            //配置外部唤醒按键/事件

      app_easy_timer(500, timer_wake_up_cb);         //定时器唤醒500*10=5S

}}

写定时回调函数timer_wake_up_cb

static void timer_wake_up_cb()
{
    app_button_press_cb();	
}

 

 

 

实验目的:DA14580睡眠5秒后自动唤醒。

 

 

 

 

 

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dear_Wally

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值