two 200kHz complementary PWM Signals

hello all,

I want to generate two 200kHz 50% duty cycle non-overlapping complementary PWM signals, A & B.

So, A== HIGH when B == LOW and vice versa, and they are non-overlapped, I want to introduce a deadtime for 100ns or so.

I don't want to use built-in function like digitalWrite and/or analogWrite because I think they are not precise to do this job. So I want to use the timers, but having difficulties to configure them.

Any help in programming this ?

I am using Arduino Uno,

thanks in advance,

1 Like

What about a pnp transistor to get the complementary signal. That also means only one Arduino pin is used.

Or a 74ACT04, very fast transition time - mere nanoseconds.

I don't have experience setting up the timers for that.

Bio_man:
hello all,

I want to generate two 200kHz 50% duty cycle non-overlapping complementary PWM signals, A & B.

So, A== HIGH when B == LOW and vice versa, and they are non-overlapped, I want to introduce a deadtime for 100ns or so.

Sounds tricky to do with just the internal timer/counters.

Normally the dead time would be introduced using an external circuit. It's been a long time since I've done it, but I always used to use a small delay element for the dead time (eg small RC and Schmitt trigger) and then form the non-complementary signal as (x AND x*) and the complementary signal as (x NOR x*). Where x is the PWM signal and x* is the 100ns delayed version.

Sketch the waveforms for the above and you'll soon see how it works. And you can implement all of that logic (except the delay) with just one quad NOR chip btw.

Thinking a bit more about doing it all internally. You could get complimentary signals, with dead time included, as follows.

  1. Use the timer in dual slope PWM mode, no prescaler.

  2. Set one output compare unit for normal (clear on rising slope) PWM and the other output compare unit for complementary (set on rising slope) pwm.

  3. Set the compare unit for the non-complementary output to be 1 count less than half scale, and the complementary one to be 1 count more than half scale. This gets you two clocks (125ns) of dead time.

The problem of course is that you can't get 200kHz with both compare units in operation like this. You are basically stuck with about 31kHz operation because the of the full count timers and the dual slope operation. I'm guessing that you may have already thought of this, but dismissed it for that reason.

There is another way however, but it gets a bit tricky. You need both timer0 and timer2 and you need to use the synchronization bits (in the GTCCR) to do it. Note that I've never tried this myself, but the following could well work.

  1. Set the TMS (timer sync mode) and both prescaler reset bits to one in the GTCCR (general timer contron register).

  2. Set both timers 0 and 2 for waveform generation mode 7 (dual slope pwm short cycle) with compare unit A of each timer set for 40 (corresponding to 2.5 microsec per slope with full 16MHz clock).

  3. Set timer0 compare unit B to 19 and its output mode to non complementary PWM.

  4. Set timer2 compare unit B to 21 and its output mode to complementary PWM.

  5. Clear the TMS bit in GTCCR to allow both timers to start in synchronicity.

The normal output is on OC0B and the complementary output on OC2B. As I said, I've never tried it but I believe it could work.

So, A== HIGH when B == LOW and vice versa, and they are non-overlapped, I want to introduce a deadtime for 100ns or so.

What is meant by non-overlapped? Is the intention that A is high, B is low, then A goes low and 100ns later B goes high?
I would say that is 100n of low overlap. Or is the 'deadtime' the overlap of the low signals?

Arrrh! I think there is a subtle flaw in the above.

According to the precsaler block diagram in figure 22-12 (pg 202 of the 328p datasheet), it looks like the synchronization mode will only work if you've got a prescaler other than one. So that would make it a no go. :frowning:

They don't explicitly say that you can't sync them without a prescaler other than 1, but the block diagram strongly suggests that you can't.

TBH it's probably one of those thing that you'd have to test and see to know for sure though.Block diagrams are often simplified and may not always accurately represent every intricacy. I really wish that they would have explicitly stated that sync doesn't work with a full speed clock input instead of leaving up to the block diagram to imply it.

CrossRoads:
What is meant by non-overlapped? Is the intention that A is high, B is low, then A goes low and 100ns later B goes high?
I would say that is 100n of low overlap. Or is the 'deadtime' the overlap of the low signals?

I assumed that a deadtime when both signals are low is what was wanted. That is, A goes low and 100ns later B goes high. Then later B goes low and 100ns later A goes back to high.

This is normally needed when switching power devices (eg MOSFETs IGBTs BJTs) in a configuration where if both devices are on at the same time it will cause a short circuit. Because many power devices turn off somewhat more slowly than they turn on, then a dead time is necessary.

I want to generate two 200kHz 50% duty cycle non-overlapping complementary PWM signals, A & B.

Always 50% duty? (squarewave, symetrical)

Do you mean 2 channels? (2 pairs of signals for 4 outputs total)

If multiple channels non-overlaping, do you mean synchrounous? (all outputs updated at exactly the same time)

The Arduino Due has these features (complimentary PWM). Highly configurable with many options - all in hardware.

stuart0 wrote

Thinking a bit more about doing it all internally. You could get complimentary signals, with dead time included, as follows.

  1. Use the timer in dual slope PWM mode, no prescaler.

  2. Set one output compare unit for normal (clear on rising slope) PWM and the other output compare unit for complementary (set on rising slope) pwm.

  3. Set the compare unit for the non-complementary output to be 1 count less than half scale, and the complementary one to be 1 count more than half scale. This gets you two clocks (125ns) of dead time.

The problem of course is that you can't get 200kHz with both compare units in operation like this. You are basically stuck with about 31kHz operation because the of the full count timers and the dual slope operation.

This is a good idea, but you can get 200Hkz by using Timer1 on the uno. Timer1 is a 16 bit timer with input capture, and there is an extra register available to use for TOP and still get hardware output on two pins. You use a PWM mode with a top count of ICR1. But, as stuart0 says, the duty cycle will be 47.5% to get dead spaces of 125 ns between pulses.

Mode 10 is PWM(dual slope) to ICR1 top count. If ICR1 = 80 and no prescaler, than then the period is 5 microseconds for 200KHz.

//Timer1 Mode 10 PWM to ICR1
//Dual pin 200KHz PWM generator
//47.5% duty cycle 125ns 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
  //80 counts x .0625 = 5 us = 200Khz

  TCCR1B |= _BV(CS10); //no prescaler
  ICR1 = 40;//PWM mode counts up and back down for 80 counts

  OCR1A = 21; //Pin 9 match
  //output A set rising/clear falling
  //Rise at TCNT 21 upslope, High 38 counts, Fall at TCNT 21 downslope
  //47,5% Duty Cycle Pulse centered on TCNT 40. High 38 Low 42
  TCCR1A |= _BV(COM1A1) | _BV(COM1A0); //output A set rising/clear falling

  OCR1B = 19; //Pin 10 match
  //output B clear rising/set falling
  //Fall at TCNT 19 upslope, Low 42, Rise at TCNT 19 downslope
  //47.5% Duty Cycle Pulse centered on TCNT 0. High 38 Low 42
  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() {}
1 Like

cattledog:
you can get 200Hkz by using Timer1 on the uno. Timer1 is a 16 bit timer with input capture, and there is an extra register available to use for TOP

Thanks cattledog. Yes Timer1 has a lot more functionality than the other two. Actually I've just been using Timer2 so far and had only skimmed over Timer1 in the datasheet. I knew it had 16 bits and input capture capabilities, but I didn't know it could do variable "TOP" without using up either of the compare registers. That's really useful to know.

I tell you one thing though, the first time you read the datasheet section on the timers it makes your head spin. I had to read it about 3 or 4 times before all of the functions really started to make sense. :slight_smile:

Oh and BTW, what I said about the prescaler synchronization not working for the full speed clock (no prescaler) didn't turn out to be the case (which is good because it would have been stupid if it didn't work). So my original idea of synchronizing timers0 and timer2 to do this task would actually work.

The interesting thing is that the block diagram for the prescaler synchronization clearly shows it operating only the the prescaler unit and therefore (apparently) having no effect when using the 16MHz clock direct. That seems like a pretty naff thing to do though, to have it work for some clock rates and not others, and especially to not even explicitly document such a shortcoming. This made me suspect that the synchronization might indeed work without a prescaler, even though the block diagram says it shouldn't. So I tested it, and sure enough the prescaler synchronization bits in the GTCCR do indeed stop the clock to allow for syncing, even when the prescaler is not in use. The datasheet documentation on this aspect could certain to with a bit of work.

cattledog:
stuart0 wrote
This is a good idea, but you can get 200Hkz by using Timer1 on the uno. Timer1 is a 16 bit timer with input capture, and there is an extra register available to use for TOP and still get hardware output on two pins. You use a PWM mode with a top count of ICR1. But, as stuart0 says, the duty cycle will be 47.5% to get dead spaces of 125 ns between pulses.

Mode 10 is PWM(dual slope) to ICR1 top count. If ICR1 = 80 and no prescaler, than then the period is 5 microseconds for 200KHz.

//Timer1 Mode 10 PWM to ICR1

//Dual pin 200KHz PWM generator
//47.5% duty cycle 125ns 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
  //80 counts x .0625 = 5 us = 200Khz

TCCR1B |= _BV(CS10); //no prescaler
  ICR1 = 40;//PWM mode counts up and back down for 80 counts

OCR1A = 21; //Pin 9 match
  //output A set rising/clear falling
  //Rise at TCNT 21 upslope, High 38 counts, Fall at TCNT 21 downslope
  //47,5% Duty Cycle Pulse centered on TCNT 40. High 38 Low 42
  TCCR1A |= _BV(COM1A1) | _BV(COM1A0); //output A set rising/clear falling

OCR1B = 19; //Pin 10 match
  //output B clear rising/set falling
  //Fall at TCNT 19 upslope, Low 42, Rise at TCNT 19 downslope
  //47.5% Duty Cycle Pulse centered on TCNT 0. High 38 Low 42
  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() {}

Thanks man for sharing this code! Actually I tried it ion my Arduino but I got some triangular waves, can you spot any problem in the code? I am attaching a screenshot for the waveforms

Sorry I am attaching the waveforms here

stuart0:
Thanks cattledog. Yes Timer1 has a lot more functionality than the other two. Actually I've just been using Timer2 so far and had only skimmed over Timer1 in the datasheet. I knew it had 16 bits and input capture capabilities, but I didn't know it could do variable "TOP" without using up either of the compare registers. That's really useful to know.

I tell you one thing though, the first time you read the datasheet section on the timers it makes your head spin. I had to read it about 3 or 4 times before all of the functions really started to make sense. :slight_smile:

Oh and BTW, what I said about the prescaler synchronization not working for the full speed clock (no prescaler) didn't turn out to be the case (which is good because it would have been stupid if it didn't work). So my original idea of synchronizing timers0 and timer2 to do this task would actually work.

The interesting thing is that the block diagram for the prescaler synchronization clearly shows it operating only the the prescaler unit and therefore (apparently) having no effect when using the 16MHz clock direct. That seems like a pretty naff thing to do though, to have it work for some clock rates and not others, and especially to not even explicitly document such a shortcoming. This made me suspect that the synchronization might indeed work without a prescaler, even though the block diagram says it shouldn't. So I tested it, and sure enough the prescaler synchronization bits in the GTCCR do indeed stop the clock to allow for syncing, even when the prescaler is not in use. The datasheet documentation on this aspect could certain to with a bit of work.

Thanks stuart0 for your feedback. and yes I am still lost reading the timer sections :frowning: I got no where, this is my first time dealing with internal timers. do you suggest any workable examples in Arduino to guide me how to use them or I need exactly to understand what is there in the datasheet?

dlloyd:
Always 50% duty? (squarewave, symetrical)

Do you mean 2 channels? (2 pairs of signals for 4 outputs total)

If multiple channels non-overlaping, do you mean synchrounous? (all outputs updated at exactly the same time)

The Arduino Due has these features (complimentary PWM). Highly configurable with many options - all in hardware.

Always 50% duty? (squarewave, symetrical)
Yes, exactly.

Do you mean 2 channels? (2 pairs of signals for 4 outputs total)
only two signals, (2 outputs) A&B. So when A is LOW, B is HIGH and vice versa.

If multiple channels non-overlapping, do you mean synchronous? (all outputs updated at exactly the same time)
non-overlapping means when A goes HIGH to LOW, B waits for sometime (100ns in this case) and then it goes HIGH. This is to prevent those signals to turn on two MOSFETS at the same time which cause short circuit between Vc and GND

The Arduino Due has these features (complimentary PWM). Highly configurable with many options - all in hardware.
I guess also Arduino UNO has them but it is matter of configuration. Timers need to be configured to provide such signals, and this is the part I am struggling with right now

do you suggest any workable examples in Arduino to guide me how to use them or I need exactly to understand what is there in the datasheet?

A great place to get started is with Nick Gammon's tutorial on Timer/Counters

Regarding your scope traces, I believe there is something wrong with how you are taking your measurments. Is the output connected to a circuit? Can you measure the standard PWM output with analogWrite()? It's not possible to directly generate a triangle wave from the timers on the uno.

cattledog:
A great place to get started is with Nick Gammon's tutorial on Timer/Counters
Gammon Forum : Electronics : Microprocessors : Timers and counters

Regarding your scope traces, I believe there is something wrong with how you are taking your measurements. Is the output connected to a circuit? Can you measure the standard PWM output with analogWrite()? It's not possible to directly generate a triangle wave from the timers on the uno.

I measured the outputs from Pin9 and Pin10 directly, first I thought it may be something with the circuit although they are connected to high impedance ( gate of the mosfets) and I disconnect them. The same waveforms are found!

I agree with you it is really wired but can't tell where is the problem.
BTW, when I use analogWrite () function, I got nice and smooth pulses but for low frequencies something like 1kHz. but for higher frequencies, the waveforms are distorted. and I checked it online, some suggest because of using built-in function and might be useful to generate these pulses using the timers.

and thank you cattledog for sharing the link for Gammon's tutorials, I will have a look at them.

If you want a square wave source to test your measurements, you can use tone(). The syntax is tone(pin,frequency). The highest frequency available is 65KHz. On the uno it will use Timer2 to generate the pulse train. No libraries required as it is part of the ide.
https://www.arduino.cc/en/Reference/Tone

cattledog:
If you want a square wave source to test your measurements, you can use tone(). The syntax is tone(pin,frequency). The highest frequency available is 65KHz. On the uno it will use Timer2 to generate the pulse train. No libraries required as it is part of the ide.
https://www.arduino.cc/en/Reference/Tone

You are right, and it really handy function but the problem with tone function, I can generate only one square function at a time. ( I tried that in Arduino and it is mentioned in the reference provided). Although, I can use external circuit (simple digital inverter) to invert this signal but for now I want to generate two signals from the micro-controller which saves me from using other external stuff.

I only suggested tone() as a way to figure out what is going on with your oscilloscope. It is a square wave source at varying frequencies. Can you read a square wave at 50KHz using tone()?

There are no ramped waveforms output by a UNO. I don't have a scope, but I'm fairly certain that the code I provided outputs two slightly separated square waves at 200KHz. Using a frequency counter I can see each pulse at 200KHz.