delayMicroseconds() limit

Hello,

I would like to send a '1' from digital i/o for 3 microseconds and then send a '0' for 3 microseconds.

Tried doing so and observed the outcome via an oscillopscope and what I saw is that my i/o pin was set on '1' and '0' for roughly 13 microseconds rather than 3, also tried to decrease to 1 microsecond however the outcome was the same, 13 microseconds.

Any help is appreciated.

Use port manipulation rather than digitalWrite.

You can read about port manipulation here.

I've used it to get delays down to 62,5ns (one clock cycle), and in steps of 62.5ns.

Thanks you both for your answers.

I am using arduino mega, does this look correct?

void setup()
{
DDRB |= 1 << DDB7; //pin 13 is set as output. 
}

void loop()
{
PORTB |= 1 << PORTB7; //drive pin high
delayMicriseconds(3);
PORTB &= ~(1 << PORTB7);//drive pin low
delayMicroseconds(3);
}

MichaelThe2nd:
I would like to send a '1' from digital i/o for 3 microseconds and then send a '0' for 3 microseconds.

I'm guessing that by '1' you mean 'HIGH' and by '0' you mean 'LOW'. So you want to start with the output LOW, then set it to HIGH and then 3 microseconds later set it to LOW and then three microseconds later set it to HIGH? Of course you can only do that once because now the output is HIGH and you can't change it to HIGH. So you only want to do this once?

“I am using arduino mega, does this look correct?”

You can answer/check this :wink:

“delayMicriseconds”.

You really should turn on error checking in your complier if that was uploaded..

There is some awesome reference material out there that goes over exactly how long each instruction takes to execute. Even delayMicroseconds(0) takes “some” time.

I think this will give you the fastest square wave possible. Adding “_NOP();” lines should increase the period in intervals of 1/16th of a microsecond.

void setup()
{
  DDRB |= 1 << DDB7; //pin 13 is set as output.
}


void loop()
{
  while (1)
  {
    PINB = 1 << PB7; // Toggle output pin
    // Add _NOP(); here to iincrease the period by 1/16th of a microsecond
  }
}

If you want to use the rest of your Arduino for anything you should use Timer1 or Timer2 to generate the square wave frequency you want. It should be able to do 166 2/3 kHz (6 microsecond period) and do it in hardware so the rest of the Arduino to do other stuff.

Unfortunately, that’s too fast for delayMicroseconds().

This should do it (off the top of my head, since I’ve been fiddling with delays in assembler for neopixel output) - this assumes the pin in question is Port B pin 7 (PB7).

byte oldSREG=SREG; //save sreg
cli(); //disable interrupts
PINB=1<<PB7;
asm volatile(
"rjmp .+0"                "\n\t" // 2 clock cycles
"rjmp .+0"                "\n\t" // 4
"rjmp .+0"                "\n\t" // 6
"rjmp .+0"                "\n\t" // 8
"rjmp .+0"                "\n\t" // 10
"rjmp .+0"                "\n\t" // 12
"rjmp .+0"                "\n\t" // 14 // writing PINB1 will take 2 clock cycles, bringing us to 16, ie, 1us on a 16MHz board. 
);
PINB=1<<PB7;
asm volatile(
"rjmp .+0"                "\n\t" // 2 
"rjmp .+0"                "\n\t" // 4
"rjmp .+0"                "\n\t" // 6
"rjmp .+0"                "\n\t" // 8
"rjmp .+0"                "\n\t" // 10
"rjmp .+0"                "\n\t" // 12
"rjmp .+0"                "\n\t" // 14
"rjmp .+0"                "\n\t"//16 //1us
"rjmp .+0"                "\n\t" // 2 
"rjmp .+0"                "\n\t" // 4
"rjmp .+0"                "\n\t" // 6
"rjmp .+0"                "\n\t" // 8
"rjmp .+0"                "\n\t" // 10
"rjmp .+0"                "\n\t" // 12
"rjmp .+0"                "\n\t" // 14
"rjmp .+0"                "\n\t"//16 //2us
"rjmp .+0"                "\n\t" // 2 
"rjmp .+0"                "\n\t" // 4
"rjmp .+0"                "\n\t" // 6
"rjmp .+0"                "\n\t" // 8
"rjmp .+0"                "\n\t" // 10
"rjmp .+0"                "\n\t" // 12
"rjmp .+0"                "\n\t" // 14
);
PINB=1<<PB7; //or whatever you need to do at the end of that 3us; use direct port manipulation if you're writing pins. 
SREG=oldSREG; //reenable interrupts if they were previously enabled.