Go Down

Topic: BUG: delayMicroseconds(0) leads to a huge delay (Read 2198 times) previous topic - next topic

atetervak

Aug 03, 2011, 11:22 pm Last Edit: Aug 03, 2011, 11:27 pm by atetervak Reason: 1
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
   );
}

Marius

Why would one pass a zero to a delay function? Dangerous I would say.
Rather people think you to be a fool than you open your mouth and confirm it.

Aeturnalus

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.

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 delayMicroseconds will perform precisely for smaller delay-times. "

Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

atetervak


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

Code: [Select]
float my_rate(float x){
   // something here
}
float my_scale = 1.5;

// something here

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



atetervak

#5
Aug 04, 2011, 04:47 pm Last Edit: Aug 04, 2011, 04:50 pm by atetervak Reason: 1

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.

AWOL

Code: [Select]
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.     :D
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

robtillaart


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:
Quote
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)
Code: [Select]
if (--us == 0)
  return;


==>

(proposed code)
Code: [Select]
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 :) .

Can't report it as a bug/fix at the moment as the site - http://code.google.com/p/arduino/issues/list - is not available ...


Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

addition

for the 8 Mhz version of delayMicrosecond()

Code: [Select]
if (us < 3)
  return;
us -=2;
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart


Problem reported as an issue  - http://code.google.com/p/arduino/issues/detail?id=576 - 
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up