The PCA9685 is interfacing with PIC18F4550 controller to operate multiple servo motors by using the PWM signal generated by the PCA9685 controller.

PCA9685 is 16 Channel LED controller device which is optimized to drive Red, Blue, Green, and Amber (RBGA) LEDs. The RBGA LEDs could be operated at a required brightness with the help of PWM signal generated by the PCA9685 controller. Each PWM signal generated is programmed by a 12 bit ON register and a 12 bit OFF register. Thus both duty cycle and the phase shift could be varied. A PRE-SCALE register is also available which will help us program the frequency of the PWM signal for a given clock frequency. The PWM signals generated can also be used to operate multiple servo motors, making it convenient for applications like robotics. The PCA9685 is controlled with I2C communication from PIC microcontroller and operates at the 5V power supply.

I2C Communication

I2C is a multi-master multi-slave, two wire synchronous communication protocol where one wire is used as the data line and the other for clock signal generated by the master device. It is intended for short distance communication between different peripherals of a single device.

The master, upon sensing an idle channel, will provide a start signal followed by the address of the slave device which is unique for each device. The read or write command is also provided with the address and the slave device, upon recognizing its address, will provide an acknowledgment signal and start the communication. At the end of the communication, a stop signal is issued by the master to release the I2C channel. The master can also issue a restart signal if it wants to start a new communication without releasing the channel.

A more in-depth explanation of the working of I2C communication and its configuration is available in our previous chapter I2C Module In PIC18F4550.


pca_pin_Interfacing of PCA9685 with PIC18F4550

PCA9685 has 16 independent PWM output channels (LED0 to LED15), each of which could be used to drive an RBGA LED. The device is controlled with I2C communication from the PIC microcontroller through the SDA and SCL pins. The address pins (A0 to A5) is used to hardware design the I2C slave address of the device. The slave address of PCA9685 will be in the format:

address_Interfacing of PCA9685 with PIC18F4550
The PCA9685 has a 25MHz internal clock which is used to generate the PWM signal. An external clock signal of up to 50MHz could also be provided at the EXTCLK pin, which will help synchronize the clock signal if two or more PCA9685 devices are used at once. An active low output pin OE (Pin 23) is also provided to hardware disable or enable the device. To enable the output of PCA9685, a low signal must be applied at the OE pin.

PCA9685 Registers

The PCA9685 uses several read or write registers for its operation addressed from 0x00 to 0xFF.

table_Interfacing of PCA9685 with PIC18F4550

All these registers are accessed by writing their address to the Control Register for a read or write operation.

Control register

After successful acknowledgment of the slave address and the read/write mode, the master device will specify the address of the register to be accessed. This address is stored in the Control Register and is used as a pointer to access the location.

After accessing a register location, the address stored in Control Register may or may not increment automatically depending on the AI (Bit 5) bit in Mode 1 register. The auto increment feature is disabled by default.

Mode 1 register

The Mode 1 register is used to configure the device and define the subaddress and all call address if required. The Mode 1 register can be accessed at the location 0x00.

MODE1_Interfacing of PCA9685 with PIC18F4550
RESTART:- Used to enable or disable Restart signal
EXTCLK:- Decides if the internal clock or an external clock should be used
AI:- Bit used to enable or disable auto increment of the Control register
SLEEP:- When enabled will switch to low power mode with oscillator turned off
SUB[1:3]:- Enable or disable response to I2C-bus sub addresses SUBADR1, SUBADR2, and SUBADR3
ALLCALL:- Enable or disable response to I2C-bus LED ALL CALL address

Note 1: All features are enabled by setting it to logic 1.
Note 2: By default, SLEEP and ALLCALL bits are set to logic 1 and the rest to logic 0 when the device is turned on.

Mode 2 register

The Mode 2 register can be accessed at the location 0x01.

MODE2_Interfacing of PCA9685 with PIC18F4550
INVRT:- Used to invert the output logic state
OCH:- When enabled will change the output on ACK signal. Else output changed on Stop signal
OUTDRV:- If enabled will use totem pole structure. Else open_drain structure is used
OUTNE[1:0]:- Defines output when output is disabled (OE=1)

Subaddress registers

The Sub-address registers available are SUBADR1, SUBADR2 and SUBADR3 located at the address 0x02, 0x03 and 0x04 respectively. These registers could be used to store sub-address in addition to the slave address, which could be used to access a required combination of PCA9685 chips.

After power-up, the PCA9685 will have the default sub-addresses as E2h, E4h, and E8h but will be disabled. To enable the sub call, the corresponding SUBx bit of Mode 1 register must be set. The 7 MSB bits of the sub-address register can be programmed as required. The LSB bit in ALLCALLADR register is a read-only bit (0). If a combination of PCA9685 chips has the same sub-address and the master device uses this subaddress as the slave address for an operation, all the corresponding PCA9685 chips will acknowledge the request and can be operated simultaneously.


The ALLCALLADR address register stores the slave address for an All call feature, which will simultaneously program all the PCA9685 chips connected in the I2C network. The default ALLCALLADR value is E0h and is enabled at power-up. The All call feature can be disabled by making the ALLCALL bit in Mode 1 register as logic 0.

The 7 MSB bits of the ALLCALLADR value can also be changed and be used as a sub call. The LSB bit in ALLCALLADR register is a read-only bit (0).

LED on and led off registers

Each of the 16 PWM outputs has a corresponding 12 bit ON count value and a 12 bit OFF count value. The 8 LSB bits of the ON count is stored in the LEDn_ON_L register and the 4 MSB bits at LEDn_ON_H[3:0]. The LEDn_ON_H[4] is used as always ON bit which will ignore the ON count and OFF count and keep the output always ON. Similarly, the 8 LSB bits of the OFF count is stored in the LEDn_OFF_L register and the 4 MSB bits at LEDn_OFF_H[3:0], with the LEDn_OFF_H[4] bit as the always OFF bit. The LED ON and OFF registers occupy address location from 06h to 15h.

The LEDn_ON and LEDn_OFF count can vary from 0 to 4095 and must never be programmed with the same value. This count value is compared with a counter variable, incremented at a particular time period, to get the corresponding PWM signal.

ALL LED ON and all led off registers

All LED ON and OFF registers are used to configure the output PWM signals of all 16 output pins simultaneously. The All LED ON and OFF feature is implemented with the registers ALL_LED_ON_L, ALL_LED_ON_H, ALL_LED_OFF_L, and ALL_LED_OFF_H. It has a bit format similar to the LED ON and OFF registers and occupies the location FAh to FDh.

Pre_scale register

The value stored in PRE_SCALE register is used to pre-scale the clock output before using it to increment the counter value. The pre-scale value along with the clock frequency decides the time period of the PWM signal. For a required update rate, the pre_scale value can be calculated as

prescale_value = round( clock_rate/(4096 * update_rate ) – 1

PRE_SCALE register is hardware limited to have a minimum value of 3 (03h) and a maximum value of 255 (FFh). Thus using the 25MHz internal oscillator, the maximum value of update_rate is 1526 Hz (prescale_value=0x03h) and the minimum value of update_rate is 24 Hz (prescale_value=0xFFh).

By default, the PRE_SCALE register is loaded with the value 30 (0x1Eh) giving us an update_rate of 200 Hz with the 25MHz internal oscillator.

Programming PWM Signal

The PWM signal output is programmed by loading appropriate ON count and OFF count values for each output pin. The PCA9685 has an internal counter value, incremented at a particular update rate, counting from 0 to 4095. The counter value is constantly compared with the ON count and the OFF count to generate the PWM signal. The PWM signal is turned HIGH when the counter value equals the ON count and is turned LOW when the counter value equals the OFF count. Thus the ON count will account for the phase shift and the difference between OFF count and ON count will decide the duty cycle of the PWM signal. The logic levels could also be reversed by setting the INVRT bit in Mode 2.

Let us consider an example of designing a delay time of 10% and duty cycle of 30% at output pin LED0.

The total count is fixed at 4096.

Delay = 10% of 4096 = 409.6 ~ 410.
Count starts from 0 to 4095 (must be subtracted by 1), so ON count = 409 = 0x199h.
Thus, LED0_ON_H = 0x01h and LED_ON_L = 0x99h

Duty cycle = 30% of 4096 = 1228.8 ~ 1229
So OFF count = Delay + Duty cycle = 409 + 1229 = 1638 = 0x666h
Thus, LED0_OFF_H = 0x06h and LED_OFF_L = 0x66h


wave_interfacing of PCA9685 with PIC18F4550

Interfacing with PIC18F4550

To program the PCA9685 chip with PIC18F4550, we will use functions implementing the I2C communication. Before setting the count registers, we need to configure the PCA9685 by enabling the output (OE=0) and configuring the Mode 1 register.

To that end, we need to apply a LOW voltage at OE pin and give a start signal followed by the slave address and mode of operation. After receiving the acknowledgment from the PCA9685, the Control register is loaded with the address of the Mode 1 register. The Mode 1 register is then updated with an appropriate value. The communication is ended with a Stop signal.

Firmware Example :

#define i2c_freq 100000UL
#define _XTAL_FREQ 20000000UL

unsigned int pca_addr;                  //Global variable to store slave address

void pca_init(unsigned int addr)
    pca_addr=addr;                      //Assigning global variable with slave address
    PORTBbits.RB2=0;                    //Enabling PCA9685 with OE=0
    i2c_init(i2c_freq);                 //Initializing I2C communication at 100KHz
    i2c_start();                        //Start signal
    i2c_write(pca_addr);                //Specifying slave address in write mode
    i2c_write(0x00);                    //Control register set to address 00h
    i2c_write(0x21);                    //Mode 1 configured to with AI=1 and ALLCALL=1
    i2c_stop();                         //Stop signal

To enable the output LEDn, we need to load the ON count and the OFF count in the registers associated with the LEDn output. A start signal is provided followed by the slave address in write mode. After receiving the acknowledgement, the Control register is loaded with the address of LEDn_ON_L register. The LEDn_ON_L, LEDn_ON_H, LEDn_OFF_L and LEDn_OFF_H registers are sequentially loaded with appropriate values according to the required ON count and OFF count. Finally, a Stop signal is also provided to end the communication.

Firmware Example :

void pca_write(unsigned int ledn, unsigned int on_count, unsigned int off_count)
    if(ledn>15)                         //Checking for invalid output pin number
    i2c_init(i2c_freq);                 //Initializing I2C communication at 100KHz
    i2c_start();                        //Start signal
    i2c_write(pca_addr);                //Specifying slave address in write mode
    i2c_write((ledn*4)+6);              //Control register set to address LEDn_ON_L
    i2c_write(on_count&0xFF);           //Writing 8 LSB bits of ON count
    i2c_write((on_count&0xF00)>>8);     //Writing 4 MSB bits of ON count
    i2c_write(off_count&0xFF);          //Writing 8 LSB bits of OFF count
    i2c_write((off_count&0xF00)>>8);    //Writing 4 MSB bits of ON count    
    i2c_stop();                         //Stop signal


Circuit Diagramcircuit_Interfacing of PCA9685 with PIC18F4550

Here all the address pins of PCA9685 are grounded. The PWM output can be observed with an oscilloscope. The PWM output can also be used to operate an LED connected to it at a required brightness.

Spread the love, share this