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%
i2c.c
- Committer:
- Bas
- Date:
- 2012-06-15
- Revision:
- 0:62c7c3514d8f
File content as of revision 0:62c7c3514d8f:
#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 */ }