nRF52840 Power consumption with SLEEP OFF mode and SLEEP ON mode

We are nRF52840 in one of our products. When we use SYSTEM OFF mode with with hardware design, current consumption is around 3uA but when we use SYSTEM ON mode with RAM retention current increases to 17uA. But according to datasheet of nRF52840, current consumption is 2.35uA when SYSTEM ON mode is used with RAM retention. But considering our current in SYSTEM off mode is 3uA, it should be around 5uA in SYSTEM ON mode. 

We are using zephyr PM APIs to take device into SYSTEM OFF or SYSTEM ON mode like this:
pm_power_state_force((struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});\

we tried both these are for SYSTEM ON mode: PM_STATE_STANDBY and PM_STATE_SUSPEND_TO_RAM but current is still 17uA.

Can you please guide use where we are doing wrong or is this a correct way to use it? 

Parents
  • Hi

    Okay, can you upload the .ppk plot as an attachment here (in a .zip file) so I can review the current consumption plot. That could give us a pointer to what is drawing power. Is something that might draw power connected to the nRF52840, like a sensor or something. If it is powered by the nRF52, then the lower consumption when the nRF52 is turned off would make sense. But it could also just be the amount of RAM blocks being retained that draws this current.

    Best regards,

    Simon

  • Hi,

    how can we disable or not retain RAM blocks if they are not being uses during idle mode? 

  • Hi  

    On further investigation, I found that GPIO interrupts are taking current, if I disable GPIO interrupts, current consumption comes down to 4uA from 17uA. We have four button in our design and I am configuring GPIO interrupt through this code. Can you please check is the issue with this code when I enable GPIO interrupt through this code current increases from 4uA to 17uA:

    #include <zephyr.h>
    #include <device.h>
    #include <drivers/gpio.h>
    #include <sys/printk.h>
    
    #define BUTTON0_PORT_NODE DT_NODELABEL(gpio0)
    #define BUTTON1_PORT_NODE DT_NODELABEL(gpio0)
    #define BUTTON2_PORT_NODE DT_NODELABEL(gpio1)
    #define BUTTON3_PORT_NODE DT_NODELABEL(gpio1)
    
    static struct gpio_callback button_cb_data[2]; // Two callbacks, one for each port
    static const struct gpio_dt_spec buttons[] = {
        GPIO_DT_SPEC_GET_OR(DT_ALIAS(button0), gpios, {0}),
        GPIO_DT_SPEC_GET_OR(DT_ALIAS(button1), gpios, {0}),
        GPIO_DT_SPEC_GET_OR(DT_ALIAS(button2), gpios, {0}),
        GPIO_DT_SPEC_GET_OR(DT_ALIAS(button3), gpios, {0}),
    };
    
    void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
    {
        for (int i = 0; i < ARRAY_SIZE(buttons); i++) {
            if ((buttons[i].port == dev) && (pins & BIT(buttons[i].pin))) {
                printk("Button %d pressed\n", i);
            }
        }
    }
    
    void main(void)
    {
        const struct device *port0;
        const struct device *port1;
        int ret;
    
        port0 = device_get_binding(DT_LABEL(BUTTON0_PORT_NODE));
        if (!port0) {
            printk("Error: Port0 device not found.\n");
            return;
        }
    
        port1 = device_get_binding(DT_LABEL(BUTTON2_PORT_NODE));
        if (!port1) {
            printk("Error: Port1 device not found.\n");
            return;
        }
    
        for (int i = 0; i < ARRAY_SIZE(buttons); i++) {
            const struct device *port = buttons[i].port;
            
            if (!device_is_ready(port)) {
                printk("Error: Button %d device not ready.\n", i);
                return;
            }
    
            ret = gpio_pin_configure(port, buttons[i].pin, GPIO_INPUT | GPIO_PULL_UP);
            if (ret != 0) {
                printk("Error %d: failed to configure button %d pin\n", ret, i);
                return;
            }
    
            ret = gpio_pin_interrupt_configure(port, buttons[i].pin, GPIO_INT_EDGE_TO_ACTIVE);
            if (ret != 0) {
                printk("Error %d: failed to configure button %d interrupt\n", ret, i);
                return;
            }
        }
    
        gpio_init_callback(&button_cb_data[0], button_pressed, BIT(buttons[0].pin) | BIT(buttons[1].pin));
        gpio_add_callback(port0, &button_cb_data[0]);
    
        gpio_init_callback(&button_cb_data[1], button_pressed, BIT(buttons[2].pin) | BIT(buttons[3].pin));
        gpio_add_callback(port1, &button_cb_data[1]);
    
        printk("Press the buttons\n");
    }
    

Reply
  • Hi  

    On further investigation, I found that GPIO interrupts are taking current, if I disable GPIO interrupts, current consumption comes down to 4uA from 17uA. We have four button in our design and I am configuring GPIO interrupt through this code. Can you please check is the issue with this code when I enable GPIO interrupt through this code current increases from 4uA to 17uA:

    #include <zephyr.h>
    #include <device.h>
    #include <drivers/gpio.h>
    #include <sys/printk.h>
    
    #define BUTTON0_PORT_NODE DT_NODELABEL(gpio0)
    #define BUTTON1_PORT_NODE DT_NODELABEL(gpio0)
    #define BUTTON2_PORT_NODE DT_NODELABEL(gpio1)
    #define BUTTON3_PORT_NODE DT_NODELABEL(gpio1)
    
    static struct gpio_callback button_cb_data[2]; // Two callbacks, one for each port
    static const struct gpio_dt_spec buttons[] = {
        GPIO_DT_SPEC_GET_OR(DT_ALIAS(button0), gpios, {0}),
        GPIO_DT_SPEC_GET_OR(DT_ALIAS(button1), gpios, {0}),
        GPIO_DT_SPEC_GET_OR(DT_ALIAS(button2), gpios, {0}),
        GPIO_DT_SPEC_GET_OR(DT_ALIAS(button3), gpios, {0}),
    };
    
    void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
    {
        for (int i = 0; i < ARRAY_SIZE(buttons); i++) {
            if ((buttons[i].port == dev) && (pins & BIT(buttons[i].pin))) {
                printk("Button %d pressed\n", i);
            }
        }
    }
    
    void main(void)
    {
        const struct device *port0;
        const struct device *port1;
        int ret;
    
        port0 = device_get_binding(DT_LABEL(BUTTON0_PORT_NODE));
        if (!port0) {
            printk("Error: Port0 device not found.\n");
            return;
        }
    
        port1 = device_get_binding(DT_LABEL(BUTTON2_PORT_NODE));
        if (!port1) {
            printk("Error: Port1 device not found.\n");
            return;
        }
    
        for (int i = 0; i < ARRAY_SIZE(buttons); i++) {
            const struct device *port = buttons[i].port;
            
            if (!device_is_ready(port)) {
                printk("Error: Button %d device not ready.\n", i);
                return;
            }
    
            ret = gpio_pin_configure(port, buttons[i].pin, GPIO_INPUT | GPIO_PULL_UP);
            if (ret != 0) {
                printk("Error %d: failed to configure button %d pin\n", ret, i);
                return;
            }
    
            ret = gpio_pin_interrupt_configure(port, buttons[i].pin, GPIO_INT_EDGE_TO_ACTIVE);
            if (ret != 0) {
                printk("Error %d: failed to configure button %d interrupt\n", ret, i);
                return;
            }
        }
    
        gpio_init_callback(&button_cb_data[0], button_pressed, BIT(buttons[0].pin) | BIT(buttons[1].pin));
        gpio_add_callback(port0, &button_cb_data[0]);
    
        gpio_init_callback(&button_cb_data[1], button_pressed, BIT(buttons[2].pin) | BIT(buttons[3].pin));
        gpio_add_callback(port1, &button_cb_data[1]);
    
        printk("Press the buttons\n");
    }
    

Children
  • Hi

    Okay, can you try to enable interrupts, but disable the callbacks so that we can narrow this down to either being the interrupt itself or the post-processing from the interrupt callback that is drawing this power. We think this could be due to the edge detection on the GPIOs as that does draw a bit more power, but it could also be post-processing we think.

    Best regards,

    Simon

Related