delayMicroseconds(0) = 16383µs

So, I've noticed that when ever I have a situation such that:

delayMicroseconds(0), the actual delay turns out to be 16383µs.

Obviously I just do a quick work around like such:

if (variable = 0)
{
variable = 1;
}

delayMicroseconds(variable);

does anyone know how to fix the library? It's a little beyond me.

Just sayin.

	__asm__ __volatile__ (
		"nop" "\n\t"
		"nop"); //just waiting 2 cycle
	if (--us == 0)
		return;

Their intention was to run two NOPs and then subtract from us. But they did the subtraction first.

A cure would be to do the test first and then run through that sequence.

@ dhenry,

that's code quote you posted is

#if F_CPU >= 20MHz

However, I'm running the ATmega328P @ 16MHz. so I don't think it applies if the library is working properly...

I made my original measurements with a Tektronix TDS2014B measuring a pulse output on a digital pin.

Obviously I just do a quick work around like such:

I hope not exactly like that.

=

it suffered from the same problem: it performs a subtraction before it performs a test. So a '0' is essentially passed to the call as -1, which is 64k-1, as the argument is cast to unsigned int.

Your choice is to change the code, or recast it to your own version:

#define mydelayMicroseconds(us) do {if (us) delayMicroseconds(us);} while (0)

And change all calls to delayMicroseconds to mydelayMicroseconds.

Or don't call delayMicroseconds with 0.

so....

you think it might be more efficient to write:

#define mydelayMicroseconds(us) do {if (us) delayMicroseconds(us);} while (0)

instead of:

if (variable = 0)
{
variable = 1;
}
delayMicroseconds(variable);

why not both?

if (variable)
{
    delayMicroseconds(variable);
}
if (variable = 0)
{
variable = 1;
}

is STILL wrong!

you think it might be more efficient to write:

I think

mydelayMicroseconds(us);

is a lot easier to write than

if (variable = 0)
{
variable = 1;
}
delayMicroseconds(variable);

If most of your delays are greater than say, 10 us, you can just call delayMicroseconds(delay+1)

or create a Macro:

#define FIX_DELAY(x) ((x==0)?(1):(x))

and call delayMicroSeconds(FIX_Delay(delay));

dhenry:

you think it might be more efficient to write:

I think

mydelayMicroseconds(us);

is a lot easier to write than

if (variable = 0)

{
variable = 1;
}
delayMicroseconds(variable);

Not to mention the fact that:

if (variable = 0)
{
variable = 1;
}
delayMicroseconds(variable);

doesn't do what is wanted... as PaulS has pointed out TWICE!

You could use a macro and be done with it.
You don't even have to change the name.
i.e.

#define delayMicroseconds(us) do { if(us) delayMicroseconds(us);} while(0)

This will work fine. It does add a slight overhead of a runtime check if us is a variable and not a constant
but then any solution that does a run time check on the delay value will have this.

The real question is if you want a delay of 1us when the delay you are asking for is 0?

And my question of curiosity is why are you asking for a delay of zero?
Is this caused by some sort calculation that results in truncation?

--- bill

Just out of curiosity, what is the purpose of the do/while here?

PeterH:
Just out of curiosity, what is the purpose of the do/while here?

It is a way to define a multi statement macro that works regardless of whether used
along side or inside other constructs such an if statement regardless of whether
braces are used.

Suppose the macro were defined as:

#define delayMicroseconds(us) if(us) delayMicroseconds(us)

and then the code that used it were:

if(xxx)
    delayMicroseconds(delay);
else
    foo(); // do other work

If you expand that out it becomes:

if(xxx)
    if (delay) delayMicroseconds(delay);
else
    foo(); // do other work

This silently/unexpectedly changes what the author wanted
in that now foo(); is called if delay is zero
vs if xxx is zero, and when xxx is zero nothing happens.

For readibility here is the resulting code re-formatted

if(xxx)
    if (delay)
        delayMicroseconds(delay);
    else
        foo(); // do other work

This change would not have happened if the original code used brackets

if(xxx)
{
    delayMicroseconds(delay);
}
else
{
    foo(); // do other work
}

But since using brackets is not mandatory for simple statements, the
macro should still work as expected when brackets are not used since it appears to be a simple function.
The do/while essentially turns the multi-statement macro back into a simple/single statement that can work
correctly when braces are not used.

Further reading:

--- bill

maybe a "fast" if is better for readability:

#define delayMicroseconds(us) us?delayMicroseconds(us);

Don't you need a colon in there to complete the ternary operator '?' ?

And the semi colon on the back will break a simple if statement with no braces but an else.

KeithRB:
Don't you need a colon in there to complete the ternary operator '?' ?

the colon is for false statement, isn't it optional?

And the semi colon on the back will break a simple if statement with no braces but an else.

you are right, or you use the define without adding semicolon (not intuitive) or you you remove the semicolon from the define. should be fine.

lesto:

KeithRB:
Don't you need a colon in there to complete the ternary operator '?' ?

the colon is for false statement, isn't it optional?

I think a ternary can have an empty expression 1 but must have an expression 2 (the "else" part after the colon)
To flip it, remove the semi colon, and ensure the ternary expression is fully evaluated before the ! (not) in case they pass
in more than a simple variable or constant you could do

#define delayMicroseconds(us) !(us)?:delayMicroseconds(us)

Works, but I bet it isn't as obvious to most as the do/while(0) loop.
do/while(0) is also much more flexible for future modifications.

But we still need to hear from k7michal as all his examples were attempting
to replace a zero delay with a one Us delay to see if that is really a requirement
and why a zero is being passed in to begin with .

--- bill