I investigated precision of delayMicroseconds(x) Function

BLOG_POST

I highly Recommend reading my Blog Post above, there are graphs & Program & everything.

Basically, I found out that delayMicroseconds(x) delays (on Arduino UNO, 16MHz)

  1. 7 Clock cycles for (x = 0, 1)

  2. 14 Clock cycles Short for (x >= 2)

I noticed a too quick delay on 'x = 2' case. And that was why I investigate this whole situation.

The Reason I am posting on here is to share this test result + get feedback.

If you guys have any suspicion on the accuracy of my Code, or find some errors, OR, can find the reason why I noticed some bugs in my program(in the Post), PLEASE let me know whether through this Forum, or through WordPress comments.

Thank You So Much.

Yeah; it looks like the addition of Link Time Optimization has seriously compromised the accuracy of delayMicroseconds when it is used with a constant argument. Various bits of math inside the code that are carefully accounted for just aren't happening any more, and function call overhead (also accounted for) doesn't happen because the code is inlined.

Suggested workaround: use the avr-libc functions described here instead: avr-libc: <util/delay.h>: Convenience functions for busy-wait delay loops (make sure you understand the limitations of these, though. they ONLY support constant values in their arguments!)

westfw:
Yeah; it looks like the addition of Link Time Optimization has seriously compromised the accuracy of delayMicroseconds when it is used with a constant argument. Various bits of math inside the code that are carefully accounted for just aren't happening any more, and function call overhead (also accounted for) doesn't happen because the code is inlined.

Suggested workaround: use the avr-libc functions described here instead: avr-libc: <util/delay.h>: Convenience functions for busy-wait delay loops (make sure you understand the limitations of these, though. they ONLY support constant values in their arguments!)

Thanks for your input, I saw your issue on Arduino Repository. (I don't know assembly language :slight_smile: )

So at the Blog Post, I mentioned that calling, for example, delayMicroseconds(10) => 10 Times would sometimes only delay about 3 microseconds... And I thought there was something wrong with my code...

Do you think you know any reason this might be possible? And if 'Link Time Optimization' related to it, can you please explain how that can cause the symptom I observed?

I mentioned that calling, for example, delayMicroseconds(10) => 10 Times would sometimes only delay about 3 microseconds.

I didn't see that in the post. I looked again and I still don't see it...
You should disable interrupts around the actual delay; an unlucky interrupt might take a couple of us, and cause timer overflow when you weren't expecting it.

Wait; are your results all from your test program, or from other attempts as well. AFAIK, the problem I noticed should only happen when calling delayMicroseconds() with a constant argument; your example where you constantly vary the time in a loop should behave differently (and less "wrong.") Hmm. I guess I should look at things more closely!

westfw:
I didn't see that in the post. I looked again and I still don't see it...
You should disable interrupts around the actual delay; an unlucky interrupt might take a couple of us, and cause timer overflow when you weren't expecting it.

Wait; are your results all from your test program, or from other attempts as well. AFAIK, the problem I noticed should only happen when calling delayMicroseconds() with a constant argument; your example where you constantly vary the time in a loop should behave differently (and less "wrong.") Hmm. I guess I should look at things more closely!

  1. Sorry if you couldn't see that. It was in almost at the end of the Blog Post.
    I captured the part where I explained it.
    You can see the screenshot from Here : SCREENSHOT_BLOG
    And after reading what you suggested about 'unlucky interrupt', I think that is Highly possible.

Because this program always gave the same, Buggy (delaying too less) result in Exactly same Numbers. So this meant that Program has some internal situation going on, precisely timed since Startup. And most likely that would be an Interrupt. Otherwise, how can Exactly Same Buggy Numbers Appear always??(It is not a luck)


  1. Yes, all the result was from one single experiment.

And that result is very consistent if I set "TEST_COUNT" to 5. Otherwise, mostly when it Increased, it spitted out Buggy results. Which I suspect, is because the Test was long enough to meet an 'unlucky' interrupt During delayMicroseconds(x) Execution.

Have a Nice Day :slight_smile:

Heh. It works much better using MiniCore, with lto turned off:

NOW, testing delayMicrsoeconds()

0: 16, 16, 16, 16, 16, Average : 16.00 Stddev : 0.00
1: 16, 16, 16, 16, 16, Average : 16.00 Stddev : 0.00
2: 32, 32, 32, 32, 32, Average : 32.00 Stddev : 0.00
3: 48, 48, 48, 48, 48, Average : 48.00 Stddev : 0.00
4: 64, 64, 64, 64, 64, Average : 64.00 Stddev : 0.00
5: 80, 80, 80, 80, 80, Average : 80.00 Stddev : 0.00
6: 96, 96, 96, 96, 96, Average : 96.00 Stddev : 0.00
7: 112, 112, 112, 112, 112, Average : 112.00 Stddev : 0.00
8: 128, 128, 128, 128, 128, Average : 128.00 Stddev : 0.00
9: 144, 144, 144, 144, 144, Average : 144.00 Stddev : 0.00
10: 160, 160, 160, 160, 160, Average : 160.00 Stddev : 0.00
11: 176, 176, 176, 176, 176, Average : 176.00 Stddev : 0.00
12: 192, 192, 192, 192, 192, Average : 192.00 Stddev : 0.00
13: 208, 208, 208, 208, 208, Average : 208.00 Stddev : 0.00
14: 224, 224, 224, 224, 224, Average : 224.00 Stddev : 0.00

Wow, does minicore and arduino differ so much?

Your result is really accurate!!

MiniCore provides a Tools > Compiler LTO menu that allows you to disable LTO. I suspect if you install Arduino AVR Boards 1.6.11 (the last version before LTO was added) you will get the same results as MiniCore.