Blog

PCA9685 16-Channel 12-bit PWM/Servo Driver

PCA9685 16-Channel 12-bit PWM/Servo Driver

I2C Interface for Arduino and Raspberry Pi Projects

Introduction

The PCA9685 is a 16-channel, 12-bit PWM controller with an I2C interface, perfect for controlling multiple servos or LEDs. This compact module can drive up to 16 servos with just 2 pins (SDA and SCL) from your microcontroller.

PCA9685 Module

Key Features

🎛️ 16 PWM Channels

Independent control of 16 outputs

📊 12-bit Resolution

4096 steps of PWM control

🔌 I2C Interface

Simple 2-wire communication

External Power

Supports 2.3V-5.5V for PWM outputs

Technical Specifications

Channels 16 independent PWM outputs
Resolution 12-bit (4096 steps)
Interface I2C (up to 1MHz)
Addresses 62 possible I2C addresses
PWM Frequency 40Hz to 1000Hz (adjustable)
Logic Voltage 2.3V to 5.5V
Output Voltage Same as V+ (2.3V-5.5V)
Current per Channel 25mA max (200mA total)

Pin Configuration

PCA9685 Pinout

Pin Function Description
VCC Power 2.3V-5.5V logic power
GND Ground Common ground
SCL I2C Clock Serial clock input
SDA I2C Data Serial data input/output
V+ Output Power 2.3V-5.5V for PWM outputs
OE Output Enable Active low output enable
PWM0-15 PWM Outputs 16 PWM output channels

Wiring with Arduino

PCA9685 Arduino Wiring

// Basic I2C Connection:
// VCC → Arduino 5V
// GND → Arduino GND
// SCL → Arduino A5 (or SCL pin)
// SDA → Arduino A4 (or SDA pin)
// V+  → External power (for servos)

Wiring with Raspberry Pi

PCA9685 Raspberry Pi Wiring

# Basic I2C Connection:
# VCC → Pi 3.3V
# GND → Pi GND
# SCL → Pi GPIO 3 (SCL)
# SDA → Pi GPIO 2 (SDA)
# V+  → External power (for servos)

Arduino Code Example

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

void setup() {
  Serial.begin(9600);
  pwm.begin();
  pwm.setPWMFreq(60);  // Analog servos run at ~60 Hz
}

void loop() {
  // Move servo on channel 0 from 0 to 180 degrees
  for (uint16_t pulselen = 150; pulselen < 600; pulselen++) { pwm.setPWM(0, 0, pulselen); delay(5); } delay(500); for (uint16_t pulselen = 600; pulselen > 150; pulselen--) {
    pwm.setPWM(0, 0, pulselen);
    delay(5);
  }
  delay(500);
}

Raspberry Pi Python Example

from board import SCL, SDA
import busio
from adafruit_pca9685 import PCA9685
from adafruit_motor import servo

i2c = busio.I2C(SCL, SDA)
pca = PCA9685(i2c)
pca.frequency = 50  # Servos typically run at 50Hz

servo1 = servo.Servo(pca.channels[0])

while True:
    for angle in range(0, 180, 5):  # 0 to 180 degrees
        servo1.angle = angle
    for angle in range(180, 0, -5):  # 180 to 0 degrees
        servo1.angle = angle

Advanced Applications

LED Dimming

// Set LED brightness (0-4095)
pwm.setPWM(channel, 0, brightness);

Multiple Servos

// Control multiple servos
pwm.setPWM(0, 0, servo1Pos);
pwm.setPWM(1, 0, servo2Pos);
pwm.setPWM(2, 0, servo3Pos);

Cascading Modules

// Control multiple PCA9685s
Adafruit_PWMServoDriver pwm2 = Adafruit_PWMServoDriver(0x41);
pwm2.setPWMFreq(60);

Troubleshooting

No Response

  • Check I2C connections (SDA/SCL)
  • Verify power supply is connected
  • Confirm I2C address (default 0x40)

Servo Jitter

  • Ensure adequate power supply
  • Check for loose connections
  • Try different PWM frequency (50-60Hz for servos)

I2C Errors

  • Verify pull-up resistors on SDA/SCL
  • Check for address conflicts
  • Test with different I2C speed