![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
I2C driver for the NXP chip PCA9685 16xPWM LED controller A total of 4 RGBA LEDs can be controlled by 1 chip giving a RGBA value in the form of: rgba(0-255,0-255,0-255,0-100) then dimmed by 0-100%
Revision 0:62c7c3514d8f, committed 2012-06-15
- Comitter:
- Bas
- Date:
- Fri Jun 15 23:30:43 2012 +0000
- Commit message:
Changed in this revision
diff -r 000000000000 -r 62c7c3514d8f i2c.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i2c.c Fri Jun 15 23:30:43 2012 +0000 @@ -0,0 +1,237 @@ +#include "mbed.h" +#include "i2c.h" +#include "pca9685_reg.h" /* Light Driver Chip */ + +I2C i2c(p9, p10); // sda, scl + + +/******************************************/ +/* */ +/* Probe the I2C bus, and show the */ +/* user what we have found */ +/* */ +/* */ +/* */ +/******************************************/ +void i2c_probe(void) +{ + printf("Searching for I2C devices...\n"); + + int count = 0; + for (int address=4; address<256; address+=2) { + if (!i2c.write(address, NULL, 0)) { // 0 returned is ok + printf(" - I2C device found at address 0x%02X\r\n", address); + count++; + } + } + printf("%d devices found\r\n", count); +} + +/******************************************/ +/* */ +/* Philips PCA9685 I2C Driver, 16 channel */ +/* Lighting controler chip */ +/* */ +/* */ +/******************************************/ + +/******************************************/ +/* */ +/* Init code for the PCA9685 */ +/* */ +/******************************************/ + +void init_pca9685(unsigned char address) +{ + unsigned char buf[30]; + + printf("Setting up channel %d\n\r",address); + + buf[0] = PCA9685_MODE1; + buf[1] = PCA9685_AI; + //buf[2] = PCA9685_OUTDRV; + buf[2] = PCA9685_INVRT; + i2c.write(address,(char *) buf, 3); +} + +/******************************************/ +/* */ +/* Send data to a given channel of a */ +/* given PCA9685 chip */ +/* */ +/******************************************/ + +void pca9685_led(unsigned char addr, int led, unsigned char *values) +{ + unsigned char buf[5]; + + if (led == PCA9685_ALL_LEDS) { + buf[0] = PCA9685_ALL_LED_ON_L; + } else { + buf[0] = PCA9685_BASE(led); + } + + buf[1] = values[0]; + buf[2] = values[1]; + buf[3] = values[2]; + buf[4] = values[3]; + i2c.write(addr, (char *)buf, 5); +} + +/******************************************/ +/* */ +/* Send all the data to a single rgba led */ +/* at once to the PCA9685 chip */ +/* */ +/* */ +/* */ +/* color[0] = red (0-255) */ +/* color[1] = green (0-255) */ +/* color[2] = blue (0-255) */ +/* color[3] = amber (0-100%) */ +/* total brightness = level (0-100%) */ +/******************************************/ +void pca9685_rgba_led(unsigned char addr, int rgba_led, unsigned char *color, unsigned char level) +{ + int led; + unsigned int on, off; + unsigned char buf[17]; + + if (level > 100){ + //printf("Level percentage range 0 - 100 (Trying for %d)\n\r",level); + return; + } + if (color[3] > 100) { + //printf("Amber percentage range 0 - 100 (Trying for %d)\n\r",color[3]); + return; + } + on=0; + if (rgba_led == PCA9685_ALL_LEDS) { + buf[0] = PCA9685_ALL_LED_ON_L; + if (color[0]==0 || level==0){ + buf[1]=0; + buf[1+PCA9685_LED_ON_H] = 0;//buf[2] + buf[3]=0; + buf[1+PCA9685_LED_OFF_H] = PCA9685_LED_OFF;//buf[4] + //printf("all on, zero brightness\r\n"); + } + else if (color[0]==0xff && level==100){ + buf[1]=0; + buf[1+PCA9685_LED_ON_H] = PCA9685_LED_ON;//buf[2] + buf[3]=0; + buf[1+PCA9685_LED_OFF_H] = 0;//buf[4] + //printf("all on, full brightness\r\n"); + } + else{ + off = (4096 * color[0]*level) / 0xff / 100; + buf[1+PCA9685_LED_ON_L] = on & 0xff;//buf[1] + buf[1+PCA9685_LED_ON_H] = (on >> 8) & 0xf;//buf[2] + buf[1+PCA9685_LED_OFF_L] = off & 0xff;//buf[3] + buf[1+PCA9685_LED_OFF_H] = (off >> 8) & 0xf;//buf[4] + } + i2c.write(addr, (char *)buf, 5); + //printf("All leds on\r\n"); + return; + } else { + buf[0] = PCA9685_BASE(rgba_led); + } + for (led=0;led<=3;led++){ + if (color[led]==0 || level==0){ + buf[led*4+1+PCA9685_LED_ON_H] = 0; + buf[led*4+1+PCA9685_LED_OFF_H] = PCA9685_LED_OFF; + continue; + } + if (((color[led]==100 && led==3)|| color[led]==0xff)&& level==100) { + buf[led*4+1+PCA9685_LED_ON_H] = PCA9685_LED_ON; + buf[led*4+1+PCA9685_LED_OFF_H] = 0; + continue; + } + off = (4096 * color[led]*level) / 0xff / 100; + buf[led*4+1+PCA9685_LED_ON_L] = on & 0xff; + buf[led*4+1+PCA9685_LED_ON_H] = (on >> 8) & 0xf; + buf[led*4+1+PCA9685_LED_OFF_L] = off & 0xff; + buf[led*4+1+PCA9685_LED_OFF_H] = (off >> 8) & 0xf; + } + i2c.write(addr, (char *)buf, 17); +} +/******************************************/ +/* */ +/* Calculate the register values for a */ +/* given brightness percentage */ +/* */ +/******************************************/ + +void pca9685_brightness(int percent, unsigned char *values) +{ + unsigned int on, off; + + if (percent == 0) { + values[PCA9685_LED_ON_H] = 0; + values[PCA9685_LED_OFF_H] = PCA9685_LED_OFF; + return; + } + if (percent == 100) { + values[PCA9685_LED_ON_H] = PCA9685_LED_ON; + values[PCA9685_LED_OFF_H] = 0; + return; + } + on = 0; + off = (4096 * percent) / 100; + values[PCA9685_LED_ON_L] = on & 0xff;//0 + values[PCA9685_LED_ON_H] = (on >> 8) & 0xf;//1 + values[PCA9685_LED_OFF_L] = off & 0xff;//2 + values[PCA9685_LED_OFF_H] = (off >> 8) & 0xf;//3 +} + +/******************************************/ +/* */ +/* Set a given channel to a given level */ +/* */ +/******************************************/ +void channel_light(unsigned char ch, unsigned char lev) +{ + char chip,led; /* Chip Number, channel number */ + unsigned char v[4]; /* register data for givern level */ + + led = ch%16; + v[0]=0; + v[1]=0; + v[2]=0; + v[3]=0; + + if(lev > 100){ + printf("Level percentage range 0 - 100 (Trying for %d)\n\r",lev); + return; + } + + switch(ch/16){ + case 0 : + chip=LEDDRV1; + break; + case 1 : + chip=LEDDRV2; + break; + case 2 : + chip=LEDDRV3; + break; + case 3 : + chip=LEDDRV4; + break; + case 4 : + chip=LEDDRV5; + break; + case 5 : + chip=LEDDRV6; + break; + default : + printf("Error unknown chip %d\n\r",ch/16); + return; + } + + printf("Setting channel %d to brightness level %d chip = %d(%d),%d\n\r", + ch,lev,chip,ch/16,led); + pca9685_brightness(lev,v); /* Calculate the brightness level */ + printf("Brightness level is %02x,%02x,%02x,%02x\n\r",v[0],v[1],v[2],v[3]); + pca9685_led(chip,led,v); /* Send to chip */ +} +
diff -r 000000000000 -r 62c7c3514d8f i2c.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i2c.h Fri Jun 15 23:30:43 2012 +0000 @@ -0,0 +1,10 @@ +/* I2C bus Functions */ + +void i2c_probe(void); + +void init_pca9685(unsigned char address); +void channel_light(unsigned char ch, unsigned char lev); +void pca9685_led(unsigned char addr, int led, unsigned char *values); +void pca9685_rgba_led(unsigned char addr, int rgba_led, unsigned char *color, unsigned char level); +void pca9685_brightness(int percent, unsigned char *values); +
diff -r 000000000000 -r 62c7c3514d8f main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Fri Jun 15 23:30:43 2012 +0000 @@ -0,0 +1,69 @@ +#include "mbed.h" +#include "i2c.h" +#include "pca9685_reg.h" + +DigitalOut myled(LED1); +Serial pc(USBTX, USBRX); +AnalogIn mypot(p20); + +int main() { + + + unsigned char level; + unsigned char rgba_color[4]; + + i2c_probe(); + init_pca9685(LEDDRV1); + + rgba_color[0]=0xff; //red (0-255) + rgba_color[1]=0x00; //green (0-255) + rgba_color[2]=0x00; //blue (0-255) + rgba_color[3]=100; //amber (0-100) (0.00-1.00) + + while (1) { + level=mypot*100; + printf("level: %d\r\n",level); + pca9685_rgba_led(LEDDRV1,RGBA_LED1,rgba_color,level); + //channel_light(0,r*level/0xff); + //channel_light(1,g*level/0xff); + //channel_light(2,b*level/0xff); + + } +} + +/* void loop() { + int r, g, b; + + // fade from blue to violet + for (r = 0; r < 256; r++) { + analogWrite(REDPIN, r); + delay(FADESPEED); + } + // fade from violet to red + for (b = 255; b > 0; b--) { + analogWrite(BLUEPIN, b); + delay(FADESPEED); + } + // fade from red to yellow + for (g = 0; g < 256; g++) { + analogWrite(GREENPIN, g); + delay(FADESPEED); + } + // fade from yellow to green + for (r = 255; r > 0; r--) { + analogWrite(REDPIN, r); + delay(FADESPEED); + } + // fade from green to teal + for (b = 0; b < 256; b++) { + analogWrite(BLUEPIN, b); + delay(FADESPEED); + } + // fade from teal to blue + for (g = 255; g > 0; g--) { + analogWrite(GREENPIN, g); + delay(FADESPEED); + } +} +-------------------------------------------------------------------------------- +*/
diff -r 000000000000 -r 62c7c3514d8f mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Fri Jun 15 23:30:43 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/737756e0b479
diff -r 000000000000 -r 62c7c3514d8f pca9685_reg.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pca9685_reg.h Fri Jun 15 23:30:43 2012 +0000 @@ -0,0 +1,128 @@ +#ifndef __PCA9685_H +#define __PCA9685_H + +/* Devices */ +#define LEDDRV1 0xb8 +#define LEDDRV2 0xba +#define LEDDRV3 0xd8 +#define LEDDRV4 0xda +#define LEDDRV5 0xc8 +#define LEDDRV6 0xca + +/* RGBA LED's. Max 4 on 1 chip */ +#define RGBA_LED1 0 +#define RGBA_LED2 1 +#define RGBA_LED3 2 +#define RGBA_LED4 3 + +/* Registers */ +#define PCA9685_MODE1 0x00 +#define PCA9685_MODE2 0x01 +#define PCA9685_SUBADR1 0x02 +#define PCA9685_SUBADR2 0x03 +#define PCA9685_SUBADR3 0x04 +#define PCA9685_ALLCALLADR 0x05 +#define PCA9685_LED0_ON_L 0x06 +#define PCA9685_LED0_ON_H 0x07 +#define PCA9685_LED0_OFF_L 0x08 +#define PCA9685_LED0_OFF_H 0x09 +#define PCA9685_LED1_ON_L 0x0a +#define PCA9685_LED1_ON_H 0x0b +#define PCA9685_LED1_OFF_L 0x0c +#define PCA9685_LED1_OFF_H 0x0d +#define PCA9685_LED2_ON_L 0x0e +#define PCA9685_LED2_ON_H 0x0f +#define PCA9685_LED2_OFF_L 0x10 +#define PCA9685_LED2_OFF_H 0x11 +#define PCA9685_LED3_ON_L 0x12 +#define PCA9685_LED3_ON_H 0x13 +#define PCA9685_LED3_OFF_L 0x14 +#define PCA9685_LED3_OFF_H 0x15 +#define PCA9685_LED4_ON_L 0x16 +#define PCA9685_LED4_ON_H 0x17 +#define PCA9685_LED4_OFF_L 0x18 +#define PCA9685_LED4_OFF_H 0x19 +#define PCA9685_LED5_ON_L 0x1a +#define PCA9685_LED5_ON_H 0x1b +#define PCA9685_LED5_OFF_L 0x1c +#define PCA9685_LED5_OFF_H 0x1d +#define PCA9685_LED6_ON_L 0x1e +#define PCA9685_LED6_ON_H 0x1d +#define PCA9685_LED6_OFF_L 0x20 +#define PCA9685_LED6_OFF_H 0x21 +#define PCA9685_LED7_ON_L 0x22 +#define PCA9685_LED7_ON_H 0x23 +#define PCA9685_LED7_OFF_L 0x24 +#define PCA9685_LED7_OFF_H 0x25 +#define PCA9685_LED8_ON_L 0x26 +#define PCA9685_LED8_ON_H 0x27 +#define PCA9685_LED8_OFF_L 0x28 +#define PCA9685_LED8_OFF_H 0x29 +#define PCA9685_LED9_ON_L 0x2a +#define PCA9685_LED9_ON_H 0x2b +#define PCA9685_LED9_OFF_L 0x2c +#define PCA9685_LED9_OFF_H 0x2d +#define PCA9685_LED10_ON_L 0x2e +#define PCA9685_LED10_ON_H 0x2f +#define PCA9685_LED10_OFF_L 0x30 +#define PCA9685_LED10_OFF_H 0x31 +#define PCA9685_LED11_ON_L 0x32 +#define PCA9685_LED11_ON_H 0x33 +#define PCA9685_LED11_OFF_L 0x34 +#define PCA9685_LED11_OFF_H 0x35 +#define PCA9685_LED12_ON_L 0x36 +#define PCA9685_LED12_ON_H 0x37 +#define PCA9685_LED12_OFF_L 0x38 +#define PCA9685_LED12_OFF_H 0x39 +#define PCA9685_LED13_ON_L 0x3a +#define PCA9685_LED13_ON_H 0x3b +#define PCA9685_LED13_OFF_L 0x3c +#define PCA9685_LED13_OFF_H 0x3d +#define PCA9685_LED14_ON_L 0x3e +#define PCA9685_LED14_ON_H 0x3f +#define PCA9685_LED14_OFF_L 0x40 +#define PCA9685_LED14_OFF_H 0x41 +#define PCA9685_LED15_ON_L 0x42 +#define PCA9685_LED15_ON_H 0x43 +#define PCA9685_LED15_OFF_L 0x44 +#define PCA9685_LED15_OFF_H 0x45 +#define PCA9685_ALL_LED_ON_L 0xfa +#define PCA9685_ALL_LED_ON_H 0xfb +#define PCA9685_ALL_LED_OFF_L 0xfc +#define PCA9685_ALL_LED_OFF_H 0xfd +#define PCA9685_PRE_SCALE 0xfe + +/* MODE1 bits */ +#define PCA9685_RESTART 0x80 +#define PCA9685_EXTCLK 0x40 +#define PCA9685_AI 0x20 +#define PCA9685_SLEEP 0x10 +#define PCA9685_SUB1 0x08 +#define PCA9685_SUB2 0x04 +#define PCA9685_SUB3 0x02 +#define PCA9685_ALLCALL 0x01 + +/* MODE2 bits */ +#define PCA9685_INVRT 0x10 +#define PCA9685_OCH 0x08 +#define PCA9685_OUTDRV 0x04 +#define PCA9685_OUTNE1 0x02 +#define PCA9685_OUTNE0 0x01 + +/* LEDX_ON_H bits */ +#define PCA9685_LED_ON 0x10 + +/* LEDX_OFF_H bits */ +#define PCA9685_LED_OFF 0x10 + +#define PCA9685_LED_BUFSIZ 0x04 +#define PCA9685_BASE(led) ((led * 4) + 6) +#define PCA9685_BASE_RGBA(led) (led * 16 + 6) +#define PCA9685_LED_ON_L 0x00 +#define PCA9685_LED_ON_H 0x01 +#define PCA9685_LED_OFF_L 0x02 +#define PCA9685_LED_OFF_H 0x03 +#define PCA9685_ALL_LEDS -1 + + +#endif \ No newline at end of file