ESP32 PCA9685 16-Channel 12-bit PWM/Servo Driver
The PCA9685 is a 16-channel, 12-bit PWM controller designed for LED and servo motor control applications. It operates over an IΒ²C interface, allowing for easy integration with microcontrollers like the ESP32. Each of its 16 output channels can deliver PWM signals with 12-bit resolution, enabling precise control over connected devices.
π Quick Links
π PCA9685 Price
βΉοΈ About PCA9685 16-Channel 12-bit PWM/Servo Driver
The PCA9685 is a powerful 16-channel PWM driver, ideal for controlling servos, LEDs, and other PWM-based devices. It communicates via IΒ²C, making it easy to integrate with ESP32, Arduino, and Raspberry Pi.
β‘ Key Features #
- 16 Independent PWM Channels β Control multiple servos or LEDs simultaneously.
- High-Resolution PWM β 12-bit resolution (4096 steps) for precise control.
- Adjustable PWM Frequency β Ranges from 24 Hz to 1526 Hz.
- Wide Voltage Compatibility β Logic voltage: 2.3V β 5.5V; separate V+ pin for 5Vβ6V external power.
- Expandable IΒ²C Addressing β Connect up to 62 PCA9685 modules on the same IΒ²C bus.
Thanks to its scalability and precision, the PCA9685 is perfect for robotics, automation, and advanced lighting systems requiring synchronized motion or lighting effects. π
βοΈ PCA9685 Sensor Technical Specifications
Below you can see the PCA9685 16-Channel 12-bit PWM/Servo Driver Technical Specifications. The sensor is compatible with the ESP32, operating within a voltage range suitable for microcontrollers. For precise details about its features, specifications, and usage, refer to the sensorβs datasheet.
- Type: servo
- Protocol: I2C
- Interface: I2C
- PWM Channels: 16
- PWM Resolution: 12-bit (4096 steps)
- PWM Frequency: 24 Hz to 1526 Hz
- Voltage (Logic Circuit): 2.3V to 5.5V
- Voltage (External Power): Up to 6V (typically 5V for servos)
- Output Current: Sink: 25 mA, Source: 10 mA per channel
- Addressable Modules: Up to 62 on a single I2C bus
- External Clock: Supports external clock input for synchronization
- Operating Temperature: -40Β°C to 85Β°C
π PCA9685 Sensor Pinout
Below you can see the pinout for the PCA9685 16-Channel 12-bit PWM/Servo Driver. The VCC
pin is used to supply power to the sensor, and it typically requires 3.3V or 5V (refer to the datasheet for specific voltage requirements). The GND
pin is the ground connection and must be connected to the ground of your ESP32!
The PCA9685 module has the following pins, each with specific functions: VCC
: Supplies power to the PCA9685 module. It can be connected to 3.3V or 5V, making it compatible with most microcontrollers, including the ESP32. GND
: Ground pin for the module. Connect this to the ground of your microcontroller and power source to ensure proper operation. SDA
: Serial Data pin for I2C communication. Connect this to the SDA pin of your microcontroller (e.g., GPIO21 on ESP32). SCL
: Serial Clock pin for I2C communication. Connect this to the SCL pin of your microcontroller (e.g., GPIO22 on ESP32). V+
: External power pin for the servo motors or LEDs connected to the PCA9685. Typically, a 5Vβ6V external power supply is connected here for high-current devices. Outputs 0-15
: These are the 16 PWM output pins used to control servo motors, LEDs, or other PWM devices. Each pin can generate independent PWM signals. OE
: Output Enable pin. This is an optional pin that can be used to disable all PWM outputs when pulled low. It is usually left unconnected in most setups. ADR
: Address selection pins (A0βA5). These are used to set the I2C address of the module, allowing multiple PCA9685 modules to be used on the same I2C bus.
𧡠PCA9685 Wiring with ESP32
Below you can see the wiring for the PCA9685 16-Channel 12-bit PWM/Servo Driver with the ESP32. Connect the VCC pin of the sensor to the 3.3V pin on the ESP32 or external power supply for power and the GND pin of the sensor to the GND pin of the ESP32. Depending on the communication protocol of the sensor (e.g., I2C, SPI, UART, or analog), connect the appropriate data and clock or signal pins to compatible GPIO pins on the ESP32, as shown below in the wiring diagram.
To wire the PCA9685 module with the ESP32, follow these steps: VCC
: Connect the VCC pin of the PCA9685 to the 3.3V pin on the ESP32. This powers the logic circuitry of the PCA9685. GND
: Connect the GND pin of the PCA9685 to the GND pin on the ESP32. This establishes a common ground for proper communication. SDA
: Connect the SDA pin of the PCA9685 to GPIO21 on the ESP32, which is the default I2C data pin. SCL
: Connect the SCL pin of the PCA9685 to GPIO22 on the ESP32, which is the default I2C clock pin. V+
: Connect the V+ pin of the PCA9685 to an external 5Vβ6V power supply to provide power for the connected servos or LEDs. Ensure the power supply can handle the current requirements of all devices. Outputs 0-15
: Connect the signal wire of each servo or LED to one of the PWM output pins (0-15) on the PCA9685. GND for Servos
: Ensure the ground of the external power supply is connected to the GND of both the PCA9685 and the ESP32 to maintain a common reference. This wiring ensures proper communication and power distribution for the PCA9685 and connected devices.
π οΈ PCA9685 16-Channel 12-bit PWM/Servo Driver Troubleshooting
This guide outlines a systematic approach to troubleshoot and resolve common problems with the . Start by confirming that the hardware connections are correct, as wiring mistakes are the most frequent cause of issues. If you are sure the connections are correct, follow the below steps to debug common issues.
π Servos Not Responding or Moving Erratically
Issue: Servos connected to the PCA9685 do not move as expected or exhibit erratic behavior.
Possible causes include insufficient power supply, incorrect wiring, or improper PWM signal configuration.
Solution: Ensure that the servos receive adequate power, as they can draw significant current, especially during startup. Use a separate, stable power supply for the servos, and connect the grounds of the PCA9685, microcontroller, and power supply together to establish a common reference. Verify that the PWM frequency is set appropriately for servo operation, typically around 50 Hz.
π PCA9685 Not Detected on I2C Bus
Issue: The PCA9685 module is not recognized on the I2C bus, leading to communication failures.
Possible causes include incorrect I2C address configuration, faulty wiring, or issues with the microcontroller's I2C interface.
Solution: Use an I2C scanner sketch to detect the PCA9685's address, which defaults to 0x40 but can be changed by adjusting the address pins. Ensure that the SDA and SCL lines are correctly connected and that pull-up resistors are present if required by your setup. Confirm that no other devices on the I2C bus share the same address, as this can cause conflicts.
π‘ LEDs Connected to PCA9685 Not Responding
Issue: LEDs connected to the PCA9685 do not light up or respond to PWM signals.
Possible causes include incorrect wiring, improper LED configuration (common anode vs. common cathode), or incorrect PWM settings.
Solution: Verify that LEDs are connected with the correct polarity and that the PCA9685's output mode matches the LED configuration. For common anode LEDs, ensure that the outputs are sinking current, and for common cathode LEDs, that they are sourcing current. Adjust the PWM duty cycle settings in your code to control the LED brightness appropriately.
π‘οΈ PCA9685 Module Overheating
Issue: The PCA9685 module becomes excessively hot during operation.
Possible causes include excessive current draw from connected devices, inadequate power supply, or short circuits.
Solution: Ensure that the total current draw of all connected devices does not exceed the PCA9685's specifications. Use appropriate current-limiting resistors for LEDs and verify that servos or motors are within the current limits. Check for any wiring mistakes that could cause short circuits, and provide adequate ventilation to dissipate heat.
π» Code Examples
Below you can find code examples of PCA9685 16-Channel 12-bit PWM/Servo Driver with ESP32 in several frameworks:
If you encounter issues while using the PCA9685 16-Channel 12-bit PWM/Servo Driver, check the Common Issues Troubleshooting Guide.

ESP32 PCA9685 Arduino IDE Code Example
Fill in your main
Arduino IDE sketch file with the following code to use the PCA9685 16-Channel 12-bit PWM/Servo Driver:
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
// Create a PCA9685 object
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// Define the servo parameters
#define SERVOMIN 150 // Minimum pulse length count
#define SERVOMAX 600 // Maximum pulse length count
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz
void setup() {
Serial.begin(115200);
pwm.begin();
pwm.setPWMFreq(SERVO_FREQ); // Set PWM frequency to 50 Hz
}
void loop() {
// Sweep the servo back and forth
for (int pulselen = SERVOMIN; pulselen <= SERVOMAX; pulselen++) {
pwm.setPWM(0, 0, pulselen); // Channel 0 controls the servo
delay(10);
}
for (int pulselen = SERVOMAX; pulselen >= SERVOMIN; pulselen--) {
pwm.setPWM(0, 0, pulselen);
delay(10);
}
}
This Arduino sketch interfaces with the PCA9685 PWM Servo Driver over I2C using the Adafruit PWM Servo Driver library.
Required Library #
To use this code, ensure you have installed the Adafruit PWM Servo Driver library. You can install it via the Arduino Library Manager:
- Open Arduino IDE.
- Navigate to Sketch β Include Library β Manage Libraries.
- Search for 'Adafruit PWM Servo Driver' and install it.
Alternatively, you can download it from the official Adafruit GitHub repository:
π Adafruit PWM Servo Driver Library
Connect your ESP32 to your computer via a USB cable, Ensure the correct Board and Port are selected under Tools, Click the "Upload" button in the Arduino IDE to compile and upload the code to your ESP32.

ESP32 PCA9685 ESP-IDF Code ExampleExample in Espressif IoT Framework (ESP-IDF)
If you're using ESP-IDF to work with the PCA9685 16-Channel 12-bit PWM/Servo Driver, here's how you can set it up and read data from the sensor. Fill in this code in the main
ESP-IDF file:
#include <stdio.h>
#include "driver/i2c.h"
#include "esp_log.h"
// PCA9685 I2C address and parameters
#define I2C_MASTER_NUM I2C_NUM_0
#define I2C_MASTER_SDA_IO 21
#define I2C_MASTER_SCL_IO 22
#define I2C_MASTER_FREQ_HZ 100000
#define PCA9685_ADDR 0x40
#define PCA9685_MODE1 0x00
#define PCA9685_PRESCALE 0xFE
#define SERVO_MIN 150
#define SERVO_MAX 600
#define CHANNEL_0 0
static const char *TAG = "PCA9685_SERVO";
void i2c_master_init() {
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = I2C_MASTER_SCL_IO,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
};
i2c_param_config(I2C_MASTER_NUM, &conf);
i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0);
}
void pca9685_write_byte(uint8_t reg, uint8_t data) {
uint8_t write_buf[2] = {reg, data};
i2c_master_write_to_device(I2C_MASTER_NUM, PCA9685_ADDR, write_buf, 2, 1000 / portTICK_PERIOD_MS);
}
void pca9685_set_pwm(uint8_t channel, uint16_t on, uint16_t off) {
uint8_t write_buf[5] = {
0x06 + 4 * channel, // LEDn_ON_L register address
on & 0xFF, // Low byte of ON value
on >> 8, // High byte of ON value
off & 0xFF, // Low byte of OFF value
off >> 8 // High byte of OFF value
};
i2c_master_write_to_device(I2C_MASTER_NUM, PCA9685_ADDR, write_buf, 5, 1000 / portTICK_PERIOD_MS);
}
void pca9685_init() {
pca9685_write_byte(PCA9685_MODE1, 0x10); // Put PCA9685 into sleep mode
uint8_t prescale = (uint8_t)(25000000 / (4096 * 50) - 1); // Set PWM frequency to 50 Hz
pca9685_write_byte(PCA9685_PRESCALE, prescale);
pca9685_write_byte(PCA9685_MODE1, 0xA0); // Restart and set to normal mode
}
void app_main() {
ESP_LOGI(TAG, "Initializing I2C...");
i2c_master_init();
ESP_LOGI(TAG, "Initializing PCA9685...");
pca9685_init();
while (1) {
// Sweep the servo from minimum to maximum
for (int pulse = SERVO_MIN; pulse <= SERVO_MAX; pulse++) {
pca9685_set_pwm(CHANNEL_0, 0, pulse);
vTaskDelay(10 / portTICK_PERIOD_MS);
}
// Sweep the servo back from maximum to minimum
for (int pulse = SERVO_MAX; pulse >= SERVO_MIN; pulse--) {
pca9685_set_pwm(CHANNEL_0, 0, pulse);
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
}
This ESP-IDF code demonstrates how to control a servo motor using the PCA9685 PWM driver module. The i2c_master_init
function initializes the ESP32's I2C interface for communication with the PCA9685. The pca9685_init
function sets up the PWM frequency to 50 Hz, ideal for controlling servos. The pca9685_set_pwm
function sends PWM signals to a specific channel, determining the servo position based on pulse width. In the app_main
function, the servo is swept back and forth by incrementally adjusting the pulse length between SERVO_MIN
and SERVO_MAX
on channel 0.
Update the I2C pins (I2C_MASTER_SDA_IO
and I2C_MASTER_SCL_IO
) to match your ESP32 hardware setup, Use idf.py build to compile the project, Use idf.py flash to upload the code to your ESP32.

ESP32 PCA9685 ESPHome Code Example
Fill in this configuration in your ESPHome YAML configuration file (example.yml
) to integrate the PCA9685 16-Channel 12-bit PWM/Servo Driver
pca9685:
- id: pca9685_hub1
frequency: 500
output:
- platform: pca9685
pca9685_id: 'pca9685_hub1'
channel: 0
This configuration sets up a PCA9685 PWM driver in ESPHome. The pca9685
section defines a hub with an ID pca9685_hub1
and a frequency of 500 Hz. The output
section specifies a single output channel (channel 0) controlled by the PCA9685 hub. This is useful for controlling devices like servos or LEDs. For more details, visit ESPHome PCA9685 Output Documentation.
Upload this code to your ESP32 using the ESPHome dashboard or the esphome run
command.

ESP32 PCA9685 PlatformIO Code Example
For PlatformIO, make sure to configure the platformio.ini
file with the appropriate environment and libraries, and then proceed with the code.
Configure platformio.ini
First, your platformio.ini
should look like below. You might need to include some libraries as shown. Make sure to change the board to your ESP32:
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
adafruit/Adafruit PWM Servo Driver Library @ ^2.4.0
wire
build_flags =
-D CONFIG_I2C_MASTER_SDA=21
-D CONFIG_I2C_MASTER_SCL=22
monitor_speed = 115200
ESP32 PCA9685 PlatformIO Example Code
Write this code in your PlatformIO project under the src/main.cpp
file to use the PCA9685 16-Channel 12-bit PWM/Servo Driver:
#include <Wire.h>
#include "Adafruit_PWMServoDriver.h"
// Create PCA9685 object
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// Define servo parameters
#define SERVOMIN 150 // Minimum pulse length count
#define SERVOMAX 600 // Maximum pulse length count
#define SERVO_FREQ 50 // Servo frequency (50 Hz)
void setup() {
Serial.begin(115200); // Initialize serial communication
Serial.println("Initializing PCA9685...");
pwm.begin(); // Initialize PCA9685
pwm.setPWMFreq(SERVO_FREQ); // Set PWM frequency to 50 Hz
}
void loop() {
// Sweep the servo from minimum to maximum
for (int pulselen = SERVOMIN; pulselen <= SERVOMAX; pulselen++) {
pwm.setPWM(0, 0, pulselen); // Channel 0
delay(10);
}
// Sweep the servo back from maximum to minimum
for (int pulselen = SERVOMAX; pulselen >= SERVOMIN; pulselen--) {
pwm.setPWM(0, 0, pulselen); // Channel 0
delay(10);
}
}
This code controls a servo motor using the PCA9685 module with an ESP32. The Adafruit_PWMServoDriver
library is used to communicate with the PCA9685 over I2C. The setup
function initializes the PCA9685 and sets the PWM frequency to 50 Hz, suitable for most servos. In the loop
, the servo motor connected to channel 0 is swept back and forth by varying the pulse length between SERVOMIN
(150) and SERVOMAX
(600), which define the servo's angular range. The pwm.setPWM
function sends these pulse values to the PCA9685 to control the servo position.
Upload the code to your ESP32 using the PlatformIO "Upload" button in your IDE or the pio run --target upload
command.

ESP32 PCA9685 MicroPython Code Example
Fill in this script in your MicroPython main.py file (main.py
) to integrate the PCA9685 16-Channel 12-bit PWM/Servo Driver with your ESP32.
from machine import Pin, I2C
from time import sleep
from pca9685 import PCA9685
# Initialize I2C
i2c = I2C(0, scl=Pin(22), sda=Pin(21), freq=100000)
# Initialize PCA9685
pwm = PCA9685(i2c)
pwm.freq(50) # Set frequency to 50 Hz for servos
# Servo pulse range
SERVOMIN = 150 # Minimum pulse length
SERVOMAX = 600 # Maximum pulse length
def set_servo_angle(channel, angle):
"""Convert angle (0-180) to pulse length and set PWM."""
pulse = SERVOMIN + int((SERVOMAX - SERVOMIN) * angle / 180)
pwm.channels[channel].duty_u16(pulse)
try:
while True:
# Sweep servo from 0 to 180 degrees
for angle in range(0, 181, 1):
set_servo
This MicroPython code demonstrates how to control a servo motor using the PCA9685 module. The PCA9685
library is used to communicate with the module over I2C, where pins 22
(SCL) and 21
(SDA) are configured. The pwm.freq(50)
sets the PWM frequency to 50 Hz, which is required for controlling servo motors. The set_servo_angle
function calculates the appropriate pulse length for a given angle (0-180 degrees) and sends it to a specified channel. In the loop, the servo sweeps back and forth by incrementing and decrementing the angle, controlling the servo's position. The try
block allows stopping the program gracefully using a keyboard interrupt.
Upload this code to your ESP32 using a MicroPython-compatible IDE, such as Thonny, uPyCraft, or tools like ampy
.
Conclusion
We went through technical specifications of PCA9685 16-Channel 12-bit PWM/Servo Driver, its pinout, connection with ESP32 and PCA9685 16-Channel 12-bit PWM/Servo Driver code examples with Arduino IDE, ESP-IDF, ESPHome and PlatformIO.