Skip to content

delayMicroseconds(0) delays far longer than expected. [imported] #576

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
cmaglie opened this issue Nov 15, 2012 · 3 comments
Closed

delayMicroseconds(0) delays far longer than expected. [imported] #576

cmaglie opened this issue Nov 15, 2012 · 3 comments
Labels
Type: Duplicate Another item already exists for this topic

Comments

@cmaglie
Copy link
Member

cmaglie commented Nov 15, 2012

This is Issue 576 moved from a Google Code project.
Added by 2011-08-05T07:49:00.000Z by [email protected].
Please review that bug for more context and additional comments, but update this bug.

Original labels: Type-Defect, Priority-Medium

Original description

What steps will reproduce the problem?

See - http://arduino.cc/forum/index.php/topic,68383.0.html

Due to predecrement of the param us, the function does not work as expected when the param is 0.

snippet of the code:

void delayMicroseconds(unsigned int us)
{
if (--us == 0)
return;
...

What is the expected output? What do you see instead?

Expected an immediate return;
See, long busy wait

Please provide any additional information below.

Fix proposed - http://arduino.cc/forum/index.php/topic,68383.msg504892.html#msg504892

replace
if (--us == 0)
return;

with (16 Mhz)
if (us < 2)
return;
us--;

Fix not tested.

@RobTillaart
Copy link

Patched version of the function delayMicroseconds()

/* 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 zero- or one-microsecond delay, simply return.  the overhead
// of the function call yields a delay of approximately 1 1/8 us.

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 zero-, 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 < 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
);

}

@RobTillaart
Copy link

updated for 20Mhz

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 >= 20000000L
    // for the 20 MHz clock on rare Arduino boards

    // for a one-microsecond delay, simply wait 2 cycle and return. The overhead
    // of the function call yields a delay of exactly a one microsecond.
    __asm__ __volatile__ (
        "nop" "\n\t"
        "nop"); //just waiting 2 cycle
    if (us <= 1)
        return;
    us--;

    // the following loop takes a 1/5 of a microsecond (4 cycles)
    // per iteration, so execute it five times for each microsecond of
    // delay requested.
    us = (us<<2) + us; // x5 us

    // account for the time taken in the preceeding commands.
    us -= 2;

#elif 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.

//  FIX
//  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.


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

@agdl agdl added the Type: Duplicate Another item already exists for this topic label Jan 9, 2015
@agdl
Copy link
Member

agdl commented Jan 9, 2015

See #1121

@agdl agdl closed this as completed Jan 9, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Duplicate Another item already exists for this topic
Projects
None yet
Development

No branches or pull requests

5 participants