• Become a member
  • Log In
The Institution of Electronics
  • Home
  • About us
    • Our Objectives
    • Our History
    • Governance of the Institution
  • The Electron Magazine
    • 2024
      • 2024 – Winter
      • 2024 – Spring
      • 2024 – Summer
      • 2024 – Autumn
    • 2025
      • 2025 – Winter
      • 2025 – Spring
      • 2025 – Summer
      • 2025 – Autumn
    • 2026
      • 2026 – Winter
  • Members
    • Membership Grades and Fees
    • Members’ Resources
      • The Electron Newsletter
      • The Archives
  • Education and Projects
    • National Electronics Competition
    • Student Members’ Projects
    • Arkwright Engineering Scholarships
  • News
  • Contact Us
  • Menu Menu
Uncategorised

Implementing a DAC: The battle of the PWMs

Ones and zeroes: are clustered or spread out bits better? “It depends,” is the answer. Well, at least sorta.

In the Comments section of a recent Design Idea for a DAC (Reference 1), one reader expressed a full-throated preference for an alternative to the common type of PWM used therein. For this “common” PWM, the ones in a repetitive cycle are “clustered” together, as are the zeroes. The reader’s preferred alternative is a “spread” type, in which the ones and zeroes are evenly disbursed within each cycle.

The clustered PWM tends to concentrate energy toward the lower frequencies, versus toward the higher with the spread PWM. Noting the relative ease of filtering out the higher frequencies, the reader argued that a microcontroller implementing the spread PWM filtered by a first order low pass (single resistor, single capacitor) filter was superior to the clustered version followed by a more complex third order filter (three pairs of these components.) So, which is the better choice? Let’s take a look.

The job of a PWM filter

PWMs generally produce repetitive sequences of NO ones and NZ zeroes of length N = NO + NZ. A sequence’s filtered resolution is 1/N. Its duty cycle (DC) is its average value, NO / N. The filter will take some settling time TS to get to within some value VST of a new DC. And as long as DC is neither zero nor one, there will be an AC “ripple” signal of some level at the filter output.

Not only must the ripple signal’s contribution to TS be considered, but its post-setting time peaks and valleys must be closer than some error value VRip to DC. Typically, VRip is set to .5/N. The ideal filter meets this requirement while minimizing TS for a VST of 1/N. These requirements must hold for all DCs and transitions between them.

Verdict first, then the trial

With apologies for my paraphrase of a famous quote from Lewis Carroll’s Queen of Hearts, there’s enough math and batch file simulations required to adjudicate this PWM shoot-out that I thought it best to present the somewhat surprising (to me at least) conclusions without forcing you to first endure the derivations (perhaps this reported result will spur an interest in that math). Figure 1 provides the summary:


Figure 1 This graph shows the settling time TS for clustered and spread PWMs at various clock speeds. The spread filter employs a single resistor and capacitor; the clustered, 3 pairs of the same (see Table 1 for filter details.) Dividing the clock frequency by a factor multiplies the settling time by that same factor. The error VST at the settling time is 1/N. The post-settling time absolute maximum ripple error VRip is .5/N.

If implemented fully in hardware, such as with an FPGA, it would be possible to clock both PWM types at the same rate and compare their performances. For PWMs of more than 8 bits, the spread PWM (purple trace) with a first order analog filter does indeed settle faster than its clustered competitor (red trace) with a third order filter. The situation is reversed for PWMs of less than 8 bits. A simple explanation for this behavior is that below 8 bits, the clustered filter’s time constants turn out to be less than those of the spread, and the situation reverses above 8 bits. However, it’s worth noting that matched clocking is not possible in a microcontroller.

In a microcontroller, until a change in duty cycle is required, an initialized, clustered PWM can run indefinitely without further processor intervention. It can also benefit from the fastest clock available to the controller. Not so with the spread PWM; it requires code to be executed every PWM clock cycle period. I have assumed 6 machine cycles to execute this spread code within an infinite loop (blue trace). As such, only 16 bit and lengthier PWMs will favor the spread option.

Of course, if you need the processor to do more than just run a spread PWM, these additional functions will increase the effective spread clock period well beyond a mere 6 machine cycles. Obviously, this increases the settling time of the associated filter. And by the way, any non-PWM code had better take a constant number of clock cycles to execute, or the spread PWM output will jitter and its accuracy suffer. The less-than-pristine “cherry on top” is that processor interrupts while supporting a spread PWM are problematic.

PWM bits

Sequence length

 Spread R·C/T:
filter time constant / clock period

Spread settling time TS (ms),
1/6 MHz clock

Spread settling time TS (ms),
1 MHz clock

Clustered filter

Clustered settling time TS (ms),
1 MHz  clock

1

2

9.102E-01

6.00E-03

1.00E-03

See Reference 2 which points to a spreadsheet for filter design

7.92E-04

2

4

3.228E+00

3.00E-02

5.00E-03

3.32E-03

3

8

7.810E+00

1.08E-01

1.80E-02

1.01E-02

4

16

1.696E+01

3.12E-01

5.20E-02

2.93E-02

5

32

3.527E+01

8.04E-01

1.34E-01

8.32E-02

6

64

7.187E+01

1.97E+00

3.29E-01

2.34E-01

7

128

1.451E+02

4.67E+00

7.78E-01

6.53E-01

8

256

2.915E+02

1.08E+01

1.80E+00

1.81E+00

9

512

5.843E+02

2.24E+01

3.74E+00

4.98E+00

10

1024

1.170E+03

5.05E+01

8.42E+00

1.36E+01

11

2048

2.341E+03

1.12E+02

1.87E+01

3.71E+01

12

4096

4.684E+03

2.48E+02

4.13E+01

1.00E+02

13

8192

9.369E+03

5.42E+02

9.03E+01

2.71E+02

14

16384

1.874E+04

1.11E+03

1.85E+02

7.28E+02

15

32768

3.748E+04

2.40E+03

4.00E+02

1.95E+03

16

65536

7.496E+04

5.17E+03

8.61E+02

5.21E+03

17

131072

1.499E+05

1.11E+04

1.84E+03

1.39E+04

18

262144

2.999E+05

2.36E+04

3.94E+03

3.68E+04

19

524288

5.997E+05

4.81E+04

8.01E+03

9.75E+04

20

1048576

1.199E+06

1.02E+05

1.70E+04

2.58E+05

21

2097152

2.399E+06

2.16E+05

3.59E+04

6.80E+05

22

4194304

4.798E+06

4.55E+05

7.58E+04

1.79E+06

23

8388608

9.596E+06

9.57E+05

1.59E+05

4.71E+06

24

16777216

1.919E+07

1.94E+06

3.23E+05

1.24E+07

Table 1 This table details spread and clustered settling times and filter characteristics. Multiply the R·C / T term by the desired spread PWM clock period T to obtain the product of the resistance and capacitance of the first order analog filter (see Figure 4).

To avoid large settling times, recall the option of operating a most significant and a least significant 8-bit PWM simultaneously and adding their outputs as seen in Reference 2. A filter with a 16-bit settling time can be swapped for one with a much shorter 8-bit settling time. Should you want even more resolution, use this concept to add a third PWM.

All this being said, read on for some important sequence characteristics and how best to implement k-bit spread PWMs where k = 1, 2, 3… 24.

Clustered-bit PWM sequences

Clustered-bit PWMs’ NO ones and NZ zeroes each appear in contiguous streams. An example of a waveform for such can be seen in Figure 2. Most microcontrollers can implement these with no software overhead. Just “set ‘em and forget ‘em”: specifically, program the count (NO – 1) after which a one-to-zero output transition is to be produced, and the count (N – 1) after which the counter returns to 0 and the output to a one. The PWM goes on its merry way with no further intervention necessary from executable code unless a change in the value of the duty cycle DC is required.

8 and 16-bit counters are typically available, and so DC values of A / B can be had for any integers such that 0 ≤ A ≤ B ≤ either 28 or 216, respectively. Typically, these counters can be clocked from the same high frequency clock source used to execute the microprocessor instruction set. This is useful because in general, the higher the frequency, the shorter the settling time of the filter needed to suppress the ripple.


Figure 2 This plot is of a clustered-bit PWM where NO = 16, N = 256, and T = 1uS.

Spread-bit PWM sequences

Another type of PWM produces the same number of ones and zeroes in a cycle, but spreads these binary values as evenly as possible. An example can be seen in Figure 3.


Figure 3 With this spread-bit PWM, NO = 16, N = 256, and T = 1uS.

Notice that lowest frequency of the spread PWM is far higher (16 times) than that of the clustered one. Accordingly, a faster-settling filter can be used to suppress the ripple. So what rule governs the positions of the ones and zeroes in the spread sequence? A very simple one.

Consider a parameter X which can take on the values 0, 1, 2… or N – 1. Y is periodically updated to the value of (Y + X) modulo N. If an update reduces Y, the PWM output is one; otherwise, it’s zero. The DC is X / N. This process has at least two important properties:

  1. The period of the PWM sequence is N. This can be shown by considering a parameter W upon which the process W = W + X is repeatedly performed (no modulus is involved in the W update.) If the initial values of Y and W were both C, then Y = (Y + X) modulo N and (W + X) modulo N would be equal after each process step. N steps later, W would be C + N X. For any X, (C + N · X) modulo N is C. Since the moduli of W and Y are always equal, C is also the value of Y after N process steps. And so for any X, the PWM sequence is periodic in N.
  2. To gain insight as to how spreading works, consider when X is 0. Y would never be reduced, and so there would never be a PWM output of one. If X were 1, the PWM would produce a one only once every N steps. If X were increased, there would be ones approximately (if not exactly) every N/X steps. As X approached N/2, the proportion of ones in the output would increase, but as long as X ≤ N/2, ones would never appear in succession. For X ≥ N/2, there would never be any zeroes in succession. And as X approached N, a reversed version of the aforementioned progression of ones would apply to the zeroes.

How might this process be executed on a basic 8-bit microcontroller? The simplest implementation would be to set N to 28 and periodically hijack a portion of the processor’s executable bandwidth to run the process. The following code implements a spread 8-bit PWM of duty cycle X / 28, where the value of X is in register r17 and that of Y is in register r16:

ADD 	r16, 	 r17	; r17 holds the value of NO which can be anywhere from 0 to 28-1.
			; r16 is a simple accumulator which overflows periodically.
ROL	 r20		; The carry bit ( 0 or 1) from the prior addition goes to bit 0 of r20.
OUT	PORTB, r20	; Bit 0 of the PORTB GPIO register takes on the carry bit value.

Of course, you can include a few more instructions so that the other PORTB bits are unaffected. It’s important to note that this code must be executed regularly. Aperiodic, “jittery” execution will impact the accuracy of the filtered value of the output stream. This means that all non-PWM code must always take the same amount of time to execute, making interrupts on the processor problematic.

Want a PWM with more resolution? Place the following instruction after the existing ADD:

ADC	r18, 	r19	; r19 is the MSbyte of the input X and r17, the LSbyte.

This additional instruction enables a 16-bit duty cycle of X / 216. It’s obvious how to further increase resolution by additional factors of 28 to obtain 224, etc.

The inputs of spread PWMs can range from X = 0, 1, 2… to N-1. But if N is limited to integral powers of 28, there’s a very big jump (a factor of 28) of sequence lengths between these options. That means a proportional jump in filter cutoff frequencies and, more importantly, in settling times. Fortunately, a finer range of selections is readily available. Simply limit the allowable values of X to those for which X / 2k is an integer, where k = 1, 2… log2(N)-1. The result is a (log2(N) – k) bit DAC.

The settling times of filters meeting the ripple suppression requirement are now available in increments of a factor of 2. Of course, a spread-bit DAC can have any integer value for N. But values other than 2k require additional code which must explicitly compare Y to N to generate a carry, and then conditionally update Y by subtracting N from it. Also, the spacing between successive values of X could vary unless all N possible input values were used. Perhaps a better approach would be to operate multiple PWMs simultaneously, whose outputs are weighted differently by a factor of 28. The relatively quick settling time of an 8-bit filter would be a benefit.

Analog filters

For PWM filter designs, it’s necessary to determine the input-dependent output sequence whose ripple which is the most challenging for a filter to adequately suppress. As discussed in Reference 3, the worst case for a clustered PWM is a 50% DC. To achieve reasonable settling times (TS) to within an error VTS of 1/N while meeting the Vrip requirements of .5/N, a third order lowpass filter is employed. The structure of such a filter is seen in Figure 4. The referenced Design Idea offers a downloadable spreadsheet which designs filters to users’ specifications of PWM cycle frequency and of peak-peak ripple as a fraction of full-scale output.  It was used to populate the settling time entries in Table 1 for the clustered PWM.

For the spread PWM, the worst case was determined by running simulations of all 256 output sequences of an 8-bit spread PWM applied to a first order filter (see Figure 4 again.) But what first order filter? To answer this question, I started by assuming (perhaps counterintuitively) that the worst case for ripple suppression occurs for 1 one, that is, when PWM input X = 1. (Since zeroes and ones are fully symmetric, this is equivalent to the case of 1 zero, or X = 255.) What will the ripple troughs and peaks look like for each input value at the output of a filter with a time constant selected to provide the necessary ripple suppression for X =1 only?


Figure 4 With these first and third order low-pass analog filter structures, the filters are buffered with op amps because their inputs employ resistors of high values. This is done to limit the errors imposed by the unequal resistances of the logic high and low outputs of ICs such as the 74AC04 which drive the filter inputs (Reference 4).

First we have to find that time constant. We start by writing equations for ripple starting at time t = 0. Here, R and C are the first-order filter components, and NO + NZ = N as before. The filter output is:

  1. V0 (immediately before a zero-to-one transition)
  2. V1 = V0·e-NO·T/(R·C) + (1 – e-NO·T/(R·C)) (immediately before the next one-to-zero transition)
  3. V2 = V1·e-NZ·T/(R·C) (immediately before the next zero-to-one transition)

in the steady state, after the filter settles from a change in duty cycle, V2 = V0. Solving:

  1. V₁ss = (1 − e-NO·T/(R·C)) / (1 − e-N·T/(R·C)) + 1/N (ripple peak)
  2. V₀ss = 1/N – (e-NZ·T/(R·C) − e-N·T/(R·C)) / (1 − e-N·T/(R·C)) (ripple trough)
  3. Vrip = V1ss – V0ss = (1 – e-NO·T/(R·C)) · (1 – e-NZ·T/(R·C) ) / (1 – e-N·T/(R·C) ) (peak – trough)

Setting V₁ss in #4 above to .5/N for N = 28 and solving numerically, a value of 291.5 is obtained for the unit-less term R·C / T. Setting V0SS in #5 to .5/N with R·C / T = 291.5 yields a smaller error than .5/N for the trough; the peak error is the larger of the two (tabulations of this term for a range of N values were calculated from #4 and appear in Table 1). In a simulation, T was set to 1uS, R to 1MegΩ and C to 291.5pF. Output sequences resulting from inputs from 1, 2… 255 were applied to an 8-bit spread PWM.

Figure 5 shows a graph verses the input X values of the maximum ripple deviations from DC and of half the peak-to-trough differences. It’s clear that the biggest error is associated with inputs both of 1 one and of 255 ones (1 zero). This filter time constant 291.5uS does indeed limit the deviation from the duty cycle of 1/N (1/256) to .5/N times the PWM’s full-scale output, one half of the PWM resolution, and an input of X = 1 does yield the worst-case ripple. For any clock period T, simply multiply the Table 1 unit-less parameter R·C / T by T to obtain the filter’s R-C time constant.


Figure 5 This graph shows the filter output deviations from DC in the steady state vs. input values of 1, 2… 255 for an 8-bit spread PWM. A 100mS wait was employed before measurements to ensure settling, more than 300 times the 291.5uS filter time constant.

It might be surprising that the worst ripple peaks are associated with a single one or zero in the output sequence. But a little thought reveals that a single pulse is the case where the lowest frequency f1 = 1/(N·T) Hz that the PWM can produce has the largest amplitude. Note that input values which are powers of 2 have the lowest maximum errors. This is in part because they have no energy at f1 Hz. I have spot-checked sequences of N-4096 and those for N < 256 and found an input of X = 1 to consistently produce the maximally deviant ripple.

Settling times of the spread PWM filter

Tired of the math by now? You ain’t seen nothin’ yet!

Because an analog filter is being driven by a digital sequence, difference equations can be used to calculate the filter output. The worst case for setting time is when the filter output at time t = 0 is DC = 1 (NO = 256) and the input transitions to NO = 1. Then:

  1. y[k]      =          a*y[k-1] + (1-a)*x[k],              y[0] = 1,           a = e-T/(R·C),       k = 0, 1, 2…

where x[k] = 1 when k modulo N = 0, and 0 otherwise.

Ripple peaks occur when x[k] = 1 and troughs when k modulo N = N – 1 =255 (immediately before a peak.) We have:

  1. Yp[k·N]             =          ak·N + (1 – a)*(1 – a(k+1)·N) / (1 – aN),                   ripple peaks
  2. Yt[k·N – 1]        =          ak·N -1 + (1 – a)*(aN-1 – a(k+1)·N-1) / (1 – aN),          ripple troughs
  3. yp_SS                 =          (1 – a) / (1 – aN)                                                steady state ripple peak
  4. ypp                             =          (1 − a)(1 − aN−1) / (1 − aN)                                steady state p-p ripple
  5. k1st_peak = N * Ceiling [ Log { ( (2/N) · (1 – b) + a – 1) / (1 + (a – 2)·b) } / Log(b) ],       b = aN

where k1st_peak is the smallest value of k for which all ripple peaks are less than 2/N.

It’s worth taking a look at what is going on for the worst-case ripple when N = 256. See Figure 6.


Figure 6 This graph represents data for a spread PWM with N = 256 and filter outputs starting at one (1 volt.) At time t = 0, the red trace reflects a change of input to X = 1 and the blue, an input change to X = 0. X = 1 takes longer to settle because it spends 1/N of its time with an input of one, whereas X = 0 spends all of its time with an input of zero.

From #12, k1st_peak is the smallest value of k for which ripple peaks y[k·N] are less than or equal to 2/N. In this case, that corresponds to k = 8·N at 2.048mS ( y[7·N] is slightly larger than 2/N.) Finally, #7 is used to iterate all integer values of k from 7·N to 8·N find the smallest value of k = kS (that is, the first time) for which y[k] and all subsequent values of y[k] are less than 2/N. The settling time is then T·kS. This procedure is used to populate in Table 1 the spread PWM settling times at various cycle lengths N for a 1MHz clock.

In conclusion…

PWMs can be implemented by microcontrollers. For a clustered-bit PWM, no further intervention is required by the controller beyond the cycle length of a programmable counter and the latest value of DC. Typically, the counter can be advanced by the highest speed clock available to the controller. But for a spread-bit PWM, a supportive block of code consisting of multiple instructions must be executed periodically This must be done at consistently timed intervals if accuracy is to be maintained.

To allow the processor to perform other functions, these intervals, the effective period of the spread clock, can be quite long in comparison to those of the clustered-bit PWM. Longer clock periods lengthen the settling time of the filter needed to suppress a PWM’s ripple. Granted, the spread sequence has generally much less lower frequency energy than a comparably clocked clustered sequence and therefore can employ a faster settling time filter for ripple suppression. But in practice, microcontrollers cannot clock code-driven spread PWMs at the rates of clustered ones, which have inherent hardware support. Comparable resolution spread PWM filters generally take longer to settle than those of their clustered cousins when microcontrollers implement these PWMs.

It’s intriguing to consider that the spread PWM discussed herein can be considered to be a first order delta-sigma modulator (Reference 5). The overflow of the registers can be thought of as an accumulator which, when instead of overflowing, adds a value of -N to its input X. Modulators of order higher than the first can shift even more low frequency energy to higher frequencies, relaxing ripple-suppression requirements even more and reducing settling time. Most commercial implementations of such techniques replace analog filters with digital versions thereof which then drive conventional multi-bit DACs, all implemented on a single IC.

If our PWM types were to be implemented in hardware such as an FPGA, their clock rates could be identical. As per Table 1, at identical clock rates, some sequence lengths N would favor the spread PWM with a simple single R-C pair (first order) filter, and others which would favor the clustered PWM with its three-pair (third order) R-C filter. However, the spread PWM would also benefit by replacing its first order filter with a third order one, something I plan to discuss in a forthcoming Design Idea.

PWMs: the gift that keeps on giving!

References:

  1. Custom design PWM filters easily
  2. Ibid, Figure 3.
  3. Ibid
  4. Ibid, see the SN74AC04-induced errors section.
  5. https://www.ti.com/lit/an/slyt423a/slyt423a.pdf

Christopher Paul has worked in various engineering positions in the communications industry for over 40 years.

Related Content

  • A nice, simple, and reasonably accurate PWM-driven 16-bit DAC
  • Parsing PWM (DAC) performance: Part 1—Mitigating errors
  • Parsing PWM (DAC) performance: Part 2—Rail-to-rail outputs
  • Parsing PWM (DAC) performance: Part 3—PWM analog filters
  • Parsing PWM (DAC) performance: Part 4 – Groups of inhomogeneous duty cycles

The post Implementing a DAC: The battle of the PWMs appeared first on EDN.

30 June 2026
http://institutionofelectronics.ac.uk/wp-content/uploads/2022/12/IOE_LOGO.png 0 0 whdsolutions http://institutionofelectronics.ac.uk/wp-content/uploads/2022/12/IOE_LOGO.png whdsolutions2026-06-30 15:42:562026-06-30 15:42:56Implementing a DAC: The battle of the PWMs

Latest news

  • Cheap and cheerful LMC555 RC PWM pulse generator12 August 2026 - 13:56
  • Record high wafer shipments. Can fabs keep pace?12 August 2026 - 07:51
  • Analog uncertainty-aware design: How it replaces Monte Carlo with certifiable yield intelligence11 August 2026 - 16:31
  • Automotive low side output switch architecture suitable for 8 to 48 volt buses and beyond11 August 2026 - 13:26
  • Inference 2.0: How enterprise AI is reshaping AI system architectures11 August 2026 - 07:19
  • Dissecting third-party camera batteries, part 2: Swelling10 August 2026 - 14:00
  • Component and layout rules for USB-C, PD, and CMTI10 August 2026 - 07:53
  • Bear on a power pole7 August 2026 - 13:46
  • Why software-defined systems require a dynamic data layer7 August 2026 - 10:42
  • Paper-based passives show impact of re-thinking substrate6 August 2026 - 16:22
IOE LOGO 2

Become a member

click here

Become a member

click here

Become a subscriber

click here

Become a sponsor

click here

© Copyright - The Institution of Electronics | Website by WHD Solutions
  • Link to LinkedIn
  • Link to Facebook
  • Link to X
Link to: CoWoS, wafer-scale and CoWoP: Why AI packaging bottleneck is moving Link to: CoWoS, wafer-scale and CoWoP: Why AI packaging bottleneck is moving CoWoS, wafer-scale and CoWoP: Why AI packaging bottleneck is moving Link to: Hidden underflow in BF16 divider in mixed-precision FP designs Link to: Hidden underflow in BF16 divider in mixed-precision FP designs Hidden underflow in BF16 divider in mixed-precision FP designs
Scroll to top Scroll to top Scroll to top