Producing complimentary square waves with variable frequency and duty cycle with constant dead time

I am intending to produce a high voltage high current square wave using 4 IGBTs. To drive the switches, I am considering producing TWO square waves (A & B) of variable frequencies ranging from 10 - 4500 Hz complementary to each other using Arduino UNO.
Additionally, I want to control the duty cycle of "A" wave from 40% to 100%.
Additionally, I want to insert a constant dead time of 400 ns no matter what the frequency is to prevent a short circuit among the high and low IGBTs.
I do not want to use external logic gate ICs like 7404 to invert the signals or to insert delays.

void setup ()
{
  TCCR1A = (TCCR1A & 0x0F) | 0xB0 ; // set pin 10 inverted
  int val = 100 ;
  int dead = 2 ;
  analogWrite (9, val) ;
  analogWrite (10, val+dead) ;
}
void loop ()
{}

The above code has already been explored in vain; I am unable to maintain constant dead time duration since dead time is a function of the frequency.

Kindly advise on the way forward.
Thanks in advance

There's been some discussion of generating complementary PWM signals with dead time on arduino over the years if you search for it.

Perhaps try switching to one of the black pill boards? I have done complementary PWM with dead time for a high voltage inverter using the built-in features on the STM32F4. But that was native code generated from the STM32 Cube utility, not arduino. Just a thought.

One other alternative would be do it all with bit manipulation operations. It would limit you to a fairly slow PWM rate, but you'd have complete control over everything.

Where do you draw the line between external IGBTs, their drivers and the Arduino internals?

What happens during reset when all the port pins are tristated? Since the arduino does not support pure atomic sequences in code you will have to disable the interrupts when switching. Look at this link it will give you some idea of what I am saying. Demonstration: Atomic access and Interrupt routines

This requires a 1/64 prescaler for frequencies down to 2Hz. Then the timer clock period is 4µs resulting in a minimum 8µs step width between two PWM outputs.

This would require a timer clock of 200MHz for a 400ns step between PWM outputs. No chance for a hardware solution with an Arduino.

An interrupt solution may work, provided that higher priority or disabled interrupts do not interfere too much.

Hello Sir,
Since the frequency is relatively low and the time period for the highest required frequency (4000 Hz) is 250 us, a delay of 8 us or 16 us would be acceptable as the percentage of the cycle is only reduced by 3.2 - 6.4 %.
Kindly let me know what would be your way of approach to achieving the goal.

Regards
E. Boome

Then a 16MHz/64 clock for T1 in phase and frequency correct mode will do what you want. PWM steps in 8µs up to a frequency of 4kHz or 250µs.

The higher frequencies also can be reached with a 16MHz/8 clock and 1µs steps. This setting goes down to 16Hz. With an 8MHz clock you can reach 8Hz and 2µs steps over the full frequency range.

Your IGBT driver should have an Enable input for safe operation during controller startup or shutdown.

Thank you for your response. Kindly explain what you meant by the above-quoted text.

Would this work?

https://www.st.com/en/power-management/sg3524.html#overview

Rt and Ct, I believe, set the switching frequency.

A power driver should be OFF unless a program is running that provides the right control signals. Also see #4.

Hello sir, I want to use timer 1 in inverting (complementary ) mode. Signal B gets high when signal A is low. Which registers do I need to set high in TCCRnA to get this kind of operation?
Similarly, what command do I use to insert dead time in the program?

There are many PWM driver ICs that have built-in dead-time, and all they need as input is the PWM signal. Implementing DT in code can get tricky.

1 Like

Please share your comment on the following code

#include <TimerOne.h>
int frequency = 1000; //Frequency in Hertz
unsigned long halfPeriod = 1000 / (frequency) * 1000;

void setup()
{
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);

Timer1.initialize(halfPeriod);  // Frequency, 100us = 10khz
Timer1.pwm(9,705);       // 50% DC on pin 9
Timer1.pwm(10,410); 

//Timer1.pwm(10,255);    // 25% DC on pin 10

// D.C. 
// 10KHz
// You can use 2 to 1023 
// 0 & 1 gives a constant LOW 
// 1024 gives a constant HIGH
// 2 gives ~125ns HIGH pulses
// 1023 gives ~125ns low pulses
// 512 gives 50us
}

void loop()
{
}

The COM1x0 bits invert the A/B channel. See table 16-3 in the data sheet.

Let one compare register differ from the other by at least 1.

Hello,
I tried the following date sheet. It does not have table No. 16-3. Kindly share a link to the intended sheet. Thanks.

If you know the register name then look into the Register Description of the Timer/Counter1.

Hello sir, I tried to change frequency and duty cycle in timer 1(pin 9 and pin 10) of Arduino Uno. Whenever I try to change default frequency, the complementary( or inverted ) signal in pin 10 becomes normal signal. I want to change the frequency with complementary signal in pin 10.

This is my code

// C++ code
//
/***************************************************

#include <TimerOne.h>

#define pinA 9
#define pinB 10
#define dutyPin A0
#define freqPin A1

int dutycycle = 60;
int deadtime = 1;    // 0.0078% -> total signal loss
int frequency = 500;
int time_period = 1000000.0/frequency;
int signal1 = 100;

float last_dutycycle = -1;
float last_frequency = -1;

void setup ()
{
  Serial.begin(9600);
  pinMode(pinA, OUTPUT);
  pinMode(pinB, OUTPUT);
  pinMode(dutyPin, INPUT);
  pinMode(freqPin, INPUT);

  TCCR1A = (TCCR1A & 0x0F) | 0xB0 ; // set pin 10 inverted 1/64
   
}

void loop ()
{
  dutycycle = map(analogRead(dutyPin), 0, 1023, 0, 100);  
  frequency = map(analogRead(freqPin), 0, 1023, 40, 4000);

  time_period = 1000000.0/frequency; // time period in micro seconds
 
  if ((dutycycle != last_dutycycle) or (frequency != last_frequency)){
    digitalWrite(pinA, LOW);
    digitalWrite(pinB, LOW);
    delayMicroseconds(1);

    TCCR1A = (TCCR1A & 0x0F) | 0xB0 ; // set pin 10 inverted 1/64
    
    Timer1.initialize(time_period);  //set time period of 1 Hz
    signal1 = 255.0*dutycycle/100.0;    // signalB to pin 10 is inverted
    if (dutycycle > 95){
      analogWrite(pinA, 255);
      digitalWrite(pinB, LOW);
    }
    else if (dutycycle < 5){
      digitalWrite(pinA, LOW);
      analogWrite(pinB, 255);
    } 
    else{
      analogWrite (pinA, signal1-deadtime) ;
      analogWrite (pinB, signal1+deadtime) ;
    }
    last_dutycycle = dutycycle;
    last_frequency = frequency;
  }
      
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.