Topic 27 · Digital Electronics

Digital-to-Analog Converter (DAC)

A DAC turns a digital code into a proportional analog voltage — enabling audio output, motor control, signal synthesis, and sensor calibration. Understand R-2R ladder networks, key specs, and Verilog with an interactive 8-bit bit-toggle simulator.

R-2R Ladder Network (4-bit)

4-bit R-2R Ladder DAC — V_out = (D/16) × V_ref V_out → Op-Amp GND 2R R SW D3 (MSB) +Vref/2 2R R SW D2 +Vref/4 2R R SW D1 +Vref/8 2R 2R SW D0 (LSB) +Vref/16 Vref 2R (shunt) R (series) Bit switch (0=GND / 1=Vref)

Each bit switch connects its 2R resistor to either Vref (bit=1) or GND (bit=0). The MSB (D3) contributes Vref/2, D2 contributes Vref/4, and so on — a binary-weighted sum using only two resistor values.

DAC Output Voltage & Resolution

Output Voltage
Vout = (D / 2N) × Vref
D = digital code (0 to 2N−1). D=128 on 8-bit → Vout = 0.5 × Vref.
LSB Voltage
VLSB = Vref / 2N
Smallest output step. 12-bit at 3.3V → VLSB = 0.806mV per step.
Full Scale
VFS = Vref × (1 − 2−N)
Maximum output (code = 2N−1). Always 1 LSB below Vref.
R-2R MSB Contribution
VMSB = Vref / 2
By Thevenin: each bit contributes half the previous bit's contribution.
Update Rate
fmax = 1 / tsettle
Maximum useful output update rate. Limited by settling time, not clock.
SNR (ideal)
SNR = 6.02N + 1.76 dB
Same as ADC — 8-bit DAC → 49.9dB ideal SNR. Real SNR is lower.

DAC Types Compared

TypeResolutionAccuracySpeedKey PropertyUsed In
R-2R Ladder 4–16 bitGoodModerate Only 2 resistor values (R, 2R) — easy to match on-chip Audio, general-purpose, FPGA GPIO networks
Weighted Resistor 4–8 bitPoor at high NFast R, 2R, 4R, 8R… range grows as 2N−1, hard to match Low-cost 4-bit, educational circuits
Current Steering 12–16 bitExcellentVery fast (GHz) Thermometer-coded current sources; fast switching, low glitch RF/comms, arbitrary waveform generators
Sigma-Delta (ΣΔ) 16–24 bitExcellentLow–medium PWM-like 1-bit output + low-pass filter; oversampling reduces noise Audio playback, medical imaging
PWM DAC 8–16 bit (effective)ModerateLimited by fpwm RC filter averages PWM duty cycle — no true DAC IC needed MCU volume control, motor set-point, cheap sensors

DAC Specs Explained

SpecSymbolWhat It MeansTypical Value
ResolutionN bitsNumber of distinct output levels (2N)8–24 bits
Settling TimetsettleTime to settle to ±½ LSB after code change1ns – 10µs
DNLLSBDeviation of each step from ideal 1 LSB; DNL > −1 = no missing codes<±0.5 LSB
INLLSBMax deviation of output from ideal straight line<±1 LSB
Glitch EnergynV·sSpike area at major carry transitions (0111→1000)1–200 nV·s
THDdBTotal Harmonic Distortion for sinusoidal output<−80dB (audio)
MonotonicityOutput always increases with code; requires DNL > −1 LSBGuaranteed for good DAC
Output ImpedanceΩThevenin output resistance; must be buffered for loadsVaries; buffer adds ~0Ω

8-bit DAC — Toggle Bits to Set Output

Click bits to toggle (D7=MSB, D0=LSB) · Vref = 3.3V
1.650 V
Digital Code
128
Hex
0x80
% of Vref
50.2%
VLSB
12.9mV
SNR (ideal)
49.9dB
Weighted Sum
D7×1.65+…

DAC Models in Verilog

Behavioral DAC (Simulation)

// Behavioral DAC — simulation only (uses real type)
module dac_model #(
  parameter      N    = 12,
  parameter real VREF = 3.3
)(
  input  wire [N-1:0] din,    // digital input code
  output real         vout   // analog output (simulation)
);
  // Vout = (D / 2^N) * Vref
  assign vout = ($itor(din) / $itor(1 << N)) * VREF;
endmodule

R-2R DAC on FPGA (GPIO Pin Network)

// R-2R DAC: FPGA drives N output pins into external resistor network
// No special IP — just N GPIO pins + external R/2R resistors
module r2r_dac_driver #(
  parameter N = 8
)(
  input  wire        clk,
  input  wire        rst_n,
  input  wire [N-1:0] code,    // digital value to output
  output reg  [N-1:0] dac_pins  // connect MSB→D7 through external R-2R network
);
  // Register the code to align with external network settling time
  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) dac_pins <= '0;
    else        dac_pins <= code;
  end
endmodule

// Usage note:
// dac_pins[7] (MSB) → 2R shunt to Vout, then R series to dac_pins[6] node
// dac_pins[0] (LSB) → 2R shunt, terminated with 2R to GND
// Vout taken before op-amp buffer for high impedance loads

PWM DAC with RC Filter

// PWM-based DAC: digital code → PWM duty → RC filter → analog Vout
// Effective resolution limited by PWM frequency vs ripple tradeoff
module pwm_dac #(
  parameter N = 8      // 8-bit → 256 duty levels
)(
  input  wire        clk,
  input  wire        rst_n,
  input  wire [N-1:0] code,     // 0=0V, 255=Vref (8-bit)
  output wire        pwm_out  // connect to external RC low-pass filter
);
  reg [N-1:0] cnt;

  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) cnt <= '0;
    else        cnt <= cnt + 1;
  end

  assign pwm_out = (cnt < code);
  // External: pwm_out → 10kΩ → Vout → 100nF → GND
  // f_pwm = f_clk/256; filter cutoff ≈ f_pwm/10 for <1% ripple
endmodule

SPI-Controlled DAC Interface

// SPI interface to drive external DAC (e.g. MCP4921 12-bit SPI DAC)
// Sends 16-bit frame: [4 config bits][12 data bits]
module spi_dac_ctrl (
  input  wire        clk,
  input  wire        rst_n,
  input  wire [11:0] dac_code,  // 12-bit DAC value
  input  wire        send,      // pulse to trigger SPI transfer
  output reg         sck,       // SPI clock
  output reg         mosi,      // SPI data
  output reg         cs_n,      // Chip select (active low)
  output reg         done       // Transfer complete
);
  reg [15:0] shift_reg;
  reg [4:0]  bit_cnt;
  reg         busy;

  // MCP4921 frame: 0011 + 12-bit code (BUF=0, GA=1, SHDN=1)
  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      cs_n <= 1; sck <= 0; mosi <= 0; done <= 0; busy <= 0;
    end else if (send && !busy) begin
      shift_reg <= {4'b0011, dac_code};  // load frame
      bit_cnt   <= 15;
      cs_n      <= 0;   // assert CS
      busy      <= 1;
      done      <= 0;
    end else if (busy) begin
      sck  <= ~sck;           // toggle clock
      if (!sck) begin        // output on falling edge
        mosi      <= shift_reg[15];
        shift_reg <= shift_reg << 1;
        if (bit_cnt == 0) begin
          cs_n <= 1; busy <= 0; done <= 1;
        end else bit_cnt <= bit_cnt - 1;
      end
    end else done <= 0;
  end
endmodule

Frequently Asked Questions

What is a DAC and how does it work?

A DAC converts an N-bit digital code D into a proportional analog voltage: Vout = (D / 2N) × Vref. Code 0 → 0V, code 2N−1 → Vref × (1 − 2−N). An 8-bit DAC at 3.3V has 256 levels, each 12.9mV apart.

How does an R-2R ladder DAC work?

The R-2R ladder uses only two resistor values. Each bit switch connects a 2R shunt to either Vref (bit=1) or GND (bit=0). By Thevenin analysis, the MSB contributes Vref/2, next bit Vref/4, etc. Only R and 2R values needed regardless of N — easy to match on-chip.

Why not use weighted resistors for a DAC?

Weighted resistors (R, 2R, 4R, 8R…) work for 4 bits but the resistor range spans 2N−1×. For 12 bits: 2048:1 ratio — impossible to match accurately. R-2R limits the range to 2:1, making it practical for 16+ bit resolution on a chip.

What is glitch energy and why does it matter?

Glitch energy is the area of the voltage spike at the output during code transitions, worst at the half-scale crossing (0111→1000). Caused by switches not changing simultaneously. Measured in nV·s. Matters in audio (audible clicks) and RF (spectral spurs). Low-glitch DACs use thermometer coding or deglitching S&H circuits.

What is monotonicity in a DAC?

A monotonic DAC always increases its output when the code increases. Non-monotonicity (DNL < −1 LSB) causes the output to dip for a rising code — catastrophic in closed-loop control systems. Guaranteed monotonicity requires DNL > −1 LSB across all codes and all temperatures.

Can you build a DAC with just an FPGA and resistors?

Yes — drive N GPIO pins into an external R-2R resistor network. The FPGA sets the bit pattern, the resistors sum it into an analog voltage. This is popular for audio projects and cheap test setups. Accuracy is limited by resistor matching (0.1% resistors give ~10-bit effective accuracy). Add an op-amp buffer if driving a low-impedance load.

What is a PWM DAC?

A PWM DAC uses a PWM output filtered by an RC low-pass filter. The RC averages the duty cycle into an analog voltage: Vout = D% × Vcc. 8-bit PWM at 50kHz + RC filter (cutoff ~1kHz) gives ~8-bit resolution at audio rates. No true DAC IC needed — common in microcontrollers for volume control and motor set-points.