Studio 4 - PWM Programming
In EPP2 Quiz, whenever you see PWM, it is by default using Phase-Correct Mode.
PWM Concepts
In previous studios, we learnt how to generate digital signals using the GPIO pins. This studio will introduce Pulse-Width Modulation (PWM), a digital technique used to simulate an analog signal by rapidly toggling a signal between a HIGH (1) and a LOW (0) state at a controlled frequency. By adjusting the proportion of time the signal remains HIGH versus LOW, we can approximate different analog voltages.
The PWM signal has two key parameters:
Period
Duty Cycle

Period
Period is the total duration of one cycle.
The period of the PWM signal (measured in seconds) indicates the amount of time it takes for the signal to complete one cycle. The frequency of the PWM signal is .
Duty Cycle
The Duty Cycle represents the percentage of time the signal is HIGH (ON Time, a.k.a pulse width) during a cycle. The relationship between duty cycle and ON Time is characterized by the Equation below:
When observing a PWM signal closely, the ON and OFF states within a single period appear distinct and separate. However, as the PWM signal's frequency increases, it becomes more difficult to distinguish between these states, making the signal appear more continuous and averaged over time. A peripheral, such as a servo motor, interprets the PWM signal as an effective analog voltage between 0 V and VCC, depending on the duty cycle. The value of this average analog signal can be determined by the Duty Cycle in the PWM waveform:
PWM vs. DAC
We have already seen how PWM works above. Now, let's take a look at how modern DAC (Digital Analog Converter) works.
How Modern DAC Works
A Digital-to-Analog Converter (DAC) converts a digital value (e.g., an 8-bit or 16-bit number) directly into a corresponding analog voltage or current. Modern DACs employ techniques such as:
Resistor Ladder (R-2R): Uses a network of resistors to produce an analog voltage proportional to the binary input.
Sigma-Delta Modulation: Employs oversampling and noise shaping for high-precision output.
Unlike PWM, a DAC generates a smooth, continuous analog signal without relying on time-averaging. The output voltage scales linearly with the digital input, offering fine control and high resolution depending on the bit depth (e.g., 12-bit or 16-bit).
Key Differences
Here are the primary distinctions between PWM and DAC, with additional context integrated:
Signal Nature:
PWM: Produces a digital square wave. The analog effect arises from averaging the signal over time, making it an approximation rather than a true analog output.
DAC: Outputs a genuine analog signal with continuous voltage levels, requiring no averaging.
Hardware Complexity:
PWM: Requires minimal hardware—just a digital pin on a microcontroller or a simple timer circuit—making it cost-effective and easy to implement.
DAC: Involves dedicated analog circuitry, which is more complex and typically more expensive.
Precision and Smoothness:
PWM: The perceived smoothness depends on the switching frequency and the device’s response. At lower frequencies, the digital pulses may cause noticeable effects (e.g., flickering in LEDs). Adding a low-pass filter can smooth the signal into a near-continuous voltage, but it’s still not as seamless as a DAC.
DAC: Delivers a smooth, stable analog output with no inherent switching, providing higher precision and consistency.
Applications:
PWM: Commonly used for power control in devices like motors, LEDs, and heaters, where the averaging effect suffices and cost is a concern.
DAC: Suited for applications needing precise analog signals, such as audio reproduction, scientific instrumentation, or communication systems.
Why PWM Is Considered Analog-Like
Despite being a digital signal, PWM is often described as simulating an analog output because:
Devices respond to the average voltage rather than the individual pulses.
At high frequencies, the switching occurs too quickly for many systems to detect, mimicking a continuous voltage.
With a low-pass filter, the PWM signal can be physically smoothed into a nearly continuous analog waveform.
However, PWM remains a digital approximation—its effectiveness as an "analog" signal depends on the frequency and the connected device’s characteristics. In contrast, a DAC provides a true analog output without such dependencies.
PWM is considered "analog" in this context because of its output effect, not its waveform.
This is also why we mentioned this sentence above because the role of frequency in PWM signal generation,
However, as the PWM signal's frequency increases, it becomes more difficult to distinguish between these states, making the signal appear more continuous and averaged over time.
Timer/Counter
In ATmega328p, the core concept to generate a PWM waveform involves utilizing the 8-bit Timer/Counter to precisely control the duration of the signal’s high and low states, enabling us to achieve the specified period and duty cycle for the PWM waveform.

Some Useful Terms
BOTTOM
The counter reaches the BOTTOM when it becomes zero (0x00 for 8-bit counters, or 0x0000 for 16-bit counters).
MAX
The counter reaches its Maximum when it becomes 0xFF (decimal 255, for 8-bit counters) or 0xFFFF (decimal 65535, for 16-bit counters).
TOP
The counter reaches the TOP when it becomes equal to the highest value in the count sequence. The TOP value can be assigned to be the fixed value MAX or the value stored in the OCR0A Register. The assignment is dependent on the mode of operation.
Timer/Counter Clock Sources
The Timer/Counter can be clocked by an internal or an external clock source. The clock source is selected by writing to the Clock Select Bit (CS0[2:0]) bits in the TCCRnB.
Selecting the clock source and prescaler determines the frequency of the timer/counter.
Counter Unit
The Counter Unit block diagram (Figure 1.3) is shown as follows for reference:

Once the clock is set, the TCNTn register increments at a certain frequency which is determined above.
Always remember to initialize the counter value to 0
Output Compare Unit
The Output Compare Unit block diagram is shown as follows,

The comparator continuously compares TCNTn with the Output Compare Registers (OCR0A and OCR0B). Whenever TCNTn equals OCR0A or OCR0B, the comparator signals a match. A match will be used in 2 ways:
it will be used to set the Output Compare Flag (
OCF0AorOCF0B) at the next timer clock cycle. If the corresponding interrupt is enabled, the Output Compare Flag generates an Output Compare interrupt.it will be used by the Waveform Generator to generate an output on the Output Compare pins (
OCnAorOCnB) according to operating mode set byWGMx[2:0]and Compare Output mode (COMnx[1:0])
Modes of Operation
There are four modes of operation on for the timer/counter unit on ATmega328p, they are
Normal mode (Not discussed)
Clear Timer on Compare Match (CTC) Mode
Fast PWM Mode (Not discussed for now)
Phase Correct PWM Mode
CTC Mode
This is not a PWM mode!
In CTC Mode, the counter is cleared to ZERO when the counter value (TCNT0) matches the OCR0A. An example timing diagram for the CTC mode is shown below.

In this example, the Compare Output Mode of OC0A is set to toggle mode, and it will toggle its logical level on each compare match.
In CTC Mode, the TOP value of the TC Module is always set to
OCRnA/OCRnB.An interrupt can be generated each time the counter value reaches the TOP value by setting the
OCF0AFlag. If the interrupt is enabled, the interrupt handler routine can be used for updating the TOP value.The
OCRnA/OCRnBvalue is always updated immediately!
Phase Correct PWM Mode
The Phase Correct PWM Mode is based on dual-slope operation: The counter counts repeatedly from BOTTOM to TOP, and then from TOP to BOTTOM. The dual-slope opeartion has a lower maximum operation frequency than single-slope operation. An example timing diagram for the Phase-Correct PWM Mode is shown below (The small horizontal line marks on the TCNT0 slopes represent compare matches between OCR0x and TCNT0):

In this example, the Compare Output Mode of OC0A is set to either inverting mode (COMnx[1:0]=0x10) or non-inverting mode (COMnx[1:0]=0x11). The PWM waveform is generated by
clearing (or setting) the
OC0xRegister at the compare match betweenOCR0xandTCNT0when the counter increments, andsetting (or clearing) the
OC0xRegister at compare match betweenOCR0xandTCNT0when the counter decrements.
The Timer/Counter Overflow Flag (TOV0) is set each time the counter reaches BOTTOM
The
OCRnxUpdate is always done at TOP!
At the very start of period 2 in the timing diagram above, OC0x has a transition from high to low even though there is no Compare Match. This transition serves to guarantee symmetry around BOTTOM.
Bare Metal Programming
Set Period
The period of the PWM signal depends on 3 factors here:
the frequency of the clock source (internal or external)
the prescaler
the value
Clock source
This is done by setting
CSx[2:0]inTCCRnBregister.
In CG2111A, at most times, we will use the internal clock source, whose frequency is denoted by and the frequency value is .
Prescaler
This is done by setting
CSx[2:0]inTCCRnBregister also.
The prescaler is used to slow down your clock source. For example, if your prescaler is , then your timer/counter's frequency will become , meaning that your timer/counter will update by 1 in every seconds.
TOP
This is done by setting the
WGMn[2:0]bits (WGM[1:0]are inTCCR0A,WGM02is inTCCR0B)
The TOP value defines the maximum value the counter will count to. Why it affects the period of PWM?
In Phase-Correct PWM Mode, the period of the PWM signal is equal to the time when the counter counts from BOTTOM to TOP and then from TOP to BOTTOM. Thus, the period will be
Since , we will get the following formula for Phase-Correct PWM Mode from the ATmega328p data sheet
where refers to the frequency of the Phase-Correct PWM.
Set Duty Cycle
The duty cycle is determined by the value stored in the OCRnA register, based on the following formula.
For generating the desired PWM waveform with 75% duty cycle, we have:
Thus, the value we want to write to OCR0A is 191.
Set Interrupts
The timer can be configured to generate interrupts:
whenever there is an output compare match (
OCFxInterrupt Flag)timer overflow flag (
TOVn), this depends on which PWM we are using.
All interrupt request signals are visible in the Timer Interrupt Flag Register (TIFRn). (We don't need to configure this register since the flag will be set automatically based on compare match and overflow)

And all interrupts are individually masked with the Timer Interrupt Mask Register (TIMSKn). (We need to configure this register because this mask can enable or disable the three interrupt flags above)

Here, we want to enable the OCFA output compare flag, which basically means when there is a output compare match between TCNT0 and OCR0A. So, we will set OCIEA to 1. Thus, we should write 0b10 to TIMSK0.
Set Desired PWM Mode
Here, we need to determine 2 modes:
Waveform Generation Mode (
WGMn[2:0]): these bits will control the following accroding to the Table 19-9 belowTimer/Counter Operating Mode
the TOP counter value
the time to update
OCRnxthe time to set
TOVFlag

Waveform Generation Mode Bit Representation (P140) Compare Output Mode (
COMnx[1:0]): These bits will control the Output Compare Pin (OCnx) behavior. (Below is an example if we use Phase Correct PWM Mode)
Compare Output Mode, Phase Correct PWM Mode (P140)
Summary
Control Register A (TCCR0A)
TCCR0A)Select Compare Output Mode in
COM0A/B[1:0]. See Compare Output Mode (Timer 0)Set
WGM01andWGM00. See Wave Generation Mode (Timer 0)

Control Register B (TCCR0B)
TCCR0B)Set
WGM02. See Wave Generation Mode (Timer 0)Select clock source via
CS0[2:0]. See Configure Clock source (Timer 0)

Counter Register (TCNT0)
TCNT0)Nothing but an 8-bit register.

Output Compare A (Duty Cycle, OCR0A)
OCR0A)Nothing but an 8-bit register.

Interrupt Mask Register (TIMSK0)
TIMSK0)Enable the Output Pin Interrupt (OCIEA for OC0A and OCIEB for OC0B)

Output Pin
OC0A: PD6, Arduino Pin 6OC0B: PD5, Arduino Pin 5
Compare Output Mode (Timer 0)

Wave Generation Mode (Timer 0)

Configure Clock source (Timer 0)

Demo setup Code
Control Register A (TCCR1A)
TCCR1A)Select compare output mode in
COM1A/B[1:0]. See Compare Output Mode (Timer 1)Set
WGM11andWGM00. See Wave Generation Mode (Timer 1)

Control Register B (TCCR1B)
TCCR1B)Set
WGM13andWGM12. See Wave Generation Mode (Timer 1)Select
CS1[2:0]. See Configure Clock Source (Timer 1)

Counter Register (TCNT1L and TCNT1H)
TCNT1L and TCNT1H)TCNT1L: an 8-bit register for low byteTCNT1H: an 8-bit register for high byte
Output Compare Register (OCR1AL and OCR1AH)
OCR1AL and OCR1AH)Input Capture Register 1 (ICR1L and ICR1H)
ICR1L and ICR1H)This is to customize the value.
Interrupt Mask Register (TIMSK1)
TIMSK1)
Output Pin
OC1A(PB1, Arduino Pin 9)OC1B(PB2, Arduino Pin 10)
Compare Output Mode (Timer 1)

Wave Generation Mode (Timer 1)

Configure Clock Source (Timer 1)

Demo setup code
Last updated