Implementing a delay with a for-loop (and why it’s not a good idea)
I thought I’d interject on a specific issue that some of our students have been encountering, and that is how to implement a delay in C or C++ on the new Arm Compiler v6.
Remember that the compiler is what converts your C/C++ code to machine code. In doing this, there is a balance to be struck:
- How efficient that conversion is (speed / size)
- How much it aligns to the C code you write (making it easier to debug)
In the new compiler v6, it would seem there has been a shift towards point 1 at the expense of point 2.
Consider the following code that might be temped to write as a simple delay:
for (unsigned int n=0; n<10; n++) { }
If you write this, consider it’s meaning…. “Do nothing 10 times”.
- From the compilers perspective, maintaining this loop is considered an overhead (it’s not producing any useful output – it’s just a iteration mechanism), which compilers always aim to reduce or better, remove.
- The body of the loop contains no instructions, so there is nothing to compile in the loop block
An optimising compiler will look at this and consider the impact it has on the memory and hardware state before and after, to which the answer is NOTHING. Like most modern compilers, it will simply remove this code because it does nothing.
So what if you wanted to keep this code?
The simple answer is to give it something to repeat. The simplest is a single “nop” assembly instruction (it stands for no operation, which simple consumes one instruction cycle)
So, we rewrite the code as follows:
for (unsigned int n=0; n<10; n++) { asm("nop"); }
Now the loop has something purposeful to repeat, and this is clearly intentional (as expressed by the programmer), so the loop remains in the code, at least using the default settings.
Now watch the following video:
https://plymouth.cloud.panopto.eu/Panopto/Pages/Viewer.aspx?id=b1559069-70ba-4f72-a00b-aae900e597ae
In summary:
- If the for loop is just an overhead, the compiler might try to remove it and “unfold” the loop (assuming there is something to unfold!). It will only do this if there is sufficient memory.
- There needs to be something to repeat or some form of state change, otherwise the loop may be removed
- it is far better to poll a timer or use a timer interrupt to implement a loop.