The Baseline: Default Arduino PWM Frequency Mapping

When prototyping embedded systems in 2026, the Arduino Uno and Nano (based on the ATmega328P) remain ubiquitous due to their supply chain resilience and vast peripheral ecosystem. However, relying on the default analogWrite() function often leads to suboptimal performance in precision applications. By default, the Arduino PWM frequency is not uniform across all pins, a hardware quirk dictated by the microcontroller's internal timer architecture.

Understanding this baseline is the first step in signal calibration. The ATmega328P utilizes three hardware timers (Timer0, Timer1, and Timer2) to generate Pulse Width Modulation signals. Because these timers are also responsible for core system functions, their default prescalers are configured as a compromise between audio-frequency noise avoidance and system timing stability.

Arduino Pins Associated Timer Timer Resolution Default Frequency Primary System Dependency
D5, D6 Timer0 8-bit ~976.56 Hz millis(), delay()
D9, D10 Timer1 16-bit ~490.20 Hz Servo library, Tone generation
D3, D11 Timer2 8-bit ~490.20 Hz Tone generation on specific pins

For basic LED dimming, a 490 Hz or 980 Hz frequency is imperceptible to the human eye. However, if you are driving DC motors via an H-bridge, a 490 Hz PWM signal will induce an audible, high-pitched whine. Furthermore, if you are multiplexing LED matrices or capturing video with high-speed cameras, these default frequencies will cause severe beat-frequency flickering and rolling shutter artifacts.

The Timer0 Trap: Why Blind Calibration Fails

A common and catastrophic mistake made by intermediate developers is attempting to globally increase the Arduino PWM frequency by altering Timer0's prescaler. Timer0 is an 8-bit timer that drives the microcontroller's internal millisecond counter.

Critical Warning: Modifying the Timer0 prescaler (register TCCR0B) to change the PWM frequency on pins D5 and D6 will instantly break the millis(), micros(), and delay() functions. If your application relies on RTOS scheduling, sensor polling intervals, or timeout watchdogs, altering Timer0 will cause systemic timing failure.

For calibration and accuracy purposes, we strictly isolate our frequency modifications to Timer1 (pins 9, 10) and Timer2 (pins 3, 11), leaving Timer0 untouched to preserve the Arduino core timing library.

Engineering Custom Frequencies via Prescalers

To calibrate the Arduino PWM frequency for specific peripherals—such as driving a 20 kHz ultrasonic transducer or a 25 kHz PC fan—we must manipulate the timer's prescaler and waveform generation mode. The Microchip ATmega328P Datasheet details how the system clock (16 MHz) is divided before reaching the timer counter.

The Math Behind the Magic

The fundamental formula for calculating PWM frequency in Fast PWM mode is:

Frequency = Clock_Speed / (Prescaler * (1 + TOP))

For 8-bit timers (Timer2), the TOP value is fixed at 255 in standard Fast PWM mode. Therefore, the frequency is strictly determined by the prescaler. Let us examine the calibration matrix for Timer2 (Pins D3, D11):

Prescaler Value Register Bits (CS22, CS21, CS20) Resulting Frequency Use Case Scenario
1 0, 0, 1 62,500 Hz (62.5 kHz) High-speed switching power supplies
8 0, 1, 0 7,812.5 Hz (7.8 kHz) Audio synthesis, piezo drivers
32 0, 1, 1 1,953.1 Hz Standard DC motor control (silent)
64 1, 0, 0 976.56 Hz Default Timer0 equivalent
128 1, 0, 1 488.28 Hz Default Arduino PWM (approx)

To set Timer2 to a prescaler of 8 (yielding ~7.8 kHz), you bypass the analogWrite() setup and write directly to the Timer/Counter Control Register:

// Clear Timer2 prescaler bits
TCCR2B = TCCR2B & B11111000;
// Set prescaler to 8 (CS21 bit)
TCCR2B = TCCR2B | B00000010;

Achieving Sub-Hertz Accuracy with 16-bit Timer1

While 8-bit timers offer simplicity, they lack the resolution required for precise duty-cycle calibration at high frequencies. If you need exactly 20,000 Hz for a resonant circuit, an 8-bit timer cannot achieve it without altering the system clock. This is where Timer1 (16-bit) becomes indispensable.

By utilizing the Phase and Frequency Correct PWM mode and setting the ICR1 (Input Capture Register) as the TOP value, we gain granular control over both frequency and duty cycle resolution. According to National Instruments' guide on PWM signal integrity, phase-correct PWM is critical for motor control because it centers the pulses, preventing overlapping shoot-through currents in H-bridge MOSFETs.

Calibration Code for Exact 20 kHz Output

To achieve exactly 20 kHz on Pin D9 (OC1A), we calculate the ICR1 value:

ICR1 = (Clock_Speed / (Prescaler * Target_Frequency * 2)) - 1

Using a prescaler of 1: ICR1 = (16,000,000 / (1 * 20,000 * 2)) - 1 = 399.

void setup() {
  pinMode(9, OUTPUT);
  
  // Clear Timer1 control registers
  TCCR1A = 0;
  TCCR1B = 0;
  
  // Set Phase and Frequency Correct PWM mode
  // WGM13 = 1, WGM12 = 0, WGM11 = 0, WGM10 = 0
  TCCR1B |= (1 << WGM13);
  
  // Set non-inverting mode on OC1A (Pin 9)
  TCCR1A |= (1 << COM1A1);
  
  // Set TOP value for exactly 20 kHz
  ICR1 = 399;
  
  // Set 50% duty cycle (Half of ICR1)
  OCR1A = 199;
  
  // Start timer with prescaler 1 (CS10 = 1)
  TCCR1B |= (1 << CS10);
}

This configuration yields a mathematically perfect 20,000 Hz signal with a 400-step duty cycle resolution, providing 0.25% granularity for calibration loops.

Hardware Calibration: Verifying Signal Integrity

Software configuration is only half the battle. True calibration requires hardware verification to account for parasitic capacitance, trace inductance, and logic-level rise times. In 2026, relying solely on software math without oscilloscope verification is considered poor engineering practice for production peripherals.

Recommended Test Equipment

  • 12-Bit Oscilloscope: The Rigol DHO800 series (retailing around $399) offers 12-bit ADC resolution, which is vastly superior for measuring the slight voltage droop and ripple on PWM-driven inductive loads compared to legacy 8-bit scopes.
  • Logic Analyzer: The Saleae Logic Pro 8 (~$119) is essential for measuring PWM jitter over long durations. By sampling at 12 MS/s, you can capture millions of PWM cycles and use the software's histogram tool to calculate the standard deviation of the pulse width.

Mitigating Rise-Time Jitter and Capacitive Loading

When probing high-frequency PWM signals (e.g., >30 kHz), the capacitance of a standard 1x oscilloscope probe (often >100pF) will artificially slow the rise and fall times of the ATmega328P's GPIO pins. This skew can make a 50% duty cycle appear as 48% on your measurement equipment, leading to false calibration adjustments.

  1. Always use a 10x Probe: This reduces the capacitive load on the microcontroller pin to roughly 10-15pF, preserving the true edge rates of the PWM signal.
  2. Minimize Ground Lead Length: The standard alligator-clip ground lead acts as an antenna and introduces inductive ringing on fast PWM edges. Use the probe's spring-tip ground accessory to connect directly to the PCB ground plane adjacent to the PWM trace.
  3. Measure at the Load, Not the Source: For motor control calibration, measure the PWM signal at the gate of the MOSFET or the input of the motor driver IC (e.g., DRV8833). Trace inductance and optocoupler propagation delays (which can add 1-2 µs of latency) will alter the effective duty cycle reaching the peripheral.

Summary of Best Practices

Calibrating the Arduino PWM frequency requires a transition from abstracted functions to direct register manipulation. By respecting the system dependencies of Timer0, leveraging the 16-bit resolution of Timer1 for exact frequency targeting, and validating the physical signal with high-impedance probing techniques, you can achieve industrial-grade accuracy. Whether you are silencing medical-grade fluid pumps or driving precision laser diodes, mastering the ATmega328P's timer architecture is the definitive path to reliable peripheral integration.