Dead time between PWM signals

Hi everyone!
I have the following code which runs on Arduino Mega 2560. It generates 3 SPWM signals which are 120 degrees phase shifted to each other on pins: 10 (phase 1) , 9 (phase 2) and 11 (phase 3). All the three signals are also inverted and givens to pins: 2 (phase 1 inverted), 5 (phase 2 inverted) and 12 (phase 3 inverted). But I need a dead time of 1- 5 us between each signal and its inverted signal (between 10 and 2, between 9 and 5, between 11 and 12), so that the original signal and the inverted signal won;t be ON at the same time. Is there a way to implement such a dead time between the signals?

Here is my code:

/*
 *
 * DDS Sine Generator mit ATMEGS 328
 * Timer2 generates the  31250 KHz Clock Interrupt
 * Use Timer2 Interrupt to change duty cycle for the output PWM signals
 * D. Tolken
 * 120 degress out of phase signals for 3 phase BLDC motor controller
 * CPUT, South Africa


a Huge thumbs up and thanks must be given to Martin Nawrath for the developement of the original code to generate a sine wave using PWM and a LPF.
Link:
                                         http://interface.khm.de/index.php/lab/experiments/arduino-dds-sinewave-generator/
*/

#include "avr/pgmspace.h" //Store data in flash (program) memory instead of SRAM

// Look Up table of a single sine period divied up into 256 values. Refer to PWM to sine.xls on how the values was calculated
PROGMEM const uint16_t sine256[]  = {
  127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
  242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
  221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
  76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
  33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124

};
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) //define a bit to have the properties of a clear bit operator
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))//define a bit to have the properties of a set bit operator

int PWM1= 10;// PWM1 output, phase 1
int PWM2 = 9; //PWM2 ouput, phase 2
int PWM3 = 11; //PWM3 output, phase 3
int PWM4 = 2; // PWM phase 1 inverted
int PWM5 = 5; //PWM phase 2 inverted
int PWM6 = 12; //PWM phase 3 inverted

int offset_1 = 85; //offset 1 is 120 degrees out of phase with previous phase, Refer to PWM to sine.xls
int offset_2 = 170; //offset 2 is 120 degrees out of phase with offset 1. Refer to PWM to sine.xls
int program_exec_time = 6; //monitor how quickly the interrupt trigger
int ISR_exec_time = 7; //monitor how long the interrupt takes

double dfreq;
const double refclk=31376.6;      // measured output frequency

// variables used inside interrupt service declared as voilatile
volatile byte current_count;              // Keep track of where the current count is in sine 256 array
volatile byte ms4_delay;             //variable used to generate a 4ms delay
volatile byte c4ms;              // after every 4ms this variable is incremented, its used to create a delay of 1 second
volatile unsigned long phase_accumulator;   // pahse accumulator
volatile unsigned long tword_m;  // dds tuning word m, refer to DDS_calculator (from Martin Nawrath) for explination.
 #define NOP __asm__ __volatile__("nop\n\t");
#define DELAY_CYCLES(n) __builtin_avr_delay_cycles(n)
void setup()
{
  pinMode(PWM1, OUTPUT);      //sets the digital pin as output
  pinMode(PWM2, OUTPUT);      //sets the digital pin as output
  pinMode(PWM3, OUTPUT);      //sets the digital pin as output
  pinMode(PWM4, OUTPUT);
  pinMode(PWM5, OUTPUT);
  pinMode(PWM6, OUTPUT);
  
  pinMode(program_exec_time, OUTPUT);      //sets the digital pin as output
  pinMode(3, OUTPUT);         //sets the digital pin as output
  sbi(PORTD,program_exec_time); //Sets the pin
    pinMode(8,OUTPUT);

  Setup_timer1();
  Setup_timer2();
  Setup_timer3();
  
  //Disable Timer 1 interrupt to avoid any timing delays
 // cbi (TIMSK0,TOIE0);              //disable Timer0 !!! delay() is now not available
 
  sbi (TIMSK2,TOIE2);              //enable Timer2 Interrupt

  dfreq=50.0;                    //initial output frequency = 1000.o Hz
  tword_m=pow(2,32)*dfreq/refclk;  //calulate DDS new tuning word 

}
void loop()
{
  while(1) 
  {
      sbi(PORTD,program_exec_time); //Sets the pin 
      if (c4ms > 250) // c4ms = 4ms, thus 4ms *250 = 1 second delay
       {                 
        c4ms=0;                          //Reset c4ms
//        dfreq=analogRead(0);             //Read voltage on analog 1 to see desired output frequency, 0V = 0Hz, 5V = 1.023kHz
        cbi (TIMSK2,TOIE2);              //Disable Timer2 Interrupt
        tword_m=pow(2,32)*dfreq/refclk;  //Calulate DDS new tuning word
        sbi (TIMSK2,TOIE2);              //Enable Timer2 Interrupt 
      }
  }
}

//Timer 0 setup
//Set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer3(void)
{
  // Timer0 Clock Prescaler to : 1
  sbi (TCCR3B, CS30);
  cbi (TCCR3B, CS31);
  cbi (TCCR3B, CS32);
  
  // Timer0 PWM Mode set to Phase Correct PWM
  cbi (TCCR3A, COM3A0);
  sbi (TCCR3A, COM3A1);
  cbi (TCCR3A, COM3B0); 
  sbi (TCCR3A, COM3B1);

  // Mode 1 / Phase Crrect PWM
  sbi (TCCR3A, WGM30); 
  cbi (TCCR3A, WGM31);
  cbi (TCCR3B, WGM32);
  //cbi (TCCR0B, WGM03);
}


//Timer 1 setup
//Set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock

// void Setup_timer0(void){
//  cbi  (TCCR0A, COM0A1);
//  cbi  (TCCR0A, COM0A0);
//  cbi  (TCCR0A, COM0B1);
//  cbi  (TCCR0A, COM0B0);

//  cbi (TCCR0A, WGM00); 
//  cbi (TCCR1A, WGM01);

//   sbi (TCCR0B, CS00);
//   cbi (TCCR0B, CS01);
//   cbi (TCCR0B, CS02);
// }

void Setup_timer1(void)
{
  // Timer1 Clock Prescaler to : 1
  sbi (TCCR1B, CS10);
  cbi (TCCR1B, CS11);
  cbi (TCCR1B, CS12);
  
  // Timer1 PWM Mode set to Phase Correct PWM
  cbi (TCCR1A, COM1A0);
  sbi (TCCR1A, COM1A1);
  cbi (TCCR1A, COM1B0); 
  sbi (TCCR1A, COM1B1);

  // Mode 1 / Phase Correct PWM
  sbi (TCCR1A, WGM10); 
  cbi (TCCR1A, WGM11);
  cbi (TCCR1B, WGM12);
  cbi (TCCR1B, WGM13);
}

//Timer 1 setup
//Set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer2() 
{
  // Timer2 Clock Prescaler to : 1
  sbi (TCCR2B, CS20);
  cbi (TCCR2B, CS21);
  cbi (TCCR2B, CS22);

  // Timer2 PWM Mode set to Phase Correct PWM
  cbi (TCCR2A, COM2A0);  // clear Compare Match
  sbi (TCCR2A, COM2A1);
  cbi (TCCR2A, COM2B0); 
  sbi (TCCR2A, COM2B1);
   
  // Mode 1  / Phase Correct PWM
  sbi (TCCR2A, WGM20);  
  cbi (TCCR2A, WGM21);
  cbi (TCCR2B, WGM22);
}


//Timer2 Interrupt Service at 31372,550 KHz = 32uSec
//This is the timebase REFCLOCK for the DDS generator
//FOUT = (M (REFCLK)) / (2 exp 32)
//Runtime : 8 microseconds
ISR(TIMER2_OVF_vect)
{
  cbi(PORTD,program_exec_time); //Clear the pin
  sbi(PORTD,ISR_exec_time);          // Sets the pin

  phase_accumulator=phase_accumulator+tword_m; //Adds tuning M word to previoud phase accumulator. refer to DDS_calculator (from Martin Nawrath) for explination.
  current_count=phase_accumulator >> 24;     // use upper 8 bits of phase_accumulator as frequency information                      
  
  OCR2A=pgm_read_byte_near(sine256 + current_count); // read value fron ROM sine table and send to PWM.. pin 10
  OCR2B=pgm_read_byte_near(sine256 + (uint8_t)(current_count + offset_1)); // read value fron ROM sine table and send to PWM, 120 Degree out of phase of PWM1..pin9
  
  OCR1A = pgm_read_byte_near(sine256 + (uint8_t)(current_count + offset_2));// read value fron ROM sine table and send to PWM, 120 Degree out of phase of PWM2..pin11
  
//   //OCR1B = pgm_read_byte_near(sine256 + (uint8_t)(current_count + offset_2));// read value fron ROM sine table and send to PWM, 120 Degree out of phase of PWM2
 


  OCR3B= 255-OCR2A; //pin2
  OCR3A= 255-OCR2B; //pin5
  OCR1B= 255-OCR1A; //pin12

  //increment variable ms4_delay every 4mS/125 =  milliseconds 32uS
  if(ms4_delay++ == 125) 
  {  
    c4ms++;
    ms4_delay=0; //reset count
   }   

 cbi(PORTD,ISR_exec_time);            //Clear the pin
}

If you use digitalWrite() instead of direct port access you get a constant delay.

Without further explanation I don't understand what you want to achieve at all. It looks like you want to generate 3 sine waves for driving what? And what's the purpose of the inverted signals?

You might need an MCU with a more advance timer if you want to implement a true hardware dead-time insertion. I'm not an expert in power electronics but isn't dead-time between some signals required in order not to "burn" your power mosfets?

Hi. Thanks for replying. I want 6 signals to drive 6 transistors in a 3 phase inverter as shown in the figure attached. I need a dead time between each signal and its inverted signal so as to prevent burning the transistors.

The inherent delay of code execution of digitialWrite over direct memory access did not give the needed delay? delayMicros(5) did not work?

Why don't you drive the transistors by a rectangle instead of sine? The PWM driven outputs will be anything but a sine on inductive loads.

If you are running your PWM timer at full speed that will be a gap of 16 to 80 clock ticks. Let's say 20 for an example.

If you are using phase-correct PWM you can set the regular PWM cycle to begin and end at a lower number than the inverted PWM.

I think that all you need to do is to limit your sine values to 235 instead of 255. On the up counts, PWM will go off at 0 to 235 and inverse PWM will come on at 20 to 255. On the down count the inverse PWM will turn off at 255 to 20 and the PWM will turn on at 235 to 0. The ON signal will turn OFF 20 clocks before the OFF signal turns ON.

For larger gaps, just re-calculate your sine table for the gap you want: 235 for a gap of 20 (1.25 uS), 175 for a gap of 80 (5 uS).

You don't want to drive both transistors in one PWM cycle. Instead use the H-bridge model with a direction signal that only enables the upper or lower transistor on the positive or negative half-wave of the sine.

You have to drive the transistors by dedicated hardware that can invert the signal. Most probably the high side driver will always invert the signal. See typical H-bridge and BLDC motor driver circuit diagrams.

1 Like

Hi,
Have you tried your code yet?
Have you looked at the output of the controller with a scope?

Can you please post a circuit diagram showing your driver circuit to the switching transistors?
What transistors will you be using, MOSFET or IGBT?

Thanks.. Tom... :grinning: :+1: :coffee: :australia:

You are begging for random hardware failures by not putting any necessary deadtime into the driver hardware design. Depending on software to work correctly 100% of the time, even if the software crashes, is a fools errand. .

Hi. Thanks for replying. I think your reply is in the right direction. But I did not understand it completely. So basically I want the signals as shown in the picture: Between every falling edge and rising edge, there should be a dead time of 1 us. So according to the picture, the falling edge of every signal should be there only. But the rising edge should get delayed ( dead time ) by 1us.

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