Interrupt energy intensive

When I program an interrupt, the NRF52840 requires 250uA extra. I read something about the sense interrupt, but I cannot find any working example. How should I implement an interrupt when my power is on a budget?

static const struct gpio_dt_spec signal = GPIO_DT_SPEC_GET(ZEPHYR_USER_NODE, signal_gpios);
static struct gpio_callback _interrupt;

void _isr(const struct device *dev, struct gpio_callback *cb, uint32_t pins) {  
  LOG_INF("isr given");
  k_work_schedule(&_proces, K_NO_WAIT); 
}


void attachinterrupt(void) {

	__ASSERT(device_is_ready(signal.port), "custom device not ready");
	if(gpio_pin_configure_dt(&signal, GPIO_INPUT)) {
    LOG_ERR("error configure signalgpio");
  }

	if(gpio_pin_interrupt_configure_dt(&signal, GPIO_INT_EDGE_TO_ACTIVE)) {
    LOG_ERR("error configure interrupt signalgpio");
  };
	gpio_init_callback(&_interrupt, _isr, BIT(signal.pin));
	if(gpio_add_callback(signal.port, &_interrupt)) {
    LOG_ERR("callback for interrupt not set");
 };
}

I tried to replace gpio_pin_interrupt_configure_dt with a sense configuration, but I don't really get how this is suppose to work:

#include <hal/nrf_gpio.h>

nrf_gpio_cfg_input(signal.pin, NRF_GPIO_PIN_PULLDOWN);
nrf_gpio_cfg_sense_set(signal.pin, NRF_GPIO_PIN_SENSE_HIGH);

Also, I read a pin interrupt consumes more than a port interrupt. How would I implement a port interrupt (my system needs only 1 interrupt)?

Parents
  • You may also consider enabling level triggering instead of edge triggering by replacing the GPIO_INT_EDGE_TO_ACTIVE flag with GPIO_INT_LEVEL_ACTIVE. Edge triggering uses GPIOTE IN instead of GPIOTE PORT events, which increases the idle current to ~17 uA. PORT events are suitable for detecting lower frequency inputs.

  • Thanks, but that'll only work when I configure my hardware to have a latched interrupt. This will cause an infinite loop, which I don't know how to resolve. I can immidiately disable the interrupt from the ISR routine. This won't ensure tough things are not executed twice. What triggers also belong to GPIOTE PORT event?

    It does save ~12uA, thanks!

  • Are you saying that you need to clear the PORT event within your interrupt handler to prevent the interrupt from firing repeatedly? I'm also not sure I understand which hardware changes you're referring to. Could you please post a snippet of your current code?

    boris bergman1 said:
    What triggers also belong to GPIOTE PORT event

    Any GPIO input enabled with sense can trigger the PORT event.

  • 'm also not sure I understand which hardware changes you're referring to.

    I meant I configured my peripheral to signal 1 until _data_handler is executed.

    Could you please post a snippet of your current code?

    static void lsm6dsl_data_handler(struct k_work *work);
    K_WORK_DELAYABLE_DEFINE(_proces, _data_handler);
    
    void _isr(const struct device *dev, struct gpio_callback *cb, uint32_t pins) {  
      gpio_pin_interrupt_configure_dt(&signal, GPIO_INT_DISABLE);
      LOG_INF("isr given");
    
      k_work_schedule(&_proces, K_NO_WAIT); 
    }
    
    void attachinterrupt(void) {
    
    	__ASSERT(device_is_ready(signal.port), "custom device not ready");
    	if(gpio_pin_configure_dt(&signal, GPIO_INPUT)) {
        LOG_ERR("error configure signalgpio");
      }
    
    	if(gpio_pin_interrupt_configure_dt(&signal, GPIO_INT_LEVEL_HIGH)) {  //GPIO_INT_EDGE_TO_ACTIVE
        LOG_ERR("error configure interrupt signalgpio");
      };
    	gpio_init_callback(&_interrupt, _isr, BIT(signal.pin));
    	if(gpio_add_callback(signal.port, &_interrupt)) {
        LOG_ERR("callback for interrupt not set");
     };
    }

    Any GPIO input enabled with sense can trigger the PORT event.

    I don't really get how this translates to the events in Zephyr.

  • PORT events are used when you use the *_LEVEL_* flags with the gpio_pin_interrupt_configure_dt() function, and IN events are used when you use the *_EDGE_* flags. I don't know what your input signal looks like, but are you not having this problem when using GPIO_INT_EDGE_TO_ACTIVE?

    I meant I configured my peripheral to signal 1 until _data_handler is executed.

    Sorry, but I'm not sure what you mean by this.

  • Sorry, but I'm not sure what you mean by this.

    I mean my trigger signal is HIGH(1) until my function (_data_handler) reads the register of my peripheral, then it turns LOW(0).

    An GPIO_INT_EDGE_TO_ACTIVE trigger will only trigger once, when the signal goes from LOW to HIGH. a level trigger will trigger indefinite as long as this signal is HIGH.

    That's the reason I turn of the trigger in my ISR (see my previous code snippet).

Reply Children
Related