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?
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
}
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.
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?
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.
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.