Skip to content
EESP32S Wiki
Documentation/PCA9685 with ESP32: Servo Wiring, Power & PWM
PRODUCT DOCUMENTATION

PCA9685 with ESP32: Servo Wiring, Power & PWM

Separate logic and servo power, connect the I2C driver and test one positional servo before expanding to more channels.

Updated Oct 21, 2026 · View product ↗
On this pageSeparate logic power from servo powerPrepare one unloaded servoConnect I2C and external servo powerInstall the PWM driverTry a small pulse-width changeCalibrate before using all channelsTroubleshootingReferences and next stepsRelated product
PCA9685 Servo Driver — product reference photo
Product reference photo. Check your hardware revision and printed pin labels before wiring.

Control one positional servo from an ESP32 through the PCA9685 16-channel PWM module. Establish a small, unloaded movement first, then expand only after the servo power and pulse range have been checked.

Separate logic power from servo power

VCC powers the PCA9685 logic, while V+ supplies the servo connectors on typical breakout boards. They are separate rails. Use 3.3 V logic with the ESP32 and a separate regulated supply suitable for the chosen servo on V+. A PWM signal is not a motor-power output.

Prepare one unloaded servo

The controller for this example is an ESP32-C3 Supermini. Confirm that its USB upload and serial test works before adding the module. Use ESP32C3 Dev Module with USB CDC On Boot enabled for native USB, and open Serial Monitor at 115200 baud. Disconnect power while changing wires.

Use a positional servo rated for the 50 Hz signal in this example. Remove mechanical loads or linkages for the first movement. Continuous-rotation servos interpret the pulse differently, so they should not be expected to move to a particular angle.

Connect I2C and external servo power

Module label ESP32-C3 example Purpose
VCC — logic only 3V3 3.3 V logic supply for this setup
GND GND Common ground
SDA GPIO6 I2C data
SCL GPIO7 I2C clock

GPIO6 and GPIO7 are explicit assignments for this C3 example. They are not physical header positions or universal ESP32 defaults. For another board, select free exposed pins using its own pinout and update Wire.begin(). Keep ESP32 I2C pull-ups at 3.3 V.

Servo-side connection Destination
Suitable regulated servo-supply positive V+ terminal, within both board and servo ratings
Servo-supply negative PCA9685 GND and common ESP32 GND
One servo signal Channel 0 PWM
Servo power and return Channel 0 V+ and GND, after checking connector labels

Check polarity from printed labels, not wire color alone. Do not feed the servo through the ESP32 3V3 pin. Start with one servo and provide a supply that can handle its start/stall demand; the USB connection used to program the ESP32 does not establish the servo supply capacity.

Install the PWM driver

In Arduino Library Manager install Adafruit PWM Servo Driver Library and Adafruit BusIO. Accept the required dependencies. Paste the complete example into a new sketch, click Verify, then Upload. If reporting a problem, include the board profile, package version and library version.

The ordinary individual address starts at 0x40 with the standard address-link configuration. A PCA9685 may also acknowledge an All Call address, so an extra scanner response is not automatically another board. Confirm address straps if your individual address differs.

Try a small pulse-width change

The example begins at 1,500 µs, then alternates between 1,400 and 1,600 µs on channel 0. These are conservative starting values for many ordinary positional servos, not a guaranteed angle range for every servo. Stop if the mechanism binds, buzzes heavily or the supply collapses.

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

Adafruit_PWMServoDriver servos(0x40, Wire);
void setup() {
  Serial.begin(115200);
  delay(1500);
  Wire.begin(6, 7);
  if (!servos.begin()) {
    Serial.println("PCA9685 not found.");
    while (true) delay(1000);
  }
  servos.setPWMFreq(50); // For a positional servo rated for 50 Hz.
  delay(10);
  servos.writeMicroseconds(0, 1500);
  delay(2000);
}
void loop() {
  servos.writeMicroseconds(0, 1400);
  Serial.println("Channel 0: 1400 us");
  delay(2000);
  servos.writeMicroseconds(0, 1600);
  Serial.println("Channel 0: 1600 us");
  delay(2000);
}

Calibrate before using all channels

  1. Confirm small movement on channel 0 with no linkage attached.
  2. Check the actual servo pulse and supply behavior if the response is unexpected.
  3. Determine safe endpoints for the particular servo and mechanism gradually.
  4. Only then add channels, accounting for combined power demand and connector limits.

All channels share the PWM frequency on this chip. The library's microsecond conversion depends on the oscillator estimate and programmed frequency. Do not infer an exact mechanical angle from a pulse number without calibration.

Troubleshooting

Symptom What to check
Driver not found Check logic VCC, common ground, address links and SDA/SCL.
I2C works but servo does not move Check the separate V+ rail, channel number, servo connector orientation and output-enable state.
ESP32 resets when servo starts Inspect servo supply sizing and return wiring; keep motor current out of the controller supply path.
Servo runs continuously Confirm whether it is a continuous-rotation model.
Endpoint causes buzzing or binding Return to the unloaded center test and calibrate a smaller safe range.

References and next steps

PCA9685PW 16 Channel 12-Bit PWM Servo Shield Driver I2C Interface PCA9685 Module For Raspberry Pi →

Need help with your board?

Share the product link, hardware revision, software version and any error messages.

Contact ESP32S support →
Shop
Sidebar
Wishlist
0 items Cart
My account
Rates by ExchangeRate-API