This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

GPIO interrupts cause high current consumption during sleep on nrf9160 and nrf52833

I am doing power optimizations on a custom hardware that has nrf9160 and nrf52833 on it. These are connected via GPIO pins and I use two pins to send interrupts to each other.

I noticed when I turn off the interrupts, nrf9160 has around 5.5 - 7 uA sleep current and nrf52833 has around 2 uA sleep current. But when I turn on the interrupts nrf9160 has around 40 uA sleep current and nrf52833 has 10 uA sleep current. I tested on several boards and all have similar results.

So why does GPIO interrupts cause higher sleep current and how can I lower it?

I use zephyr gpio api for configuring the pins and interrupts. For turning off the interrups I just comment out the following function.

static void com_gpio_init(void)
{
    gp_gpio = device_get_binding(DT_LABEL(DT_NODELABEL(gpio0)));
    gpio_pin_configure(gp_gpio, COM_INT_OUT_PIN, GPIO_OUTPUT_INACTIVE);
    gpio_pin_configure(gp_gpio, COM_INT_IN_PIN, GPIO_INPUT | GPIO_PULL_DOWN);
    gpio_pin_interrupt_configure(gp_gpio, COM_INT_IN_PIN, GPIO_INT_EDGE_RISING);
    gpio_init_callback(&g_gpio_callback, com_gpio_callback_func, 1u << COM_INT_IN_PIN);
    gpio_add_callback(gp_gpio, &g_gpio_callback);
}

Parents
  • Hello,

    Please try replace the GPIO_INT_EDGE_RISING flag with GPIO_INT_LEVEL_HIGH and see if that helps lowering the IDLE current. The difference between the two is that the latter will configure GPIOTE to use PORT events which should have little to no impact on sleep current.

    Idle current - GPIOTE IN events vs. GPIOTE Port events (Sleep)

  • While using the GPIO_INT_LEVEL_HIGH flag the interrupt is not triggered unless I put a delay between set 1 and set 0 function calls on the other side. And even when I put a delay as small as 1ns then the interrupt is triggered multiple times which causes problems for the application.

    Do you have any suggestions to make sure the interrupts is triggered only once when using the level flags? I've  tried disabling the interrupt at the beginning of callback and reenabling at the end but it is still triggered multiple times.

    static void com_gpio_callback_func(const struct device *p_port, struct gpio_callback *p_cb, gpio_port_pins_t pins)
    {
        gpio_pin_interrupt_configure(gp_gpio, COM_INT_IN_PIN, GPIO_INT_DISABLE);
        k_sem_give(&g_com_sem);
        gpio_pin_interrupt_configure(gp_gpio, COM_INT_IN_PIN, GPIO_INT_LEVEL_HIGH);
    }

  • Does it help if you increase the pulse width to lets say 100 useconds? I can't think of any good reason for why you would get multiple events when using GPIOTE PORT , but not when using edge triggering with GPIOTE IN.

Reply Children
  • It doesn’t help. I tried 1us, 10us, 100us, and 1ms. All of them caused interrupt to trigger multiple times. I think it keeps triggering while the signal is high when using level flags.

  • Did you not get these duplicate events when you use EDGE triggering earlier? That's the part that confuses me the most. I would expect edge triggering to produce more events if anything.

    Assume you have common ground between the chips, but do they also share the same IO voltage? Also, do you have an oscilloscope that you can probe the signal with?

  • No, I didn't see any duplicate events when using rising edge trigger. I don't really understand why you would expect that. Shouldn't edge trigger be more guaranteed to have a single event since the signal takes a really short time to rise from low to high?

    And yes, the chips have common ground. I use the default gpio voltages for the both chips which should be 3.3V. I'll try probing the signals from test points on the board and post another reply.

    Also for edge triggering I used the following function for sending an interrupt which worked totally fine:

    static void com_send_interrupt(void)
    {
        gpio_pin_set(gp_gpio, COM_INT_OUT_PIN, 1);
        gpio_pin_set(gp_gpio, COM_INT_OUT_PIN, 0);
    }

    For the level flags though, this didn't trigger the interrupt at all. It only triggered when I put a k_sleep between set 1 and set 0 calls, but like I said before I see multiple events this way.

  • I probed the signal with an oscilloscope and when there is no sleep between set 1 and set 0, the pulse width is 1us.

    If I put 1us sleep between set 1 and set 0 then the pulse width is around 100us.

    For 100us sleep, the pulse width becomes 200us. And for 200us sleep, the pulse width becomes 300us.

    In each test, the interrupt keeps firing as long as the signal stays at high while using LEVEL flag. (except the test with no sleep, which doesn't trigger the interrupt at all)

    But the interrupt triggers only once when using EDGE trigger, no matter the pulse width.

  • Seems like k_sleep causes a much higher delay, I assume it's due to thread managing. I realized I should use k_busy_wait instead. I can change the pulse width with ~1us accuracy. When I put 10us delay the interrupt triggers only once with LEVEL flags.

    To summarize,

    For GPIO_INT_EDGE_RISING flag: don't need any delay, which sends a 1us wide pulse. But causes high idle current.

    For GPIO_INT_LEVEL_HIGH flag: 10us delay with k_busy_wait seems to trigger the interrupt only once (lower delays sometimes cause the interrupt to not trigger). And the idle current is much lower.

Related