Reference
PCA9685 16-Channel PWM/Servo Driver
A 16-channel, 12-bit I2C PWM driver that turns two ESP32 wires into enough hardware-generated outputs for a whole rack of servos or an LED array. Covers the pinout, address selection, register map, and the safe way to power servos without browning out the board.
- 16 channels
- 12-bit
- I2C Fm+ up to 1 MHz
- 24 to 1526 Hz
The PCA9685 16-channel PWM/servo driver module is one of the easiest ways to add PWM, LED dimming and servo control to your ESP32 project. The module is based on the PCA9685 from NXP and gives you 16 independent, 12-bit PWM outputs over a simple two-wire I²C bus. The MCP23017 gave you 16 extra digital pins, but it can’t do PWM. This module is the answer.
In this complete guide we cover:
- What the PCA9685 is
- Technical specifications
- Pinout (16-channel breakout)
- I²C address selection
- PWM channel overview – all 16 outputs and their functions
- ESP32-C6 SUPER MINI wiring
- Register map explained
- Setting the PWM frequency (the prescale formula)
- ESP-IDF example code (LED dimming + servo)
- Arduino example code
- Powering servos the right way
- PCA9685 vs ESP32 native LEDC comparison
- Practical engineering tips
The chip numbers in this guide come from the NXP PCA9685 datasheet. The details of the servo breakout board come from common practice, so check your own board.
What is the PCA9685?
The PCA9685 is a 16-channel, 12-bit PWM controller driven over I²C. Each of its 16 outputs can be set independently to any duty cycle from 0 to 4095 (12-bit resolution), which makes it ideal for driving LEDs, RGB strips and, most famously, hobby servos.
Unlike bit-banging PWM from your microcontroller, the PCA9685 generates all 16 signals in hardware. Once you write a value, the chip keeps toggling the pin on its own, so your ESP32 does nothing until you change it.
Key features:
- 16 independent PWM channels
- 12-bit resolution per channel (4096 steps)
- One programmable frequency for all channels (≈24 Hz – 1526 Hz)
- 25 MHz internal oscillator, or an external clock up to 50 MHz
- Configurable totem-pole or open-drain outputs
- Output Enable (OE) pin to switch all channels off at once
- Up to 62 devices on one I²C bus (992 PWM channels!)
- Built-in software reset and “All Call” addressing
Every channel has its own ON and OFF timing registers, so you can not only set the duty cycle but also phase-shift each output, a neat trick to spread inrush current when driving many LEDs.
Technical Specifications
| Parameter | Value |
|---|---|
| PWM channels | 16 |
| Resolution | 12-bit (4096 steps) per channel |
| Interface | I²C (Fast-mode Plus, up to 1 MHz) |
| I²C address range | 0x40 – 0x7F (6 address pins) |
| Logic supply (VCC) | 2.3V – 5.5V |
| Output supply (V+) | Up to 6V (servo/LED power rail) |
| Current per output | 25 mA sink / 10 mA source |
| PWM frequency | ≈24 Hz – 1526 Hz (shared) |
| Internal oscillator | 25 MHz (external clock up to 50 MHz) |
| Output type | Totem-pole or open-drain (OUTDRV) |
| Operating temperature | -40°C to +85°C |
⚠️ Power the logic side (VCC) from 3.3V when using it with an ESP32 so the I²C levels match. The servo/LED side (V+) needs its own supply, so never try to run servos from the ESP32’s 3.3V pin (see Powering servos below).
Dimensions
The PCA9685 chip is a small SMD package (TSSOP-28 and HVQFN-28 are the common ones). You nearly always buy it on a breakout board with 16 three-pin servo headers, a screw terminal for the servo supply, and solder jumpers for the address. These boards are about 62 × 25 mm in the common design, but sizes differ between makers, so measure yours before you design a case.
Source: NXP PCA9685 datasheet for the chip. The board size is typical, not from the datasheet.
Pinout
The standard 16-channel breakout exposes a header on each side plus 16 three-pin output groups:
| Pin | Description |
|---|---|
| VCC | 3.3V logic supply |
| GND | Ground (shared with V+ ground) |
| SDA | I²C data |
| SCL | I²C clock |
| OE | Output enable: active-low, tie to GND to run |
| V+ | Servo/LED power rail (screw terminal, up to 6V) |
| A0 – A5 | I²C address selection (solder jumpers) |
| PWM0 – PWM15 | The 16 PWM outputs (each with its own V+ and GND) |
Each output group has three pins in the classic servo order: PWM signal, V+, GND, so a servo plugs straight in without any adapter.
⚠️ The OE pin is active-low. On many clone boards it is left floating, which can cause all outputs to switch off unpredictably. Tie OE to GND to keep the outputs permanently enabled, or route it to a spare ESP32 GPIO if you want a hardware “all-off” switch.
I²C Address Selection
The six solder-jumper pads A0–A5 set the 7-bit I²C address, giving a base of 0x40 with nothing bridged. Bridging a pad adds its bit:
| Bridged pads | I²C Address |
|---|---|
| none | 0x40 |
| A0 | 0x41 |
| A1 | 0x42 |
| A0 + A1 | 0x43 |
| A2 | 0x44 |
| A5 + A4 + A3 | 0x78 |
| all (A0–A5) | 0x7F |
That allows a theoretical 62 modules on one bus, up to 992 PWM channels. Two addresses are reserved by default: 0x70 (LED All Call) and the software-reset address 0x00, so avoid those.
⚠️ For a single module, bridge nothing and use the default address 0x40.
PWM Channel Overview – Capabilities and Functions
Every one of the 16 outputs is identical. This table shows what each channel can and cannot do:
| Function | Available? | Notes |
|---|---|---|
| Hardware PWM output | ✅ | 12-bit, independent duty cycle |
| LED dimming | ✅ | 0–4095 brightness steps |
| Hobby servo control | ✅ | At 50 Hz, ~150–600 counts |
| Per-channel phase shift | ✅ | Separate ON and OFF registers |
| Independent frequency per pin | ❌ | All channels share one frequency |
| Analog output (true DAC) | ❌ | Use an [MCP4725] for a real DAC |
| Analog input (ADC) | ❌ | Use an ADS1115 |
| High current per pin | ❌ | 25 mA sink, use a driver for more |
The PCA9685 is perfect for servo arms, pan/tilt rigs, robotic legs, LED walls, RGB(W) lighting and motorised blinds, anything that needs many smooth, hands-off PWM signals at the same frequency.
Connecting to the ESP32-C6 SUPER MINI
Only four signal wires are needed, plus a separate power feed for the servo rail:
| PCA9685 Module | ESP32-C6 SUPER MINI | Wire |
|---|---|---|
| VCC | 3V3 | Red |
| GND | GND | Black |
| SDA | GPIO6 | Green |
| SCL | GPIO7 | Yellow |
| OE | GND | |
| V+ | External 5V supply | |
| GND (V+) | External supply GND |
Notes:
- GPIO6 and GPIO7 are free, safe pins on the ESP32-C6 SUPER MINI: the I²C peripheral can be routed to any GPIO thanks to the ESP32 GPIO matrix.
- Avoid GPIO8: on most SUPER MINI boards the onboard RGB LED is connected there.
- The ESP32 ground and the external 5V ground must be connected together (common ground) or the signals will not be referenced correctly.
- The onboard I²C pull-ups on the breakout are fine for short runs, so no external resistors needed.
Register Map
The PCA9685 is controlled through a small set of registers. The most important ones:
| Register | Address | Function |
|---|---|---|
| MODE1 | 0x00 | Sleep, restart, auto-increment, All Call |
| MODE2 | 0x01 | Output type, invert, output-change timing |
| LED0_ON_L | 0x06 | Channel 0 “ON” time, low byte |
| LED0_ON_H | 0x07 | Channel 0 “ON” time, high byte |
| LED0_OFF_L | 0x08 | Channel 0 “OFF” time, low byte |
| LED0_OFF_H | 0x09 | Channel 0 “OFF” time, high byte |
| LEDn… | 0x06 + 4n | Four registers per channel (n = 0…15) |
| ALL_LED_ON_L…H | 0xFA – 0xFB | Set all channels’ ON time at once |
| ALL_LED_OFF_L…H | 0xFC – 0xFD | Set all channels’ OFF time at once |
| PRE_SCALE | 0xFE | PWM frequency prescaler |
Each channel uses four registers: a 12-bit ON count and a 12-bit OFF count. For simple duty-cycle control you set ON = 0 and OFF = your value (0–4095). To phase-shift a channel, give it a non-zero ON value.
⚠️ Enable the auto-increment (AI) bit in MODE1 (0x20) so you can write all four LED registers in one I²C transaction. It also makes the code much shorter.
Setting the PWM Frequency
All 16 channels share one frequency, set by the PRE_SCALE register. The formula:
prescale = round( 25 000 000 / (4096 × frequency) ) − 1
For 50 Hz (standard hobby servos):
prescale = round( 25 000 000 / (4096 × 50) ) − 1 = 121 (0x79)
⚠️ The PRE_SCALE register can only be written while the chip is asleep. The sequence is: set the SLEEP bit → write PRE_SCALE → clear SLEEP → wait 500 µs → set the RESTART bit. The example code below does exactly this.
ESP-IDF Example Code
The example configures the module for 50 Hz, dims an LED on channel 0 and sweeps a servo on channel 1, using the new ESP-IDF I²C master driver:
#include <stdio.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2c_master.h"
#include "esp_log.h"
#define I2C_SDA_GPIO 6
#define I2C_SCL_GPIO 7
#define PCA9685_ADDR 0x40
/* PCA9685 registers */
#define REG_MODE1 0x00
#define REG_MODE2 0x01
#define REG_LED0_ON_L 0x06
#define REG_PRESCALE 0xFE
/* MODE1 bits */
#define MODE1_RESTART 0x80
#define MODE1_AI 0x20
#define MODE1_SLEEP 0x10
static const char *TAG = "PCA9685";
static i2c_master_dev_handle_t pca;
static esp_err_t write_reg(uint8_t reg, uint8_t val)
{
uint8_t buf[2] = { reg, val };
return i2c_master_transmit(pca, buf, sizeof(buf), -1);
}
static esp_err_t read_reg(uint8_t reg, uint8_t *val)
{
return i2c_master_transmit_receive(pca, ®, 1, val, 1, -1);
}
/* Set one channel: on = 0..4095 start, off = 0..4095 stop */
static void set_pwm(uint8_t ch, uint16_t on, uint16_t off)
{
uint8_t buf[5] = {
(uint8_t)(REG_LED0_ON_L + 4 * ch),
(uint8_t)(on & 0xFF), (uint8_t)(on >> 8),
(uint8_t)(off & 0xFF), (uint8_t)(off >> 8),
};
i2c_master_transmit(pca, buf, sizeof(buf), -1);
}
static void set_frequency(float hz)
{
uint8_t prescale = (uint8_t)(roundf(25000000.0f / (4096.0f * hz)) - 1);
uint8_t old_mode;
read_reg(REG_MODE1, &old_mode);
write_reg(REG_MODE1, (old_mode & ~MODE1_RESTART) | MODE1_SLEEP); /* sleep */
write_reg(REG_PRESCALE, prescale); /* set freq */
write_reg(REG_MODE1, old_mode); /* wake */
vTaskDelay(pdMS_TO_TICKS(1));
write_reg(REG_MODE1, old_mode | MODE1_RESTART | MODE1_AI); /* restart + AI */
}
void app_main(void)
{
i2c_master_bus_config_t bus_config = {
.i2c_port = I2C_NUM_0,
.sda_io_num = I2C_SDA_GPIO,
.scl_io_num = I2C_SCL_GPIO,
.clk_source = I2C_CLK_SRC_DEFAULT,
.glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = true,
};
i2c_master_bus_handle_t bus;
ESP_ERROR_CHECK(i2c_new_master_bus(&bus_config, &bus));
i2c_device_config_t dev_config = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = PCA9685_ADDR,
.scl_speed_hz = 400000,
};
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus, &dev_config, &pca));
set_frequency(50.0f); /* 50 Hz for servos */
ESP_LOGI(TAG, "PCA9685 ready at 0x%02X", PCA9685_ADDR);
int brightness = 0, step = 64;
while (1) {
/* Channel 0: breathing LED */
brightness += step;
if (brightness >= 4095 || brightness <= 0) step = -step;
set_pwm(0, 0, brightness);
/* Channel 1: sweep servo between ~1 ms and ~2 ms */
for (int pos = 150; pos <= 600; pos += 15) {
set_pwm(1, 0, pos);
vTaskDelay(pdMS_TO_TICKS(20));
}
for (int pos = 600; pos >= 150; pos -= 15) {
set_pwm(1, 0, pos);
vTaskDelay(pdMS_TO_TICKS(20));
}
}
}
Because the PCA9685 works with plain register reads and writes, no external library is required: the ESP-IDF I²C driver is all you need.
Prefer Arduino?
With the Adafruit PWM Servo Driver library it’s much shorter:
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pca = Adafruit_PWMServoDriver(0x40);
void setup() {
Wire.begin(6, 7); // SDA = GPIO6, SCL = GPIO7
pca.begin();
pca.setPWMFreq(50); // 50 Hz for servos
}
void loop() {
pca.setPWM(1, 0, 150); // servo ~1 ms
delay(500);
pca.setPWM(1, 0, 600); // servo ~2 ms
delay(500);
}
Powering Servos the Right Way
This is the single most common mistake with the PCA9685, so it gets its own section.
⚠️ Never power servos from the ESP32. A single small servo can draw 500 mA – 1 A during a stall, far more than the ESP32’s 3.3V regulator can deliver. Doing so causes brownouts, random reboots and I²C errors.
Do this instead:
- Feed the V+ rail from a dedicated 5V supply sized for your servos (a couple of amps for several servos).
- Connect the VCC logic pin to the ESP32’s 3.3V. The logic side draws only a few milliamps.
- Tie all grounds together: ESP32 GND, PCA9685 GND and the 5V supply GND.
- Add a large electrolytic capacitor (470–1000 µF) across V+ and GND close to the module to absorb servo current spikes.
Using It with an ESP32-S3 and MG996R Servos
This is how I wire the PCA9685 in my animatronic Pit Droid, with an ESP32-S3-DevKitC-1 and MG996R servos:
| PCA9685 | ESP32-S3-DevKitC-1 | Note |
|---|---|---|
| VCC | 3V3 | Logic power only |
| GND | G | Common ground |
| SDA | GPIO8 | The default I2C pin in the Arduino core |
| SCL | GPIO9 | The default I2C pin in the Arduino core |
| V+ (screw terminal) | 5 to 6 V supply | Servo power, not from the ESP32-S3 |
The servo supply is separate, and its ground goes to the ground of the board. With the Adafruit library the servo setup is:
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);
void setup() {
Wire.begin(8, 9); // SDA, SCL
pwm.begin();
pwm.setOscillatorFrequency(27000000);
pwm.setPWMFreq(50); // 50 Hz for servos
pwm.writeMicroseconds(0, 1500); // channel 0 to the centre
}
void loop() {}Centre every servo with a servo tester first. The oscillator value of 27 MHz is the number from Adafruit’s examples. The real frequency of your chip differs a little, so adjust it if the pulses are a bit off.
Buying one: PCA9685 servo driver*. Links marked * are affiliate links.
PCA9685 vs ESP32 Native LEDC
The ESP32 already has hardware PWM through its LEDC peripheral, so when do you need a PCA9685?
| Feature | PCA9685 | ESP32 LEDC (native) |
|---|---|---|
| PWM channels | 16 per module | 6–8 (varies per ESP32 model) |
| Resolution | 12-bit (fixed) | Up to 14-bit |
| Interface | I²C (2 wires) | Direct GPIO |
| Uses ESP32 GPIOs | Only 2 (SDA/SCL) | One GPIO per channel |
| Independent frequency | No (shared) | Yes (per timer) |
| Devices chainable | Up to 62 (992 ch.) | One MCU |
| Extra hardware needed | Yes (the module) | No |
When to Choose the PCA9685
- You need more channels than the ESP32 has PWM pins
- You’re driving many servos or a large LED array
- You want to keep ESP32 GPIOs free
- You need to daisy-chain many outputs across boards
When to Choose Native LEDC
- You only need a handful of PWM outputs
- You want per-channel frequency control
- You want zero extra components and the lowest latency
Practical Engineering Tips
1. Use a Separate Servo Supply
The number one cause of “my ESP32 keeps rebooting”: servos brown out the board. Give V+ its own 5V rail and share the ground.
2. Run an I²C Scanner First
Before any application code, scan the bus. If 0x40 shows up, your wiring is correct. If not, check VCC, GND, SDA/SCL and the OE pin.
3. Calibrate Your Servos
The 150–600 count range is a safe default, but cheap servos vary. Find each servo’s real minimum and maximum experimentally to get the full sweep without buzzing at the end stops.
4. Add a Bulk Capacitor
A 470–1000 µF capacitor across V+ smooths the current spikes when several servos move at once and keeps the whole system stable.
5. Phase-Shift Big LED Arrays
Driving all 16 LED channels on at the same instant creates a large inrush. Give each channel a different ON value so they turn on at slightly different moments, so the supply barely notices.
Real gotchas
- Never power servos from the ESP32. A stalled servo draws an amp or more. Use a separate 5 V to 6 V supply on V+, with a common ground.
- OE is active low. A floating OE pin can switch the outputs off. Tie it to GND, or drive it from a GPIO.
- The default address is 0x40, and 0x70 is the all-call address. Every PCA9685 answers on 0x70 by default (LED All Call), and on 0x00 for the software reset. Keep other devices off those addresses.
- The frequency is shared. All 16 channels use one PWM frequency, set with PRE_SCALE. You can only write PRE_SCALE while the chip is asleep.
- The internal oscillator is not exact. It is 25 MHz typical, so 50 Hz is not exactly 50 Hz. Servos usually do not care, but calibrate if you need accuracy.
- Totem pole by default. The outputs source 10 mA and sink 25 mA. For driving a MOSFET or a LED to a higher voltage, switch the outputs to open-drain with the OUTDRV bit.
- Auto-increment must be on. To write the four registers of a channel in one go, set the AI bit in MODE1.
- The chip is 5.5 V tolerant, not 6 V. The V+ rail of the breakout is the servo rail and is separate from the chip supply on most boards. Do not feed 6 V to the logic VCC pin.
- Servo jitter. If servos twitch when others move, the supply is too weak. Add a capacitor of 470 to 1000 µF on V+.
- A reset is needed after a crash. If the chip is stuck, send the software reset (0x06 to the general-call address 0x00).
Safety notes
Before you wire anything up
- Never feed more than the supply the chip is rated for (2.3 to 5.5 V) on the logic side.
- Servo supplies can deliver amps. A short circuit or a stalled servo can heat wires and connectors, so use proper wire and a fuse.
- Keep fingers away from moving servo arms when you power the board.
- Never connect mains to any pin. This is a low-voltage board.
- A servo controller is not a safety device. Do not use it as the only control of a motion that can hurt someone.
- Never connect the board to mains voltage. Keep it on a low-voltage supply.
- Disconnect the power before you change the wiring.
Conclusion
The PCA9685 16-channel PWM/servo driver is a small module that solves a big problem: not enough PWM. Combined with the ESP32-C6 SUPER MINI it turns two I²C wires into 16 rock-steady, hardware-generated PWM outputs.
It offers:
- 16 independent 12-bit PWM channels over just 2 wires
- Hardware PWM: the ESP32 stays free to do other work
- Perfect for servos, LED dimming and RGB lighting
- Up to 62 modules per bus: 992 PWM channels
- Simple register-based control, no library required
Where the MCP23017 adds digital pins and the CD74HC4067 adds analog inputs, the PCA9685 completes the set by adding analog-style outputs. For any ESP32 project involving motion or light, it’s one of the best-value building blocks you can add to your parts drawer.
More guides
Keep building.
From ESP32 HomeKit accessories to Arduino and ATtiny reference guides, there’s more where this came from.
All guides

