Table of Contents
KEY TAKEAWAYS
- ADC converts analog signals (sensor voltages) to digital values the microcontroller can process
- ADC resolution (8, 10, 12 bits) determines the number of discrete levels: 2^n possible values
- DAC converts digital values back to analog voltages for driving analog outputs
- Sampling rate must be at least twice the signal frequency (Nyquist theorem) for accurate conversion
The Analog-Digital Gap
What is a DAC in a microcontroller, and how does it differ from an ADC?
The physical world is analog. Temperature, light, pressure, and sound all vary continuously. But microcontrollers are digital: they work with discrete binary values (0s and 1s). To bridge this gap, we use:
- ADC (Analog-to-Digital Converter) – Reads analog voltages and converts them to digital numbers the MCU can process
- DAC (Digital-to-Analog Converter) – Takes a digital number and produces a corresponding analog voltage
Analog World Microcontroller Analog World
(sensors) (digital processing) (actuators)
Temperature ──[ADC]──> Process ──[DAC]──> Audio output
Light ──[ADC]──> Calculate Motor speed (via PWM)
Pressure ──[ADC]──> Decide Analog meter
ADC (Analog-to-Digital Converter)
How ADC Works
An ADC measures the voltage on an input pin and converts it to a digital number proportional to a reference voltage.
Digital Value = (V_input / V_reference) * (2^resolution - 1)
Example (10-bit ADC, 3.3V reference, input = 1.65V):
Digital Value = (1.65 / 3.3) * (1024 - 1) = 511ADC Resolution
Resolution determines how many distinct values the ADC can output:
| Resolution | Levels | Step Size (3.3V ref) | Step Size (5V ref) | Common In |
|---|---|---|---|---|
| 8-bit | 256 | 12.9 mV | 19.6 mV | Simple MCUs |
| 10-bit | 1024 | 3.22 mV | 4.88 mV | Arduino (ATmega328) |
| 12-bit | 4096 | 0.81 mV | 1.22 mV | STM32, ESP32 |
| 16-bit | 65536 | 0.05 mV | 0.076 mV | External ADCs (ADS1115) |
Higher resolution means the ADC can detect smaller voltage changes. For example, a 12-bit ADC can distinguish voltages that differ by less than 1 mV, while an 8-bit ADC needs at least 13 mV difference.
Key ADC Parameters
Sampling Rate: How many conversions per second. A 1 MSPS (mega-samples per second) ADC takes 1 million readings per second. Audio needs at least 44.1 kHz. Temperature readings might only need 10 Hz.
Reference Voltage (Vref): The maximum voltage the ADC can measure. Input voltages above Vref give the maximum digital value. Voltages below 0V can damage the ADC.
Input Impedance: The ADC input has limited impedance. High-impedance sources (like some sensors) may need a buffer amplifier for accurate readings.
Reading an ADC: Code Example
// STM32 HAL example
#include "stm32f4xx_hal.h"
ADC_HandleTypeDef hadc1;
uint16_t read_adc(void) {
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
uint16_t value = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
return value;
}
float adc_to_voltage(uint16_t adc_value) {
return (adc_value / 4095.0f) * 3.3f; // 12-bit, 3.3V ref
}
int main(void) {
HAL_Init();
// ... clock and ADC configuration ...
while (1) {
uint16_t raw = read_adc();
float voltage = adc_to_voltage(raw);
printf("ADC: %d, Voltage: %.3f V\n", raw, voltage);
HAL_Delay(1000);
}
}Improving ADC Accuracy
- Averaging: Take multiple readings and average them to reduce noise.
uint32_t sum = 0; for (int i = 0; i < 16; i++) { sum += read_adc(); } uint16_t average = sum / 16; - Decoupling capacitor: Place a 100nF capacitor between the ADC input and GND to filter high-frequency noise.
- Stable reference voltage: Use a dedicated voltage reference IC instead of relying on VCC.
- Avoid reading during noisy operations: WiFi transmissions, motor switching, and other noisy activities can affect ADC readings.
Troubleshooting Common ADC Problems
When ADC readings are inaccurate or unstable, these are the most common causes and solutions:
Reference Voltage Issues
- Problem: ADC readings drift or are inconsistent across different power conditions
- Cause: Using VCC as reference when VCC varies with load or battery level
- Solution: Use a dedicated voltage reference IC (like TL431 or MAX6350) for stable Vref
Electrical Noise
- Problem: ADC readings jump erratically or show high-frequency variations
- Cause: Switching circuits, motors, or digital signals coupling into analog inputs
- Solution:
- Add 10-100nF capacitor directly at ADC pin to GND
- Use twisted pair or shielded cables for analog signals
- Separate analog and digital ground planes when possible
- Take ADC readings when noisy circuits are idle
Source Impedance Mismatch
- Problem: Readings are lower than expected or change based on sampling rate
- Cause: High-impedance sensor (>10kΩ) cannot charge ADC sample-and-hold capacitor quickly
- Solution: Add op-amp buffer or reduce sampling rate to allow settling time
Grounding Problems
- Problem: ADC readings shift when other circuits turn on/off
- Cause: Ground loops or voltage drops in ground connections
- Solution: Use star ground topology, ensure low-resistance ground connections
DAC (Digital-to-Analog Converter)
How DAC Works
A DAC does the opposite of an ADC. You give it a digital number, and it produces a corresponding analog voltage.
V_output = (Digital Value / (2^resolution - 1)) * V_reference
Example (12-bit DAC, 3.3V reference, digital value = 2048):
V_output = (2048 / 4095) * 3.3V = 1.65VDAC Resolution
Like ADCs, DAC resolution determines the number of distinct voltage levels it can produce. A 12-bit DAC with a 3.3V reference can output voltages in steps of about 0.8 mV.
DAC Code Example
// STM32 HAL example
#include "stm32f4xx_hal.h"
DAC_HandleTypeDef hdac;
void set_dac_voltage(float voltage) {
// Convert voltage to 12-bit value
uint16_t dac_value = (uint16_t)((voltage / 3.3f) * 4095.0f);
if (dac_value > 4095) dac_value = 4095;
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dac_value);
}
int main(void) {
HAL_Init();
// ... clock and DAC configuration ...
HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
// Generate a staircase waveform
while (1) {
for (float v = 0.0f; v <= 3.3f; v += 0.3f) {
set_dac_voltage(v);
HAL_Delay(100);
}
}
}DAC Applications
- Audio output: Generate sounds and tones
- Waveform generation: Create sine, triangle, or sawtooth waves for testing
- Analog control signals: Set reference voltages for comparators or control loops
- Calibration: Provide precise voltages for testing other analog circuits
Not All MCUs Have a DAC
Many microcontrollers (including Arduino/ATmega328 and many Cortex-M0 chips) do not have a built-in DAC. Alternatives include:
PWM + Low-Pass Filter
A PWM signal filtered with an RC circuit approximates an analog output. This is the most common approach for microcontrollers without DACs.
Simple RC Low-Pass Filter:
PWM Pin ──[R]──┬── Analog Output
│
[C]
│
GND
R = 1kΩ to 10kΩ
C = 100nF to 10μF
Cutoff frequency = 1/(2π×R×C)When to use PWM vs DAC:
- Use PWM + filter when:
- Slow-changing signals (LED dimming, motor speed control)
- Cost is critical
- 8-bit resolution is sufficient
- Some ripple voltage is acceptable
- Use true DAC when:
- Audio applications requiring low distortion
- High-resolution control (12-bit or higher)
- Fast-changing signals
- Minimal output ripple required
Improved PWM filtering with active filter:
PWM Pin ──[R1]──┬──[R2]──┬── Analog Output
│ │
[C1] ┌─[C2]
│ │ │
GND │ GND
│
[Op-Amp Buffer]
Two-stage filter reduces ripple further
Op-amp provides low output impedanceExternal DAC Chips
- External DAC chip: MCP4725 (12-bit I2C), AD5220 (SPI), or other dedicated DAC ICs
- Resistor ladder (R-2R): Simple but requires precise resistor matching
ADC vs DAC Comparison
| Feature | ADC | DAC |
|---|---|---|
| Function | Analog → Digital | Digital → Analog |
| Input | Analog voltage | Digital number |
| Output | Digital number | Analog voltage |
| Resolution Examples | 8-16 bits typical | 8-16 bits typical |
| 8-bit range (3.3V) | 0-255 (12.9mV steps) | 0-255 (12.9mV steps) |
| 12-bit range (3.3V) | 0-4095 (0.81mV steps) | 0-4095 (0.81mV steps) |
| 16-bit range (3.3V) | 0-65535 (0.05mV steps) | 0-65535 (0.05mV steps) |
| Common Applications | Sensor reading, measurement | Audio, waveform generation |
| Key Parameter | Sampling rate | Settling time |
| Availability | Nearly all MCUs | Mid-range MCUs and up |
Summary
ADCs and DACs are the bridge between the analog physical world and the digital microcontroller. ADCs let your MCU read sensors and measure real-world signals, while DACs enable precise analog output control. Understanding their resolution, sampling rates, and limitations is crucial for building reliable embedded systems that interact with the physical world.
Remember that not all microcontrollers include DACs, but PWM with proper filtering can often substitute for many applications. For critical applications requiring high precision or low noise, dedicated external converters may be necessary.

Vivek Bhageria — Lead Firmware R&D Engineer, 12+ years. Ex-Bosch (automotive powertrain), MusicTribe (real-time audio), medical devices. M.Tech BITS Pilani. I write at NerdyElectronics — practical, register-level embedded systems for engineers who want to understand what’s actually happening under the hood.





