Arduino UNO, Timer 2, Fast PWM bug?

I am implementing a fast PWM with Timer 2 on an Arduino UNO Board. Nothing special. But i got a very interesting behavior, and i want to know if anyone can explain this?

I ran the following code exactly like it is:

void setup() {
  DDRD |= (1<<PD3);    // Output Pin 3 (Arduino DIO 3) for PD3 PWM Timer OC2B output
  TCCR2A = (1<<COM2B1) | (1<<COM2B0) /*| (1<<WGM21) |*/ (1<<WGM20);	// Inverting Fast PWM mode 3 using OCR B unit
	TCCR2B = (1<<CS20);	// No-Prescalar
  OCR2B = 0xFF - 20;
}

void loop() {

}

The resulting PWM has 31kHz frequency and runs fine as i would expect.

BUT: when i uncomment the Bit 'WGM21' in the code above, everything changes. Look at the picture:

The resulting PWM has 62kHz as expected, but it's not always there. How long it's there changes together with the Duty Cycle in Register OCR2B, even it's not identical with it.

Has anyone an explanation for this, or at least can verify it? (You can copy&paste the exact code from above.)
I tried it with two Arduino Boards so far.

Thank you!

  TCCR2A = (1 << COM2B1) | (1 << COM2B0) | /*(1<<WGM21) |*/ (1 << WGM20); // Inverting Fast PWM mode 3 using OCR B unit

That's because WGM1 is a Phase Correct PWM mode that runs half as fast.

WGM3 is the FastPWM mode you wanted. It's not clear why your HIGH part of the cycle appear to be modulated.

The same characteristic is observed when simulated, however the example from here works as expected ...

Tip: Your preferred scope settings can be saved in diagram.json

      "attrs": {
        "mySampleTimeUs": "20",
        "mySampleTimeMs": "0",
        "myTriggerChannel": "1",
        "myTriggerMode": "1"
      }
1 Like

Cool, you can toggle it and see phase correct happen with:

void setup() {
  pinMode(3, OUTPUT);
  pinMode(11, OUTPUT);
  TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
  TCCR2B = _BV(WGM22) | _BV(CS22);
  OCR2A = 180;
  OCR2B = 50;
}

void loop() {
  static bool toggle = false;
  static uint32_t last = 0;
  if(millis() - last >= 1000){
    last += 1000;
    toggle = !toggle;    
     TCCR2A = toggle ? (TCCR2A & ~_BV(WGM21)) : (TCCR2A | _BV(WGM21)) ;
  }
}

1 Like

Yes, this is the question: Why does it seem to be modulated? And it clearly IS modulated, i zoomed in and out on my scope. It happens only with Fast PWM with no prescaler. When i set a prescaler or use normal 31kHz PWM, everything works fine as expected.
For now, i go with 31kHz. But the question remains, if any arduino initialization in the background changes or toggles anything? I have no explanation for it.

What is the frequency of the modulation?

The modulation occured with around 10 Hz (at least in the picture above).
The 'modulation frequency' did not change when i changed the duty cycle of the PWM, but the 'modulation duty cycle' did indeed change.
At around 40% duty cycle, the 'modulation duty cycle' was at 100%. But above around 60%, the 'modulation duty cycle' occured as an 'inverted pwm' duty cycle.
Very strange behavior for this simple program.

If i need those 62kHz later on, i would test this program directly on the uC, without all the arduino IDE around.

Oh interesting, i did not know about the simulator.
But i can't really confirm this behavior. It seems to be more of a resolution problem of the scope, that makes it appearing like it? Because when i zoom in and out, this effect seems only to be visible in certain settings, with no changes to the program. Or am i wrong?

Your original code with 62.5kHz pulse looks like below with the scope at its limits. To take high frequency measurements, their Logic Analyzer works really well.

The Logic Analyzer requires the PulseView installed and setup on your PC, then you can zoom in and measure ...

Pulse Width (1.3µs) ...

Pulse Period and Frequency ...

Zoomed out ...

Your original code on Wokwi using (1<<WGM21)...

Note:

  • Duty cycle is (1.3/16)*100 = 8.125%

  • In post #1 you show /*| (1<<WGM21) |*/ which has 2 binary OR operators.
    (there should only be 1)

I just tested your code with old good Nano :slight_smile: and didn't see any modulation at high level part of signal:
timer2

I think your assumption is correct:

These are some problems with your log analyzer or something like this. The AVR timers are used by millions of users and all the errors in it have long been known.

the code

void setup() {
  DDRD |= (1<<PD3);    // Output Pin 3 (Arduino DIO 3) for PD3 PWM Timer OC2B output
  TCCR2A = (1<<COM2B1) | (1<<COM2B0) | (1<<WGM21) | (1<<WGM20);  // Inverting Fast PWM mode 3 using OCR B unit
  TCCR2B = (1<<CS20); // No-Prescalar
  OCR2B = 0xFF - 20;
}

void loop() {}

You can count the vertical lines from the scope image. It toggles yellow/dim at close to the clock frequency of the MCU.

  • Try "star ground point" for your connections. That is, only one ground point with a single ground wire going to each device. There should be no ground loops (GND to GND connections in series)

  • Try adding a 0.1uF ceramic capacitor from this ground point to VCC.

  • Most importantly, use X10 on your probe and setup the scope for X10.

Yes indeed - It's the scope :grimacing:
Somehow the frequency exactly matches the scope resolution, even with zooming in and out, so that it gets canceled out in some areas. This was absolutely not on my mind, was thinking with my 60MHz scope i would not have such issues.
But anyway, thank you for all your ideas and your help on this! :+1:

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