The Direct Answer: Locating PWM Pins on Arduino Boards

If you are looking for the PWM pins on Arduino boards, the direct answer depends on your specific microcontroller variant. On the Arduino Uno R3 and Nano v3 (both based on the ATmega328P), the hardware PWM pins are 3, 5, 6, 9, 10, and 11. On the Arduino Mega 2560, the hardware PWM pins are 2 through 13, plus 44, 45, and 46.

You can physically identify these on the PCB silkscreen by looking for the tilde symbol (~) printed next to the pin number. This symbol indicates that the pin is tied to one of the microcontroller's internal hardware timers, allowing it to output a Pulse Width Modulated signal via the analogWrite() function. If a pin lacks this tilde, calling analogWrite() on it will simply result in a digital HIGH (if the value is ≥128) or LOW (if <128), completely defeating the purpose of your analog-style fade or motor speed control.

ATmega328P Timer-to-Pin Mapping (Uno R3 / Nano v3)

Understanding which timer controls which pin is critical for debugging, especially when you introduce libraries that hijack specific timers. The ATmega328P has three timers: Timer0 (8-bit), Timer1 (16-bit), and Timer2 (8-bit).

PWM Pin Hardware Timer Timer Resolution Default Frequency Common Library Conflicts
~3 Timer 2 (OC2B) 8-bit 490 Hz Tone library
~5 Timer 0 (OC0B) 8-bit 980 Hz delay(), millis() (Do not alter Timer0)
~6 Timer 0 (OC0A) 8-bit 980 Hz delay(), millis() (Do not alter Timer0)
~9 Timer 1 (OC1A) 16-bit 490 Hz Servo library
~10 Timer 1 (OC1B) 16-bit 490 Hz Servo library
~11 Timer 2 (OC2A) 8-bit 490 Hz Tone library

Source: Arduino Uno Rev3 Documentation and ATmega328P Datasheet.

Project Build: Multi-Channel PWM LED Fader with Fault Detection

This build demonstrates independent PWM fading on three channels while incorporating runtime error handling to catch invalid pin assignments—a common issue when porting code between board variants.

Difficulty Rating: Beginner / Intermediate
Target Board Variant: Arduino Uno R3 (Rev3) or Arduino Nano v3 (ATmega328P)

Parts List

  • Microcontroller: Arduino Uno R3 (Rev3) with ATmega328P DIP or SMD
  • LEDs: 3x 5mm Red Diffused LEDs (or any standard 20mA indicator LED)
  • Current Limiting Resistors: 3x 220Ω 1/4W carbon film or metal film resistors
  • Prototyping: Half-size solderless breadboard, male-to-male jumper wires

Wiring Steps

  1. Insert the Arduino Uno into your workspace and connect it via USB to your PC.
  2. Place the three 220Ω resistors on the breadboard. Connect one leg of each resistor to the Uno's PWM pins 3, 5, and 6 using jumper wires.
  3. Connect the anode (long leg) of each LED to the free leg of its corresponding resistor.
  4. Connect the cathode (short leg) of all three LEDs to a common ground rail on the breadboard.
  5. Run a jumper wire from any GND pin on the Arduino to the common ground rail.

Complete Compilable Code

This sketch targets the Uno R3. It defines valid PWM pins, validates them at runtime to prevent silent failures, and executes a staggered fade sequence.

/*
 * Multi-Channel PWM Fader with Pin Validation
 * Target Board: Arduino Uno R3 (ATmega328P)
 */

// --- PIN DEFINITIONS ---
const int PWM_PIN_A = 3;  // Timer 2
const int PWM_PIN_B = 5;  // Timer 0
const int PWM_PIN_C = 6;  // Timer 0

// --- FADE PARAMETERS ---
const int FADE_STEP = 5;
const int DELAY_MS = 15;

// --- VALIDATION ARRAY FOR UNO R3 ---
const int validPWMPins[] = {3, 5, 6, 9, 10, 11};
const int numValidPins = sizeof(validPWMPins) / sizeof(validPWMPins[0]);

// Function to check if a pin supports hardware PWM on Uno R3
bool isValidPWMPin(int pin) {
  for (int i = 0; i < numValidPins; i++) {
    if (validPWMPins[i] == pin) return true;
  }
  return false;
}

void setup() {
  Serial.begin(115200);
  while (!Serial) { ; } // Wait for serial port (native USB boards)
  
  Serial.println("Initializing PWM Channels...");
  
  // Validate and setup pins
  int pinsToSetup[] = {PWM_PIN_A, PWM_PIN_B, PWM_PIN_C};
  for (int i = 0; i < 3; i++) {
    if (isValidPWMPin(pinsToSetup[i])) {
      pinMode(pinsToSetup[i], OUTPUT);
      Serial.print("Pin "); Serial.print(pinsToSetup[i]); Serial.println(" configured for PWM.");
    } else {
      // Exact error string for debugging
      Serial.print("ERR: Pin "); Serial.print(pinsToSetup[i]); 
      Serial.println(" is not a valid hardware PWM pin on Uno R3. Output forced to digital LOW.");
      pinMode(pinsToSetup[i], OUTPUT);
      digitalWrite(pinsToSetup[i], LOW); // Fail safe
    }
  }
}

void loop() {
  // Only fade if pins are valid
  if (isValidPWMPin(PWM_PIN_A) && isValidPWMPin(PWM_PIN_B) && isValidPWMPin(PWM_PIN_C)) {
    // Fade up all channels
    for (int brightness = 0; brightness <= 255; brightness += FADE_STEP) {
      analogWrite(PWM_PIN_A, brightness);
      analogWrite(PWM_PIN_B, constrain(brightness - 85, 0, 255)); // Staggered
      analogWrite(PWM_PIN_C, constrain(brightness - 170, 0, 255)); // Staggered
      delay(DELAY_MS);
    }
    // Fade down all channels
    for (int brightness = 255; brightness >= 0; brightness -= FADE_STEP) {
      analogWrite(PWM_PIN_A, brightness);
      analogWrite(PWM_PIN_B, constrain(brightness - 85, 0, 255));
      analogWrite(PWM_PIN_C, constrain(brightness - 170, 0, 255));
      delay(DELAY_MS);
    }
  } else {
    Serial.println("HALT: Invalid pin configuration detected. Check pin definitions.");
    delay(5000); // Halt and wait
  }
}

Debugging: First Three Things to Check When PWM Fails

When your motor stutters or your LED simply snaps on and off instead of fading, run through these three bench checks before rewriting your code.

  1. Verify the Silkscreen Tilde (~): Look physically at the board. If you wired your component to pin 4 or 7 on an Uno, you are on a purely digital pin. analogWrite() will compile without errors, but the hardware will just output 5V or 0V based on the threshold. Move your wire to a pin with the ~ marker.
  2. Check for Timer Conflicts: If pins 9 and 10 suddenly stop outputting PWM, check your #include statements. The standard Arduino Servo library hijacks Timer1 to generate the precise 50Hz pulses required by hobby servos. Because pins 9 and 10 are tied to Timer1 on the Uno, the library disables their PWM capability to prevent signal corruption.
  3. Measure with a Multimeter: Set your multimeter to DC Voltage. A true PWM pin outputting a 50% duty cycle will read roughly 2.5V (half of 5V). If you are on a non-PWM pin and send analogWrite(pin, 128), the multimeter will still read ~2.5V due to internal averaging, but an oscilloscope or logic analyzer will show a flat 5V line with rapid software toggling, which inductive loads (like motors) will not interpret correctly as a reduced voltage.

Decoding the Exact Error String

If you are using the validation code provided above, you may encounter this exact serial output:

ERR: Pin 4 is not a valid hardware PWM pin on Uno R3. Output forced to digital LOW.

Ranked Causes for this Error:

  1. Typo in Pin Definition: You defined const int PWM_PIN_A = 4; instead of 3. Pin 4 is digital-only on the Uno.
  2. Board Variant Mismatch: You ported code from an Arduino Mega (where pin 4 is a PWM pin) to an Uno without updating the pin mapping array or constants.
  3. Analog Pin Confusion: You attempted to use A0 through A5. While these can be used as digital I/O, they do not have hardware PWM timers connected to them on the ATmega328P.

Extending and Simplifying Your PWM Build

Depending on your project requirements, you will eventually hit the limits of the Uno's six native PWM channels. Here is how to scale up or strip down your build.

How to Extend (More Channels or Higher Power)

  • Add an I2C PWM Driver: If you need to drive 16 servos or RGB LED strips, do not use shift registers. Use a PCA9685 16-Channel 12-bit PWM Driver (commonly sold as an Adafruit or generic breakout board for ~$5 to $12). It communicates over I2C (pins A4/A5 on the Uno) and handles the PWM timing in hardware, freeing up your microcontroller's timers entirely.
  • Upgrade the Board Variant: If you want native pins without external ICs, migrate to an Arduino Mega 2560 (15 PWM pins) or an Arduino Zero / MKR (SAMD21 ARM Cortex-M0+, which offers up to 12 PWM pins and 12-bit resolution via analogWriteResolution(12)).
  • Switch to Logic-Level MOSFETs: The Uno's ATmega328P can only source/sink 20mA per pin safely. To drive high-power loads like 12V LED strips or DC motors, wire the PWM pin to the gate of a logic-level N-channel MOSFET like the IRLZ44N. This allows you to switch amps of current using the 5V PWM signal.

How to Simplify (Fewer Components)

  • Drop the Validation Overhead: If you are flashing a finalized sketch to a dedicated project and memory (SRAM) is tight, remove the isValidPWMPin() array and function. Hardcode your known-good pins and trust the silkscreen.
  • Use Hardware RC Filters: If you need a true analog DC voltage (e.g., 0-5V to control a laboratory power supply) rather than a square wave, solder a simple low-pass RC filter (e.g., 4.7kΩ resistor and 10µF ceramic capacitor) to your PWM pin. This smooths the 490Hz square wave into a steady DC voltage proportional to the duty cycle.

Frequently Asked Questions About Arduino PWM

Can I use analogWrite() on any digital pin?

No. While the Arduino IDE will compile analogWrite() on any pin without throwing a compiler error, it only generates a true hardware PWM signal on pins marked with a tilde (~). On non-PWM pins, the function falls back to a software trick: it outputs HIGH if the value is 128 or greater, and LOW if it is less than 128. This is useless for motor speed control or LED fading.

Why do my PWM pins 9 and 10 stop working when I use the Servo library?

On the Arduino Uno (ATmega328P), pins 9 and 10 are controlled by Timer1. The standard Arduino Servo.h library requires exclusive control of Timer1 to generate the highly accurate 50Hz (20ms period) pulses that hobby servos demand. When you initialize a Servo object, the library reconfigures Timer1, which inherently breaks the standard 490Hz analogWrite() functionality on pins 9 and 10. If you need simultaneous servo control and PWM on the Uno, use pins 3, 5, 6, or 11 for your PWM outputs.

What is the default PWM frequency on the Arduino Uno?

The default PWM frequency is 490 Hz for most pins (3, 9, 10, 11). However, pins 5 and 6 operate at 980 Hz. This is because pins 5 and 6 are tied to Timer0, which is also used by the millis() and delay() functions. The Arduino core configures Timer0 to run at a faster rate to ensure accurate timekeeping. If you are driving audio circuits or specific motor controllers that require a higher base frequency, keep your loads on pins 5 and 6.

How do I change the PWM frequency on an Arduino?

Changing the frequency requires manipulating the microcontroller's timer prescaler registers directly. For example, to change Timer1 (pins 9 and 10) to a 31kHz frequency (useful for audio to push the whine out of human hearing range), you would add TCCR1B = TCCR1B & B11111000 | B00000001; in your setup() function. Warning: Altering Timer0 (pins 5 and 6) will break delay() and millis() timing. Always consult the ATmega328P datasheet before modifying TCCR registers. For a safer, software-based approach, look into the community-maintained PWM.h library, which abstracts these register changes.