I am running on an STM32F0xx micro, and I have the following code that simply toggles a pin using blocking delays (yes I know blocking delays are bad, not point here).
uint32_t ticks = 0;
// Disable interrupts
__disable_irq();
for (int bit = 0; bit < 10; bit++) {
// Toggle pin high
WritePin(GPIO_PIN_SET);
ticks = 500;
while (ticks--) {
__NOP();
}
// Toggle pin low
WritePin(GPIO_PIN_RESET);
ticks = 500;
while (ticks--) {
__NOP();
}
// Repeat
WritePin(GPIO_PIN_SET);
ticks = 500;
while (ticks--) {
__NOP();
}
WritePin(GPIO_PIN_RESET);
ticks = 500;
while (ticks--) {
__NOP();
}
}
__enable_irq();
I disable interrupts to make sure nothing else is going on at this point. When I scope these waveforms, I see 10 clock periods; however, the periods of these waveforms do not all match. All even waveforms (0,2,4,6,8) have the same period, and all odd waveforms (1,3,5,7,9) have the same period, but the even and odd waveforms differ by a significant amount (%12). The even waveforms correlate to the first delay toggling, and odd to the second in the for loop. I do not have any idea why these would differ in period. Anyone have any insight here?
See this documentation about NOP
on ARM Cortex-M0 core:
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/CHDJJGFB.html
Operation
NOP performs no operation and is not guaranteed to be time consuming. The processor might remove it from the pipeline before it reaches the execution stage.
Use NOP for padding, for example to place the subsequent instructions on a 64-bit boundary.
To that, you must add other varying factors like pipeline refills (due to branching) and flash wait-states (varying because the instruction blocks in different loops might not be aligned perfectly for the flash accelerator).
The only reliable way to perform precise delays is to use timer.