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

PORT event not waking up with interrupts disabled

Hi,

I'm building a low power application utilizing a MEMS accelerometer providing a data ready signal with configurable intervals. The intent is to use this signal as a wakeup from system_on sleep. The low power execution is in a loop where I do not need the execution overhead of interrupt handling. I tried to implement a wakeup using the port event without interrupts enabled, but in this case wakeup does not take place although the SEVONPEND is set. The essential code is below

NRF_GPIO->PIN_CNF[IO_MEMS_INT1_PIN] |= (GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos);
NVIC_DisableIRQ(GPIOTE_IRQn);
SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Enabled << GPIOTE_INTENSET_PORT_Pos;
while (1) {
	NRF_GPIOTE->EVENTS_PORT = 0;
	__SEV();		// Set event register
	__WFE();		// clear event register
	if (nrf_gpio_pin_read(IO_MEMS_INT1_PIN)) {
		__WFE();   // sleep
	}
// Read MEMS to clear data ready condition...
}

Execution does not leave __WFE when the pin goes down. If I change NVIC_DisableIRQ(GPIOTE_IRQn) to EnableIRQ, wake-up takes place and the interrupt executes properly. The documentation is in my opinion insufficient regarding the wake-up on event behavior. It is e.g. unclear whether the corresponding INTENSET bit relating to a event needs to be set for the wakeup to take place. I have a similar need for wakeup without interrupt for AD conversion and SPI master. I wouldn't like to have the execution go through the interrupts as it introduces additional execution overhead and moreover enforces state checking in the interrupt routines as I use them differently (and preferably exclusively) in another operation mode. As far as I've understood from the documentation it should be possible to achieve wakeup without interrupts enabled. How? My chip is NRF51822_QFACA1

  • configuring NRF chip to generate interrupt and configuring ARM chip to detect or not detect are two different things.

    NRF_GPIO->PIN_CNF[IO_MEMS_INT1_PIN] |= (GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos);
    NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Enabled << GPIOTE_INTENSET_PORT_Pos;
    

    Here You have configured NRF chip to generate interrupt (not just events) when the pin goes low.

    NVIC_DisableIRQ(GPIOTE_IRQn);
    SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
    

    Here you have told the ARM chip to disable (mask) GPIOTE interrupt. This means that the intrrupt coming from NRF chip to ARM chip is simply masked. Also you set the SEVONPEND bit in SCR which means that you it should wakeup from WFE if the interrupt was generated from NRF chip.

    So far so good.

    1. The documentation is complete regarding this and ARM provides this. infocenter.arm.com/.../index.jsp

    In addition, if the SEVONPEND bit in the SCR is set to 1, any new pending interrupt triggers an event and wakes up the processor, even if the interrupt is disabled or has insufficient priority to cause exception entry. For more information about the SCR see System Control Register .

    It clearly says that the condition for it wakeup from sleep is to have a new pended interrupt which triggers and event on ARM. Please do not get confused about the events on nRF chip and events that wake ARM core. They are different. Events on nRF chip are not mapped to events on ARM chip. The connection is only through interrupts (enabled or disabled on ARM core depending on SEVONPEND setting)

    1. How do you know that execution does not leave WFE after the pin goes low? Are you saying this based on power consumption? because i do not see any debug pins used in your code. Also If i were you I would change your code little

      // Configure and Enable interrupt on nRF side NRF_GPIO->PIN_CNF[IO_MEMS_INT1_PIN] |= (GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos); NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Enabled << GPIOTE_INTENSET_PORT_Pos;

      // Configure ARM chip to wakeup on interrupt from nRF side, but no need to call ISR NVIC_DisableIRQ(GPIOTE_IRQn); SCB->SCR |= SCB_SCR_SEVONPEND_Msk;

      while (1) { NRF_GPIOTE->EVENTS_PORT = 0; NVIC_ClearPendingIRQ(GPIOTE_IRQn);

       if (nrf_gpio_pin_read(IO_MEMS_INT1_PIN)) {
           __WFE();   // sleep
       }
      
      // either woken up or didn't sleep. Clear event register anyways.
       __SEV();        // Set event register
       __WFE();        // clear event register
      

      // Read MEMS to clear data ready condition... }

    We have been extensively using SEVONPEND bit feature in our solutions. And I am absolutely sure that there is no problem in the hardware with how it works. Maybe you can clarify how you are testing this.

  • Hello Aryan, Thank you for the response. Seemingly, my code should work as expected as the proposed change only changed order of things inside the while loop in a permutable way. The interface between the nRF chip and the ARM cortex is a good clarification. I stick to my opinion that the documentation could be more extensive in decribing this interface. I tested the behavior in debug mode through the J-link interface on the PCA10028 connected to my custom board, by having a breakpoint after the sleep. With this approach I got very infrequent wakeups, whereas a pin polling loop as well as the interrupt-enabled approach got it right. I do have debug led pin toggling further down in the while loop, but I haven't tested the behavior of the code above without the debugger interface. As said, with the interrupt enabled approach it works fine both with and without debugger.

  • Hi Kim,

    I have changed the order in which __WFE is called and the event is cleared, though that is only significant for the first cycle of the loop. Also notice the NVIC_ClearPendingIRQ that was added. It is important to clear the pended interrupt as it is not cleared automatically.

    OK, the debugger should behave correctly with __WFE,Is this the only place you are sleeping? is it possible that the CPU is stuck in some other parts of ISR after wakeup and is not returning the context back to this loop? could I get your project to reproduce that problem on my desk?

  • I think the ClearPendingIRQ might be the crucial trick. As noted there was confusion between nRF events, interrupts and ARM events, I expected that the NRF_GPIOTE->EVENTS_PORT = 0; and __SEV, __WFE sequence would clear all latches, but apparently the interrupt needs to be cleared separately. I will test this soon and report.

Related