Is an Arduino fast enough to delay a signal by microseconds?

I want to take an input square wave (say 1Hz), and have it output the same wave, but delayed by X amount of microseconds (where X is say 1-1,000,000).

I was thinking of just having the Arduino detect rising edges on the input wave, wait X microseconds, then output high, then output low, etc.

I can't seem to find an elegant way to do this. I have been looking at how to use the 16-bit timer1. However, the datasheet for it is not very informative and I can't find very many examples explaining the syntax of timer1 or how to use it in general.

Anyone know if/how an arduino could do this? Or should I take a look at other microcontrollers?

My first thought is to use an interrupt pin for the input. In the interrupt, either re-generate the output for "short" delays (I'd say in the 1us - 10us range) otherwise set a timer to generate the interrupt for "long" delays.

The difficulty will be the tight 1us minimum delay: handling an interrupt and deciding what to do and generating a signal output all in 16 processor cycles will be challenging, and having written that I'm going to say "impossible". You'll need a faster processor, or be resigned to delays longer than 1us.

The other difficulty is precision: generating the output at EXACTLY the delay that you want. Your numbers suggest you want 1us resolution. That's 16 processor cycles, and should be doable, but might require some oscilloscope work and some tweaking.

Just some initial thoughts....

--
The Gadget Shield: accelerometer, RGB LED, IR transmit/receive, speaker, microphone, light sensor, potentiometer, pushbuttons

you could do it but for small values of x you'd have to be running right on the metal with no timer involved, just spinning instructions to soak up the delay. At delays in the dozens or hundreds of uS you could use standard arduino routines but you'd have some jitter. if the micro doesn't have to do anything else it might just be easier to keep the spin-type delay. Have a look at the beginning parts of delayMicroseconds().

maybe you should describe what you're doing overall though and you might get some better ideas - maybe discrete components or analog delays. I wonder if you really care whether a delay is 1,2, or 3 uS, if so do you care if it's 41,42, or 43 etc. At some point surely it doesn't matter. also, how will it know how long to delay the pulses?

bill2009:
maybe you should describe what you're doing overall though and you might get some better ideas - maybe discrete components or analog delays. I wonder if you really care whether a delay is 1,2, or 3 uS, if so do you care if it's 41,42, or 43 etc. At some point surely it

We have a photon detector that we want to check the timing resolution for by shooting photons at it at regular intervals and want to compare it to a 1MHz input signal. If we can delay that 1MHz signal precisely and check everything on a scope and whatnot, we can make sure that if we are shooting say 1KHz photon pulses at it that that's what we actually read out.

Not sure off the top of my head whether 1, 2, or 3 is more important than 41,42,43, but for now if it is possible to be able to do the latter and not the former, I think that would make a good start. Is the arduino accurate enough to be able to specify a delay of say 243 microseconds vs 244 microseconds?

how will it know how long to delay the pulses?

I assume I would just be able to change a number in the code and re upload it to the arduino? I will have it hooked up to the computer at all times, it doesn't need to be a stand alone circuit.

you can certainly do a fixed delay of a few microseconds by using an interrupt routine and just spinning the required number of instructions. 1 uS would be doable but 2 or 3 would be easy enough.

I would start by setting up attachInterrupt(0, your routine, CHANGE) and use direct port manipulation in your routine to copy what you see on pin 2 to your output. Scope the input and output and the delay should be under a uS but maybe not much under. Then you can stick a few padding instructions into the start of your routine to bring it to where you need. Don't use any arduino digitalRead, write or other functions.

bill2009:
Scope the input and output and the delay should be under a uS but maybe not much under. Then you can stick a few padding instructions into the start of your routine to bring it to where you need. Don't use any arduino digitalRead, write or other functions.

I was initially using read and write and it cant seem to give a nice square wave ona scope past a few KHz... I don't have much experience with an arduino yet - how would I go about copying the input of one pin to the output of another w/o using read/write?

http://www.arduino.cc/playground/Learning/PortManipulation

This should be helpful.

bill2009:
Then you can stick a few padding instructions into the start of your routine to bring it to where you need.

What kind of functions? would delayMicroseconds() be viable in this section?

growler:
http://www.arduino.cc/playground/Learning/PortManipulation

This should be helpful.

Thanks I will check that out. I hate how these learning pages don't have any examples that you can run to play around with =\

@csnsc14320:
Would this not be sufficient?
http://www.arduino.cc/en/Reference/DelayMicroseconds

I used it for timing purposes while interfacing with a 24-bit ADC, where precision of down to 5-10 microseconds was necessary; worked well.

I would probaby say the AVR is capable of doing what you want, but not necessarily the Arduino - you'll have overhead of timer interrupts with Arduino, which will introduce jitter to your delay.
This may or may not be a problem for you.

Below some code to get you started; I propose to have a separate IRQ for the rising edge and the falling edge. This way you don't need to access a state variable which makes it a (few) clockcycle(s) faster again. Furthermore the code has two #defines so the delay for the RISING and FALLING edge can be tuned separately. To get this working the signal should be connected to both pin 2 and pin 3.

#define DELAYUP 42
#define DELAYDOWN 42

// please note that output pin 7 is hard coded in this sketch, to change it 

void IRQup()
{
  // DELAY PART
  delayMicroseconds(DELAYUP);  
  // SET PIN 7 HIGH
  PORTD = B10000000;  // bit 7 === PIN 7 
  // PORTD = PORTD |  B10000000;  // better but a bit slower =>  keeps other values in register intact
}

void IRQdown()
{
  // DELAY PART
  delayMicroseconds(DELAYDOWN);
  // SET PIN 7 LOW
  PORTD = B00000000; 
  // PORTD = PORTD & B01111111;  // keeps other values in register intact
}

void setup()
{
  Serial.begin(115200);
  Serial.println("Photon delay 0.1");  // reminder for what has been configured

  Serial.print("  UP delay: ");
  Serial.println(DELAYUP, DEC);
  Serial.print("DOWN delay: ");
  Serial.println(DELAYDOWN, DEC);

  pinMode(7, OUTPUT);
  digitalWrite(7, LOW);  // initial state output pin

  pinMode(2, INPUT);    // is irq 0 pin
  pinMode(3, INPUT);    // is irq 1 pin

  attachInterrupt(0, IRQup, RISING);
  attachInterrupt(1, IRQdown, FALLING);
}

void loop() {}  // do nothing

If the delay should be really small (< 2 us) tune it with assembler instructions: a NOP is an instruction that does nothing except burning one CPU cycle.
By adding nops you could tune it in steps of 1/16 us. (2 us = 32 nops)

void IRQup()
{
  // DELAY PART made with nops
  asm volatile(
   "nop"
   "nop"
   "nop"
   );
  // SET LINE HIGH
  PORTD = B10000000; 
}

Finally a combination is very well possible. use delayMicroSeconds() for the "big" delay and add some nops for finetuning. remember that because every edge has a separate IRQ, you can finetune them independantly.

void IRQup()
{
  // DELAY PART - finetuned
  delayMicroseconds(DELAYUP);  
  asm volatile(
   "nop"
   "nop"
   "nop"
   );
  // SET LINE HIGH
  PORTD = B10000000;  // bit 7 === PIN 7 
}

Tweak with care :wink:
Rob

I am not sure what the OP is up to but these things were thrashed out in:-

Is he I wonder capable of understanding answers.

Is he I wonder capable of understanding answers.

Maybe he is, maybe not; maybe someone in his team or his boss, teacher, parent, kid etc, don't know. I do know by a quick look at the other thread that he has enough information to get started building and experimenting.

csnsc14320:
arduino accurate enough to be able to specify a delay of say 243 microseconds vs 244 microseconds?

I read somewhere that the AVR only had repeatability down to 2uS. If true, then no, not reliably. But that's hearsay. And frankly, I don't even remember where I read it.

Gerg,
I think you may be referring to delayMicroseconds having a min delay of 4uS.
I think that's documented in the Reference section.

That could be. I've been doing lots and lots of reading over the last couple of days. I very well could be confused here.

Something else to consider, IIRC, the typical crystal used on an arduino seems have an error of 50ppm. If accuracy is important with us repeatability, chances are a different crystal should be used. Doesn't a typical wristwatch have an error of 10ppm-20ppm? And if the experiment is to run over the span of minutes or hours, those errors really start to add up. Or did I misunderstand, whereby, timing is strictly provided by an external clock?

Or did I misunderstand, whereby, timing is strictly provided by an external clock?

Yes you did ... it is.

10ppm crystals are available, for example

For a couple dollars more, 0.5ppm oscillators are available, for example

robtillaart:
Below some code to get you started

This is amazing! Thank you - I will play around with this and try to get it to what I need it to. I am new to the idea of ports so actually seeing some of the syntax is really helpful.

Grumpy_Mike:
I am not sure what the OP is up to but these things were thrashed out in:-
Detecting a change from LOW to HIGH on a pin - #18 by system - Programming Questions - Arduino Forum
Is he I wonder capable of understanding answers.

I am just trying to get an idea of how this can be done from varying view points. There seems to be a number of ways to do this - port manipulation, using timer1, disregarding the arduino and just going for flip flops... I wanted to get multiple perspectives from different sub-forums to find the most efficient way of doing this.