I'm trying to generate 2 PWM signal shifted 180 degrees from each other. I was able to generate them using FAST PWM mode using timer1, but I can not apply phase shift between them. I have tried to add interrupt, but it is not working.
void setup() {
interrupts();
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
//InitTimer1
TCNT1 = 0;
TCCR1A = 0;
TCCR1B = 0;
//set to mode 14 fast pwm to ICR1 top value
//non inverted output on pins 9 (A) and 10 (B)
//ICR1 set frequency OCR1A and OCR1B set duty cycle
//prescaler 8 gives .5 microseconds per timer tick
// TCCR1A
// Bit 7 6 5 4 3 2 1 0
// Bit Name COM1A1 COM1A0 COM1B1 COM1B0 ----- ----- WGM11 WGM10
// Initial Value 0 0 0 0 0 0 0 0
// changed to 1 0 1 0 0 0 1 0
TCCR1A = B10100010;
// TCCR1B prescaler 8 .5us/tick
// Bit 7 6 5 4 3 2 1 0
// Bit Name ICNC1 ICES1 ---- WGM13 WGM12 CS12 CS11 CS10
// Initial Value 0 0 0 0 0 0 0 0
// changed to 0 0 0 1 1 0 1 0
TCCR1B = B00011010;
ICR1 = 99;//Set Top Value, -> frequency 20 kHz with 16 MHz internal clock, count is 0 referenced for 100 ticks
OCR1A = 50; //duty cycle pin 9 value 0-99
OCR1B = 10; //duty cycle pin 10 value 0-99
}
ISR(TIMER1_COMPA_vect) {// Timer1 interrupt service routine
int toggleState;
if (toggleState == false) {
digitalWrite(9, HIGH);
delayMicroseconds(0.025);
digitalWrite(10, HIGH);
toggleState = true;
}
else
{
digitalWrite(9, LOW);
digitalWrite(10, LOW);
toggleState = false;
}
}
void loop() {}
TC1 has two chnnels: Ch-A and Ch-B. You can generate inverted PWM signal on Ch-B by consulting the bits' meanings of the following Register (Fig-1) . What is the frequency of your PWM signal?
Figure-1:
Sketch to genertae 5 kHz PWM (Mode-14) signal: Ch-A and inverted Ch-B
I want to generate 20Khz fast PWM, inverting the pwm will not work for duties less than 50%. For example, at 40% duty cycle I want PWM A to be on 40/100 then off 60/100. for PWM B to be on 40/100 and 60/100 also. there is a period of 20/100 where both of them is off.
at 40% duty cycle I want PWM A to be on 40/100 then off 60/100. for PWM B to be on 40/100 and 60/100 also. there is a period of 20/100 where both of them is off.
I think think this dual slope (mode10) timer setup will do what you want. Compiles but not actually tested.
//Timer1 Mode 10 PWM to ICR1
//Dual pin 20KHz PWM generator
//40% duty cycle 20% dead band between pulses
void setup() {
pinMode(9, OUTPUT); //output A
pinMode(10, OUTPUT); //output B
TCCR1A = 0; //clear timer registers
TCCR1B = 0;
TCNT1 = 0;
//ICR1 and Prescaler sets frequency
//no prescaler .0625 us per count @ 16Mh
//800 counts x .0625 = 50 us = 20Khz 400 up 400 down
//40% = 320 counts
//deadband 160 counts
TCCR1B |= _BV(CS10); //no prescaler
ICR1 = 400;//PWM mode counts up and back down for 800 counts 20Khz
OCR1A = 240 ; //Pin 9 match
//output A set rising/clear falling
//40% Duty Cycle Pulse centered on TCNT 400.
//Rise at TCNT 240 upslope, High 320 counts, Fall at TCNT 240 downslope
TCCR1A |= _BV(COM1A1) | _BV(COM1A0); //output A set rising/clear falling
OCR1B = 160; //Pin 10 match
//output B clear rising/set falling
//40% Duty Cycle Pulse centered on TCNT 0
//Fall at TCNT 160 upslope, Low 480, Rise at TCNT 160 downslope
//40% Duty Cycle Pulse centered on TCNT 0
TCCR1A |= _BV(COM1B1); //output B clear rising/set falling
TCCR1B |= _BV(WGM13); //PWM mode with ICR1 Mode 10
TCCR1A |= _BV(WGM11); //WGM13:WGM10 set 1010
}
void loop() {}
Changing OCR1A and OCR1B with the same values doesn't work properly. For example I want duty of PWM 1 30% and PWM 2 30%. I have tried OCR1A= 200 and OCR1B = 120 but the output is that each PWM is with different duty ratio
For phase shift PWM, you want to use Mode-10 Phase. Fast PWM will not line up correctly for 180 PSPWM except maybe at 50% duty. Assuming you need duty that is variable (at run-time), you'll want Mode-10 Phase PWM with A-channel in Normal compare and B-channel in Complimentary compare. Another gotcha is the Complimentary channel must use 'mirrored' duty-cycle (if A=22%, B=[100-22] % ). In this way, both PWM pulses are positive going but exactly 180 degrees out of phase.
Here's some sample code to run an Uno at 180 degrees PSPWM using Timer1. If you change the A-channel duty, you must change the B-channel to the mirror of A.