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%

Dependencies:   mbed

Committer:
Bas
Date:
Fri Jun 15 23:30:43 2012 +0000
Revision:
0:62c7c3514d8f

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Bas 0:62c7c3514d8f 1 #include "mbed.h"
Bas 0:62c7c3514d8f 2 #include "i2c.h"
Bas 0:62c7c3514d8f 3 #include "pca9685_reg.h" /* Light Driver Chip */
Bas 0:62c7c3514d8f 4
Bas 0:62c7c3514d8f 5 I2C i2c(p9, p10); // sda, scl
Bas 0:62c7c3514d8f 6
Bas 0:62c7c3514d8f 7
Bas 0:62c7c3514d8f 8 /******************************************/
Bas 0:62c7c3514d8f 9 /* */
Bas 0:62c7c3514d8f 10 /* Probe the I2C bus, and show the */
Bas 0:62c7c3514d8f 11 /* user what we have found */
Bas 0:62c7c3514d8f 12 /* */
Bas 0:62c7c3514d8f 13 /* */
Bas 0:62c7c3514d8f 14 /* */
Bas 0:62c7c3514d8f 15 /******************************************/
Bas 0:62c7c3514d8f 16 void i2c_probe(void)
Bas 0:62c7c3514d8f 17 {
Bas 0:62c7c3514d8f 18 printf("Searching for I2C devices...\n");
Bas 0:62c7c3514d8f 19
Bas 0:62c7c3514d8f 20 int count = 0;
Bas 0:62c7c3514d8f 21 for (int address=4; address<256; address+=2) {
Bas 0:62c7c3514d8f 22 if (!i2c.write(address, NULL, 0)) { // 0 returned is ok
Bas 0:62c7c3514d8f 23 printf(" - I2C device found at address 0x%02X\r\n", address);
Bas 0:62c7c3514d8f 24 count++;
Bas 0:62c7c3514d8f 25 }
Bas 0:62c7c3514d8f 26 }
Bas 0:62c7c3514d8f 27 printf("%d devices found\r\n", count);
Bas 0:62c7c3514d8f 28 }
Bas 0:62c7c3514d8f 29
Bas 0:62c7c3514d8f 30 /******************************************/
Bas 0:62c7c3514d8f 31 /* */
Bas 0:62c7c3514d8f 32 /* Philips PCA9685 I2C Driver, 16 channel */
Bas 0:62c7c3514d8f 33 /* Lighting controler chip */
Bas 0:62c7c3514d8f 34 /* */
Bas 0:62c7c3514d8f 35 /* */
Bas 0:62c7c3514d8f 36 /******************************************/
Bas 0:62c7c3514d8f 37
Bas 0:62c7c3514d8f 38 /******************************************/
Bas 0:62c7c3514d8f 39 /* */
Bas 0:62c7c3514d8f 40 /* Init code for the PCA9685 */
Bas 0:62c7c3514d8f 41 /* */
Bas 0:62c7c3514d8f 42 /******************************************/
Bas 0:62c7c3514d8f 43
Bas 0:62c7c3514d8f 44 void init_pca9685(unsigned char address)
Bas 0:62c7c3514d8f 45 {
Bas 0:62c7c3514d8f 46 unsigned char buf[30];
Bas 0:62c7c3514d8f 47
Bas 0:62c7c3514d8f 48 printf("Setting up channel %d\n\r",address);
Bas 0:62c7c3514d8f 49
Bas 0:62c7c3514d8f 50 buf[0] = PCA9685_MODE1;
Bas 0:62c7c3514d8f 51 buf[1] = PCA9685_AI;
Bas 0:62c7c3514d8f 52 //buf[2] = PCA9685_OUTDRV;
Bas 0:62c7c3514d8f 53 buf[2] = PCA9685_INVRT;
Bas 0:62c7c3514d8f 54 i2c.write(address,(char *) buf, 3);
Bas 0:62c7c3514d8f 55 }
Bas 0:62c7c3514d8f 56
Bas 0:62c7c3514d8f 57 /******************************************/
Bas 0:62c7c3514d8f 58 /* */
Bas 0:62c7c3514d8f 59 /* Send data to a given channel of a */
Bas 0:62c7c3514d8f 60 /* given PCA9685 chip */
Bas 0:62c7c3514d8f 61 /* */
Bas 0:62c7c3514d8f 62 /******************************************/
Bas 0:62c7c3514d8f 63
Bas 0:62c7c3514d8f 64 void pca9685_led(unsigned char addr, int led, unsigned char *values)
Bas 0:62c7c3514d8f 65 {
Bas 0:62c7c3514d8f 66 unsigned char buf[5];
Bas 0:62c7c3514d8f 67
Bas 0:62c7c3514d8f 68 if (led == PCA9685_ALL_LEDS) {
Bas 0:62c7c3514d8f 69 buf[0] = PCA9685_ALL_LED_ON_L;
Bas 0:62c7c3514d8f 70 } else {
Bas 0:62c7c3514d8f 71 buf[0] = PCA9685_BASE(led);
Bas 0:62c7c3514d8f 72 }
Bas 0:62c7c3514d8f 73
Bas 0:62c7c3514d8f 74 buf[1] = values[0];
Bas 0:62c7c3514d8f 75 buf[2] = values[1];
Bas 0:62c7c3514d8f 76 buf[3] = values[2];
Bas 0:62c7c3514d8f 77 buf[4] = values[3];
Bas 0:62c7c3514d8f 78 i2c.write(addr, (char *)buf, 5);
Bas 0:62c7c3514d8f 79 }
Bas 0:62c7c3514d8f 80
Bas 0:62c7c3514d8f 81 /******************************************/
Bas 0:62c7c3514d8f 82 /* */
Bas 0:62c7c3514d8f 83 /* Send all the data to a single rgba led */
Bas 0:62c7c3514d8f 84 /* at once to the PCA9685 chip */
Bas 0:62c7c3514d8f 85 /* */
Bas 0:62c7c3514d8f 86 /* */
Bas 0:62c7c3514d8f 87 /* */
Bas 0:62c7c3514d8f 88 /* color[0] = red (0-255) */
Bas 0:62c7c3514d8f 89 /* color[1] = green (0-255) */
Bas 0:62c7c3514d8f 90 /* color[2] = blue (0-255) */
Bas 0:62c7c3514d8f 91 /* color[3] = amber (0-100%) */
Bas 0:62c7c3514d8f 92 /* total brightness = level (0-100%) */
Bas 0:62c7c3514d8f 93 /******************************************/
Bas 0:62c7c3514d8f 94 void pca9685_rgba_led(unsigned char addr, int rgba_led, unsigned char *color, unsigned char level)
Bas 0:62c7c3514d8f 95 {
Bas 0:62c7c3514d8f 96 int led;
Bas 0:62c7c3514d8f 97 unsigned int on, off;
Bas 0:62c7c3514d8f 98 unsigned char buf[17];
Bas 0:62c7c3514d8f 99
Bas 0:62c7c3514d8f 100 if (level > 100){
Bas 0:62c7c3514d8f 101 //printf("Level percentage range 0 - 100 (Trying for %d)\n\r",level);
Bas 0:62c7c3514d8f 102 return;
Bas 0:62c7c3514d8f 103 }
Bas 0:62c7c3514d8f 104 if (color[3] > 100) {
Bas 0:62c7c3514d8f 105 //printf("Amber percentage range 0 - 100 (Trying for %d)\n\r",color[3]);
Bas 0:62c7c3514d8f 106 return;
Bas 0:62c7c3514d8f 107 }
Bas 0:62c7c3514d8f 108 on=0;
Bas 0:62c7c3514d8f 109 if (rgba_led == PCA9685_ALL_LEDS) {
Bas 0:62c7c3514d8f 110 buf[0] = PCA9685_ALL_LED_ON_L;
Bas 0:62c7c3514d8f 111 if (color[0]==0 || level==0){
Bas 0:62c7c3514d8f 112 buf[1]=0;
Bas 0:62c7c3514d8f 113 buf[1+PCA9685_LED_ON_H] = 0;//buf[2]
Bas 0:62c7c3514d8f 114 buf[3]=0;
Bas 0:62c7c3514d8f 115 buf[1+PCA9685_LED_OFF_H] = PCA9685_LED_OFF;//buf[4]
Bas 0:62c7c3514d8f 116 //printf("all on, zero brightness\r\n");
Bas 0:62c7c3514d8f 117 }
Bas 0:62c7c3514d8f 118 else if (color[0]==0xff && level==100){
Bas 0:62c7c3514d8f 119 buf[1]=0;
Bas 0:62c7c3514d8f 120 buf[1+PCA9685_LED_ON_H] = PCA9685_LED_ON;//buf[2]
Bas 0:62c7c3514d8f 121 buf[3]=0;
Bas 0:62c7c3514d8f 122 buf[1+PCA9685_LED_OFF_H] = 0;//buf[4]
Bas 0:62c7c3514d8f 123 //printf("all on, full brightness\r\n");
Bas 0:62c7c3514d8f 124 }
Bas 0:62c7c3514d8f 125 else{
Bas 0:62c7c3514d8f 126 off = (4096 * color[0]*level) / 0xff / 100;
Bas 0:62c7c3514d8f 127 buf[1+PCA9685_LED_ON_L] = on & 0xff;//buf[1]
Bas 0:62c7c3514d8f 128 buf[1+PCA9685_LED_ON_H] = (on >> 8) & 0xf;//buf[2]
Bas 0:62c7c3514d8f 129 buf[1+PCA9685_LED_OFF_L] = off & 0xff;//buf[3]
Bas 0:62c7c3514d8f 130 buf[1+PCA9685_LED_OFF_H] = (off >> 8) & 0xf;//buf[4]
Bas 0:62c7c3514d8f 131 }
Bas 0:62c7c3514d8f 132 i2c.write(addr, (char *)buf, 5);
Bas 0:62c7c3514d8f 133 //printf("All leds on\r\n");
Bas 0:62c7c3514d8f 134 return;
Bas 0:62c7c3514d8f 135 } else {
Bas 0:62c7c3514d8f 136 buf[0] = PCA9685_BASE(rgba_led);
Bas 0:62c7c3514d8f 137 }
Bas 0:62c7c3514d8f 138 for (led=0;led<=3;led++){
Bas 0:62c7c3514d8f 139 if (color[led]==0 || level==0){
Bas 0:62c7c3514d8f 140 buf[led*4+1+PCA9685_LED_ON_H] = 0;
Bas 0:62c7c3514d8f 141 buf[led*4+1+PCA9685_LED_OFF_H] = PCA9685_LED_OFF;
Bas 0:62c7c3514d8f 142 continue;
Bas 0:62c7c3514d8f 143 }
Bas 0:62c7c3514d8f 144 if (((color[led]==100 && led==3)|| color[led]==0xff)&& level==100) {
Bas 0:62c7c3514d8f 145 buf[led*4+1+PCA9685_LED_ON_H] = PCA9685_LED_ON;
Bas 0:62c7c3514d8f 146 buf[led*4+1+PCA9685_LED_OFF_H] = 0;
Bas 0:62c7c3514d8f 147 continue;
Bas 0:62c7c3514d8f 148 }
Bas 0:62c7c3514d8f 149 off = (4096 * color[led]*level) / 0xff / 100;
Bas 0:62c7c3514d8f 150 buf[led*4+1+PCA9685_LED_ON_L] = on & 0xff;
Bas 0:62c7c3514d8f 151 buf[led*4+1+PCA9685_LED_ON_H] = (on >> 8) & 0xf;
Bas 0:62c7c3514d8f 152 buf[led*4+1+PCA9685_LED_OFF_L] = off & 0xff;
Bas 0:62c7c3514d8f 153 buf[led*4+1+PCA9685_LED_OFF_H] = (off >> 8) & 0xf;
Bas 0:62c7c3514d8f 154 }
Bas 0:62c7c3514d8f 155 i2c.write(addr, (char *)buf, 17);
Bas 0:62c7c3514d8f 156 }
Bas 0:62c7c3514d8f 157 /******************************************/
Bas 0:62c7c3514d8f 158 /* */
Bas 0:62c7c3514d8f 159 /* Calculate the register values for a */
Bas 0:62c7c3514d8f 160 /* given brightness percentage */
Bas 0:62c7c3514d8f 161 /* */
Bas 0:62c7c3514d8f 162 /******************************************/
Bas 0:62c7c3514d8f 163
Bas 0:62c7c3514d8f 164 void pca9685_brightness(int percent, unsigned char *values)
Bas 0:62c7c3514d8f 165 {
Bas 0:62c7c3514d8f 166 unsigned int on, off;
Bas 0:62c7c3514d8f 167
Bas 0:62c7c3514d8f 168 if (percent == 0) {
Bas 0:62c7c3514d8f 169 values[PCA9685_LED_ON_H] = 0;
Bas 0:62c7c3514d8f 170 values[PCA9685_LED_OFF_H] = PCA9685_LED_OFF;
Bas 0:62c7c3514d8f 171 return;
Bas 0:62c7c3514d8f 172 }
Bas 0:62c7c3514d8f 173 if (percent == 100) {
Bas 0:62c7c3514d8f 174 values[PCA9685_LED_ON_H] = PCA9685_LED_ON;
Bas 0:62c7c3514d8f 175 values[PCA9685_LED_OFF_H] = 0;
Bas 0:62c7c3514d8f 176 return;
Bas 0:62c7c3514d8f 177 }
Bas 0:62c7c3514d8f 178 on = 0;
Bas 0:62c7c3514d8f 179 off = (4096 * percent) / 100;
Bas 0:62c7c3514d8f 180 values[PCA9685_LED_ON_L] = on & 0xff;//0
Bas 0:62c7c3514d8f 181 values[PCA9685_LED_ON_H] = (on >> 8) & 0xf;//1
Bas 0:62c7c3514d8f 182 values[PCA9685_LED_OFF_L] = off & 0xff;//2
Bas 0:62c7c3514d8f 183 values[PCA9685_LED_OFF_H] = (off >> 8) & 0xf;//3
Bas 0:62c7c3514d8f 184 }
Bas 0:62c7c3514d8f 185
Bas 0:62c7c3514d8f 186 /******************************************/
Bas 0:62c7c3514d8f 187 /* */
Bas 0:62c7c3514d8f 188 /* Set a given channel to a given level */
Bas 0:62c7c3514d8f 189 /* */
Bas 0:62c7c3514d8f 190 /******************************************/
Bas 0:62c7c3514d8f 191 void channel_light(unsigned char ch, unsigned char lev)
Bas 0:62c7c3514d8f 192 {
Bas 0:62c7c3514d8f 193 char chip,led; /* Chip Number, channel number */
Bas 0:62c7c3514d8f 194 unsigned char v[4]; /* register data for givern level */
Bas 0:62c7c3514d8f 195
Bas 0:62c7c3514d8f 196 led = ch%16;
Bas 0:62c7c3514d8f 197 v[0]=0;
Bas 0:62c7c3514d8f 198 v[1]=0;
Bas 0:62c7c3514d8f 199 v[2]=0;
Bas 0:62c7c3514d8f 200 v[3]=0;
Bas 0:62c7c3514d8f 201
Bas 0:62c7c3514d8f 202 if(lev > 100){
Bas 0:62c7c3514d8f 203 printf("Level percentage range 0 - 100 (Trying for %d)\n\r",lev);
Bas 0:62c7c3514d8f 204 return;
Bas 0:62c7c3514d8f 205 }
Bas 0:62c7c3514d8f 206
Bas 0:62c7c3514d8f 207 switch(ch/16){
Bas 0:62c7c3514d8f 208 case 0 :
Bas 0:62c7c3514d8f 209 chip=LEDDRV1;
Bas 0:62c7c3514d8f 210 break;
Bas 0:62c7c3514d8f 211 case 1 :
Bas 0:62c7c3514d8f 212 chip=LEDDRV2;
Bas 0:62c7c3514d8f 213 break;
Bas 0:62c7c3514d8f 214 case 2 :
Bas 0:62c7c3514d8f 215 chip=LEDDRV3;
Bas 0:62c7c3514d8f 216 break;
Bas 0:62c7c3514d8f 217 case 3 :
Bas 0:62c7c3514d8f 218 chip=LEDDRV4;
Bas 0:62c7c3514d8f 219 break;
Bas 0:62c7c3514d8f 220 case 4 :
Bas 0:62c7c3514d8f 221 chip=LEDDRV5;
Bas 0:62c7c3514d8f 222 break;
Bas 0:62c7c3514d8f 223 case 5 :
Bas 0:62c7c3514d8f 224 chip=LEDDRV6;
Bas 0:62c7c3514d8f 225 break;
Bas 0:62c7c3514d8f 226 default :
Bas 0:62c7c3514d8f 227 printf("Error unknown chip %d\n\r",ch/16);
Bas 0:62c7c3514d8f 228 return;
Bas 0:62c7c3514d8f 229 }
Bas 0:62c7c3514d8f 230
Bas 0:62c7c3514d8f 231 printf("Setting channel %d to brightness level %d chip = %d(%d),%d\n\r",
Bas 0:62c7c3514d8f 232 ch,lev,chip,ch/16,led);
Bas 0:62c7c3514d8f 233 pca9685_brightness(lev,v); /* Calculate the brightness level */
Bas 0:62c7c3514d8f 234 printf("Brightness level is %02x,%02x,%02x,%02x\n\r",v[0],v[1],v[2],v[3]);
Bas 0:62c7c3514d8f 235 pca9685_led(chip,led,v); /* Send to chip */
Bas 0:62c7c3514d8f 236 }
Bas 0:62c7c3514d8f 237