I am trying to generate a 1 MHz clock and synchronize an output pulse to the generated 1 MHz clock.
The generation works fine, the synchronizing does not.
I thought I could sample the output clock using PINB until I saw it go from low to high in order to find the rising edge, then output my pulse.
The output pulse is not consistently placed relative to the rising edge. It's always placed during the same half-cycle of the clock, but it can be in any of 8 different places.
Any help is appreciated!
//use timer/counter 1 to generate a 1MHz square wave on Arduino pin 9
//output a pulse synchronized with the 1MHz clock
const int pulseOutPin = 7;
const int clkOutPin = 9;
int newTemp = 0;
int oldTemp = 0;
void setup() {
TCCR1A = _BV(COM1A0); //toggle OC1A on compare match
OCR1A = 7; //top value for counter, 7 = 1MHz
TCCR1B = _BV(WGM12) | _BV(CS10); //CTC mode, prescaler clock/1
pinMode (pulseOutPin, OUTPUT);
pinMode (clkOutPin, OUTPUT);
}
void loop() {
oldTemp = PINB & B00000010;
newTemp = PINB & B00000010;
if (newTemp == 2 && oldTemp == 0){
PORTD = PORTD & B01111111; //take pulseOutPin low for 1 cycle to show sync
PORTD = PORTD | B10000000; //take pulseOutPin high again
}
}
Here is a scope image of my output. The yellow trace shows the 8 different locations of the output pulse. This was taken with infinite persistence. On any one cycle there is only one pulse, 125 ns wide, at one of the 8 locations.
I would like to get the output to be at the same location every time.
Thanks for the suggestion!
Here's some new code using interrupts, followed by a new scope plot.
Why is the output still varying in time? In the scope plot, the left pulse trails the rising edge of the 1 MHz clock by 5 cycles, the center pulse trails the rising edge by 6 cycles, and the right pulse trails the rising edge by 7 cycles. The placement appears random, but it is always one of these 3 positions. Why aren't they always in the same position?
They all appear to be trailing the rising edge by 5-7 cycles. I don't think I am doing anything to make them favor the rising edge rather than the trailing edge. Why do they never trail the falling edge?
Any help is appreciated!
//use timer/counter 1 to generate a 1MHz square wave on Arduino pin 9
//output a pulse synchronized with the 1MHz clock
const int pulseOutPin = 7;
const int clkOutPin = 9;
ISR(TIMER1_COMPA_vect)
{
PORTD = PORTD & B01111111; //take pulseOutPin low for 1 cycle to show sync
PORTD = PORTD | B10000000; //take pulseOutPin high again
}
void setup()
{
TCCR1A = _BV(COM1A0); //toggle OC1A on compare match
OCR1A = 7; //top value for counter, 7 = 1MHz
TCCR1B = _BV(WGM12) | _BV(CS10); //CTC mode, prescaler clock/1
TIMSK1 = bit (OCIE1A); //interrupt on Compare A Match
pinMode (pulseOutPin, OUTPUT);
pinMode (clkOutPin, OUTPUT);
}
void loop() {}
PORTD = PORTD & B01111111; //take pulseOutPin low for 1 cycle to show sync
PORTD = PORTD | B10000000; //take pulseOutPin high again
With this:
PIND = 0b10000000; // toggle state of bit 7 by writing 1 to input register
PIND = 0b10000000; // toggle state of bit 7 by writing 1 to input register.
The variation - 1 MHz is a change every 16 system clocks. Interrupt takes a couple clocks to save states on the stack/heap etc, jump to the ISR code, do that part, and return.
You would think it'd be a bit more deterministic, I can't really explain the variation.
There are other things going on as well as your code eg the counts for micros and mills which will delay taking action on the external interrupt. I think the arduino is just to slow for this job. A hardware only solution would work much better.
Crossroads, I see you were going for the 'toggle'. I'm not sure at all why that made it so much worse.
David, thank you for the suggestion. Much of my learning came from that site. My sketch is VERY similar to his 'Timer Interrupts' example, with the exception that I also use the 'toggle on compare match' function of the counter.
I got the 1 MHz output working, and then when I saw his example for the Timer Interrupts which only added 1 line to the timer setup and a simple ISR, I felt sure it would work.
Mark, you may be right. That was my initial feeling, but I'm pretty close. Is there a way to kill millis and micros so I can see if that is what causes the jitter? I considered switching to a UNO32 for the additional speed, but I'd have to relearn the timers and interrupts.
The only way I can think of to get rid of mills etc is to use AVR studio. But you maybe able to turn them off.
A hardware only solution would also be cheaper.
Mark
Unfortunately that also keeps you from reacting to the 1 MHz.
Not if,
Just thinking that you could (assuming that you will never do anything else in this program) then you could put a loop forever in your ISR. The asm would look something like this
ISR(
label: set pin high
set pin low
nop * n // n = right number of nops to waste the rest of the micro second
jump label
)
Of course the Arduinos 16MHz freq has a lot of slop in it and will drift. Only the first edge of your 1MHz clk is ever, used just start the ISR.
The ISR has to wait for the currently executing instruction to finish. This could be one source of jitter. Another is that once the ISR completes, at least one instruction in the program is executed.