PCA9685 works with LEDs but not with Servos

Hi everybody.
I'm fairly new to Arduino and this is my first post in the forum so I hope I'm in the right category.
I am working on my fist bigger project, which will be a robot arm with 4-6 Servos but have run into problems when trying to get my set up working with even one servo.
I have tried several different libraries, examples from said libraries, code & tutorials from different online sources and I've read just about everything I can find on the PCA9685 but to no avail.
For some reason I can't get any servo to move with any code I use or any slot I plug it into, but I did figure out that the communication with the board works and that there is a Voltage on the PCA9685'S pins by using the "PWMtest" Example from the Adafruits PWM Servo Library.
I got an LED to fade up and down and I can measure a voltage on all pins that's fading up and down like it's supposed to. When I use servos and the servo example or any other code I write / find it doesn't work.

I have re-wired everything several times to make sure I didn't mess up anywhere and I have tested this with several different MG995 Servos and with a SG90 Micro Servo to make sure those are not the issue.
I have attached a picture of my circuit and one showing a voltage measurement at the power terminal of the PCA.

At first I thought my power supply might be the issue, but it's delivering the exact voltage i set on the buck converter to the power terminal on the PCA9685. I have set the buck converter to 5V as well as 6V (which is the recommended voltage for the MG995) and the current is limited to about 1.5 Amps for testing with one Servo right now but I can increase it to about 6 Amps if I need to, based on my power supply.

I tried to use the small SG90 Servo and power it straight from the Arduino by connecting V+ on the PCA to the 5V pin on Arduino,but it doesn't work either. (And yes I have only tried this with 1 micro servo to test and I'm aware you can't power servos of the Arduino).

I also ran an I2C Scan and it finds a device at the standard address of 0x40 and as stated above I can apparently send signals to the PCA since the LED experiment works.

I am using:

Arduino Uno R3
PCA9685
XL4016 Buck Converter
Power Supply with Output of 19.5 V, 6.7 A max.
I will be using MG995 Servos for the final Arm but I also have a SG90 micro servo which I've used to test as well, same results

Here is the PWMtest code that makes an LED fade up and down successfully:

/*************************************************** 
  This is an example for our Adafruit 16-channel PWM & Servo driver
  PWM test - this will drive 16 PWMs in a 'wave'

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/815

  These displays use I2C to communicate, 2 pins are required to  
  interface. For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

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

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);

#if defined(ARDUINO_ARCH_SAMD)  
// for Zero, output on USB Serial console, remove line below if using programming port to program the Zero!
   #define Serial SerialUSB
#endif

void setup() {
#ifdef ESP8266
  Wire.pins(2, 14);   // ESP8266 can use any two pins, such as SDA to #2 and SCL to #14
#endif
  
  Serial.begin(9600);
  Serial.println("16 channel PWM test!");

  pwm.begin();
  pwm.setPWMFreq(1600);  // This is the maximum PWM frequency

  // if you want to really speed stuff up, you can go into 'fast 400khz I2C' mode
  // some i2c devices dont like this so much so if you're sharing the bus, watch
  // out for this!
#ifdef TWBR    
  // save I2C bitrate
  uint8_t twbrbackup = TWBR;
  // must be changed after calling Wire.begin() (inside pwm.begin())
  TWBR = 12; // upgrade to 400KHz!
#endif
}

void loop() {
  // Drive each PWM in a 'wave'
  for (uint16_t i=0; i<4096; i += 8) {
    #ifdef ESP8266
    yield();
    #endif
    for (uint8_t pwmnum=0; pwmnum < 16; pwmnum++) {
      pwm.setPWM(pwmnum, 0, (i + (4096/16)*pwmnum) % 4096 );
    }
  }
}

Here is (one of) the example codes i tried to use, which doesn't work for me:

/*************************************************** 
  This is an example for our Adafruit 16-channel PWM & Servo driver
  Servo test - this will drive 16 servos, one after the other

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/815
![IMG_20220213_235740|375x500](upload://zbqbEI2VJFZlUwsmC20TZAd4yVb.jpeg)
![IMG_20220213_234917|375x500](upload://tUYJ29bufvqNXavnXCcyAtPHdaH.jpeg)

  These displays use I2C to communicate, 2 pins are required to  
  interface. For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

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

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);

// Depending on your servo make, the pulse width min and max may vary, you 
// want these to be as small/large as possible without hitting the hard stop
// for max range. You'll have to tweak them as necessary to match the servos you
// have!
#define SERVOMIN  150 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  600 // this is the 'maximum' pulse length count (out of 4096)

// our servo # counter
uint8_t servonum = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");

  pwm.begin();
  
  pwm.setPWMFreq(50);  // Analog servos run at ~60 Hz updates

  yield();
}

// you can use this function if you'd like to set the pulse length in seconds
// e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. its not precise!
void setServoPulse(uint8_t n, double pulse) {
  double pulselength;
  
  pulselength = 1000000;   // 1,000,000 us per second
  pulselength /= 50;   // 50 Hz
  Serial.print(pulselength); Serial.println(" us per period"); 
  pulselength /= 4096;  // 12 bits of resolution
  Serial.print(pulselength); Serial.println(" us per bit"); 
  pulse *= 1000;
  pulse /= pulselength;
  Serial.println(pulse);
  pwm.setPWM(n, 0, pulse);
}

void loop() {
  // Drive each servo one at a time
  Serial.println(servonum);
  for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
    pwm.setPWM(servonum, 0, pulselen);
  }

  delay(500);
  for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
    pwm.setPWM(servonum, 0, pulselen);
  }

  delay(500);

  servonum ++;
  if (servonum > 7) servonum = 0;
}

I hope someone can help me because after days of googeling and experimenting I'm stuck.
If you need any additional information, let me know.
Thanks a lot in advance :slight_smile:


Hi, I realized I forgot to attach a schematic, here is a very rough hand drawn one of my test circuit that I'm using right now

Thanks!

I had some problems with that device but I simply added pull up resistors to the I2C bus. Check to be sure all the grounds are connected.

That should be 50, look in the example

 pwm.setPWMFreq(50);  // This is the maximum PWM frequency

Tom... :grinning: :+1: :coffee: :australia:

Hi guys, thank you for the replies @gilshultz , @TomGeorge .
@gilshultz how did you add the pull ups and what would that fix? Thanks

@TomGeorge This was just one of my examples, I've tried lots of different code and you're right that servos operate at 50Hz but just changing that didn't fix it for me!

After doing some more tests and getting a second PCA to make sure it's not just faulty, it seems like on both of my boards the terminal block's positive side is not connected to the PWM Pins?
If I keep the negative end of my power supply in the terminal block and put the postive side directly to the V+ pin on the side , I can get one servo to move.
I am a bit concerned about running it this way and I'd prefer to hook my power to the terminal block but that doesn't work on either of my 2 PCA9685's...
Any ideas? This seems to be the problem but I don't just wanna buy a third PCA in hopes that this one's terminal block is connected properly..

Pull ups are resistors from the +5 to the SCL and SDA lines.

Hi,
Where did you get your 9685 modules from.
They aren't Adafruit, looking at the Adafruit module schematic there is a reverse voltage MOSFET between Vcc and 5V.


Tom... :grinning: :+1: :coffee: :australia:

Thanks. Still not 100% clear on that, sorry. Which +5 do you mean? Because the SCL and SDA lines are going to A4 & A5, so do you mean add a resistor between those? Or do you mean connecting SDA & SCL to 5V on the Arduino or the V+ on the PCA9586 somehow? Thanks a lot.

Thanks tom. No both of my boards were knock offs but I've seen them used on similar projects and I didn't see the Adafruit one but if I do have to get another one I'll go for the original.
But wouldn't a MOSFET between VCC and 5V just ensure that the Chip is protected from high voltage through the external supply? Or is that actually responsible for passing on the voltage to the PWM Pins? Sorry, I'm a newbie just trying to understand! I will link my board & datasheet in the next reply. Thanks!

The MOSFET is used as a polarity protection diode, the advantage being when it conducts in the correct current direction, the volt drop across the MOSFET will be much much smaller than a conventional diode or Schottky diode in forward bias mode.

Tom... :grinning: :+1: :coffee: :australia:
PS, What I am glad about is that your investigations found the "fault" :+1:

Here is the 2 PCA Boards I've tried so far:
1:
https://www.amazon.de/gp/product/B06XSFFXQY/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1

2:

Unfortunately I couldn't find the data sheets for these exact models, although I feel like I've seen them somewhere. I'll link them if I find them

Oh I see, thanks again. So you think the Voltage drop across the diode that this board is using is too large compared to one with a MOSFET?
I appreciate that, I was trying to figure it out as much as possible before taking up somebody's time in this forum! :smiley:

Hi guys, so I ended up getting another board with a different design and on this one the Terminal Block is connected and everything is functioning as it should.

I got it to work with the two "faulty" boards as well by running one of these tiny jumper wires from the positive of my power supply to the V+ side break out on the PCA9586, but I decided to still get another board because I didn't want to run so much current through a tiny wire.

Here is the link in case this helps anybody else:

Thank you so much for the replies & help!

They are the same, it does not matter.

?

PCA9685 supply (VCC on one/both short sides) and servo power (screw terminal) are and must be completely independent of each other. Only grounds are shared (through the board).

VCC must connect to VCC of the Arduino, which is the 5volt pin on a 5volt Arduino or 3.3volt pin on a 3.3volt Arduino.

Connecting screw terminal (+) to VCC of the board will surely blow the PCA9685 or Arduino pins at some stage because of phantom-powering between servo power and Arduino pins.

The screw terminals should only connect to the servo power supply.
Leo..

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.