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:

  1. Period

  2. Duty Cycle

A typical PWM waveform with one period zoom in

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 1period(s)\frac{1}{\text{period(s)}}.

Note the unit for period is seconds!

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:

Duty Cycle=On TimePeriod\text{Duty Cycle}=\frac{\text{On Time}}{\text{Period}}

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.

Timer/Counter Block Diagram (P126)

Note that many register and bit references are presented in a generalized form: n represents the Timer/Counter number, x = A, B denotes Unit A or B.

Some Useful Terms

Constant
Description

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.

Counter Unit

The Counter Unit block diagram (Figure 1.3) is shown as follows for reference:

Couter Unit Block Diagram (P127)

Once the clock is set, the TCNTn register increments at a certain frequency which is determined above.

Output Compare Unit

The Output Compare Unit block diagram is shown as follows,

Output Compare Unit Block Diagram (P129)

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:

  1. it will be used to set the Output Compare Flag (OCF0A or OCF0B) at the next timer clock cycle. If the corresponding interrupt is enabled, the Output Compare Flag generates an Output Compare interrupt.

  2. it will be used by the Waveform Generator to generate an output on the Output Compare pins (OCnA or OCnB) according to operating mode set by WGMx[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

  1. Normal mode (Not discussed)

  2. Clear Timer on Compare Match (CTC) Mode

  3. Fast PWM Mode (Not discussed for now)

  4. 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.

CTC Mode Timing Diagram (P132)

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.

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):

Phase Correct Mode Timing Diagram (P132)

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

  1. clearing (or setting) the OC0x Register at the compare match between OCR0x and TCNT0 when the counter increments, and

  2. setting (or clearing) the OC0x Register at compare match between OCR0x and TCNT0 when the counter decrements.

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:

  1. the frequency of the clock source (internal or external)

  2. the prescaler NN

  3. the TOP\text{TOP} value

1

Clock source

This is done by setting CSx[2:0] in TCCRnB register.

In CG2111A, at most times, we will use the internal clock source, whose frequency is denoted by clkI/O\text{clk}_{\text{I/O}} and the frequency value is 16Mhz16\text{Mhz}.

2

Prescaler

This is done by setting CSx[2:0] in TCCRnB register also.

The prescaler is used to slow down your clock source. For example, if your prescaler is NN, then your timer/counter's frequency will become clkI/ON\frac{\text{clk}_{\text{I/O}}}{N}, meaning that your timer/counter will update by 1 in every NclkI/O\frac{N}{\text{clk}_{\text{I/O}}} seconds.

3

TOP

This is done by setting the WGMn[2:0] bits (WGM[1:0] are in TCCR0A, WGM02 is in TCCR0B)

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

T=NclkI/O×2×TOPT=\frac{N}{\text{clk}_{\text{I/O}}}\times 2\times \text{TOP}

Since f=1Tf=\frac{1}{T}, we will get the following formula for Phase-Correct PWM Mode from the ATmega328p data sheet

where fOCnxPCPWMf_{\text{OCnxPCPWM}} 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:

  1. whenever there is an output compare match (OCFx Interrupt Flag)

  2. 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)

TIMSK0 register (P143)

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:

  1. Waveform Generation Mode (WGMn[2:0]): these bits will control the following accroding to the Table 19-9 below

    1. Timer/Counter Operating Mode

    2. the TOP counter value

    3. the time to update OCRnx

    4. the time to set TOV Flag

    Waveform Generation Mode Bit Representation (P140)

  2. 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)

  1. Select Compare Output Mode in COM0A/B[1:0]. See Compare Output Mode (Timer 0)

  2. Set WGM01 and WGM00. See Wave Generation Mode (Timer 0)

COM0A for Output Pin OC0A and COM0B for Output Pint OC0B

Control Register B (TCCR0B)

  1. Select clock source via CS0[2:0]. See Configure Clock source (Timer 0)

Counter Register (TCNT0)

Nothing but an 8-bit register.

Output Compare A (Duty Cycle, OCR0A)

Nothing but an 8-bit register.

Interrupt Mask Register (TIMSK0)

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

Output Pin

  1. OC0A: PD6, Arduino Pin 6

  2. OC0B: PD5, Arduino Pin 5

Compare Output Mode (Timer 0)

Wave Generation Mode (Timer 0)

Configure Clock source (Timer 0)

Demo setup Code

Last updated