I have been using the code below to create two offset square waves. It works - with one caveat I can't seem to overcome:
The requested phase shift is 90 degrees. However, running the loop below, it will occasionally give me a shift of 270 degrees instead.
I've set the outputs into toggle mode - and if I missed a toggle, then I can see it would cause these symptoms - but I can't for the moment work out why this might be occuring. Any ideas...?
int ttlA = 9;
int ttlB = 10;
void setup() {
Serial.begin(9600);
pinMode(ttlA, OUTPUT); // Arduino Pin 9 = OCR1A
pinMode(ttlB, OUTPUT); // Arduino Pin 10 = OCR1B
// Set both outputs in toggle mode
TCCR1A = 0x00;
bitSet(TCCR1A, COM1A0);
bitSet(TCCR1A, COM1B0);
TCCR1B = 0x00;
bitSet(TCCR1B, WGM12);
bitSet(TCCR1B, WGM13);
OCR1A = 0; // First output is the base, it always toggles at 0
}
// prescaler of 1 will get us 8MHz - 122Hz
// At 16Mhz, toggling every tick (clocks per toggle=1), we toggle at 16MHz, which gives us 8Mhz frequency
// ICR1 is a 16 bit register, so a maximum value of 2^16=65536
// if clocks per toggle is 65536, then we get 122Hz
#define CLK 16000000UL // Clock speed is 16MHz on Arduino Uno
int setWaveforms(unsigned long freq, int shift) {
//Stop the timer whilst we change things and re-zero the timer registers
TCCR1B = 0x00;
unsigned long clocks_per_toggle = (CLK / freq) / 2; // /2 becuase it takes 2 toggles to make a full wave
ICR1 = clocks_per_toggle;
unsigned long offset_clocks = (clocks_per_toggle * shift) / 180UL; // Do mult first to save precision
OCR1A = 0; //counts until TCNT = O then toggles
OCR1B = offset_clocks; //counts until TCNT = offset_clocks then toggles
// Turn on timer
TCNT1H = 0x00;
TCNT1L = 0x00;
bitSet(TCCR1B, WGM12);
bitSet(TCCR1B, WGM13);
bitSet(TCCR1B, CS10);
}
void loop() {
setWaveforms(1000, 90);
delay(4000);
setWaveforms(1500, 90);
delay(4000);
setWaveforms(2000, 90);
delay(4000);
setWaveforms(2500, 90);
delay(4000);
}
to both setup and in setWaveforms (just before reenabling timer1)
However, on a scope I can still see the pase shift is sometimes 90 degrees, and sometimes 270....
Setting control bits one by one will result in possibly unwanted timer states. Better set the bits in a temporary variable and only write the final value to a timer register.
Yeah, it's puzzling. I couldn't explain the phase shift from the non-atomic bit operations, so I'm not too surprised that this modification hasn't been effective.
It sounds like you may be using a Nano, Uno or 2560 in CTC mode (toggle). If so, it will occasionally flip-phase 180 degrees when trying to adjust the phase-shift angle during run-time.
You can get around this using the Forced Output Compare registers to clean things up during the phase-change. The idea is, stop Timer, reset wavegens to LOW and re-start timer.
There is an example project at Runtime Micro that illustrates how to make run-time changes and achieve (no phase-flip) results. The down-side is your O-Scope won't like the Stop-Start action of code during phase-angle changes. The good news is the phase-flip is gone.