Closed
Description
see also - http://arduino.cc/forum/index.php/topic,132983.msg1000603.html#msg1000603
The delayMicroseconds function fails when called with a value of 0.
Although this is not done normally it can happen when called with a variable (result of some math). The bug can be traced back to the if (--us ==0) statement
BUG in 0.22 + 1.0.0 + 1.0.2
Find test program and patch below (the patch does not include the 1.0.2 20Mhz addition as I cannot test it)
Note: The patch is for up to 1.0.0 version.
Program to show bug
//
// FILE: delayMicrosecondsBUG.pde
// AUTHOR: Rob Tillaart
// DATE: 2012-11-18
//
// PUPROSE: test delayMicroseconds()
//
void setup()
{
Serial.begin(9600);
Serial.println("start...");
unsigned long m = micros();
for (uint8_t i=0; i<100; i++)
{
delayMicroseconds(0);
}
Serial.println(micros()- m);
m = micros();
for (uint8_t i=0; i<100; i++)
{
delayMicroseconds(1);
}
Serial.println(micros()- m);
m = micros();
for (uint8_t i=0; i<100; i++)
{
delayMicroseconds(2);
}
Serial.println(micros()- m);
m = micros();
delayMicroseconds(20);
Serial.println(micros()- m);
m = micros();
delayMicroseconds(200);
Serial.println(micros()- m);
m = micros();
delayMicroseconds(2000);
Serial.println(micros()- m);
}
void loop()
{}
Find below a patch for the function: (0.22 - 1.0.0)
void delayMicroseconds(unsigned int us)
{
// calling avrlib's delay_us() function with low values (e.g. 1 or
// 2 microseconds) gives delays longer than desired.
//delay_us(us);
#if F_CPU >= 16000000L
// for the 16 MHz clock on most Arduino boards
// for a one-microsecond delay, simply return. the overhead
// of the function call yields a delay of approximately 1 1/8 us.
// PATCH
// if (--us == 0)
// return;
if (us < 2) return;
us--;
// the following loop takes a quarter of a microsecond (4 cycles)
// per iteration, so execute it four times for each microsecond of
// delay requested.
us <<= 2;
// account for the time taken in the preceeding commands.
us -= 2;
#else
// for the 8 MHz internal clock on the ATmega168
// for a one- or two-microsecond delay, simply return. the overhead of
// the function calls takes more than two microseconds. can't just
// subtract two, since us is unsigned; we'd overflow.
// PATCHED LINES
// if (--us == 0)
// return;
// if (--us == 0)
// return;
if (us < 3) return;
us -= 2;
// the following loop takes half of a microsecond (4 cycles)
// per iteration, so execute it twice for each microsecond of
// delay requested.
us <<= 1;
// partially compensate for the time taken by the preceeding commands.
// we can't subtract any more than this or we'd overflow w/ small delays.
us--;
#endif
// busy wait
__asm__ __volatile__ (
"1: sbiw %0,1" "\n\t" // 2 cycles
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
);
}