I try to use three PWM pins on an Arduino Nano, each with 10kHz. I know that there are timer0, timer1 and timer3 but I wonder if I can combine them while ensuring all three PWM pins to be in sync and working at 10kHz. Additionally, I want to vary their duty cycle to have 3 cases.
Case 1: pin1 = OFF, pin2 = OFF, pin3 = OFF
Case 2: pin1 = ON, pin2 = ON, pin3 = OFF
Case 3: pin1 = ON, pin2 = OFF, pin3 = ON
The cases are changed at a frequency (f_act) of e.g. 0.25Hz
My code tried to just add a third PWM pin to the timer, which obviously does not work but illustrates my intention.
// ---------------------------------------------------------------------------
// 3-Channel synchronized PWM (software using Timer1) for high freq. PWM (10kHz)
// + State machine for custom actuation frequency (0.25Hz) (case1 → case2 → case3)
// ---------------------------------------------------------------------------
// choose desired HV output: HV = -0.0104*D^2 + 0.5791*D + 1.3643
// --> D_BUCK = (0.5791 - sqrt(0.5791*0.5791 - 4 * 0.0104 * (HV - 1.3643))) / (2 * 0.0104)
const uint16_t HV = 5; // [kV]
const uint16_t D_HV = (0.5791 - sqrt(0.5791 * 0.5791 - 4 * 0.0104 * (HV - 1.3643))) / (2 * 0.0104);
// prescaler*(1+TOP)=f_arduinoNano/f_PWM=16MHz/10kHz and TOP=resolution
const uint16_t prescaler = 1;
const uint16_t fPWM = 10000; // [Hz]
const uint16_t TOP = 16000000 / fPWM / prescaler - 1; // 1599 for 10 kHz with prescaler=1
volatile uint16_t dutyBUCK = 0;
volatile uint16_t dutyOC1 = 0;
volatile uint16_t dutyOC2 = 0;
// choose PWM 3 pins:
const uint8_t BUCK_pin = 5;
const uint8_t OC1_pin = 6;
const uint8_t OC2_pin = 7;
// Case switching variables
uint8_t caseNum = 1; // start in idle
unsigned long lastSwitch = 0;
const unsigned long switchInterval = 2000; // [ms] 4s = 0.25 Hz --> Charge&dis- same duration --> 4s/2
void setup() {
pinMode(BUCK_pin, OUTPUT);
pinMode(OC1_pin, OUTPUT);
pinMode(OC2_pin, OUTPUT);
// Timer1 configuration
cli(); // disable interrupts
TCCR1A = 0;
TCCR1B = 0;
// fast mode of Timer1: WGM13 1 WGM12 1 WGM11 1 WGM10 0
TCCR1A |= (1 << WGM11); // contains WGM10 and WGM11
TCCR1B |= (1 << WGM13) | (1 << WGM12); // contains WGM12 and WGM13
ICR1 = TOP; // set TOP (100% duty cycle)
TIMSK1 |= (1 << TOIE1); // overflow interrupt
TIMSK1 |= (1 << OCIE1A); // compare A
TIMSK1 |= (1 << OCIE1B); // compare B
TIMSK1 |= (1 << OCIE1C); // compare C
TCCR1B |= (1 << CS10); // set prescaler=1 for 10 kHz
sei(); // enable interrupts (TIMSK1) once I finished assigning values to them
}
void loop() {
unsigned long now = millis();
// Switch cases every 2 seconds
if (now - lastSwitch >= switchInterval) {
lastSwitch = now;
caseNum++;
if (caseNum > 3) caseNum = 1;
switch (caseNum) {
// ------------------- IDLE ------------------------
case 1: // BUCK=OFF, OC1=OFF, OC2=OFF
dutyBUCK = 0;//D_HV;
dutyOC1 = 0;
dutyOC2 = 0;
break;
// ------------------- CHARGING ------------------------
case 2: // BUCK=ON, OC1=ON, OC2=OFF
dutyBUCK = D_HV;
dutyOC1 = TOP; // 100% duty
dutyOC2 = 0;
break;
// ------------------- DISCHARGING ------------------------
case 3: // BUCK=ON, OC1=OFF, OC2=ON
dutyBUCK = 0;//D_HV;
dutyOC1 = 0;
dutyOC2 = TOP;
break;
}
}
}
// ---------------------------------------------------------------------------
// check if On time for Duty cycles are over for each MOSFET at 10kHz
// ---------------------------------------------------------------------------
// Timer1 overflow → start of new PWM cycle
ISR(TIMER1_OVF_vect) {
digitalWrite(BUCK_pin, HIGH); // turn all HIGH at beginning
digitalWrite(OC1_pin, HIGH);
digitalWrite(OC2_pin, HIGH);
OCR1A = dutyBUCK; // when to turn BUCK off
OCR1B = dutyOC1; // when to turn OC1 off
OCR1C = dutyOC2; // when to turn OC2 off
}
// Compare Match A → turn BUCK off
ISR(TIMER1_COMPA_vect) {
if (dutyBUCK > 0) digitalWrite(BUCK_pin, LOW);
}
// Compare Match B → turn OC1 off
ISR(TIMER1_COMPB_vect) {
if (dutyOC1 > 0) digitalWrite(OC1_pin, LOW);
}
// Compare Match C → turn OC2 off
ISR(TIMER1_COMPC_vect) {
if (dutyOC2 > 0) digitalWrite(OC2_pin, LOW);
}
Additionallysection is not relevant to this question, please ask it separately after you get the three PWM channels working