The analogWrite() Misconception: PWM vs. True DAC
When makers first encounter the analogWrite(pin, value) function in the Arduino IDE, a fundamental misunderstanding often occurs. The function name implies the generation of a true, variable analog DC voltage. However, on 90% of microcontrollers in the Arduino ecosystem, analogWrite() does not output an analog signal at all. Instead, it generates a Pulse Width Modulation (PWM) square wave, rapidly toggling the pin between 0V and the board's logic level (usually 5V or 3.3V) at a specific duty cycle.
Understanding this distinction is critical for hardware compatibility. If you are driving an LED or a DC motor via a MOSFET, PWM is perfectly adequate and often preferred. But if you are attempting to bias an audio amplifier, generate a precise reference voltage, or drive a sensitive analog sensor, a raw PWM signal will cause erratic behavior or introduce high-frequency noise. This guide breaks down exactly how analogWrite() behaves across the major microcontroller architectures in 2026, detailing pin mappings, timer conflicts, and hardware workarounds.
Board-by-Board analogWrite Compatibility Matrix
Not all boards are created equal. While the Arduino IDE abstracts the analogWrite() syntax, the underlying hardware peripherals vary wildly. Below is the definitive compatibility and specification matrix for the most popular development boards.
| Board Model | Architecture | True DAC Pins? | Default PWM Freq | Default Resolution | analogWrite Supported? |
|---|---|---|---|---|---|
| Uno R3 / Nano | AVR (ATmega328P) | No | 490 Hz / 980 Hz | 8-bit (0-255) | Yes (Pins 3,5,6,9,10,11) |
| Mega 2560 | AVR (ATmega2560) | No | 490 Hz / 980 Hz | 8-bit (0-255) | Yes (Pins 2-13, 44-46) |
| Zero | ARM (SAMD21) | Yes (1 Pin) | 732 Hz | 8-bit (0-255) | Yes (All digital pins) |
| Due | ARM (SAM3X8E) | Yes (2 Pins) | 1 kHz | 8-bit (0-255) | Yes (All digital pins) |
| GIGA R1 WiFi | ARM (STM32H747) | Yes (2 Pins) | 2.2 kHz | 8-bit (0-255) | Yes (All digital pins) |
| ESP32 DevKit | Xtensa/RISC-V | No | 5 kHz (Core v3+) | 8-bit (0-255) | Yes (All digital pins) |
Note: Default resolution can be altered on ARM and ESP32 boards using analogWriteResolution(bits), but AVR boards are hardware-locked to 8-bit.
AVR Architecture: Timer Conflicts and Frequency Mapping
On classic AVR boards like the Uno R3 and Nano (ATmega328P), PWM is generated by the chip's internal hardware timers. The analogWrite() function maps specific pins to specific timers, which dictates the PWM frequency. According to the Arduino Official Reference, the default frequencies are not uniform across all pins.
- Pins 5 and 6 (Timer 0): Operate at approximately 980 Hz. Critical Warning: Timer 0 is also responsible for keeping track of time for the
millis(),delay(), andmicros()functions. If you manually alter the prescaler for Timer 0 to change the PWM frequency on pins 5 or 6, you will completely break all time-dependent functions in your sketch. - Pins 9 and 10 (Timer 1): Operate at approximately 490 Hz. Timer 1 is a 16-bit timer, making it highly suitable for high-resolution PWM adjustments without breaking core timing functions.
- Pins 3 and 11 (Timer 2): Operate at approximately 490 Hz. Timer 2 is an 8-bit timer often used for audio generation libraries like Tone.
The Fallback Behavior on Non-PWM Pins
What happens if you call analogWrite(13, 128) on an Uno, where Pin 13 lacks a hardware PWM channel? The Arduino core implements a software fallback. If the value is less than 128, the pin is driven LOW. If the value is 128 or greater, the pin is driven HIGH. This crude thresholding is a frequent source of confusion for beginners attempting to fade an LED on a non-PWM pin, resulting in a binary on/off state rather than a smooth fade.
ARM and the True DAC Advantage
If your project strictly requires a true analog DC voltage without the high-frequency ripple of PWM, you must migrate to an ARM-based board equipped with a Digital-to-Analog Converter (DAC) peripheral. When you call analogWrite() on a designated DAC pin, the microcontroller outputs a genuine steady-state voltage.
Arduino Due and Zero
The Arduino Due features two dedicated 12-bit DAC pins (DAC0 and DAC1), capable of outputting voltages between 0.55V and 2.75V. The Arduino Zero features a single 12-bit true analog output pin, typically mapped to A0 (or the dedicated DAC pin on the header). To utilize the full 12-bit range (0-4095), you must precede your write command with analogWriteResolution(12);.
Arduino GIGA R1 WiFi
For advanced 2026 applications, the Arduino GIGA R1 WiFi (priced around $89) utilizes the powerful STM32H747 dual-core processor. It features dual 12-bit DACs mapped to pins A12 and A13. Unlike the older Due, the GIGA's DACs are heavily integrated with the board's advanced DMA (Direct Memory Access) controllers, allowing you to stream high-fidelity audio waveforms directly from memory to the DAC pins without blocking the main CPU cores.
The ESP32 Evolution: Core v2.x vs. v3.x
The ESP32's relationship with analogWrite() has been historically turbulent, making it a major compatibility hurdle for makers porting legacy code. In older ESP32 Arduino Core versions (v2.x and earlier), analogWrite() was either unsupported or highly deprecated in favor of the LED Control (LEDC) API. Developers were forced to use verbose setups like ledcSetup(channel, freq, resolution) and ledcAttachPin().
However, with the maturation of the ESP32 Arduino Core v3.x (the standard in 2026), Espressif completely overhauled the analog API to maintain backward compatibility with standard Arduino sketches. According to the Espressif PWM API Documentation, calling analogWrite(pin, duty) on an ESP32 now automatically allocates an available LEDC or MCPWM channel under the hood.
Expert Tip for ESP32 Users: WhileanalogWrite()now works natively on the ESP32, the default resolution remains 8-bit (0-255) to match the Uno. If you are driving high-precision buck converters or studio lighting, utilizeanalogWriteResolution(13)to unlock the ESP32's native 13-bit LEDC depth (0-8191), providing vastly smoother dimming curves.
Hardware Workaround: Converting PWM to True DC
If you are locked into an AVR board like the Uno Nano but desperately need a true analog voltage, you can construct a hardware Low-Pass Filter (LPF) to smooth the PWM square wave into a DC level. This is a standard technique in DIY synthesizers and motor control circuits.
Designing an RC Low-Pass Filter
By placing a resistor in series with the PWM pin and a capacitor from the output to ground, you create an RC filter. The goal is to set the cutoff frequency ($f_c$) significantly lower than the PWM frequency to eliminate the AC ripple.
- Select your components: A 4.7 kΩ resistor and a 10 µF ceramic capacitor.
- Calculate the cutoff frequency: $f_c = 1 / (2 * \pi * R * C)$. For our values, $f_c \approx 3.38$ Hz.
- Evaluate the result: Since the Uno's default PWM is 490 Hz, a 3.38 Hz cutoff will aggressively smooth the signal into a flat DC voltage. However, the trade-off is settling time. It will take roughly $5 * R * C$ (about 0.23 seconds) for the voltage to stabilize when you change the
analogWrite()value.
This RC network is perfect for setting a static bias voltage or controlling a slow-moving analog gauge, but it is entirely unsuitable for audio output or fast-reacting control loops, where the 230ms lag will cause system instability.
Troubleshooting Common analogWrite Edge Cases
- LED Flickering at Low Values: On 5V AVR boards, many standard red LEDs have a forward voltage of ~1.8V. An 8-bit
analogWrite()value of 20 out of 255 equates to an average voltage of roughly 0.39V, which is below the LED's threshold. The LED will appear completely off until the value crosses ~90. Use a gamma-correction lookup table in your code to map human-perceived brightness to PWM duty cycles. - ESP32 Touch Pin Interference: On original ESP32 DevKits, certain pins (like GPIO 2, 4, 12-15, 27, 32-33) double as capacitive touch sensors. If you have the touch peripheral initialized in your sketch, attempting to use
analogWrite()on these overlapping pins can result in erratic duty cycles or peripheral crashes. Stick to GPIO 16, 17, 18, 19, 21, 22, 23, 25, and 26 for clean PWM output. - SAMD21 (Zero) Pin Mapping: The Arduino Zero's physical silkscreen pin numbers do not always map 1:1 with the SAMD21's internal PORT definitions in the same way AVRs do. Always verify you are calling the Arduino API pin number, not the raw microcontroller port bit, to ensure the correct hardware timer is triggered.






