Is clearing the NRF_UART_EVENT_RXDRDY really sufficient before exiting the IRQ handler? Since Cortex M4 is used, there's no need to clear the pending register (to avoid the interrupt from firing continually) or that's done by nordic internally?
Is clearing the NRF_UART_EVENT_RXDRDY really sufficient before exiting the IRQ handler? Since Cortex M4 is used, there's no need to clear the pending register (to avoid the interrupt from firing continually) or that's done by nordic internally?
Hello,
Yes, it's sufficient to clear the peripheral event register. The IRQ pending bit will become cleared once you exit the ISR. But it might be woth noting that it can take a few CPU cycles for the peripheral event register to become cleared, please see "Interrupt event clearing" for more details.
Best regards,
Vidar
Thanks. So typically certain interrupts are cleared by reading the register itself? When do clearing the pending register come into the picture?
Thanks. So typically certain interrupts are cleared by reading the register itself? When do clearing the pending register come into the picture?
You must write '0' to the event register to clear the event. The only purpose of doing a "dummy" read after is to ensure that write will be performed before exiting the interrupt handler. Here is a more detailed explanation copied from the product specification:
Clearing an interrupt by writing 0 to an event register, or disabling an interrupt using the INTENCLR register, can take up to four CPU clock cycles to take effect. This means that an interrupt may reoccur immediately, even if a new event has not come, if the program exits an interrupt handler after the interrupt is cleared or disabled but before four clock cycles have passed.
Care should be taken to ensure the compiler does not remove the read operation as an optimization. If the program can guarantee a four-cycle delay after an event is cleared or an interrupt is disabled, then a read of a register is not required. (link)
When do clearing the pending register come into the picture?
All the program has to do is to clear the peripheral event register(s). Bits in the NVIC IRQ pending register are cleared automatically once the program exits the interrupt handler.
Looking at Figure 1 here and trying to relate to your description: does writing 0 to the event register result in a signal with a value of 0 which is sent out to the NVIC? Where's what we write (0 to event register) indicated in the figure? Also, what's PPI?
Is there a circuit diagram that involves both the pending register and the event register? I was curious to see how does writing 0 to event register really stops further interrupts from reocurring till the next one arrives.
To avoid an interrupt reoccurring before a new event has come, the program should perform a read from one of the peripheral registers
So basically after setting the event register to 0, the same register should be read right after to reduce the delay in terms of the number of cycles?
I would argue that instead of reading back the register and worrying about optimisation issues the DSB instruction should instead be used as that also handles bus latency. I have tested this and had no failures:
// Data Synchronization Barrier: continues when all explicit memory accesses before this instruction complete __DSB();
I should add that enabled interrupts from hardware events are generally level-sensitive, not edge-triggered, so unless the event is set to '0' it will continue to generate interrupts when the interrupt handler exits. Once the hardware event register has been set to '0' since many peripherals use a 16MHz clock instead of the 64-MHz clock it can take up to 4 clock cycles from the clear instruction in some cases. Being picky, I would suggest the DSB instruction to ensure the memory address (hardware event register) write completed, then take some extra NOPs depending on the number of cycles DSB requires; not sure if DSB is single-cycle. Edit: yes single cycle but will use 0, 1, 2 or 3 waitstates depending on cache enabled. Hmm, so how many NOPs worst-case, maybe 3 with no cache, 1 with cache hit or execute from SRAM.
Thanks for the additional input hmolesworth. The designers are aware of DSB instruction, but they still ended up with the recommendation to perform a dummy read. I'm not sure what the reasoning was. Although I agree it's not perfect considering it may get optimized away by the compiler. Either way, I think both the DSB instruction and dummy read should be redundant in most cases unless you are implementing a very minimal interrupt service routine.
Looking at Figure 1 here and trying to relate to your description: does writing 0 to the event register result in a signal with a value of 0 which is sent out to the NVIC?
Hmolesworth explained this best. The interrupt will be trigger again instantly if the peripheral event register still reads '1' when you exit the interrupt handler.
The other signal is going to the PPI — Programmable peripheral interconnect, a module which let you connect EVENT registers from one peripheral to a TASK register in another. As an example, you can use the PPI to make a periodic TIMER event trigger the SAADC sample task with no CPU involvement.
Is there a circuit diagram that involves both the pending register
The (IRQ) pending register is in the NVIC, which is a part of the ARM Cortex M4 architecture. This module is covered by the documentation from ARM.