Micro beginner ==> 5. LED with PWM
Lecture 5: To control the intensity of a LED via PWM
So far we used blinkling of a LED. Now we continue blinking, but with a high frequency.
With that blinking we change the intensity from weak to high. And this in an exact
linear manner and not with a non-linear current.
- Introduction to the PWM mode of the timer
- Hardware, components, mounting
- Timer in fast PWM mode
- Timer in phase-correct PWM mode
5.1.1 8 bit PWM
PWM means pulse width modulation. To do this the timer, on restarting, sets or clears
an output (OC0A and/or OC0B). If a compare match occurs (A or B) the polarity of the
output changes (clear, set). By reaching the largest value the polarity of the output
again changes and the cycle starts again.
The later the compare match occurs within the whole cycle the longer gets the first
phase and the shorter gets the second phase. This behaviour allows to control the power
of a DC motor as well as the intensity of LEDs. Please note that during the ON period
the transistor drives the motor with maximum available power and that only the duration
is limited. So the motor power is really linear.
The bits COM0A1 and COM0A0 in the TCCR0A port determine, how the output behaves. With
0b10 the output is set at the beginning of the PWM cycle, with 0b11 it is cleared.
Similar to this COM0B1 and COM0B0 in the same port control the output pin OC0B.
This shows how the voltage on the output OC0A changes in Fast PWM mode with TOP at 255
and a compare match at 100. The resulting pulse width is 100 / 256 = 39% high.
Within the Fast PWM mode the selection of the timer prescaler determines the PWM's
frequency. At the different clock frequencies and prescaler values the following
frequencies result and offer a wide range.
|9.6 Mcs/s||37.5 kcs/s||4.69 kcs/s||586 cs/s||146.5 cs/s||36,6 cs/s|
|4.8 Mcs/s||18.8 kcs/s||2.35 kcs/s||293 cs/s||73.3 cs/s||18.3 cs/s|
|2.4 Mcs/s||9.4 kcs/s||1.68 kcs/s||147 cs/s||36.7 cs/s||9.15 cs/s|
|1.2 Mcs/s||4.69 kcs/s||586 cs/s||73.2 cs/s||18.3 cs/s||4.6 cs/s|
|128 kcs/s||500 cs/s||62.5 cs/s||7.8 cs/s||1.95 cs/s||0.49 cs/s|
At 1.2 and 2.4 Mcs/s all PWM frequencies are in an audible range (with motors this
can result in incomfortable humming). A clock frequency of 128 kcs/s is
inappropriate for that purpose, at a prescaler value of 1,024 we can visually follow
the PWM process.
5.1.2 Phase correct 8 bit PWM
This is the signal process in the phase-correct mode. The timer counts up- and downwards,
each time the compare match is reached the polarity of the output changes. The PWM
frequency is half that in Fast PWM mode.
Phase correct PWM mode is used if the compare value changes very often and with large
changes. The change of the compare match value is buffered, the changed value comes
only into effect when the TOP value has been reached. So there are always two periods
(up-counting, down-counting) performed for each compare value. With this, the jitter is
5.1.3 PWM with different resolution
It is not always necessary to use 8 bit resolution, with 256 counting steps (0.39%
accuracy). In some cases it is sufficient to have only four (6.25%) or five (3.1%) bits
resolution of the PWM signal. For a small motor 8 bits might be overdone. If at a
count of 16 (four bit resolution) the cycle restarts, the PWM frequency increases
accordingly. This can be reached by combining the PWM mode with CTC: In that case
compare match port A is used as CTC and compare match B as PWM signal. Those two
modes are possible, as the mode table shows.
In case of a 4 bit resolution (Compare Match A = 15), with 1.2 Mcs/s clock and
a timer prescaler of 1 the PWM frequency will be at 37.5 kcs/s, well above any
audible regions (excluding bats).
In case of 16 bit timers/counters, of which ATtiny13 has none, the normal phase correct
PWM mode would have a resolution of 16 bits (accuracy: 0.0015%), which is by far higher
than any practical requirements. It is therefore nearly always necessary to reduce the
resolution. To relief Compare Match A from this CTC task and allow it to use as
additional PWM channel, an additional port (ICR) provides this task.
For the PWM intensity regulation the same hardware is used as for the previous lectures.
With the previous information on functions, properties and methods a PWM intensity
regulation can be programmed in a simple way. As PWM cycle frequency we select at
1.2 Mcs/s clock and a prescaler of 1 4.7 kcs/s. This is fast enough for
the human eye and for any digital camera.
By changing the polarity of the PWM output we reverse the inversion by the LED. The
source code is here.
One line in this code requires deeper understanding
and some background knowledge:
; * PWM control of a LED in Fast mode *
; * (C)2017 by www.avr-asm-tutorial.net *
; -------- Register -------------------------
.def rmp = R16 ; multi purpose register
; -------- Program --------------------------
; Init output pin OC0A
sbi DDRB,DDB0 ; OC0A as output
; PWM compare value to timer 0
ldi rmp,20 * 256 / 100 ; 20% intensity
out OCR0A,rmp ; to compare match port A
; Timer 0 in Fast PWM mode, output A low at cycle start
out TCCR0A,rmp ; to timer control port A
; Start Timer 0 with prescaler = 1
ldi rmp,1<<CS00 ; Prescaler = 1
out TCCR0B,rmp ; to timer control port B
; Enable sleep mode
ldi rmp,1<<SE ; Sleep enable, mode idle
out MCUCR,rmp ; to Universal control port
sleep ; go to sleep
nop ; in case of wakeup
rjmp Loop ; again to sleep
; End of source code
The term 20 * 256 / 100 usually would result in 51.2. Not
so in assembler. All mathmatical expressions are integer
operations. That means the result is 51, not 51.2. But even
more strange: if we write the term "20 / 100 * 256",
which would be - mathmatically spoken - equivalent, the result
would be 0. We can test that astounding result by adding the
ldi rmp,20 * 256 / 100 ; 20% intensity
and reformulate the above line by
; -------- Constants ------------------------
.equ cIntensity = 20 / 100 * 256
If we assemble that changed code using gavrasm and the -s
option (note that other assemblers do not provide such a
symbol list) we will see the following in the symbol list:
List of symbols:
Type nDef nUsed Decimalval Hexvalue Name
T 1 1 18 12 ATTINY13
L 1 2 9 9 LOOP
R 1 8 16 10 RMP
C 1 1 0 0 CINTENSITY
The reason for this is that the assembler ALWAYS a) uses integer
math, including interim results, and b) that he always processes
expressions from left to right, and c) follows priority rules
such as "*" and "/" higher than "+"
and "-". So the constant calculation term is processed
If you want to overrule the standard processing scheme you'll have
use brackets. So the formulation
- Divide 20 by 100 in integer mode, result = 0 (!)
- Multiply result with 250, result = 0 (!)
is always more correct as it overrules any priority and
processing sequences. See
this page for a complete list of mathmatical expressions in
This list is sorted by increasing priority.
.equ cIntensity = (20 * 250) / 100
The PWM intensity control is rather simple code. And here is
The differences in intensities are clearly visible.
Please note that the PWM cannot be set to 0% intensity because the first clock pulse
is always executed. If 0% should be really switching the LED off one has to decouple
the output pin from the PWM control and to set the port pin to high level.
The phase correct PWM mode is achieved by removing the WGM01 bit in the above source
code (WGM01 = 0). Now the PWM works at 2.34 kcs/s. Still fast enough for this
application, but a motor might hum in an audible frequency range.
©2017 by http://www.avr-asm-tutorial.net