BUG: delayMicroseconds(0) leads to a huge delay

Passing zero to the delayMicroseconds function leads to a huge delay. If the parameter is calculated inside of a user code, this zero can be unexpected outcome leading to the confusing huge delay.

In the implementation of the function, in the "wiring.c" file, the function parameter is pre-decremented, effectively switching this zero to a large value.

/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */
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.
if (--us == 0)
return;

// 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.
if (--us == 0)
return;
if (--us == 0)
return;

// 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
);
}

Why would one pass a zero to a delay function? Dangerous I would say.

If the function parameter is being calculated as the output of integer division:

delayMicroseconds(1000/1500); would give a 0 value to the parameter unexpectedly.

So do the calculation first & test it - if the result is less than 3 don't call the delay:
"Caveats and Known Issues
This function works very accurately in the range 3 microseconds and up. We cannot assure that delayMicroseconds will perform precisely for smaller delay-times. "

Marius:
Why would one pass a zero to a delay function? Dangerous I would say.

float my_rate(float x){
    // something here
}
float my_scale = 1.5;

// something here

delayMicroseconds(int(my_scale*my_rate(something_calculated)));

CrossRoads:
So do the calculation first & test it - if the result is less than 3 don't call the delay:
"Caveats and Known Issues
This function works very accurately in the range 3 microseconds and up. We cannot assure that will perform precisely for smaller delay-times. "

I do not accept your argument. It is well expected and understood that delayMicroseconds(0) won't give literally zero delay XD. Nevertheless, it is natural to expect (from the website statement) that the actual delay would be below or somewhat close to delayMicroseconds(3), this would be fine. It is totally unexpected that delayMicroseconds(0) function call produces delayMicroseconds(UINT_MAX) delay. I insist that it is a BUG.

delayMicroseconds(int(my_scale*my_rate(something_calculated)));

I'd INSIST that that code doesn't compensate correctly for the amount of processing necessary to perform those float-point operations. :smiley:

A great deal of the arduino interface is to make it easy to write code: x = digitalRead(pin); instead of low(er) level code.

People expect a certain behavior of these functions, and atetervak is expecting behavior of delayMicroseconds() which is in my opinion 100% reasonable. I also agree with his statement:

Nevertheless, it is natural to expect (from the website statement) that the actual delay would be below or somewhat close to delayMicroseconds(3), this would be fine.

On the other hand his example of the "calculated delay" is not strong, partly because it uses float math that is "slow" compared to micros (as AWOL states). But one could have a similar problem when using integer math, which is in the same order of speed.

But whether you call it a bug or not, it is unexpected behavior, that can easily be fixed by changing a few lines in the code of delayMicroseconds():

(original code)

if (--us == 0)
  return;

==>

(proposed code)

if (us < 2) 
  return;
us--;

where the first would only capture us = { 1 } the second captures both us = { 0,1 }

Not measured as I don't have an arduino at hand, but I expect the accuracy and speed will be similar.
Footprint is increased with 2 bytes (for 328, I do have a compiler :slight_smile: .

Can't report it as a bug/fix at the moment as the site - Google Code Archive - Long-term storage for Google Code Project Hosting. - is not available ...

addition

for the 8 Mhz version of delayMicrosecond()

if (us < 3) 
  return;
us -=2;

Problem reported as an issue - Google Code Archive - Long-term storage for Google Code Project Hosting. -