Interrupt is unable to wakeup CPU if NRF_GPIOTE->LATENCY is set to low power

#include <zephyr/drivers/gpio.h>
#include <zephyr/kernel.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/pm.h>
#include <zephyr/pm/state.h>

#define INTPIN DT_NODELABEL(intpin)
static const struct gpio_dt_spec interruptPin = GPIO_DT_SPEC_GET_OR(INTPIN, gpios, { 0 });
static struct k_sem semaphore;

void onInterrupt(const struct device *port,
                 struct gpio_callback *cb,
                 gpio_port_pins_t pins)
{
        k_sem_give(&semaphore);
}

int main()
{
        k_sem_init(&semaphore, 0, 1);

        gpio_pin_configure_dt(&interruptPin, GPIO_INPUT);
        gpio_pin_interrupt_configure_dt(&interruptPin, GPIO_INT_EDGE_TO_ACTIVE);
        NRF_GPIOTE->LATENCY = 0;

        gpio_callback intCb{};
        gpio_init_callback(&intCb, onInterrupt, BIT(interruptPin.pin));
        gpio_add_callback(interruptPin.port, &intCb);

        const struct device *uartDevice = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));

        printk("Started at: %u\n", k_uptime_get_32());
        while (true) {
                pm_device_action_run(uartDevice, PM_DEVICE_ACTION_SUSPEND);
                const auto ret = k_sem_take(&semaphore, K_MSEC(3 * 1000));
                pm_device_action_run(uartDevice, PM_DEVICE_ACTION_RESUME);
                if (ret) {
                        printk("Timed out: %u\n", k_uptime_get_32());
                        return -1;
                } else {
                        printk("Int: %u\n", k_uptime_get_32());
                }
        }
}


The above code is unable to wakeup CPU on interrupt. For it to work, either the latency should be left at the default value of LowLatency or the call to pm_device_action_run to suspend UART be commented. If the latency is not set to LowPower current shoots up from 10uA to 300uA.

Parents Reply Children
  • With IN event (high accuracy) on a GPIOTE you will get a separate interrupt for each GPIOTE pin, but for PORT event yo will get an interrupt for the port, and you (or typically the driver), needs to check which pin(s) there was an interrupt on, and clear that. So for instance if you get a change of state in more pins on a port at the same time, you will only get one interrupt with the port event (the driver itterats through all pins though) and you will get multiple callbacks, though.

Related