目錄
概述
1.? 軟硬件環境
1.1 軟件開發環境
1.2 硬件環境?
2 System Off 模式
2.1 模式介紹
2.2?注意事項
3 功能實現
3.1 框架結構介紹
3.2 代碼介紹
4 功能驗證
4.1 編譯和下載代碼
4.2 測試
4.3 使能CONFIG_APP_USE_RETAINED_MEM的測試
5 main.c的源代碼文件
參考文獻
概述
System Off 模式是 Nordic nRF 系列芯片最省電的工作模式,在 nRF Connect SDK 中通過 Zephyr RTOS 的電源管理框架提供完善支持。本文通過一個demo介紹system off功能的用法及其相關函數的功能。
1.? 軟硬件環境
1.1 軟件開發環境
nordic提供了基于zephyr平臺sdk, 其提供了大量的demo可供開發者參考和使用,同時nordi還提供一個集成的軟件庫工具,方便開發者安裝相應的SDK和編譯工具鏈。集成環境同時包含了其他的一些軟件,非常便于進行項目開發。
軟件工具 | 功能 | 版本信息 |
nRF Connect SDK? | nordic提供基于zephyr的代碼庫 | v2.9.0? |
nRF Connect SDK Toolchain | 代碼編譯工具 | v2.9.1 |
VS-CODE | 集成開發環境 | v1.99.3? |
nRF Connect for Desktop | nordic集成工具鏈 | v5.1.0 |
nRF Connect | 手機App |
手機App下載地址:
https://nav.nordicsemi.com/search?query=nRF%20Connect
搭建編譯環境的注意點
安裝工具時,在D:\ncs\v2.9.0目錄下執行如下語句,安裝與編譯器相關的工具鏈
pip3 install --user -r scripts/requirements.txt
運行該語句后,安裝信息如下:
1.2 硬件環境?
本案例是在nRF52832開發板(nRF52-DK)上實現的,該開發板nRF52832的主要特點如下:
1)板載j-link調試接口
2)引出所有 IO接口,用戶可根據實際應用,外載其他設備
3)支持4個LED
4)支持4路Key接口
5)板載UART調試接口,方便打印調試信息
2 System Off 模式
2.1 模式介紹
System Off 是 Nordic nRF 系列芯片的一種深度節能模式,在 nRF Connect SDK (基于 Zephyr RTOS) 中有完整的支持。這種模式可以最大限度地降低功耗,適用于電池供電設備。
System Off 模式特性
超低功耗:僅保持 RAM 保持電源 (約 0.7μA @ 3V)
喚醒源:特定 GPIO、LPCOMP、NFC、RTC 等。注意: nRF52832不支持RTC喚醒模式
數據保留:可選擇保留部分或全部 RAM 內容
系統狀態:CPU 和外設完全停止
1)電源特性
-
功耗表現:0.7μA @ 3V (RAM 保持)
-
電壓范圍:1.7V - 3.6V
-
喚醒時間:~100μs 從 OFF 到 RUN
2) 狀態對比
模式 | 電流消耗 | 喚醒源 | RAM保持 | 執行恢復 |
---|---|---|---|---|
RUN | ~4mA | 任意 | 保持 | 繼續執行 |
IDLE | ~1.5mA | 任意 | 保持 | 繼續執行 |
System Off | ~0.7μA | 有限 | 可選 | 復位重啟 |
2.2?注意事項
調試限制:在 System Off 模式下,調試器連接會斷開
外設狀態:進入 System Off 前應正確關閉所有外設
電流測量:使用高精度電流表測量實際功耗
喚醒延遲:從 System Off 喚醒會有約 100μs 的啟動延遲
GPIO 狀態:配置為喚醒源的 GPIO 必須保持有效電平
3 功能實現
3.1 框架結構介紹
軟件使用VS-CODE開發工具搭建,底層使用zephry平臺,其實現功能主要如下:
1)系統上電運行一段時間后,通過調用system off進入到低功耗模式
2)使用按button-1觸發系統重新運行
3)retained組件管理進入睡眠后的參數
3.2 代碼介紹
?1)prj.conf
代碼第1行: 使能PM管理模式
代碼第2行:使能IO工具庫
代碼第3行:使能CRC工具庫
代碼第4行:使能POWEROFF工具庫
2)main.c文件
代碼12~17行: 引入zephyr提供的代碼庫
代碼23行: 使用按鍵,其用于喚醒MCU
代碼第29行:獲取控制云臺串口端口信息
代碼第31行:check device初始化是否完成?
代碼第63行: 配置和按鍵相連的端口為輸入口?
代碼第69行:配置該端口為輸入中斷模式
代碼第78行:? 掛起控制臺設備
注釋:
pm_device_action_run
?的功能介紹
pm_device_action_run
?是 Zephyr RTOS (以及基于它的 nRF Connect SDK) 中電源管理子系統的一個重要函數,用于對設備執行特定的電源管理操作。1)函數原型
int pm_device_action_run(const struct device *dev, enum pm_device_action action);
2)參數說明
dev
: 指向目標設備的指針,可使用?DEVICE_DT_GET
?宏獲取
action
: 要執行的電源管理操作,有以下幾種可能值:
PM_DEVICE_ACTION_SUSPEND
: 掛起設備
PM_DEVICE_ACTION_RESUME
: 恢復設備
PM_DEVICE_ACTION_TURN_ON
: 打開設備
PM_DEVICE_ACTION_TURN_OFF
: 關閉設備
PM_DEVICE_ACTION_LOW_POWER
: 進入低功耗模式
PM_DEVICE_ACTION_FORCE_SUSPEND
: 強制掛起3)返回值
0: 操作成功
負數: 錯誤代碼 (如 -ENOTSUP 表示設備不支持該操作)
4)??函數的用法
- 1) 基本用法
const struct device *sensor_dev = DEVICE_DT_GET(DT_NODELABEL(bme280));// 關閉傳感器 pm_device_action_run(sensor_dev, PM_DEVICE_ACTION_TURN_OFF);// 需要時重新打開 pm_device_action_run(sensor_dev, PM_DEVICE_ACTION_TURN_ON);
- 2)批量管理多個設備
const struct device *devices[] = {DEVICE_DT_GET(DT_NODELABEL(uart0)),DEVICE_DT_GET(DT_NODELABEL(i2c0)),DEVICE_DT_GET(DT_NODELABEL(spi1)), };void suspend_all_devices(void) {for (int i = 0; i < ARRAY_SIZE(devices); i++) {pm_device_action_run(devices[i], PM_DEVICE_ACTION_SUSPEND);} }
- 3)?與電源狀態結合使用
#include <pm/pm.h>void enter_low_power_mode(void) {// 首先掛起所有設備suspend_all_devices();// 然后進入系統低功耗狀態pm_power_state_force(0, (struct pm_state_info){.state = PM_STATE_SUSPEND_TO_RAM,.substate_id = 0,.info = PM_STATE_INFO_DT_ITEMS_LIST(DT_NODELABEL(power_states))}); }
- 4)?傳感器周期性采樣
void sample_sensor_periodically(void) {const struct device *sensor = DEVICE_DT_GET(DT_NODELABEL(bme280));while (1) {// 喚醒傳感器pm_device_action_run(sensor, PM_DEVICE_ACTION_TURN_ON);k_msleep(10); // 等待穩定// 采樣sensor_sample_fetch(sensor);// 完成后再關閉pm_device_action_run(sensor, PM_DEVICE_ACTION_TURN_OFF);k_sleep(K_MINUTES(5)); // 5分鐘后再采樣} }
- 5)?電池供電設備
void manage_battery_life(void) {const struct device *display = DEVICE_DT_GET(DT_NODELABEL(ssd1306));// 用戶不活動時if (inactive_time > INACTIVITY_THRESHOLD) {// 關閉顯示屏pm_device_action_run(display, PM_DEVICE_ACTION_TURN_OFF);// 掛起非必要外設pm_device_action_run(DEVICE_DT_GET(DT_NODELABEL(i2c1)), PM_DEVICE_ACTION_SUSPEND);} }
4 功能驗證
4.1 編譯和下載代碼
編譯配置項如下:
編譯結果如下:
?下載代碼至板卡中:
4.2 測試
下載代碼到板卡中之后,可以看見如下log:
?提示信息顯示,按鍵sw0可以重新喚醒MCU,按鍵swo后,
4.3 使能CONFIG_APP_USE_RETAINED_MEM的測試
1)編譯后重新下載代碼至板卡,運行結果如下:
2)按下SW0后的log
5 main.c的源代碼文件
/** Copyright (c) 2019 Nordic Semiconductor ASA** SPDX-License-Identifier: Apache-2.0*/#include "retained.h"#include <inttypes.h>
#include <stdio.h>#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/kernel.h>
#include <zephyr/pm/device.h>
#include <zephyr/sys/poweroff.h>
#include <zephyr/sys/util.h>#if IS_ENABLED(CONFIG_GRTC_WAKEUP_ENABLE)
#include <zephyr/drivers/timer/nrf_grtc_timer.h>
#define DEEP_SLEEP_TIME_S 2
#else
static const struct gpio_dt_spec sw0 = GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios);
#endifint main(void)
{int rc;const struct device *const cons = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));if (!device_is_ready(cons)) {printf("%s: device not ready.\n", cons->name);return 0;}printf("\n%s system off demo\n", CONFIG_BOARD);if (IS_ENABLED(CONFIG_APP_USE_RETAINED_MEM)) {bool retained_ok = retained_validate();/* Increment for this boot attempt and update. */retained.boots += 1;retained_update();printf("Retained data: %s\n", retained_ok ? "valid" : "INVALID");printf("Boot count: %u\n", retained.boots);printf("Off count: %u\n", retained.off_count);printf("Active Ticks: %" PRIu64 "\n", retained.uptime_sum);} else {printf("Retained data not supported\n");}#if IS_ENABLED(CONFIG_GRTC_WAKEUP_ENABLE)int err = z_nrf_grtc_wakeup_prepare(DEEP_SLEEP_TIME_S * USEC_PER_SEC);if (err < 0) {printk("Unable to prepare GRTC as a wake up source (err = %d).\n", err);} else {printk("Entering system off; wait %u seconds to restart\n", DEEP_SLEEP_TIME_S);}
#else/* configure sw0 as input, interrupt as level active to allow wake-up */rc = gpio_pin_configure_dt(&sw0, GPIO_INPUT);if (rc < 0) {printf("Could not configure sw0 GPIO (%d)\n", rc);return 0;}rc = gpio_pin_interrupt_configure_dt(&sw0, GPIO_INT_LEVEL_ACTIVE);if (rc < 0) {printf("Could not configure sw0 GPIO interrupt (%d)\n", rc);return 0;}printf("Entering system off; press sw0 to restart\n");
#endifrc = pm_device_action_run(cons, PM_DEVICE_ACTION_SUSPEND);if (rc < 0) {printf("Could not suspend console (%d)\n", rc);return 0;}if (IS_ENABLED(CONFIG_APP_USE_RETAINED_MEM)) {/* Update the retained state */retained.off_count += 1;retained_update();}sys_poweroff();return 0;
}
參考文獻
D:\ncs\v2.9.0\zephyr\samples\boards\nordic\system_off