I have my PCA9685 running on a Raspberry Pi using C. BUT, the only thing it will do is turn on and turn off all outputs together. Since the same registers are used for using the leds with and without PWM, how do you tell the PCA9685 that you want to use PWM?
Here is the registers and their values I am using:
char writeBuff[2] = {0x00}; // register mode 1
char writeBuff2[2] = {0x10}; //sleep
char writeBuff3[2] = {0xfe}; //register set pwm hz to 50 (0x7a)n
char writeBuff4[2] = {0x7a}; //value
char writeBuff15[2] = {0x00}; // register mode 1
char writeBuff16[2] = {0x00}; //no sleep
char writeBuff5[2] = {0x01}; //register mode 2
char writeBuff6[2] = {0x06}; //change on ack, totem poll output
char writeBuff7[2] = {0x06}; //register led 0 on low byte
char writeBuff8[2] = {0xf0}; //value
char writeBuff9[2] = {0x07}; //register LED 0 On High 3,2,1,0
char writeBuff10[2] = {0x00}; //value
char writeBuff11[2] = {0x08}; //register led0 off low
char writeBuff12[2] = {0xf0}; //value
char writeBuff13[2] = {0x09}; //register led0 off high (3,2,1,0)
char writeBuff14[2] = {0x00}; //value
Thanks,
David
YouTube "Sailing Solo at 70"
Solo sailed from Greece to North Carolina 2022
Solved! Go to Solution.
After weeks of gnashing of teeth, and help from the forum, I have gotten the PCA9685 to work for controlling an RC Servo. I thought I would share the solution in what it takes, and my software solution.
First, with I2C and the PCA9685 NOT in sequential progression, one must establish I2C communication, send two bytes (register and the data), then close the I2C communication. That is the gist of how to make the PCA9685 chip work. So here is my code:
////////////pca9695.h/////////////
extern int address;
#define MODE1 0x00 // 0x00 location for Mode1 register address
#define MODE2 0x01 // 0x01 location for Mode2 register address
/* Devices */
#
/* LEDX_ON_H bits */
#define PCA9685_LED_ON 0x10
/* LEDX_OFF_H bits */
#define PCA9685_LED_OFF 0x10
extern long PWMData[];
typedef unsigned char u8;
int i2c_init(void);
void i2c_close(void);
int i2c_write(u8 slave_addr, u8 reg, u8 data);
int i2c_read(u8 slave_addr, u8 reg, u8 *result);
////////////end pca9685.h ///////////
///////////pca9685.c //////////////
#include <stdio.h>
#include <sys/types.h> // open
#include <sys/stat.h> // open
#include <fcntl.h> // open
#include <unistd.h> // read/write usleep
#include <stdlib.h> // exit
#include <inttypes.h> // unsigned char, etc
#include <linux/i2c-dev.h> // I2C bus definitions
#include <sys/ioctl.h> //Needed for I2C port
#include "pca9685.h"
int fd,g;
uint8_t writeBuffer[10]={0};
int asd_address = 0x40;
int data_address = 0x00;
int cnt = 2,len;
char writeBuff[10]={0};
char readBuff[10] = {0};
void init_iic(void);
void write_iic(void);
void set_iic_add(void);
void close_iic(void);
void init_iic(void)
{
fd = open("/dev/i2c-1", O_RDWR);
if(fd < 0) {
printf("Cannot open device file...\n");
return ;
}
printf("open done\n");
}
void set_iic_add(void)
{
if (ioctl(fd,I2C_SLAVE,asd_address) < 0)
{
printf("error in address\n");
exit(2);
}
printf("set add done\n");
}
void write_iic(void)
{
printf("made it to write\n");
g = write(fd,writeBuff,len);
printf("g = %d \n",g);
if (g != len)
{
printf("write failed\n");
exit(3);
}
printf("write done\n");
}
void close_iic(void)
{
close(fd);
}
int main(int argc, char **argv)
{
init_iic();
set_iic_add();
writeBuff[0] = 0x00; //mode 1 sleep
writeBuff[1] = 0x10;
len = 2;
write_iic();
close_iic();
init_iic();
set_iic_add();
writeBuff[0] = 0xfe; //set pwm to 50 hz
writeBuff[1] = 0x7a;
len = 2;
write_iic();
close_iic();
init_iic();
set_iic_add();
writeBuff[0] = 0x00; //mode1 wakeup
writeBuff[1] = 0x00;
len = 2;
write_iic();
close_iic();
init_iic();
set_iic_add();
writeBuff[0] = 0x01; //register for mode 2
writeBuff[1] = 0x06; //use ack and no auto increment
len = 2;
write_iic();
close_iic();
init_iic();
set_iic_add();
writeBuff[0] = 0x06; //register for led0 on low byte 0x6c for 2ms 0xd8 for 1.5ms
writeBuff[1] = 0x00; //0x3a for 1ms
len = 2;
write_iic();
close_iic();
init_iic();
set_iic_add();
writeBuff[0] = 0x07; // register for led0 off low byte (7-0) 0x0d for 2ms, 1.5ms
writeBuff[1] = 0x0e; //0x0e for 1ms
len = 2;
write_iic();
close_iic();
init_iic();
set_iic_add();
writeBuff[0] = 0x08; //register for led0 high byte (3,2,1,0) 0x0e for 1ms to 2 ms
writeBuff[1] = 0x0e;
len = 2;
write_iic();
close_iic();
init_iic();
set_iic_add();
writeBuff[0] = 0x09; //register for led0 off low byte (0-7) 0x0f for 1ms to 2 ms
writeBuff[1] = 0x0f;
len = 2;
write_iic();
close_iic();
return(0);
}
My code initializes the PCA9685 by putting the chip to sleep in MODE1 in register 0x00, set the PWM to 50Hz in register 0xfe, takes the chip out of sleep in MODE1 (register 0x00), sets MODE2 (register 0x01) to use ACK and not to increment the registers automatically. Then LED0 is set to a 1ms pulse. End of program. other values for LED0 (up to 2ms) are shown in the code. This is not the final code - an ADC will be added to provide the input for controlling the width of the pulse.
Thanks to all who have helped me.
David
Please read the datasheet page16-7.3.3 LED output and PWM control for more detail PWM setting by related registers.
Thanks for the reply. I have read the areas suggested and feel I am sending the correct information. So I have a question about sending the information. When a string of data is sent to the PCA9685, does the chip know what is data and what is a register address? In other words, if I were to send the following information to the PCA9685 as a series of contiguous bytes, would the chip know what were registers an what was data?
open I2C
0x40 send PCA9685 address
0x00 address for mode 1 register
0x10 put chip to sleep data
0xfe address for pwm prescale register
0x7a data for pwm prescale
0x00 address for mode 1 register
0x00 data to wake up chip
kind regards
David
You can use below two write methods:
After weeks of gnashing of teeth, and help from the forum, I have gotten the PCA9685 to work for controlling an RC Servo. I thought I would share the solution in what it takes, and my software solution.
First, with I2C and the PCA9685 NOT in sequential progression, one must establish I2C communication, send two bytes (register and the data), then close the I2C communication. That is the gist of how to make the PCA9685 chip work. So here is my code:
////////////pca9695.h/////////////
extern int address;
#define MODE1 0x00 // 0x00 location for Mode1 register address
#define MODE2 0x01 // 0x01 location for Mode2 register address
/* Devices */
#
/* LEDX_ON_H bits */
#define PCA9685_LED_ON 0x10
/* LEDX_OFF_H bits */
#define PCA9685_LED_OFF 0x10
extern long PWMData[];
typedef unsigned char u8;
int i2c_init(void);
void i2c_close(void);
int i2c_write(u8 slave_addr, u8 reg, u8 data);
int i2c_read(u8 slave_addr, u8 reg, u8 *result);
////////////end pca9685.h ///////////
///////////pca9685.c //////////////
#include <stdio.h>
#include <sys/types.h> // open
#include <sys/stat.h> // open
#include <fcntl.h> // open
#include <unistd.h> // read/write usleep
#include <stdlib.h> // exit
#include <inttypes.h> // unsigned char, etc
#include <linux/i2c-dev.h> // I2C bus definitions
#include <sys/ioctl.h> //Needed for I2C port
#include "pca9685.h"
int fd,g;
uint8_t writeBuffer[10]={0};
int asd_address = 0x40;
int data_address = 0x00;
int cnt = 2,len;
char writeBuff[10]={0};
char readBuff[10] = {0};
void init_iic(void);
void write_iic(void);
void set_iic_add(void);
void close_iic(void);
void init_iic(void)
{
fd = open("/dev/i2c-1", O_RDWR);
if(fd < 0) {
printf("Cannot open device file...\n");
return ;
}
printf("open done\n");
}
void set_iic_add(void)
{
if (ioctl(fd,I2C_SLAVE,asd_address) < 0)
{
printf("error in address\n");
exit(2);
}
printf("set add done\n");
}
void write_iic(void)
{
printf("made it to write\n");
g = write(fd,writeBuff,len);
printf("g = %d \n",g);
if (g != len)
{
printf("write failed\n");
exit(3);
}
printf("write done\n");
}
void close_iic(void)
{
close(fd);
}
int main(int argc, char **argv)
{
init_iic();
set_iic_add();
writeBuff[0] = 0x00; //mode 1 sleep
writeBuff[1] = 0x10;
len = 2;
write_iic();
close_iic();
init_iic();
set_iic_add();
writeBuff[0] = 0xfe; //set pwm to 50 hz
writeBuff[1] = 0x7a;
len = 2;
write_iic();
close_iic();
init_iic();
set_iic_add();
writeBuff[0] = 0x00; //mode1 wakeup
writeBuff[1] = 0x00;
len = 2;
write_iic();
close_iic();
init_iic();
set_iic_add();
writeBuff[0] = 0x01; //register for mode 2
writeBuff[1] = 0x06; //use ack and no auto increment
len = 2;
write_iic();
close_iic();
init_iic();
set_iic_add();
writeBuff[0] = 0x06; //register for led0 on low byte 0x6c for 2ms 0xd8 for 1.5ms
writeBuff[1] = 0x00; //0x3a for 1ms
len = 2;
write_iic();
close_iic();
init_iic();
set_iic_add();
writeBuff[0] = 0x07; // register for led0 off low byte (7-0) 0x0d for 2ms, 1.5ms
writeBuff[1] = 0x0e; //0x0e for 1ms
len = 2;
write_iic();
close_iic();
init_iic();
set_iic_add();
writeBuff[0] = 0x08; //register for led0 high byte (3,2,1,0) 0x0e for 1ms to 2 ms
writeBuff[1] = 0x0e;
len = 2;
write_iic();
close_iic();
init_iic();
set_iic_add();
writeBuff[0] = 0x09; //register for led0 off low byte (0-7) 0x0f for 1ms to 2 ms
writeBuff[1] = 0x0f;
len = 2;
write_iic();
close_iic();
return(0);
}
My code initializes the PCA9685 by putting the chip to sleep in MODE1 in register 0x00, set the PWM to 50Hz in register 0xfe, takes the chip out of sleep in MODE1 (register 0x00), sets MODE2 (register 0x01) to use ACK and not to increment the registers automatically. Then LED0 is set to a 1ms pulse. End of program. other values for LED0 (up to 2ms) are shown in the code. This is not the final code - an ADC will be added to provide the input for controlling the width of the pulse.
Thanks to all who have helped me.
David