[nrf51][nrf52][SDK17] NRF系列怎么实现低功耗运行,带freertos能进入吗?
一、NRF51/NRF52系统低功耗表
(浅睡)
型号 | 电流 |
---|---|
nrf51822/nrf51422 | 2.2uA-3uA |
nRF52832 | 1.9uA-2uA |
nRF52840 | 1.5uA-1.6uA |
其他 | 2uA左右 |
(深睡,唤醒就复位重启)
型号 | 电流 |
---|---|
nrf51822/nrf51422 | <1uA |
nRF52832 | 300nA |
nRF52840 | 400nA |
其他 | <1uA |
二、实测产品没有达到低功耗怎么办?
- 测量有100uA,这个时候需要检查[调试器]是否断开,需要掉电一次,再测量。
- 测量有几百uA,这一定是外设没有关闭。如下列表:
外设 | 电流 |
---|---|
UART/UARTE | 55uA |
高频时钟电路 | 250uA |
easyDMA(52810强制打开) | 2mA |
Timer0/1/2/3/4 | 70uA(建议裸机用app_timer,os用软定时器) |
FPU | >7mA |
GPIOTE | 1.3mA(IN_EVENT) / <5uA(Port event) |
SPI/TWI | mA级别 |
SAADC | mA级别 |
J-Link模式 | 100uA |
引用官方手册:
System ON模式,就是CPU可以不工作而外设可以继续工作的一种低功耗模式。
idle模式下,当CPU和所有外设都不工作时,系统电流也就有2uA左右。
(注:除了idle模式,nRF5芯片还支持一种更低功耗的低功耗模式:sleep模式(Nordic芯片手册称为System OFF模式),sleep模式下,CPU和所有外设都强制关闭,所以功耗非常低:只有零点几微安。由于sleep模式下,芯片无法发出广播包或者与手机保持蓝牙连接,所以sleep模式在BLE应用中运用得并不是很多)。
Idle模式可以被任何中断唤醒(sleep模式只能被IO口唤醒),所以idle模式在实际应用中使用得比较多。
在idle模式下,芯片仍然可以正常发出广播或者与手机保持蓝牙连接,所以大部分BLE应用都是工作在idle模式下,这样既保持了BLE功能又可以实现低功耗。
三、如何进入低功耗?
1. 软件部分优化
1.1 广播优化
1.1.1 发射功率
设置发射功率具有 9 个发射等级。系统默认的发射功率是 0dbm,发射功率越大,发射距离就越远,相应的电流消耗就越大。
在0dBm时,打开DC/DC, nRF52832发射电流5.3mA。将TX功率增加到+4dBm只增加2.2mA。减少到- 40dbm只节省2.6mA。
1.1.2 广播间隔
就是广播包发出的频率,广播间隔越长,功耗越低。
1.1.3 广播负载
蓝牙的广播包普通包长度在 31 字节,扫描响应包也有 31 字节。如果蓝牙 5.0 下的第二广播包长度更长,越长的广播负载,会造成越大的电流消耗。
1.2 连接状态优化
1.2.1 连接间隔和从机潜伏周期
连接间隔是保证主从机维持连接,相互发空包的时间间隔。连接间隔可以在 GAP 初始化中进行设置。当设置的连接间隔越长,设备的功耗越低。因此,可以在维持连接状态下,保证数据正常通信的基础下,设置尽可能长的连接间隔。
从机潜伏周期和连接间隔是同时进行配置的,从机潜伏周期允许蓝牙设备一定次数的周期不对蓝牙主机数据进行回复。在这个周期次数范围内,蓝牙主机即使没有收到蓝牙从机设备的回复确认信息包,也会认为设备正常。这种方式也可以降低蓝牙设备的功耗。
连接间隔是保证主从机维持连接,相互发空包的时间间隔。连接间隔可以在 GAP 初始化中进行设置。当设置的连接间隔越长,设备的功耗越低。因此,可以在维持连接状态下,保证数据正常通信的基础下,设置尽可能长的连接间隔。
从机潜伏周期和连接间隔是同时进行配置的,从机潜伏周期允许蓝牙设备一定次数的周期不对蓝牙主机数据进行回复。在这个周期次数范围内,蓝牙主机即使没有收到蓝牙从机设备的回复确认信息包,也会认为设备正常。这种方式也可以降低蓝牙设备的功耗。
确认理论功耗值。BLE功耗跟广播间隔或者连接间隔是成正比关系的,所以20ms连接间隔下的功耗几乎是1s状态下的50倍!,单纯地问“1mA功耗高不高?”是没有意义的,必须结合特定的应用场景才有意义。
不管是广播还是连接,特定的使用场景会有一个理论功耗值,NRF功耗网址,以获得你的使用场景下理论功耗多少,比如连接模式下,每1秒钟发20个字节的数据包,这种模式下理论功耗为:7.6uA
1.2.2 发射和接收的数据量
蓝牙数据发送和接收的数据量大小,直观的影响到了功耗。数据吞吐量越大,功耗越高。
1.3 系统及外设功耗优化
1.3.1 协议栈时钟选择
协议栈时钟可以选择外部低速时钟和内部低速时钟。选取外部低速时钟具有更低的功耗,使能外部 32kHz 晶振,通常可以节省 1-2% 的电能。默认使用外部低速晶振。在 main.c 文件,ble_stack_init() 函数中 nrf_sdh_enable_request() 找到
nrf_clock_lf_cfg_t const clock_lf_cfg ={.source = NRF_SDH_CLOCK_LF_SRC, // <0=> NRF_CLOCK_LF_SRC_RC // 内部时钟源// <1=> NRF_CLOCK_LF_SRC_XTAL // 外部晶振源// <2=> NRF_CLOCK_LF_SRC_SYNTH // 合成时钟源.rc_ctiv = NRF_SDH_CLOCK_LF_RC_CTIV,.rc_temp_ctiv = NRF_SDH_CLOCK_LF_RC_TEMP_CTIV,.accuracy = NRF_SDH_CLOCK_LF_ACCURACY};
sdk_config.h
#ifndef NRF_SDH_CLOCK_LF_SRC
#define NRF_SDH_CLOCK_LF_SRC 1
#endif
[nrf51][nrf52][S130][SDK12.3] 修改协议栈时钟
1.3.2 关闭日志打印
裸机情况下,除非jlink调试器已连接,否则 RTT 不会使用电流。
os(freertos)情况:
- 单独开一个线程刷log,功能大约在2.2uA和40uA跳动。
- 将log放在空闲线程中刷新,功耗大约在11uA。
- 空闲线程每1000个滴答,刷新一次,功耗大约在3uA。(失去实时性)
void sys_sleep(void)
{#ifdef SOFTDEVICE_PRESENT
#if NRF51sd_app_evt_wait();
#elsenrf_pwr_mgmt_run();
#endif
#else// Wait for an event.__WFE();// Clear the internal event register.__SEV();__WFE();
#endif
}/*** @brief 线程空闲处理函数*/
void idle_state_handle(void)
{static uint16_t tick = 0;tick ++;if (get_ble_conn_state()){ble_data_send_dispose();tick = 0;}if (get_ble_is_bus()){return;}if (tick > 1000){// 刷新RTT LOG缓存区if (NRF_LOG_PROCESS() == false){sys_sleep();}}
}/*** @brief [弱函数] 线程空闲* @param *argument: NULL*/
void vApplicationIdleHook(void)
{idle_state_handle();
}
1.3.3 动态使用UART
首先 UART 模块本身只需要 55uA 的工作电流,同时会自动打开高频时钟电路,也需要消耗 250uA 左右电流。如果使能了 UARTE 的 EasyDMA,那么 DMA 还需要消耗额外的 2mA 电流。这样 UARTE 工作消耗的电流会很高。因此在 UART 没有数据传输的时候建议将 UART 关掉,以节省功耗。
注:为了达到低功耗和实时性双重目的,在设计 UART 通信的时候,我们经常会额外再加 2 个 GPIO 口用来通知对方 UART要传送数据了。
关闭 UART 的 API 为:nrf_drv_uart_uninit() 或者 app_uart_close()。
如果只是单向发送,无需接收,可以采用队列的形式,当队列空闲1000滴答,则关闭串口。队列不为空,则初始化串口,开始发送。
[单片机框架] [queue] 实现一个简易的消息队列
void idle_state_handle(void)
{static uint16_t tick = 0;tick ++;if (get_ble_conn_state()){ble_data_send_dispose();tick = 0;}if (get_ble_is_bus()){return;}if (queue_de(&m_urat_send_q, g_uart_send_data)){tick = 0;bsp_uart_init(BSP_UART_0);bsp_uart_send_nbyte(BSP_UART_0, g_uart_send_data);return;}if (tick > 1000){bsp_uart_deinit(BSP_UART_0); // 内置标志位,不会每次都操作关闭// 刷新RTT LOG缓存区if (NRF_LOG_PROCESS() == false){sys_sleep();}}
}
1.3.4 动态使用SPI/TWI
在不使用的时候建议采用 uninit 函数进行关闭,这部分的外设也消耗电流。需要使用的时候进行 init 初始化开启。
SPI 开启和关闭:nrf_drv_spi_init 和 nrf_drv_spi_uninit
TWI 开启和关闭:nrf_drv_twi_enable 和 nrf_drv_twi_disable
1.3.5 动态使用SAADC
在不使用的时候建议采用 uninit 函数进行关闭,需要使用的时候进行 init 初始化开启。
ADC 开启和关闭:nrfx_saadc_init 和 nrfx_saadc_uninit
如果你发现 uninit ADC 后,功耗还是很高,建议打开这个宏 NRFX_SAADC_CONFIG_LP_MODE,再试一下,功耗有可能就降下来了。
官方SAADC低功耗例子
1.3.5 建议使用GPIOE低精度模式
GPIOE 事件模式下具有两钟模式:高精度模式(hi_accuracy 为 true)和低精度模式(hi_accuracy 为 false)。高精度模式 IN event 中断比低精度模式 Port event 中断消耗更多的电流 10~20uA。如果只是检测 IO 口电平,建议使用低精度模式,也就是所有的输入信号都使用一个中断申请,库函数调用配置:
GPIOTE_CONFIG_IN_SENSE_HITOLO(false);
1.3.5 Timer–>不建议使用硬件定时器
Timer0/1/2/3/4。Timer 的工作电流大概为 5~50uA 左右(nRF51功耗会更高),对低功耗应用来说,已经非常大了。如果你的定时精度要求不高,而且是毫秒的倍数,那么强烈建议你使用 RTC 来实现定时功能。协议栈下为 app_timer 软件定时器,app_timer 的功耗只有 0.2uA 左右。
1.3.6 FPU
由于 nRF52x 系列处理器不同于 nRF51 系列,其内核为 ARM Cortex M4 处理器。ARM Cortex M4 处理器 带 FPU 浮点运算单元。每当程序要执行浮点运算的时候,内核就会自动把 FPU 打开i。FPU 将消耗 7mA 以上的电流,此种情况下,进入 idle 模式之前必须手动关闭 FPU,手动关闭 FPU 代码如下所示:
/* Clear FPSCR register and clear pending FPU interrupts. This code is base on* nRF5x_release_notes.txt in documentation folder. It is necessary part of code when* application using power saving mode and after handling FPU errors in polling mode.*/__set_FPSCR(__get_FPSCR() & ~(FPU_EXCEPTION_MASK));(void) __get_FPSCR();NVIC_ClearPendingIRQ(FPU_IRQn);
在新版本 SDK17 中已经默认添加了
x\nRF5_SDK_17.0.2_d674dde\components\libraries\pwr_mgmt\nrf_pwr_mgmt.c
函数:nrf_pwr_mgmt_run()
1.3.7 nrf_pwr_mgmt_run()函数解析
打开 nrf_pwr_mgmt_run() 函数,BLE 状态下,如果 CPU 处于空闲状态就会进入 sd_app_evt_wait() 函数,这个函数是进入低功耗的关键,是协议栈提供的一个等待事件函数。
void nrf_pwr_mgmt_run(void)
{PWR_MGMT_FPU_SLEEP_PREPARE(); // 清除FDU异常,避免FDU中断被挂起PWR_MGMT_SLEEP_LOCK_ACQUIRE(); // 锁定临界区PWR_MGMT_CPU_USAGE_MONITOR_SECTION_ENTER(); // 用户监视段进入,监听进入低功耗的时间PWR_MGMT_DEBUG_PIN_SET(); // 置位仿真引脚// Wait for an event.
#ifdef SOFTDEVICE_PRESENT // 带协议栈状态下if (nrf_sdh_is_enabled()) // 如果协议栈被使能{ret_code_t ret_code = sd_app_evt_wait(); //调用协议栈等待函数ASSERT((ret_code == NRF_SUCCESS) || (ret_code == NRF_ERROR_SOFTDEVICE_NOT_ENABLED));UNUSED_VARIABLE(ret_code);}else
#endif // SOFTDEVICE_PRESENT // 否则,不带协议栈状态{// Wait for an event.__WFE();// Clear the internal event register.__SEV();__WFE();}PWR_MGMT_DEBUG_PIN_CLEAR(); // 清除仿真引脚PWR_MGMT_CPU_USAGE_MONITOR_SECTION_EXIT(); // 用户监视段退出PWR_MGMT_SLEEP_LOCK_RELEASE(); // 锁定临界区释放
}
1.4 软件进入低功耗需要调用的函数
static void idle_state_handle(void)
{if(NRF_LOG_PROCESS() == false) // 如果调试缓冲区没有更多日志{nrf_pwr_mgmt_run();}
}
int main(void)
{······for(;;){idle_state_handle();}
}
2. 硬件部分优化
不同的内部稳压器选择,会造成不同的电路消耗。可以通过选择不同的硬件电路配置,来选取下面两种内部稳压器:
- 内部 LDO 稳压器
- 内部 DC/DC 稳压器
LDO 是系统默认的稳压器,而 DC/DC 稳压器可用作 LDO 稳压器的替代产品。与使用 LDO 稳压器相比,使用 DC/DC 稳压器具有更低的电流消耗,但 DC/DC 稳压器需要连接外部 LC 滤波器:
其中关于 DC/DC 稳压器所连接的 外部 LC 滤波器电路上的电感和电容参数,请参看芯片手册 53 节 Reference circuitry 所提供的参考电路。
由于默认选择的是内部 LDO 稳压器,因此如果需要切换到使用内部 DC/DC 稳压器,还需要在软件上进行配置。
首先需要在主函数 main.c 中,初始化 softDevice 协议栈前,执行 NRF_POWER->DCDCEN=1。
或者在初始化softDevice 协议栈后,执行 sd_power_dcdc_mode_set(1)。
sdk_config.h 配置文件中勾选 NRFX_POWER_ENABLED 使能选项,同时把选项下的 DC/DC 使能选项 NRFX_POWER_CONFIG_DEFAULT_DCDCEN 进行勾选。
在选取电源电压为 3.0 V ,广播间隔为 500ms,发射功率为 0dbm 的情况下,选择 DC/DC 稳压方式的总平均功耗电流为 20uA,而选择 LDO 稳压方式的总平均电流在 32uA 左右。因此,选择 DC/DC 稳压方式可以大幅度的降低功耗。
电池寿命预估
已知设备的平均电流消耗和电池的容量,计算电池寿命。以下是不同能量容量电池的电池寿命计算实例:
例1:
设备的平均电流消耗 :20uA
电池容量:220mAh (标准CR2032纽扣电池 )
电池寿命:0.22Ah/0.00002A=11000hours=458days
例2:
设备的平均电流消耗 :100uA
电池容量:220mAh (标准CR2032纽扣电池 )
电池寿命:0.22Ah/0.0001A=2200hours=91days
例3:
设备的平均电流消耗 :100uA
电池容量:1000mAh (标准CR2477纽扣电池 )
电池寿命:1Ah/0.0001A=10000hours=417days
[nrf51][nrf52][SDK17] NRF系列怎么实现低功耗运行,带freertos能进入吗?相关推荐
- STM32CubeMX | STM32 F1系列HAL库低功耗STOP和STANDBY模式唤醒(RTC时钟唤醒+外部中断唤醒示例)
STM32CubeMX | STM32 F1系列HAL库低功耗STOP和STANDBY模式唤醒(RTC时钟唤醒+外部中断唤醒示例) 目录 STM32CubeMX | STM32 F1系列HAL库低功耗 ...
- Stm8L系列单片机的低功耗
Stm8L系列单片机的低功耗有五种模式: wait模式 Low power run模式 Low power wait模式 Active-halt with full RTC模式 Halt模式 最低功耗 ...
- STM32L4系列单片机的低功耗问题
基于STM32L4系列单片机的低功耗问题 首先看ST关于L4系列的官方文档官方给出了多个低功耗模式并且介绍了这几种模式 Sleep mode:CUP时钟关闭,IO口保持与运行状态相同的状态.可由wak ...
- 【定时同步系列10】16QAM基带调制+Gardener定时误差检测+解调误码率曲线之MATLAB仿真
引言 重要声明:为防止爬虫和盗版贩卖,文章中的核心代码和数据集可凭[CSDN订阅截图或公z号付费截图]私信免费领取,一律不认其他渠道付费截图! 在前面的博客中 [定时同步系列8]QPSK基带调制+Ga ...
- Cortex-M系列MCU最大亮点是低功耗
2010年9月5日上午,由中嵌协会主办,亚嵌承办的中嵌协会第二期"嵌入式与物联网"主题论坛之Cortex行业应用与芯片选型为内容的沙龙在中关村举行,有来自美国风河(WindRive ...
- [nrf51][nrf52] nrfconnect 安装说明指南
最新nrfconnect-setup-3.10.0 官方下载 根据流程安装完毕后,找到C:\Users\USER.nrfconnect-apps路径.(USER是自己的用户名) 替换apps.json ...
- [nrf52][SDK17] 如何修改BLE_MAC地址?
关键部分: ble_gap_addr_t ble_mac_addr = {0};sd_ble_gap_addr_get(&ble_mac_addr); // 先获取ble 当前mac地址ble ...
- RK3399平台开发系列讲解(低功耗篇)11.1、wakeup events framework
文章目录 1.SYSFS接口 2.Device power 2.1.device 中的dev_pm_info结构体 2.2.一个设备power目录下的有哪些相关文件 2.3.设备 wakeup att ...
- [nrf51][nrf52][三方通讯] PC/手机 MCU BLE 通讯模板 仅供参考
文章目录 一.简介 二.协议格式 三.概念 四.示例代码 五.头文件 一.简介 根据串行通信原理设计搭建了三方之间交互通信环境,通过协议相互收发数据,模块实现情况. 该设计实现三方交互通信方式,数据传 ...
最新文章
- 甘利俊一 | 信息几何法:理解深度神经网络学习机制的重要工具
- java.util.concurrent.Future基础
- [Leedcode][JAVA][第990题][等式方程的可满足性][并查集]
- centos中bash占用cpu,Linux中显示内存和CPU使用率最高的进程和SHELL脚本例子
- Oracle数据库时间修改
- R语言实现混频数据分析
- redis学习篇(九)-----高级特性之事务处理
- Kubernetes集群如何重启
- Proteus、Keli对C51芯片实现仿真流水灯
- 计算机网络(谢希仁版)知识点汇总
- 如何屏蔽搜狗浏览器中的广告 搜狗浏览器拦截广告的教程
- 谷歌浏览器插件 - 为 Microsoft Bing 搜索引擎首页添加一个【保存背景图片】的按钮(版本 1)
- 安卓ROOT工具汇总
- 学生党如何拿到阿里技术offer
- 【操作系统习题】假定某多道程序设计系统供用户使用的主存空间为100 KB ,磁带机2台,打印机1台
- 服务器部署MySQL过程
- 手机如何借用笔记本网络上网
- win7 docker的受难记——exit status 255的终极解决
- 【leetcode 简单】 第一百五十题 两个列表的最小索引总和
- 扩散模型与生成模型详解
热门文章
- 给初中级JAVA准备的面试题,致竞争激烈的秋招面试(自己总结)
- Python程序设计与科学计算精录总结Episode.3 Python高级语法:文件、异常、标准库和问题解决模式知识总结(基于Michael导师Python课程与VS2019)
- go viper:init sonyflake failed,err:parsing time ““ as “2006-01-02“: cannot parse ““ as “2006“
- Web 1.0、Web 2.0 和 Web 3.0 之间的比较
- Win11老是提示资源管理器已停止工作怎么解决
- TIMESTAMPDIFF与DATEDIFF
- DATEDIFF和TIMESTAMPDIFF区别
- kafka常见问题(持续更新)
- java世界神奇“+”的学习
- python django vue +VSCode 前后端分离