jung6717 / arduino

Automatically exported from code.google.com/p/arduino
0 stars 0 forks source link

delay() is inaccurate. #237

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
delay() has always been pretty inaccurate for low values of milliseconds,
since it is based off of millis() which is update asynchronously to delay()
calls, and sometimes is doubly-incremented (when the overflows catch up.)
This was also changed relatively recently such that millis() is now
supposed to delay for "at least" the specified number of milliseconds, but
this doesn't work all the time (ie if called just before one of those
double-increments) and will "typically" cause delay() to wait significantly
longer than specified.

There is some pretty detailed analysis in this discussion:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1271719397

BenF came up with a new proposed definition of delay() (attached) that
apparently works MUCH better, and is smaller as well.

void delay_x(uint32_t millis_delay)
{
  uint16_t micros_now = (uint16_t)micros();

  while (millis_delay > 0) {
    if (((uint16_t)micros() - micros_now) >= 1000) {
      millis_delay--;
      micros_now += 1000;
    }
  }  
}

Original issue reported on code.google.com by wes...@gmail.com on 29 Apr 2010 at 7:41

Attachments:

GoogleCodeExporter commented 8 years ago
An alternative would be to use Hans-Juergen Heinrichs
delay_x routines with named macro wrappers for backward compability:

http://www.avrfreaks.net/index.php?module=Freaks%20Academy&func=viewItem&item_id
=665&item_type=project

These are very accurate even to sub microsecond range.

Original comment by bperry...@gmail.com on 21 May 2010 at 8:42

GoogleCodeExporter commented 8 years ago
One possible concern with BenF's function is the fact that micros() disables 
interrupts.  They'd only be disabled 
for a few instructions at a time, though.  Do you think this is something that 
could cause problems?

Also, the routines from Hans-Juergen Heinrichs look like they only work with 
compile time constants.  Can't we 
just use the built-in avr-libc functions in that case (along the lines of issue 
256)?

Original comment by dmel...@gmail.com on 25 May 2010 at 8:07

GoogleCodeExporter commented 8 years ago
Also, some notes from Zack777: "I have done some testing of BenF's code 
solution and I think it is the best.  The 
use of uint16 types saves memory.  Overall the code is 20 bytes smaller than 
the existing delay() function.  In 
addition, the accuracy is impressive.  It displays an absolute accuracy of 6 
microseconds on average.  The 
fractional error at the smallest reasonable delay, 1 millisecond, is just 0.6%. 
 I also confirmed that it handles 
rollovers in the micros() counter correctly.  There are no glitches in delay() 
every 70 minutes.  Adopting this code 
also means not having to update the delay() documentation."

Original comment by dmel...@gmail.com on 25 May 2010 at 8:08

GoogleCodeExporter commented 8 years ago
I committed this.  Thanks for the good code, testing, and putting in the issues 
list.  Please test, especially if you 
think disabling interrupt is a concern.

Original comment by dmel...@gmail.com on 25 May 2010 at 8:17