I have a problem on "SS Fast PWM using TC2 and UNO".

I am preparing an online tutorial on “SS Fast PWM using TC2 and UNO” for my pandemic affected pupils. The design of the PWM signal is based on the following conceptual level hardware (Fig-1) and wave-forms (Fig-2). The design works fine for “Mode-3 Fast PWM”; but, I can’t make it work for “Mode-7 Fast PWM”. The concept of “TOP” count is not at all understood by my own faculty.

In Mode-3, the ON-time of the PWM changes nicely (I can observe in the scope) as I change the content of OCR2A Register. When I change the operation Mode to Mode-7, there is no wave-form on DPin-11. I am working on channel-A only.

What I am not doing in the right order? Any help/guidance would be highly appreciated along with the elaborate meaning/significance/use of “TOP” count.


Figure-1: PWM hardware of TCNT2 at conceptual level


Figure-2:PWM related wave-forms for TCNT2 Mode-3 Ch-A (OC2A)

The sketch for “Mode-3 Fast PWM” (tested)

void setup()
{
  Serial.begin(9600);

  pinMode(11, OUTPUT);//DPin direction for OC2A signal
  //-------------------------
  bitSet(TCCR2A, COM2A1); // non-inverting PWM
  bitClear(TCCR2A, COM2A0); //
  //-------------------------
  bitSet(TCCR2A, WGM20); //  Mode-3 operation 
  bitSet(TCCR2A, WGM21); //
  bitClear(TCCR2B, WGM22); //
  //-------------------------
  bitClear(TCCR2B, CS22); // 16 MHz clock for TC2
  bitClear(TCCR2B, CS21); //
  bitSet(TCCR2B, CS20); //
  //--------------------------
  OCR2A = 64; //(ON-time period; 1/16 Mz)*64 = 4 us PW
}

void loop()
{
  
}

I can't make it work for "Mode-7 Fast PWM". The concept of "TOP" count is not at all understood by my own faculty.

Mode 7 --"FastPWM to OCR2A" In this mode OCR2A is the top value where the timer resets. The OCR2A value controls frequency. You can not expect to use that value to adjust duty cycle as well.

cattledog:
Mode 7 --“FastPWM to OCR2A” In this mode OCR2A is the top value where the timer resets. The OCR2A value controls frequency. You can not expect to use that value to adjust duty cycle as well.

Thank you for the reply.

If OCR2A register (in Mode-7) regulates the frequency of the “TC2 based Fast PWM”, then how am I going to regulate the duty cycle (the pulse width) of the PWM signal? The following Table-17.8 of data sheet says:

(1) OCA is to hold “TOP” count. Does OCRA means OCR2A register? (edit)

(2) “Update of OCRx at BOTTOM”. Does OCRx refer to OCR2B Register as OCR2A is already engaged?

Further hints in the form of some codes would be welcomed.

GolamMostafa: (1) OCRA is to hold "TOP" count. Does OCRA means OCR2A register?

For Timer/Counter 2, yes. They don't include the Timer number so they can use the same chart for any 8-bit counter. They could have said something like OCRxA or OCRnA but they chose to just leave the number out.

GolamMostafa: (2) "Update of OCRx at BOTTOM". Does OCRx refer to OCR2B Register as OCR2A is already engaged?

Yes. Or it may refer to both, if you want to update the TOP value while the timer is running.

Thank you @johnwasser for the elegant reply.

But, my following question (made in Post#2) remains unanswered:

"If OCR2A register (in Mode-7) regulates the frequency of the "TC2 based Fast PWM", then how am I going to regulate the duty cycle (the pulse width) of the PWM signal?"

I have changed/manipulated the "Mode-3 working sketch (can be seen in the original post)" in various ways to make Mode-7 working; but, no success -- I don't see (in my scope) any waveform at DPin-11.

GolamMostafa: If OCR2A register (in Mode-7) regulates the frequency of the "TC2 based Fast PWM", then how am I going to regulate the duty cycle (the pulse width) of the PWM signal?

To use WGM 7 (Fast PWM with TOP in OCR2A) on Timer 2 you have to use the OC2B pin (UNO pin 3) for output and use the OCR2B register to set the duty cycle. Note: Set OCR2A to 0xFF if you want the same 8-bit PWM in Mode 7 as you got in Mode 3.

Use WGM 7 only when you NEED to set the PWM frequency more precisely than 'prescale' allows. You gain more precise frequency control but you lose one PWM channel.

On Timer1 there is WGM option for "Fast PWM with TOP in ICR1". That allows the more precise control of frequency AND two PWM channels.

johnwasser:
To use WGM 7 (Fast PWM with TOP in OCR2A) on Timer 2 you have to use the OC2B pin (UNO pin 3) for output and use the OCR2B register to set the duty cycle.
Note: Set OCR2A to 0xFF if you want the same 8-bit PWM in Mode 7 as you got in Mode 3.

Great! Great!! Great!!! My burning question has been answered by my Computer System (@cattledog, @johnwasser, PC, UNO, Scope, Lab Manual, Data Sheets, Sitting Char, Table, Fan, Tea, and what not).

1. The sketch (presented below) is prepared exactly as per above instructions, and I have got “62.5 kHz Mode-7 PWM” signal (Fig-1) at DPin-3 of UNO. (OCR2A = 0xFF, N = 1)

void setup()
{
  pinMode(3, OUTPUT);  //DPin-3 is Output and connected with PWM2B/OC2B
  //------------------------
  bitSet(TCCR2A, COM2B1); //non-inverting PWM for Ch-B
  bitClear(TCCR2A, COM2B0);
  //------------------------
  bitSet(TCCR2A, WGM20); //Mode-7 PWM for Ch-B/OC2B
  bitSet(TCCR2A, WGM21);
  bitSet(TCCR2B, WGM22);
  //-------------------------
  OCR2A = 0xFF; //TOP value that determines frequency of PWM
  OCR2B = 16; //initial 1 us ON-time.(clkTC2=16 MHz);(16MHz/1)*1 us = 16
  //-------------------------
  bitSet(TCCR2B, CS20); //Start TCNT2 with 16 MHz
  bitClear(TCCR2B, CS21);
  bitClear(TCCR2B, CS22);
  //-------------------------
}

void loop()
{
  while (bitRead(TIFR2, OCF2B) != HIGH)  //checking if ON-time has ended or not
  {
    ; //wait until ON-time/duty cycle ends of the PWM
  }
  bitSet(TIFR2, OCF2B); //clear OCF2B flag
  OCR2B = OCR2B + 16;   //augment duty cycle by 1 us
  delay(4000);          //wait 4 sec to see next change in duty cycle
}

2. Screen shot of “Mode-7 PWM”.

Figure-1: Mode-7 PWM signal (OC2B) at DPin-3

Use WGM 7 only when you NEED to set the PWM frequency more precisely than ‘prescale’ allows.

3. Mode-3 PWM operation sets a fixed value (0xFF) as “TOP” count. So, the available PWM frequency are (as determined by “TC2 clock prescaler”):
(1) 62500 kHz at division factor 1.
(2) 7812.5 Hz at division factor 8.
(3) 1953.125 Hz at division factor 32
(4) 976.5625 Hz at division factor 64
(5) 488.28125 Hz at division factor 128
(6) 244.140625 Hz at division factor 256
(7) 61.03515625 Hz at division factor 1024

You gain more precise frequency control but you lose one PWM channel.

4. In Mode-7 operation of Ch-B, the PWM frequency can be regulated by the “suitable combination” of two variables: content of OCR2A register (0x00 to 0xFF) and TC2 clock prescaler. As a result, there is much better control of frequency than Mode-3 operation. For example: to get 20 kHz PWM (Fig-2) with 2 us resolution, we can nicely put 24 into OCR2A at division factor 32. (If Mode-7 is invoked for Ch-B, then there will be no more PWM signal for Ch-A as OCR2A register is now engaged with Ch-B.)
fOC2BM7 = fOSC/(N*(TOP+1))
==> 20103 = 16106/(32*(TOP+1))
==> TOP = 24.

resolution = (1/20000)/(TOP+1) = 2 us.


Figure-2: 20 kHz PWM using Mode-7

The Sketch:

void setup()
{
  pinMode(3, OUTPUT);  //DPin-3 is Output and connected with PWM2B/OC2B
  //------------------------
  bitSet(TCCR2A, COM2B1); //non-inverting PWM for Ch-B
  bitClear(TCCR2A, COM2B0);
  //------------------------
  bitSet(TCCR2A, WGM20); //Mode-7 PWM for Ch-B/OC2B
  bitSet(TCCR2A, WGM21);
  bitSet(TCCR2B, WGM22);
  //-------------------------
  OCR2A = 24;//TOP value that determines frequency of PWM
  OCR2B = 2; //initial 4 us ON-time.(clkTC2= 0.5 MHz);(0.5MHz/1)*4 us = 2
  //-------------------------
  bitSet(TCCR2B, CS20); //Start TCNT2 with division factor 32 ; clkTC2 = 16 Mhz/32 = 500 kHz
  bitSet(TCCR2B, CS21);
  bitClear(TCCR2B, CS22);
  //-------------------------
}

void loop()
{
  while (bitRead(TIFR2, OCF2B) != HIGH)  //checking if ON-time has ended or not
  {
    ; //wait until ON-time/duty cycle ends of the PWM
  }
  bitSet(TIFR2, OCF2B); //clear OCF2B flag
  OCR2B = OCR2B + 2;   //augment duty cycle by 4 us
  delay(4000);          //wait 4 sec to see next change in duty cycle
}

5. If Mode-7 is invoked for Ch-B, then there will be no more PWM signal for Ch-A at DPin-11 and this is the history that I have known now from the experience of @johnwasser and the experimental results. The PWM is missing at DPin-11 for Ch-A due to the absence of “duty cycle controlling register OCR2A” which has been borrowed by Ch-B for Mode-7 operation.

6. Corrections are sought in my above supplementary comments/observations.

Very big thanks to both @cattledog and @johnwasser for taking care of my query.

Hope to come with more queries/questions on PWM in this thread as and when self-study experiments are performed.

It is not clear to me why the Mode 3 example has any more then this in loop():

void loop()
{
  OCR2B += 2;   // augment duty cycle by 4 us
  delay(4000);     // wait 4 sec to see next change in duty cycle
}

The change to OCR2B is buffered and the active register only gets changed when the timer overflows from TOP to BOTTOM. There is no need to 'synchronize' the writing of the register with the timer.

johnwasser:
It is not clear to me why the Mode 3 example has any more then this in loop():

void loop()

{
 OCR2B += 2;   // augment duty cycle by 4 us
 delay(4000);     // wait 4 sec to see next change in duty cycle
}



The change to OCR2B is buffered and the active register only gets changed when the timer overflows from TOP to BOTTOM. There is no need to 'synchronize' the writing of the register with the timer.

1. You mean: there is no need to check the OCF2B flag in order to put new value into the OCR2B register to change duty cycle; value can be written (at any time) into the buffer of this register, which will enter into the active register when TCNT2 reaches at BOTTOM count (0x00).Then, what is the use of OCF2B flag whose status could be known either by polling or interrupt process?

2. In Mode-7 operation, does TOV2 flag becomes active when TCNT2 reaches at BOTTOM count (TCNT2 is essentially reset when TCNT2 = OCR2A)? If yes, then what is the use of this flag?

GolamMostafa:
You mean: there is no need to check the OCF2B flag in order to put new value into the OCR2B register to change duty cycle; value can be written (at any time) into the buffer of this register, which will enter into the active register when TCNT2 reaches at BOTTOM count (0x00).

Yes.

GolamMostafa:
Then, what is the use of OCF2B flag whose status could be known either by polling or interrupt process?

The hardware needs it for interrupt handling. The only time you would normally touch it is when you are enabling the Output Compare 2 B interrupt. You would clear it so the interrupt doesn’t happen based on an output compare that happened before you enabled the interrupt.

GolamMostafa:
2. In Mode-7 operation, does TOV2 flag becomes active when TCNT2 reaches at BOTTOM count (TCNT2 is essentially reset when TCNT2 = OCR2A)? If yes, then what is the use of this flag?

According to the chart you published above, the Overflow flag gets set when the timer reaches MAX (0xFF) in Mode 3 or TOP (OCR2A) in Mode 7. Again, these flags are for the interrupt hardware and the only time you would normally touch it is when you are enabling the Overflow 2 interrupt. You would clear it so the interrupt doesn’t happen based on an overflow that happened before you enabled the interrupt.

johnwasser: Yes.

Cool! :)

The hardware needs it for interrupt handling.[...]

Then what kind of task, the user may prescribe in the following ISR routine?: (could it be like sensing the feedback signal from a peripheral device, calculate the error and then write the appropriate value in the compare register?)

ISR (TIMER2_COMPB_vect)
{
     //insert codes to do something

}

The only time you would normally touch it is when you are enabling the Output Compare 2 B interrupt. You would clear it so the interrupt doesn't happen based on an output compare that happened before you enabled the interrupt.

Cool! :)

According to the chart you published above, the Overflow flag gets set when the timer reaches MAX (0xFF) in Mode 3 or TOP (OCR2A) in Mode 7.

Cool! :)

Again, these flags are for the interrupt hardware [...].

Then what kind of task, the user may prescribe in the following ISR routine:

ISR (TIMER2_OVF_vect)
{
     //insert codes to do something

}

[...] and the only time you would normally touch it is when you are enabling the Overflow 2 interrupt. You would clear it so the interrupt doesn't happen based on an overflow that happened before you enabled the interrupt.

Cool! :)

GolamMostafa: Then what kind of task, the user may prescribe in the following ISR routine?: (could it be like sensing the feedback signal from a peripheral device, calculate the error and then write the appropriate value in the compare register?)

ISR (TIMER2_COMPB_vect)
{
     //insert codes to do something
}

Whatever the user needs the code to do on an output compare match. If they don't need anything done on an output compare match they would not enable the output compare match interrupt. If they don't enable the output compare match interrupt then the output compare match flag isn't used for anything.

GolamMostafa: Then what kind of task, the user may prescribe in the following ISR routine:

ISR (TIMER2_OVF_vect)
{
     //insert codes to do something
}

Whatever the user needs the code to do on a timer overflow. If they don't need anything done on a timer overflow they would not enable the timer overflow interrupt. If they don't enable the timer overflow interrupt then the timer overflow flag isn't used for anything.

1. There has been a cool reading of your Post#11.

2. I have tested your following codes (of Post#7) which advocate that the OCR2B compare register could be written at any time without checking the OCF2B flag, and they work like charm!

void loop()
{
  OCR2B += 2;   // augment duty cycle by 4 us
  delay(4000);     // wait 4 sec to see next change in duty cycle
}

3. Follow up question: (a) Assume that for Mode-7 operation of TCNT2 Ch-B, I have loaded (after calculation) 24 into 8-bit OC2RA register with clkTC2 = 500 kHz in order to get a 20 kHz PWM signal.

(b) I am asked to calculate a value that is to be loaded into 8-bit OCR2B register to get 25% duty cycle. Which one of the following two calculations should I follow? (i) n = value to be loaded into OCR2B = 255 (MAX count of OCR2A) /4 = 63.75 ==> OCR2B = 63 or 64?

(ii) Period (T) of PWM is: 1/500 kHz = 16 us ON-time (duty cycle) = 4 us (25%) n1 = 256 (Total count of TCNT2 when reset happens at the end of 16 us) n2 = number of clock pulses to be counted during ON-time = n1/4 = 256/4 = 64. ==> OCR2B = 64?

GolamMostafa: 3. Follow up question: (a) Assume that for Mode-7 operation of TCNT2 Ch-B, I have loaded (after calculation) 24 into 8-bit OC2RA register with clkTC2 = 500 kHz in order to get a 20 kHz PWM signal.

OK, I will assume that. I guess by "clkTC2 = 500 kHz" you mean the prescale has been set to 32 (16 MHz/32 == 0.5 MHz == 500 kHz).

GolamMostafa: (b) I am asked to calculate a value that is to be loaded into 8-bit OCR2B register to get 25% duty cycle.

NEITHER of your options. If you set OCR2B to 63, or 64 (or any value greater that TOP) you get 100% duty cycle.

You want (((TOP+1) * 0.25)+0.5) truncated to an integer to get (to the nearest integer) the count that will get you closest to a 25% duty cycle. Since TOP is 24 this comes out to 6 (truncated from 6.5). TOP+1 is the number of counts in a cycle. Multiply by 0.25 to get 25% duty cycle. Add 0.5 to round to the nearest integer.

The value MAX (0xFF) is not used in Mode-7.

johnwasser: NEITHER of your options. If you set OCR2B to 63, or 64 (or any value greater that TOP) you get 100% duty cycle.

I have played so much with "Mode-3 Ch-A" with fixed TOP value of 0xFF that I have totally forgotten the calculated TOP value for "Mode-7 Ch-B" which is 24 (0x18) and not 0xFF. I sincerely apologize for this unintentional mistake that has taken away some of your precious time.

You want (((TOP+1) * 0.25)+0.5) truncated to an integer to get (to the nearest integer) the count that will get you closest to a 25% duty cycle.

==> (((TOP+1)*.25)+0.5 ==> (((24+1)*0.25)+0.5 ==> (25*0.25) + 0.5 ==> (6.25) + 0.5 ==> 6 + 0.5 ==> 7

Which one of the following two approaches is appropriate to put 7 into OCR2B register?

OCR2B = 7;    //tested and found 25% duty cycle

Or

OCR2B = (round)(((OCR2A+1)*0.25)+0.5);  //tested and found 25% duty cycle

6.25 + 0.5 is 6.75 which truncates to 6

You got 7 by passing 6.75 to a function named 'round'. If you are going to round instead of truncating you should not add 0.5 first. You should have passed the 6.25 directly to 'round' to get 6.0 which truncates to 6.

You should not be using a prescale of 32 for a frequency of 20 kHz. The next smaller prescale (eight) still gives a TOP that will fit in an 8-bit register AND you then get 100 levels of PWM instead of 25.

Here's what I would do:

void setup()
{
  Serial.begin(115200);


  byte TOP = ((F_CPU / 8) / 20000) - 1;
  unsigned DutyCyclePercent = 25;


  OCR2A = TOP;
  
  OCR2B = ((TOP + 1) * (DutyCyclePercent / 100.0)) + 0.5; //tested and found 25% duty cycle


  Serial.print("TOP==");
  Serial.print(TOP);
  Serial.print("   OCR2B==");
  Serial.println(OCR2B);
}

This results in: TOP==99 OCR2B==25

johnwasser:
6.25 + 0.5 is 6.75 which truncates to 6

1. Does truncate mean – dropping of the fractional part?

2. Does round mean – if the “to be dropped” digit at the right side of the decimal point is 5 or >5, then add 1 just with the immediate left digit?

3. Why have we chosen here truncation instead of rounding?

You got 7 by passing 6.75 to a function named ‘round’. If you are going to round instead of truncating you should not add 0.5 first. You should have passed the 6.25 directly to ‘round’ to get 6.0 which truncates to 6.

4. Cool!

You should not be using a prescale of 32 for a frequency of 20 kHz. The next smaller prescale (eight) still gives a TOP that will fit in an 8-bit register AND you then get 100 levels of PWM instead of 25.

5. Yes! Now, there is much better control on the regulation of duty cycle. With prescale 32, the resolution is 0.64 us; whereas, a resolution of 0.16 us can be achieved with prescale 8. Thank you for the meticulous observation. (Resolution refers to minimum amount of time by which the duty cycle could be augmented.)

Here’s what I would do:

byte TOP = ((F_CPU / 8) / 20000) - 1;

6. The above equation is a result of derivation/manipulation:
fOC2B = fOSC/(N*(TOP+1))
==> TOP = ((fOSC/N)/fOC2B) - 1
==> TOP = ((16000000/8)/20000) - 1
==> TOP = 99

7. has the symbolic name F_CPU been defined in the Arduino.h file for 16000000?

Follow up Question:
In Mode-1 operation, the TCNT2 produces “phase corrected” PWM signal. I am looking for why it is called “phase correct” PWM?

1. My understanding-I: If TCNT2 produces waveforms on Ch-A and Ch-B simultaneously at the same frequency and polarity (say: non-inverting), then the phase difference between them (Fig-1) is to be kept at minimum. (But, the concept of phase difference exists for the synchronized waveforms. Are these two waveforms synchronized? Moreover, what is the use of this pair of signals?)


Figure-1:

2. My understanding-II: If TCNT2 produces waveforms on Ch-A and Ch-B simultaneously at the same frequency but of opposite polarity (say: Ch-A is non-inverting and Ch-B is inverting), then the phase difference between them (Fig-2) is to be kept at minimum. (But, the concept of phase difference for synchronized waveforms and w.r.t. identical zero crossing points. Here, Ch-A is at +ve zero crossing point (ZCP) and Ch-B is -ve ZCP. This kind of signals are seen to have used in driving the push-pull power stage of a bridge inverter.)


Figure-2:

phaseCorrectx.png

PhaseCorrectPWM.png

GolamMostafa: 1. Does truncate mean -- dropping of the fractional part?

Yes.

GolamMostafa: 2. Does round mean -- if the "to be dropped" digit at the right side of the decimal point is 5 or >5, then add 1 just with the immediate left digit?

Yes, for positive numbers. If you add 0.5 to a floating-point number before truncating to an integer then numbers below X.5 will truncate to X and numbers equal to or greater than X.5 will truncate to X+1.

GolamMostafa: 3. Why have we chosen here truncation instead of rounding?

The value is being stored in an integer variable so it will be truncated no matter what you do. Adding 0.5 is much faster than calling the library function 'round()'.

GolamMostafa: 7. has the symbolic name F_CPU been defined in the Arduino.h file for 16000000?

Not in Arduino.h but it is defined for all Arduino boards.

GolamMostafa: In Mode-1 operation, [...] why it is called "phase correct" PWM?

Because the time between the centers of each pulse is the same regardless of duty cycle. With Fast PWM the start of the pulse is at the start of each cycle so the center of the pulse comes later in the cycle when the duty cycle increases. Very high duty cycles can be nearly 90° delayed from very low duty cycles. If you switch between low and high duty cycles and want the phase to not shift, use phase correct PWM.

GolamMostafa: 1. My understanding-I: If TCNT2 produces waveforms on Ch-A and Ch-B simultaneously at the same frequency and polarity (say: non-inverting), then the phase difference between them (Fig-1) is to be kept at minimum.

The phase difference is not measured at the start of the pulse but at the center of the pulse. If you need the phase to match, use phase correct PWM.

johnwasser:
Because the time between the centers of each pulse is the same regardless of duty cycle. With Fast PWM the start of the pulse is at the start of each cycle so the center of the pulse comes later in the cycle when the duty cycle increases. Very high duty cycles can be nearly 90° delayed from very low duty cycles.

Your above text has not brought to me your experience. have not understood; so, I have not been able to convert your text into a visible picture.

1. I assume: when you say “pulse”, you mean: “one complete cycle” of a wave.

2. Does “center of a pulse” mean: If there is a 20 kHz wave (T = 50 us), the “center of pulse” is the 25 us point from the origin?

3. The saying “time between the centers of each pulse” is referring to what?
Have you wanted to mean that the “time difference” between the centers of the pulse of Ch-A and Ch-B in Mode-3 Non-inverting mode (Fig-1)?


Figure-1:

I have kept reading your text and hope that I will be able to come up with the intelligence of your experience and then I will do some experiments.

cenP.png

GolamMostafa:
1. I assume: when you say “pulse”, you mean: “one complete cycle” of a wave.

No. When I mean ‘cycle’ I say ‘cycle’. By ‘pulse’ I mean the positive portion of the PWM cycle. Does that make the rest clear?