I have found the following piece of code on an example from a Nordic employee. I'm curious as to its purpose.
NRF_TIMER0->EVENTS_COMPARE = 0;
Why is the register set, and then read just after?
I think a good answer can be found here:
"The memory barrier instructions, DMB and DSB, can be used to ensure that the write buffer on the processor has completed its operation before subsequent operations can be started. However, it does not check the status of the bus level write buffers. In such cases, if the system is based on AHB or AHB Lite, you might need to perform a dummy read through the bus bridge to ensure that the bus bridge has completed its operation. Alternatively, a SoC design might have a device specific status register to indicate whether the bus system write buffer is idle."
In short, register accesses take place over a peripheral bus, and sometimes the writes are buffered (the idea being to batch a bunch of writes into a burst if you can). But sometimes you need to be sure a register write actually completes before you proceed further through your program, and forcing a read access does this.
You're basically defeating a performance optimization in order to achieve correct program behavior. This is a common pastime in embedded and systems programming. :)
AmiguelS said:Why is the register set, and then read just after?
Have you checked the register description in the Product Specification for any clues?
From the nRF52832 Product Specification v1.4Section 15.8.1 Peripheral Interface, Interrupt clearing
When clearing an interrupt by writing "0" to an event register, or disabling an interrupt using the INTENCLR register, it can take up to four CPU clock cycles to take effect.
So, while I like your answer, and am still thinking about whether your answer is in fact the underlying reason for requiring clearing, I think the answer is not a pipeline flush but merely a implementation of how Nordic's registers work.
I don't think it's really a question of "Nordic's registers." The way ARM SoC designs usually work, ARM Ltd. licenses the ARM CPU core and some related peripheral blocks (like the NVIC, GIC and L2 cache controllers, depending on exactly which CPU you're talking about), while the SoC vendors connect their own custom peripheral blocks. However there are two ways to license the ARM core IP: 1) you get a pre-generated "binary-only" logic block with predefined peripheral interconnect logic (which is cheaper) or 2) you get the IP block "source code" which you can fully customize right down to the instruction level (which is much more expensive). Most SoC companies do the former. Apple is one example of a company that's done the latter.
So unless Nordic pays a lot more money, their peripheral blocks have to use the same bus interconnects as everyone else. In the nRF52832 product spec you mention above, if you look at the block diagram in section 3 (Figure 1), you'll see that peripheral blocks are all connected to the CPU (and NVIC) through an AHB to APB bridge, which is exactly what the link above describes. The ARM SysTick timer is the one device that generates interrupts which is directly attached to the CPU core, and is likely the only one which doesn't require the dummy read.