nRF91-QA-低功耗例程-串口与按键

一:按键切换LED与串口外设进入低功耗模式与唤醒

  1. 测试环境:ncs v1.8.0
  2. 例程路径:ncs\v1.8.0\peter\0_uart_off_button
  3. 测试固件:ncs\v1.8.0\peter\0_uart_off_button\merged.hex
  4. 例程源码:链接测试例程(功耗 外设 DFU FDS AT)/nRF91/v1.8.0/0_uart_off_button.zip
  5. 唤醒状态电流:522uA 图片
  6. PM_STATE_RUNTIME_IDLE模式电流:3.5uA 图片
  7. PM_STATE_SOFT_OFF模式电流:1.8uA 图片

  8. spm prj.conf 配置
    #
    # Copyright (c) 2019 Nordic Semiconductor ASA
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #
    CONFIG_NCS_SAMPLES_DEFAULTS=y

    CONFIG_IS_SPM=y
    CONFIG_FW_INFO=y
    CONFIG_GPIO=n
    CONFIG_MAIN_STACK_SIZE=4096
    CONFIG_SERIAL=n
    # Images that set CONFIG_BOOTLOADER_MCUBOOT get this value set by default.
    # The SPM image will not have CONFIG_BOOTLOADER_MCUBOOT set by default when
    # being built by a parent image. Hence we set it here to ensure that SPM
    # cleans up the core during boot.
    CONFIG_INIT_ARCH_HW_AT_BOOT=y

    # Avoid using feature that allocates PPI channels
    CONFIG_UART_0_ENHANCED_POLL_OUT=n
    CONFIG_UART_1_ENHANCED_POLL_OUT=n
  1. 0_uart_off_button prj.conf 配置
     CONFIG_PM=y
     # Required to disable default behavior of deep sleep on timeout
     CONFIG_PM_DEVICE=y
     CONFIG_GPIO=y
     CONFIG_GPIO_NRF_INT_EDGE_USING_SENSE=y
    
  2. main.c 测试代码

    /*
    * Copyright (c) 2019 Nordic Semiconductor ASA
    *
    * SPDX-License-Identifier: Apache-2.0
    */

    #include <stdio.h>
    #include <zephyr.h>
    #include <device.h>
    #include <init.h>
    #include <pm/pm.h>
    #include "retained.h"
    #include <hal/nrf_gpio.h>
    #include "sys/printk.h"
    #include <drivers/gpio.h>
    #include "logging/log.h"
    LOG_MODULE_REGISTER(main, CONFIG_LOG_DEFAULT_LEVEL);

    #define ON                1
    #define OFF               0
    #define CONSOLE_LABEL DT_LABEL(DT_CHOSEN(zephyr_console))
    #define SW0_NODE	DT_ALIAS(sw0)

    //按键P0.06
    //指示灯P0.02
    //测试,指示灯亮,程序进入工作模式,指示灯灭,程序进入低功耗模式
    static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios,{0});	
    static struct gpio_callback button_cb_data;
    static struct gpio_dt_spec led = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led0), gpios,{0});

    const struct device *cons;
    static uint8_t power_state = 0;

    /* Prevent deep sleep (system off) from being entered on long timeouts
    * or `K_FOREVER` due to the default residency policy.
    *
    * This has to be done before anything tries to sleep, which means
    * before the threading system starts up between PRE_KERNEL_2 and
    * POST_KERNEL.  Do it at the start of PRE_KERNEL_2.
    */
    static int disable_ds_1(const struct device *dev)
    {
        ARG_UNUSED(dev);

        pm_constraint_set(PM_STATE_SOFT_OFF);
        return 0;
    }

    SYS_INIT(disable_ds_1, PRE_KERNEL_2, 0);

    void button_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
    {
        if( !power_state )
        {
            power_state = 1;
        }
        else
        {
            power_state = 0;
        }
    }

    void button_init(void)
    {
        LOG_INF("button init\r\n");
        
        int ret;
        if (!device_is_ready(button.port)) 
        {
            LOG_INF("Error: button device %s is not ready\n",button.port->name);
            return;
        }

        ret = gpio_pin_configure_dt(&button, GPIO_INPUT);
        if (ret != 0) 
        {
            LOG_INF("Error %d: failed to configure %s pin %d\n",ret, button.port->name, button.pin);
            return;
        }

        ret = gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_TO_ACTIVE);
        if (ret != 0) 
        {
            LOG_INF("Error %d: failed to configure interrupt on %s pin %d\n",ret, button.port->name, button.pin);
            return;
        }

        gpio_init_callback(&button_cb_data, button_callback, BIT(button.pin));
        gpio_add_callback(button.port, &button_cb_data);
        LOG_INF("Set up button at %s pin %d\n", button.port->name, button.pin);
        
        if(!device_is_ready(led.port))
        {
            LOG_INF("Error: led device %s is not ready\n",led.port->name);
            led.port = NULL;
        }
        
        if (led.port && !device_is_ready(led.port)) 
        {
            LOG_INF("Error %d: LED device %s is not ready; ignoring it\n",ret, led.port->name);
            led.port = NULL;
        }
        
        ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT);
        if (ret != 0) 
        {
            LOG_INF("Error %d: failed to configure LED device %s pin %d\n",ret, led.port->name, led.pin);led.port = NULL;
        } 
        else 
        {
            LOG_INF("Set up LED at %s pin %d\n", led.port->name, led.pin);
        }
            gpio_pin_set_dt(&led, OFF);
    }

    void main(void)
    {
        int rc;
        cons = device_get_binding(CONSOLE_LABEL);
        button_init();
        printk("Power up enter low power mode\r\n");
        printk("Press 9160DK Button1(P0.06) enter active mode:enable uart enable led1(P0.02)\r\n");
        printk("ncs v1.8.0 nrf samples spm prj.conf need add config: CONFIG_SERIAL=n \r\n");
        printk("ncs v1.8.0 peter 0_uart_off_button prj.conf need add config: CONFIG_GPIO_NRF_INT_EDGE_USING_SENSE=y \r\n");
        while (1) 
        {
            static uint8_t spower_state = 1;
            if( spower_state ^ power_state )
            {
                spower_state = power_state;
                if( power_state )
                {
                    gpio_pin_set_dt(&led, ON);
                    //使能串口
                    rc = pm_device_state_set(cons, PM_DEVICE_STATE_ACTIVE);
                    //设置芯片恢复正常状态
                    pm_power_state_force((struct pm_state_info){PM_STATE_ACTIVE, 0, 0});
                    k_msleep(100);
                    printk("Press Button1 enter Wake up mode I= 522 uA\r\n");
                }
                else
                {
                    printk("Press Button1 enter PM_STATE_RUNTIME_IDLE mode I= 3.5 uA\r\n");
                    printk("Press Button1 enter PM_STATE_SUSPEND_TO_IDLE mode I= 3.5 uA\r\n");
                    printk("Press Button1 enter PM_STATE_STANDBY mode I= 3.6 uA\r\n");
                    printk("Press Button1 enter PM_STATE_SUSPEND_TO_DISK mode I= 3.5 uA\r\n");
                    printk("Press Button1 enter PM_STATE_SOFT_OFF mode I= 1.7 uA\r\n");
                    k_msleep(100);
                    gpio_pin_set_dt(&led, OFF);
                    //禁用串口
                    rc = pm_device_state_set(cons, PM_DEVICE_STATE_SUSPENDED); //3.5uA左右电流
                    //设置芯片进入低功耗
                    pm_power_state_force((struct pm_state_info){PM_STATE_RUNTIME_IDLE, 0, 0});
                }
            }
            k_msleep(3000);  //延时3秒钟
        }
    }

二:参考文档

  1. Devzone
  2. nRF Connect Sdk doc

新手必知

海量第三方学习资源.

超全常用工具与文档.

本站常用资源下载.

常见问题搜索.

QQ群: 542294007.

文章引用自:元仓库 OLIB.cn.