This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

current consumption increases after first GPIOTE interrupt

I have a problem with some current consumption I cannot explain. I first thought it had something to do with floating pins or something, but that does not seem to be the case.

The problem boils down to this: after startup, I configure pins, and. among other things, I configure the GPIOTE, to generate a port interrupt, and enable 2 pins which are connected to a switch. When I then go to low power, all is fine, current consumption is about 20 uA (I have some peripherals on my board, so the 20 uA is as expected).

However, when I receive a first GPIOTE interrupt, when pressing a button, my current consumption increases to about 600 uA. I really cannot figure out what I am doing wrong. The only thing is that, when I disable the GPIOTE interrupt, but still operate everything else, like timers and such, the sleep mode current stays at around 20 uA.

Is there something in a GPIOTE interrupt that keeps something awake in the chip? Can anyone give me a hint of what might be wrong?

BTW: I am not using the app_gpiote library, I wrote my own, much more limited version. Maybe I need to reset something in my interrupt routine, I do not know. Any ideas are welcome.

  • Are you using the PORT interrupt or configuring the IN interrupts for specific pins?

  • I use the port interrupt, not a pin interrupt, like this:

    Init function:

    void gpiote_init(app_sched_event_handler_t handler)
    {
        gpiote_interrupt_callback = handler;
        // Initialize GPIOTE interrupt (will not be enabled until app_gpiote_user_enable() is called).
        NRF_GPIOTE->INTENCLR = 0xFFFFFFFF;
        NVIC_ClearPendingIRQ(GPIOTE_IRQn);
        NVIC_SetPriority(GPIOTE_IRQn, APP_IRQ_PRIORITY_HIGH);
        NVIC_EnableIRQ(GPIOTE_IRQn);
    }
    

    And then enable:

    void gpiote_enable_pin(uint32_t pin,bool rising_edge)
    {
        NRF_GPIOTE->EVENTS_PORT = 0;
        NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Msk;
        NRF_GPIO->PIN_CNF[pin] &= ~GPIO_PIN_CNF_SENSE_Msk;
        if (rising_edge) NRF_GPIO->PIN_CNF[pin] |= GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos;
        else NRF_GPIO->PIN_CNF[pin] |= GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos;
    }
    

    And then turning on the actual interrupt:

    void gpiote_enable_port_interrupt()
    {
        NRF_GPIOTE->EVENTS_PORT = 0;
        NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Msk;
    }
    

    And interrupt service routine:

    void GPIOTE_IRQHandler(void) {
        gpiote_disable_port_interrupt();
    
        static uint32_t pins_state;
        pins_state = NRF_GPIO->IN;
    
        // Clear event.
        NRF_GPIOTE->EVENTS_PORT = 0;
        if (gpiote_interrupt_callback != NULL)
        {
            uint32_t retval =    app_sched_event_put(&pins_state, sizeof(pins_state), gpiote_interrupt_callback);
            if (retval != NRF_SUCCESS)
            DBG(0,"GPIOTEIRQ: scheduled handler with reval %d\n",retval);
        } }
    
  • Maybe not a useful question, but if you don't spit out the debug message, do you still see the high current draw? I'm not sure how the UART is configured, but perhaps it is being left in the ON state before going back to sleep.

    In general, the implementation seems OK to me. Since this code is interfacing with a switch, it will need some debouncing on the input also. Otherwise, the interrupt will trigger multiple times if the input bounces (although, it looks like the code handles the interrupt in the scheduler; I'm not sure where it gets reenabled or if it gets reenabled).

  • the DBG is just a macro around the SEGGER_RTT_printf function, so no UART involved. But even when it is redefined to nothing, so no printf is done, power consumption is too high.

    And about the re-enable: in the scheduler, at the end of the interrupt handler call back function, I do:

    gpiote_enable_port_interrupt();
    

    Also, the interrupt is de-bounced using a single shot timer which gets restarted when the input signal is bouncing. In the hardware there is also a low-pass filter to debounce the signal.

  • Do you have external pullup? I dont see any internal pullup being set. Is the switch going to a permanent state or is it just pushed and then released (tactile button)? If you use a pullup of 10K and the switch is pulling the input to ground, the leakage current will be Vcc/10 mA.

Related