ADC & DAC

Converters bridge analog and digital worlds. Learn resolution, LSB size, quantisation error and SNR, ADC types (flash, SAR, sigma-delta, pipelined), sampling rate, reference voltage, DAC types (R-2R, string, PWM), and key specs (INL, DNL, ENOB).

Sensors produce analog voltages; processors need numbers. ADCs sample and quantise signals; DACs turn numbers back into voltages for audio, control outputs and waveform generation.

An analogy

An ADC is like measuring height with a ruler marked only in whole centimetres — resolution is the spacing of the marks, and anything between gets rounded.

Sampling and quantisation

An ADC samples at discrete times (f_s ≥ 2 × highest frequency — Nyquist) and rounds each sample to one of 2^N levels. Quantisation error is up to ±½ LSB.

ADC architectures

Flash: fastest (GS/s), many comparators, low resolution. SAR: binary search, 8–18 bits, up to a few MS/s — the MCU standard. Sigma-delta: oversampling and noise shaping, 16–32 bits, audio and precision sensors. Pipelined: high speed and resolution for communications.

DACs

R-2R ladders and resistor strings for precise DC; current-steering for high speed; PWM + RC filter as a cheap MCU DAC. Output buffers and reconstruction filters smooth steps.

Specifications

Offset and gain errors, INL/DNL (non-linearity), missing codes, SNR, SFDR, THD and ENOB. Reference noise and input driver settling (for SAR sampling capacitors) often limit real performance.

Formulas

Worked example: 12-bit ADC

Given: V_ref = 3.3 V, N = 12

Find: LSB and ideal SNR.

Answer: 0.81 mV, 74 dB

Worked example: DAC output

Given: 12-bit DAC, V_ref 3.3 V, code 2048

Find: V_out.

Answer: 1.65 V (mid-scale)

Reading an ADC on a microcontroller (C)

#include <stdint.h>

#define VREF_MV   3300u
#define ADC_BITS  12u

/* Convert a raw 12-bit ADC code to millivolts and temperature
   for an LM35-style sensor (10 mV per °C). */
uint32_t adc_to_mv(uint16_t code) {
    return ((uint32_t)code * VREF_MV) >> ADC_BITS;     /* code * 3300 / 4096 */
}

int32_t temp_centi_deg(uint16_t code) {
    return (int32_t)adc_to_mv(code) * 10;             /* 10 mV/°C -> 0.01 °C units */
}
/* Example: code 310 -> 249 mV -> 24.90 °C */

Integer maths with a shift replaces a slow divide by 4096. Always use the actual reference voltage — errors in V_ref scale every reading.

Common mistakes

Applications

Key takeaways

Going further