SYD8801是一款低功耗高性能蓝牙低功耗SOC,集成了高性能2.4GHz射频收发机、32位ARM Cortex-M0处理器、128kB Flash存储器、以及丰富的数字接口。SYD8801片上集成了Balun无需阻抗匹配网络、高效率DCDC降压转换器,适合用于可穿戴、物联网设备等。具体可咨询:http://www.sydtek.com/
SYD8801的低功耗模式分为浅度睡眠和深度睡眠,其中浅度睡眠内存数据依旧能够保持,而深度睡眠下内存会被清空,两者比较如下:
注意:不管是深度睡眠还是浅度睡眠,在配置睡眠之前必须保证作为唤醒源的GPIO管脚对MCU而言是低电平,也就是说如果在睡眠的时候唤醒源GPIO外部状态为高电平,这里就必须要配置上gpio模块输入的反相器,也就是 PIN_CONFIG->PIN_13_POL寄存器,否则芯片不能够正确进入睡眠!
注意:如果调用协议栈lib提供的SystemSleep接口进入浅度睡眠,设置为唤醒源的IO口必须有中断的功能(使能该IO口的中断并且配置正确的回调函数)。
SYD8801深度睡眠低功耗模式
SYD8801的深度睡眠模式下芯片各部份工作情况如下:
主函数判断轮询读取按键0,如果发现按键0被按下,则调用PowerDown进行深度睡眠:
if(get_key()==1){
PowerDown();
}
PowerDown函数具体代码如下:
static void PowerDown()
{
struct gap_wakeup_config pw_cfg;
GPIO_Set_Input(KEY1,KEY1,KEY1); //key1 ·´Ïà
PIN_CONFIG->PIN_13_POL = PIN_INPUT_IVERTED;
if(GPIO_Pin_Read(KEY1)) return;
pw_cfg.wakeup_type = POWERDOWN_WAKEUP;
pw_cfg.timer_wakeup_en = 0;
pw_cfg.gpi_wakeup_en = 1;
pw_cfg.gpi_wakeup_cfg = KEY1;
WakeupConfig(&pw_cfg);
SystemPowerDown();
delay_ms(1);
}
这里配置了唤醒配置结构体 pw_cfg,其中有三个元素。pw_cfg.timer_wakeup_en代表定时器是否能唤醒MCU,为1代表定时器能够唤醒,为0代表定时器不能够唤醒;pw_cfg.gpi_wakeup_en代表GPIO管脚是否能唤醒MCU,为1代表GPIO能够唤醒,为0代表GPIO不能够唤醒,在GPIO能够唤醒的情况下pw_cfg.gpi_wakeup_cfg代表具体哪个GPIO能够唤醒MCU,比如0x00C00000代表gpio22和gpio23能够唤醒。
这里要注意:在SystemPowerDown函数之后调用 delay_ms(1);的微小延时,等待数字电路进入深度睡眠模式,否则深度睡眠很有可能不能够被按键唤醒!
注意:在配置深度睡眠之前必须保证作为唤醒源的GPIO管脚对MCU而言是低电平,也就是说如果在睡眠的时候唤醒源GPIO外部状态为高电平,这里就必须要配置上gpio模块输入的反相器,也就是 PIN_CONFIG->PIN_13_POL寄存器,否则芯片不能够正确进入睡眠!
这里上传本博客使用到的工程代码:
http://download.csdn.net/detail/chengdong1314/9818412
SYD8801浅度睡眠低功耗模式
SYD8801的浅度睡眠模式下芯片各部份工作情况如下:
当程序调用了SystemSleep函数的时候,MCU将进入浅度睡眠模式,所以必须把SystemSleep函数的调用放在合适的位置,建议放在主函数的主循环的最后面:
这里列出一个程序的主函数作为例子:
int main()
{
__disable_irq();
gpio_init();
#ifdef _DEBUG_
dbg_init();
dbg_printf("SYD Inc.\r\n");
#endif
ble_init();
oled_init();
oled_8x16str(0,0,"SYD Inc.");
timer_0_enable(32768, timer0_adv_callback);
StartAdv();
__enable_irq();
timer1s_inting=0;
while(1)
{
ble_sched_execute();
if(timer1s_inting){
timer1s_inting=0;
led_turn(LED0); // ·×ªLED0 ָʾ³ÌÐòÔËÐÐ
cnt_1s++;
if(cnt_1s>=180)
{
cnt_1s=0;
#ifdef USER_32K_CLOCK_RCOSC
LPOCalibration(); //ÕâÊÇÄÚ²¿RC32k¾§ÕñµÄУ׼º¯Êý ¾¹ý¸Ãº¯Êýºó¶¨Ê±Æ÷Äܹ»µÃµ½Ò»¸ö±È½Ï׼ȷµÄÖµ
//timer_calender_handle(); ÄÚ²¿¾§Õñ¼´Ê¹Ð£×¼ÒÀ¾ÉÓÐÒ»¸ö¹Ì¶¨µÄÆ«²î
#else
ClockSwitch(SYSTEM_32K_CLOCK_XOSC);
#endif
}
}
if(get_key()==1){
PowerDown();
}
#ifdef USER_MARCHE_STATE
march_state_process();
#endif
SystemSleep();
}
}
执行了SystemSleep();函数之后MCU就停止了,定时器中断发生或者IO口唤醒源的电平发生变化的时候,MCU从停止的地方开始执行;如果是定时器中断唤醒了MCU,那么MCU醒来的第一步就是执行定时器中断服务函数,如果IO口唤醒源配置成中断模式并且MCU由IO口唤醒,那么MCU醒来的第一步就会去执行外部中断服务函数!
如果蓝牙处于连接状态,那么不用做任何配置,当底层硬件发现蓝牙的状态发生改变的的时候(比如发生了断线或者和主机之间发生了数据通信)MCU也会被蓝牙硬件唤醒,进入蓝牙的中断!
注意:当发生了唤醒事件的时候,只有再次调用SystemSleep();函数之后MCU才会再次休眠!
浅度睡眠配置在ble_init函数中,其源代码如下:
static void ble_init()
{
struct gap_evt_callback evt;
struct smp_pairing_req sec_params;
struct gap_wakeup_config pw_cfg;
struct gap_ble_addr ble_addr;
BleInit();
MCUClockSwitch(SYSTEM_CLOCK_8M_RCOSC);
#ifdef USER_32K_CLOCK_RCOSC
ClockSwitch(SYSTEM_32K_CLOCK_RCOSC);
LPOCalibration();
#else
ClockSwitch(SYSTEM_32K_CLOCK_XOSC);
#endif
GetGATTReportHandle(&g_report);
/* security parameters */
sec_params.io = IO_NO_INPUT_OUTPUT;
sec_params.oob = OOB_AUTH_NOT_PRESENT;
sec_params.flags = AUTHREQ_BONDING;
sec_params.mitm = 0;
sec_params.max_enc_sz = 16;
sec_params.init_key = 0;
sec_params.rsp_key = (SMP_KEY_MASTER_IDEN |SMP_KEY_ADDR_INFO);
SetSecParams(&sec_params);
evt.evt_mask=(GAP_EVT_CONNECTION_SLEEP|GAP_EVT_CONNECTION_INTERVAL);
evt.p_callback=&ble_evt_callback;
SetEvtCallback(&evt);
/* Bond Manager (MAX:10) */
SetBondManagerIndex(0x00);
setup_adv_data();
pw_cfg.wakeup_type = SLEEP_WAKEUP;
pw_cfg.timer_wakeup_en = 1;
pw_cfg.gpi_wakeup_en = 0;
pw_cfg.gpi_wakeup_cfg = 0x00C00000;
WakeupConfig(&pw_cfg);
}
其中配置了唤醒配置结构体 pw_cfg,其中有三个元素。pw_cfg.timer_wakeup_en代表定时器是否能唤醒MCU,为1代表定时器能够唤醒,为0代表定时器不能够唤醒;pw_cfg.gpi_wakeup_en代表GPIO管脚是否能唤醒MCU,为1代表GPIO能够唤醒,为0代表GPIO不能够唤醒,在GPIO能够唤醒的情况下pw_cfg.gpi_wakeup_cfg代表具体哪个GPIO能够唤醒MCU,比如0x00C00000代表gpio22和gpio23能够唤醒。
注意:在配置浅度睡眠之前必须保证作为唤醒源的GPIO管脚对MCU而言是低电平,也就是说如果在睡眠的时候唤醒源GPIO外部状态为高电平,这里就必须要配置上gpio模块输入的反相器,也就是 PIN_CONFIG->PIN_13_POL寄存器,否则芯片不能够正确进入睡眠!
这里上传上本节的代码:http://download.csdn.net/detail/chengdong1314/9865161
内部上拉电阻对功耗造成的影响
SYD8801每个IO口都可以配置成上拉输入,通过PIN_CONFIG->GPIO_PULL_UP寄存器打开或关闭芯片IO口内部的上拉电阻,因为上拉电阻的一端连接VDDIO,一端连接外部输入管脚,一般情况下把VDDIO连接到芯片的供电端,也就是3.3V电源供电口。
如果外部管脚为高电平,外部管脚电压等于VDDIO,所以上拉电阻没有电流流过,也就没有了电流损耗。
如果外部管脚为低电平,电流就会通过VDDIO流经上拉电阻R到管脚地,这样不可避免的产生漏电电流造成功耗增大,因为SYD8801内部上拉为80K欧姆,所以将有41.25ua的电流流过上拉电阻,也就是说这个IO口将增加41.25UA的功耗。
在追求功耗的时候,为了避免上面这个IO口的41.25UA的功耗,必须去掉芯片内部的IO口上拉电阻!因为在追求功耗的时候,整体芯片的电流都没有这个上拉电阻大!SYD8801手环整机电流才是22UA左右!
另外对于配置成输入的IO口而言,管脚电平必须是一个明确的状态,也就是说当某个管脚配置成输入模式,那么这个管脚要么是高电平,要么是低电平,不能是除此之外的电压值,否则会造成漏电,并且这个IO口也是极其不稳定的。如果外部连接的是按键,在未按下按键的时候很有可能管脚状态就是悬空状态。所以这时候就必须要使能内部上拉电阻,让悬空状态变成高电平状态!
但是如果使能了上拉电阻,那么上面说到的IO口上拉电阻造成的41.25UA的电流就不可避免了!
如果在必须要用上拉电阻但是又要追求功耗,那么建议关闭内部上拉电阻,在外部电路做一个1M以上的上拉电阻,能把功耗减小到3.3UA。但是这样的电路在干扰强的情况下很有可能受到干扰,所以请开发者综合考虑!
进入睡眠模式后要等待硬件进入睡眠
void SystemSleepSYD(enum WAKEUP_TYPE wakeup ,uint8_t timer_wakeup_en,uint8_t gpio_wakeup_en,uint32_t io)
{
PW_CTRL->WAKE_PIN_EN |= io ;
PW_CTRL->TMR_WAKE_EN = timer_wakeup_en;
PW_CTRL->PIN_WAKE_EN = gpio_wakeup_en;
PW_CTRL->DSLP_WAKE_EN = wakeup;
if(wakeup==SLEEP_WAKEUP)
{
PW_CTRL->MCU_SLEEP=1; //执行这句话后马上进入浅睡眠模式,任何东西都不会丢失
}
else
{
led_close(LEDALL);
PW_CTRL->DSLP_SYS = 1; // 执行这句话后马上进入深度睡眠模式,唤醒将会进入复位状态,任何东西都将会丢失
while(1);
}
}
上面的代码在else分支中“led_close(LEDALL);”语句必须要在“PW_CTRL->DSLP_SYS = 1;”语句之前,因为“PW_CTRL->DSLP_SYS = 1;”之后软件虽然向硬件发送了进入深度低功耗的请求,但是硬件并没有马上能够进入深度睡眠,会顺延执行下面几条命令后硬件才能够反应过来。如果“led_close(LEDALL);”语句必须要在“PW_CTRL->DSLP_SYS = 1;”语句之后,那么在软件配置了深度睡眠之后又重新给gpio赋值,这就相当于唤醒了MCU,造成进入深度睡眠之后MCU马上又被唤醒复位了,也就是深度睡眠的现象变成了复位的现象!
当然这里也可以把“led_close(LEDALL);”语句放在“PW_CTRL->DSLP_SYS = 1;”语句之后,但是这两个语句之间必须要加上100us以上的延时,但是这时候“led_close(LEDALL);”语句永远也得不到运行了!
上面函数可做如下调用:
PIN_CONFIG->PIN_8_POL = PIN_INPUT_IVERTED;
SystemSleepSYD(POWERDOWN_WAKEUP, 0, 1, BIT8);
注意:软件要等待硬件的现象在其他系统行为中也有可能存在,必须说调用复位命令让MCU复位的时候在调用命令之后也必须等待硬件相应!复位行为请看:SYD8801代码解析二【复位等特殊系统行为要等待硬件响应】:http://blog.csdn.net/chengdong1314/article/details/73929998
低功耗测试步骤:
低功耗的测试步骤分为三步:分别烧录4K_setting、service、hex三个文件,其中4K_setting由原厂提供,只有这样才能够得到正确的低功耗!
下面简单的列出了烧录步骤,更加详细的步骤请看:http://blog.csdn.net/chengdong1314/article/details/70161095
对于批量生产的时候有专门的批量烧录工具,请看:http://blog.csdn.net/chengdong1314/article/details/68489039
1. 电脑连接上开发板的串口,打开串口,并且按下复位键,这时候PC上的工具界面如下:
2、在“setting”选项中选择官方提供的4k固件(已改在得到的工程文件中都有,以4K开头的bin文件),选择结束之后这个工具自动把固件下载到芯片中:
2. 烧写配置ROM代码的服务配置文件(随软件一起提供的TXT文件),比如《Vendor_Service_GATT_DB_160804.txt》,如下:
3. 最后烧写工程代码生成的hex文件,比如《Ble_Vendor_Service.hex》:
对于SYD8801开发板:
芯片消耗的电流是VBAT,而IO口的漏电是VDDIO,这两者加起来是SYD8801消耗的总电流,这两个电流在开发板上的J7上可以测试,原理图如下:
这里可以把J7的2和4管脚短路,这时候从3.3V电源留到J7的2和4的电流总和就是要测试的芯片电流,连线示意图如下: