Protecting the battery via sleep mode

Hello,

I am trying to protect the battery on our application by putting my device in DEEP_SLEEP_! mode when a certain voltage is reached and waking it up upon a GPIO input.

In order to understand how it works i put together a very simple piece of code that nonetheless doesn't work as expected. When executing sys_pm_force_power_state(SYS_POWER_STATE_DEEP_SLEEP_1);  the system does indeed stop execution but then when i activate the GPIO callback (in this case a button) it never comes back. On the other side if i comment out the call to the aforementioned function I can see that the callback is being called via the printk. Is there any other configuration that i am missing to be able to wake up the device from DEEP_SLEEP_1?

The device is a nr9160 based board.

The code:

#include <drivers/gpio.h>
#include <power/power.h>
#include <hal/nrf_power.h>

#define BUTTON_NODE DT_NODELABEL(button0)
#define BUTTON_GPIO_LABEL DT_GPIO_LABEL(BUTTON_NODE, gpios)
#define BUTTON_GPIO_PIN DT_GPIO_PIN(BUTTON_NODE, gpios)
#define BUTTON_GPIO_FLAGS GPIO_INPUT | DT_GPIO_FLAGS(BUTTON_NODE, gpios)
#define SYSTEM_OFF_DELAY_S K_MSEC(1000)


static const struct device *gpio_dev;
static struct gpio_callback gpio_cb;
static struct k_delayed_work system_off_work;

void button_pressed_callback(const struct device *gpiob, struct gpio_callback *cb, gpio_port_pins_t pins)
{
printk("Callback\n");
k_delayed_work_cancel(&system_off_work);
}

bool init_button(void)
{
int ret = gpio_pin_configure(gpio_dev, BUTTON_GPIO_PIN, BUTTON_GPIO_FLAGS);
if (ret != 0) {
printk("Error %d: failed to configure %s pin %d\n",
ret, BUTTON_GPIO_LABEL, BUTTON_GPIO_PIN);

return false;
}

ret = gpio_pin_interrupt_configure(gpio_dev,
BUTTON_GPIO_PIN,
GPIO_INT_EDGE_TO_ACTIVE);
if (ret != 0) {
printk("Error %d: failed to configure interrupt on %s pin %d\n",
ret, BUTTON_GPIO_LABEL, BUTTON_GPIO_PIN);

return false;
}

gpio_init_callback(&gpio_cb, button_pressed_callback, BIT(BUTTON_GPIO_PIN));
gpio_add_callback(gpio_dev, &gpio_cb);

return true;
}

static void system_off(struct k_work *work)
{
printk("Going to sleep\r\n");
k_sleep(K_MSEC(1000));
sys_pm_force_power_state(SYS_POWER_STATE_DEEP_SLEEP_1);
k_sleep(K_MSEC(1));

/* k_sleep will never exit, so below two lines will never be executed
* if system off was correct. On the other hand if someting gone wrong
* we will see it on terminal and LED.
*/
printk("ERROR: System off failed\n");
}


int main(void)
{
gpio_dev = device_get_binding(DT_LABEL(DT_NODELABEL(gpio0)));

if (!gpio_dev) {
printk("Error getting GPIO device binding\r\n");
return false;
}

if (!init_button()) {
printk("Error initializing button\r\n");
return false;
}

k_delayed_work_init(&system_off_work, system_off);
k_delayed_work_submit(&system_off_work, SYSTEM_OFF_DELAY_S);

while (1) {
printk("Running\n");
k_sleep(K_MSEC(500));
}

return 0;
}
Related