Computing stuff tied to the physical world

Fixing the Arduino’s PWM #2

In AVR, Software on Nov 9, 2011 at 00:01

Yesterday’s post identified a problem in the way different PWM pulses are generated in the ATmega.

It’s all a matter of configuration, since evidently the timers used to generate the PWM signals all run off the same clock signal, and can therefore be made to cycle at exactly the same rate (they don’t have to roll over at the same time for our purposes, but they do have to count equally fast).

The problem is caused by the fact than PWM pins D.5 and D.6 are based on timer 0, which is also used as millisecond timer, whereas PWM pin D.9 is based on timer 1. It’s not a good idea to mess with timer 0, because that would affect the delay() and millis() code and affect all parts of a sketch which are timing-dependent.

Timer 0 is set in “Fast PWM” mode, which is not perfect. So the Wiring / Arduino team decided to use “Phase Correct PWM” mode for timers 1 and 2.

In Fast PWM mode, the timer just counts from 0 to 255, and the PWM output turns high when the counter is in a specific range. So far so good.

In Phase Correct PWM mode, the timer counts from 0 to 255 and then back to 0. Again, the PWM output turns high when the counter is in a specific range.

The phase correct mode counts up and down, and takes twice as long, so that explains why the green LED output runs at half the speed of the others.

Except that… it’s not exactly twice!

Timer 0 wraps every 256 counts, and that should be kept as is to keep the millisecond code happy.

But timers 1 and 2 wrap every 0 -> 255 -> 0 = 511 counts (I think – or is it 510?). Hence the out-of-sync effect which is causing so much trouble for the LED Node.

See also Ken Shirriff informative page titled Secrets of Arduino PWM, for the ins and outs of PWM.

The solution turns out to be ridiculously simple:

    bitSet(TCCR1B, WGM12);

Just adding that single-bit change to setup() will force timer 1 into Fast PWM mode as well. The result:

DSC 2730

This picture was taken with the scope running. The signals are in lock-step and rock solid. More importantly, the result is a perfectly smooth LED light – yippie!

  1. Good find.

    There are some weird and wonderful flags lurking on that chip aren’t there. All with even weirder names!

    Oh, and 510… I think!

    0->255 254->1 then 0 is the start of the next cycle.

  2. Is your LED strip evenly lit now across its entire length? Without lowering frequency?

    • No, the middle is now white (where the power feed is), the ends are still slightly red. But the flicker is completely gone. One step at a time, please! :)

    • Sorry, just being impatient curious :)

  3. Funny, I just spent 3 days learning about avr timers and trying to figure how to set timer3 on a mega to “fast pwm” . I found the solution 2 hours ago. I should have waited for you to do the work!

    Life.

  4. You do understand that we want to see movies at a certain point, don’t you ;-)

    I’m looking forward to see the sun set in your room ;-)

    Good job!

  5. Like borg, I tried to lower the frequency of the involved timer without great results (better with the three PWMs at 250Hz, but still slightly pulsing as the signals were still dephased). But your solution works perfectly! My leds are on pin 3,5,6 so I changed timer2 instead of timer1 using this (from Ken Shirriff’s tutorial):

    TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);

    There should be a simpler syntax I guess..

    As usual, many thanks !

  6. Maybe a stupid question: but why the “on/off” trick?

    Isn’t it possible to lower the voltage to adjust the brightness?

    • You mean why dim with PWM?

      Because if you don’t and 12V comes in, then you have to either drop the voltage by turning it into heat with a resistor (wasteful), or you have to use a switching regulator with an inductor (complex).

      Also: if not PWM, how do you want to tell the circuit what the current setting should be?

      Or am I misunderstanding your question?

  7. Well, if I understood correctly, you are not dimming, but turning the led’s on and off very quickly.

    Basically I was wondering if that wouldn’t wear down the leds sooner.

    I believe that a normal “dimmer” loweres the voltage, in order to bring light levels down. So I was wondering why that isn’t an option here.

    But, judging from your answer, that would require an inductor, which would make it rather complex… (I take your word for it here :-)).

    (still wondering though, if it wouldn’t wear your leds down sooner)

  8. Actually, the LED’s will last longer! You are perhaps thinking more of an old style incandescent light bulb and a mechanical switch. In that case, since there is a large surge current when turning on a cold filament, the life is often reduced by the stress of multiple power ons creating “necking” of the filament. (With a relatively fast switching waveform, the filament does not have time to get cold again, negating this problem)

    LED action is completely different – the light emission is not from making something glow white hot (hence the better efficiency) and they are happy in this type of circuit. LED lifetime (at constant external temperature) is roughly proportional to the total light generated since it’s first power on.

  9. Ah, that explains a lot. Thanks!

Comments are closed.