当前页面为 开发中 版本,查看特定版本的文档,请在页面左下角的下拉菜单中进行选择。

Standby Mode0 P02 Key Wakeup

1 功能概述

本例程演示如何使 SoC 进入 Standby Mode 0 状态,然后通过 WKUP (P02) 按键将其唤醒。

Standby Mode 0 是芯片的最低功耗模式,只支持 P00/P01/P02 这三个 IO 将芯片唤醒(唤醒电平可配且共用)。由于 P00/P01 两个引脚默认为 SWD 功能,为方便演示本例程仅以 P02 唤醒为例进行说明。

2 环境准备

  • 硬件设备与线材:

    • PAN107X EVB 核心板底板各一块

    • JLink 仿真器(用于烧录例程程序)

    • 电流计(本文使用电流可视化测量设备 PPK2 [Nordic Power Profiler Kit II] 进行演示)

    • USB-TypeC 线一条(用于底板供电和查看串口打印 Log)

    • 杜邦线数根或跳线帽数个(用于连接各个硬件设备)

  • 硬件接线:

    • 将 EVB 核心板插到底板上

    • 为确保能够准确地测量 SoC 本身的功耗,排除底板外围电路的影响,请确认 EVB 底板上的:

      • Voltage 排针组中的 VCC 和 VDD 均接至 3V3

      • POWER 开关从 LDO 档位拨至 BAT 档位(并确认底板背部的电池座内没有纽扣电池)

    • 使用 USB-TypeC 线,将 PC USB 插口与 EVB 底板 USB->UART 插口相连

    • 使用杜邦线将 EVB 底板上的 TX 引脚接至核心板 P16,RX 引脚接至核心板 P17

    • 使用杜邦线将 JLink 仿真器的:

      • SWD_CLK 引脚与 EVB 底板的 P00 排针相连

      • SWD_DAT 引脚与 EVB 底板的 P01 排针相连

      • SWD_GND 引脚与 EVB 底板的 GND 排针相连

    • 将 PPK2 硬件的:

      • USB DATA/POWER 接口连接至 PC USB 接口

      • VOUT 连接至 EVB 底板的 VBAT 排针

      • GND 连接至 EVB 底板的 GND 排针

  • PC 软件:

    • 串口调试助手(UartAssist)或终端工具(SecureCRT),波特率 921600(用于接收串口打印 Log)

    • nRF Connect Desktop(用于配合 PPK2 测量 SoC 电流)

3 编译和烧录

例程位置:<PAN10XX-NDK>\01_SDK\nimble\samples\low_power\standby_m0_p02_key_wakeup\keil_107x

双击 Keil Project 文件打开工程进行编译烧录,烧录成功后断开 JLink 连线以避免漏电。

4 例程演示说明

  1. PC 上打开 PPK2 Power Profiler 软件,供电电压选择 3300 mV,然后打开供电开关

  2. 从串口工具中看到如下的打印信息:

    Try to load HW calibration data.. DONE.
    - Chip Info         : 0x1
    - Chip CP Version   : 255
    - Chip FT Version   : 7
    - Chip MAC Address  : E110000052E3
    - Chip UID          : 060300465454455354
    - Chip Flash UID    : 4250315A3538380B00CE12435603C678
    - Chip Flash Size   : 512 KB
    [I] App started..
    
    [I] Reset Reason: nRESET Pin Reset.
    [I] Busy wait 100ms to keep SoC in active mode..
    [I] Try to enter SoC sleep/deepsleep mode for 1000ms..
    [I] Waked up from SoC sleep/deepsleep mode.
    [I] Try to enter SoC standby mode 0..
    
  3. 此时观察芯片电流波形,发现稳定在 220nA 左右(说明芯片成功进入了 Standby Mode 0 状态):

    image

    系统初始化后进入 Standby Mode 0 状态

    芯片低功耗状态下的底电流(漏电流)与环境温度相关,温度越高,漏电流越大。

  4. 尝试按下 EVB 底板上的 WKUP 按键,由串口打印信息可知触发了唤醒并复位,复位的原因为 Standby Mode 0 EXTIO Wakeup(即 WKUP 按键唤醒),随后芯片依次进入 100ms 的 Busy 状态,1s 的 DeepSleep 状态,接着唤醒后进入 Standby Mode 0 状态继续等待 WKUP 按键唤醒:

    Try to load HW calibration data.. DONE.
    - Chip Info         : 0x1
    - Chip CP Version   : 255
    - Chip FT Version   : 7
    - Chip MAC Address  : E110000052E3
    - Chip UID          : 060300465454455354
    - Chip Flash UID    : 4250315A3538380B00CE12435603C678
    - Chip Flash Size   : 512 KB
    [I] App started..
    
    [I] Reset Reason: Standby Mode 0 EXTIO Wakeup (cnt = 1).
    [I] Busy wait 100ms to keep SoC in active mode..
    [I] Try to enter SoC sleep/deepsleep mode for 1000ms..
    [I] Waked up from SoC sleep/deepsleep mode.
    [I] Try to enter SoC standby mode 0..
    

5 开发者说明

5.1 SDK Config 配置

与本例程相关的 SDK Config (sdk_config.h) 配置有:

  • SoC Platform : Chip Power Mode

    • 芯片供电选择 DCDC 模式,以降低芯片动态功耗

    • 对应宏配置 CONFIG_SOC_DCDC_PAN1070 = 1

  • Power Management : Enable Low Power Mode

    • 使能系统低功耗功能

    • 对应宏配置 CONFIG_PM = 1

  • Log & Debug Config : Enable App Log

    • 使能 App Log 功能

    • 对应宏配置 APP_LOG_EN = 1

  • Log & Debug Config : Enable App Log : Log to UART

    • 将 App Log 输出至串口

    • 对应宏配置 CONFIG_UART_LOG_ENABLE = 1

5.2 程序代码

5.2.1 主程序

本例程中,OS 为使能状态,因此主程序 main() 函数也是 OS Main Task 的入口函数,其内容如下:

int main(void)
{
    /* Application initialization */
    app_setup();

    /* Application main infinite loop */
    app_main_loop();

    return 0;
}

5.2.2 App Setup 初始化

App 初始化 app_setup() 函数内容如下:

void app_setup(void)
{
    APP_LOG_INFO("App started..\n\n");

    uint8_t rst_reason;

    /* Get the last reset reason */
    APP_LOG_INFO("Reset Reason: ");
    rst_reason = soc_reset_reason_get();
    switch (rst_reason) {
    case SOC_RST_REASON_POR_RESET:
        APP_LOG("Power On Reset.\n");
        break;
    case SOC_RST_REASON_PIN_RESET:
        APP_LOG("nRESET Pin Reset.\n");
        break;
    case SOC_RST_REASON_SYS_RESET:
        APP_LOG("NVIC System Reset.\n");
        break;
    case SOC_RST_REASON_STBM0_EXTIO_WAKEUP:
        APP_LOG("Standby Mode 0 EXTIO Wakeup (cnt = %d).\n", ++wkup_cnt);
        break;
    default:
        APP_LOG("Unhandled Reset Reason (%d), refer to more reason define in soc_api.h!\n", rst_reason);
    }

    /* Enable P02 low level wakeup for standby mode 0 */
    wakeup_p02_key_init(0);

    APP_LOG_INFO("Busy wait 100ms to keep SoC in active mode..\n");
    soc_busy_wait(100000);

    APP_LOG_INFO("Try to enter SoC sleep/deepsleep mode for 1000ms..\n");
    vTaskDelay(pdMS_TO_TICKS(1000));
    APP_LOG_INFO("Waked up from SoC sleep/deepsleep mode.\n");

    APP_LOG_INFO("Try to enter SoC standby mode 0..\n\n");
    soc_busy_wait(1000); /* Wait for all log print done */
    soc_enter_standby_mode_0();

    APP_LOG("WARNING: Failed to enter SoC standby mode 0 due to unexpected interrupt detected.\n");
    APP_LOG("         Please check if there is an unhandled interrupt during the standby mode 0\n");
    APP_LOG("         entering flow.\n");
}
  1. 打印 App 初始化 Log

  2. 获取并打印本次芯片启动的复位原因

  3. 在 wakeup_p02_key_init() 函数中初始化 EXTIO (P02) 配置

  4. 调用 soc_busy_wait() 接口使芯片在 Active 状态下全速运行 100ms

  5. 调用 vTaskDelay() 接口使系统切换至 Idle Task 执行 1s,实际上会使芯片进入持续 1s 的 DeepSleep 状态

  6. 调用 soc_busy_wait() 接口延时 1ms,目的是确保所有串口打印消息都发送完成

  7. 调用 soc_enter_standby_mode_0() 接口,使系统进入 Standby Mode 0 低功耗状态

5.2.3 App Main Task Loop 任务循环

App Main Task 循环 app_main_loop() 函数内容如下:

void app_main_loop(void)
{
    while (1) {
        /* Busy wait */
    }
}

由于在 app_setup() 流程中已经调用了进入 Standby Mode 0 的接口 soc_enter_standby_mode_0(),所以此处 Task 主循环中仅写了一个死循环防止 Task 退出。

5.2.4 WKUP Key(P02)初始化程序

P02 初始化程序 wakeup_p02_key_init() 函数内容如下:

static void wakeup_p02_key_init(uint8_t wakeup_edge)
{
    /* Configure GPIO P02 (WKUP Key) as Lowlevel Wakeup */

    /* Configure P02 wakeup level due to wakeup_edge */
    LP_SetExternalWake(ANA, wakeup_edge);

    /* Set pinmux func of P02 as GPIO */
    SYS_SET_MFP(P0, 2, GPIO);

    /*
     * Construct GPIO init structure and Init GPIO P02:
     * - Set IO to digital input mode
     * - Enable internal pull-up or pull-down resistor depends the wakeup_edge
     */
    HAL_GPIO_InitTypeDef GPIO_InitStruct = {
        .mode   = HAL_GPIO_MODE_INPUT_DIGITAL,
    };
    if (wakeup_edge == 0) {
        /* Enable internal pull-up resistor if P02 is low level wakeup */
        GPIO_InitStruct.pull = HAL_GPIO_PULL_UP;
    } else {
        /* Enable internal pull-down resistor if P02 is high level wakeup */
        GPIO_InitStruct.pull = HAL_GPIO_PULL_DOWN;
    }
    HAL_GPIO_Init(P0_2, &GPIO_InitStruct);

    /* Wait for a while to ensure the internal pullup is stable before entering low power mode */
    soc_busy_wait(10000);
}
  1. 配置 EXTIO 的唤醒电平

  2. 配置 P02 引脚 Pinmux 至 GPIO 功能

  3. 配置 P02 为数字输入模式,并根据唤醒电平使能内部上拉或下拉电阻

  4. 等待一段时间,确保上下拉电阻稳定

5.2.5 与低功耗相关的 Hook 函数

本例程还用到了 2 个与低功耗密切相关的 Hook 函数:

CONFIG_RAM_CODE void vSocDeepSleepEnterHook(void)
{
#if CONFIG_UART_LOG_ENABLE
    reset_uart_io();
#endif
}

CONFIG_RAM_CODE void vSocDeepSleepExitHook(void)
{
#if CONFIG_UART_LOG_ENABLE
    set_uart_io();
#endif
}
  1. 上述两个 Hook 函数用于在进入 DeepSleep 前和从 DeepSleep 唤醒后做一些额外操作,如关闭和重新配置 IO 为串口功能,以防止 DeepSleep 状态下 IO 漏电

  2. 详细解释请参考 Standby Mode1 GPIO Key Wakeup 例程中的相关介绍

6 RAM/Flash资源使用情况

PAN107x:

Flash Size:  18.82k
RAM Size:  9.95 k