This is a project to replace the 8051 on a existing RGB LED board and add USB functionality. The original board relied on 8051 firmware to control the LEDs so any changes required software development. This version provides a USB interface for LED control. The USB interface is implemented as a HID with a 9 byte OutReport. In conjunction with a simple GUI the RGB LED board can now be controlled to set color patterns, intensity and pattern sequencing.

Dependencies:   PCA9635-6 mbed USBDevice

RGB GUI - Windows program to control the PCA9635 board.

/media/uploads/JimCarver/rgb_led.jpg

Revision:
0:5e18eb7da208
Child:
1:ee2692588275
diff -r 000000000000 -r 5e18eb7da208 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Dec 09 21:40:36 2011 +0000
@@ -0,0 +1,489 @@
+#include "mbed.h"
+#include "i2cmessages.h"
+#include "USBHID.h"
+
+//We declare a USBHID device. By default input and output reports are 64 bytes long.
+USBHID hid( 9, 1, 0x1Fc9, 0x0003, 0x0100, 1);
+
+//This report will contain data to be sent
+HID_REPORT send_report;
+HID_REPORT recv_report;
+
+Serial pc(USBTX, USBRX);
+
+DigitalOut myled1(LED1);
+DigitalOut myled2(LED2);
+DigitalOut myled3(LED3);
+DigitalOut myled4(LED4);
+DigitalOut led_en(p8);
+DigitalIn SW6(p11);
+DigitalIn SW5(p30);
+
+I2C i2c(p28, p27);
+
+Timer ms_timer;
+
+AnalogIn ain(p20);
+ 
+/***************************************************************************
+NAME OF MODULE:        MAIN.C                                          
+DESCRIPTION:            Main file for the LED String Demoboard                  
+                                                                         
+(C) Copyright 2008 NXP Semiconductors               
+                                                                         
+****************************************************************************/
+BYTE dflag, tflag;
+
+BYTE Buffer1[18];
+BYTE Buffer2[18];
+BYTE Buffer3[18];
+BYTE Buffer4[18];
+BYTE Buffer5[18];
+BYTE Buffer6[18];
+
+I2C_MESSAGE    I2C_Message;
+int dval;
+
+typedef struct {
+    uint32_t    LED;
+    uint8_t        RED, GREEN, BLUE, INTENSITY;
+    } LED_Report_type ;
+
+volatile LED_Report_type *LED_Report;
+
+
+typedef struct {
+// Definition for a LED location, buffer pointer, and index into that buffer
+    BYTE *buf, n;
+    } LED_type;
+    
+typedef struct {
+    LED_type    RED;
+    LED_type    GREEN;
+    LED_type    BLUE;
+    } RGB_type;
+
+typedef struct {
+    uint8_t r, g, b;
+    } RB_type;
+
+RB_type Rainbow[] = {
+    255,   0,   0,
+    255,  23,   0,
+    255,  64,   0,
+    255, 127,   0,
+    255, 193,   0,
+    255, 255,   0,
+    193, 255,   0,
+    127, 255,   0,
+    127, 255,   0,
+     63, 255,   0,
+      0, 255,   0,
+      0, 255,   7,
+      0, 255,  15,
+      0, 255,  31,
+      0, 255,  63,
+      0, 255,  91,
+      0, 255, 127,
+      0, 255, 193,
+      0, 255, 255,
+      0, 193, 255,
+      0, 127, 255,
+      0,  63, 255,
+      0,   0, 255,
+     31,   0, 255,
+     63,   0, 255,
+    127,   0, 255,
+    193,   0, 255,
+    255,   0, 255,
+    255,   0, 193,
+    255,   0, 127,
+    255,   0,  63,
+    255,   0,  15
+    };
+
+// An array of structures that define the buffer and location in the buffer for all of the LEDs
+// Due to the design of the RGB LED board this is easier than the convoluted calculation needed
+//    
+RGB_type RGB_LED[32] = {
+//  RED             GREEN           BLUE
+//  LED1-16
+    Buffer1, 2,     Buffer1, 3,     Buffer1, 4,
+    Buffer1, 5,     Buffer1, 6,     Buffer1, 7,
+    Buffer1, 8,     Buffer1, 9,     Buffer1, 10,
+    Buffer1, 11,    Buffer1, 12,    Buffer1, 13,
+    Buffer1, 14,    Buffer1, 15,    Buffer1, 16,
+    Buffer1, 17,    Buffer3, 2,     Buffer3, 3,
+    Buffer3, 4,     Buffer3, 5,     Buffer3, 6,
+    Buffer3, 7,     Buffer3, 8,     Buffer3, 9,
+    Buffer3, 10,    Buffer3, 11,    Buffer3, 12,
+    Buffer3, 13,    Buffer3, 14,    Buffer3, 15,
+    Buffer3, 16,    Buffer3, 17,    Buffer5, 2,
+    Buffer5, 3,     Buffer5, 4,     Buffer5, 5,
+    Buffer5, 6,     Buffer5, 7,     Buffer5, 8,
+    Buffer5, 9,     Buffer5, 10,    Buffer5, 11,
+    Buffer5, 12,    Buffer5, 13,    Buffer5, 14,
+    Buffer5, 15,    Buffer5, 16,    Buffer5, 17,
+
+//  LED17-32    
+    Buffer2, 2,     Buffer2, 3,     Buffer2, 4,
+    Buffer2, 5,     Buffer2, 6,     Buffer2, 7,
+    Buffer2, 8,     Buffer2, 9,     Buffer2, 10,
+    Buffer2, 11,    Buffer2, 12,    Buffer2, 13,
+    Buffer2, 14,    Buffer2, 15,    Buffer2, 16,
+    Buffer2, 17,    Buffer4, 2,     Buffer4, 3,
+    Buffer4, 4,     Buffer4, 5,     Buffer4, 6,
+    Buffer4, 7,     Buffer4, 8,     Buffer4, 9,
+    Buffer4, 10,    Buffer4, 11,    Buffer4, 12,
+    Buffer4, 13,    Buffer4, 14,    Buffer4, 15,
+    Buffer4, 16,    Buffer4, 17,    Buffer6, 2,
+    Buffer6, 3,     Buffer6, 4,     Buffer6, 5,
+    Buffer6, 6,     Buffer6, 7,     Buffer6, 8,
+    Buffer6, 9,     Buffer6, 10,    Buffer6, 11,
+    Buffer6, 12,    Buffer6, 13,    Buffer6, 14,
+    Buffer6, 15,    Buffer6, 16,    Buffer6, 17  };
+
+//
+// Lookup the buffer and index to set the desired values
+// in the appropriate locations within the I2C message buffers
+// update_LED() actually sends the buffers through I2C to the drivers
+//
+void set_LED(int LEDn, BYTE R, BYTE G, BYTE B)
+{
+    RGB_LED[LEDn].RED.buf[RGB_LED[LEDn].RED.n] = R;
+    RGB_LED[LEDn].GREEN.buf[RGB_LED[LEDn].GREEN.n] = G;
+    RGB_LED[LEDn].BLUE.buf[RGB_LED[LEDn].BLUE.n] = B;
+}
+
+void set_my_LED(int c)
+{
+    if(c & 1) {       myled4 = 1;       } else {       myled4 = 0;       }
+    if(c & 2) {       myled3 = 1;       } else {       myled3 = 0;       }
+    if(c & 4) {       myled2 = 1;       } else {       myled2 = 0;       }
+    if(c & 8) {       myled1 = 1;       } else {       myled1 = 0;       }
+}
+
+/***********************************************************************
+DESCRIPTION:    Initalization of the buffers (Buffer1, buffer2, Buffer3)
+INPUT(S):        None
+RETURNS:            Nothing
+************************************************************************/
+void Init_Buffers(void)
+{
+    int i = 0;
+    for (i = 0; i<18; i++)
+    {
+        Buffer1[i] = 0;
+        Buffer2[i] = 0;
+        Buffer3[i] = 0;
+        Buffer4[i] = 0;
+        Buffer5[i] = 0;
+        Buffer6[i] = 0;
+    }
+        
+    Buffer1[0]    = 17;
+    Buffer2[0]    = 17;
+    Buffer3[0]    = 17;
+    Buffer4[0]    = 17;
+    Buffer5[0]    = 17;
+    Buffer6[0]    = 17;
+    Buffer1[1]    = 0x82;
+    Buffer2[1]    = 0x82;
+    Buffer3[1]    = 0x82;
+    Buffer4[1]    = 0x82;
+    Buffer5[1]    = 0x82;
+    Buffer6[1]    = 0x82;
+}
+
+
+/***********************************************************************
+DESCRIPTION:    Fill all the PWM register of a device with a RGB setting
+INPUT(S):        A,B,C --> Primary colors
+RETURNS:            Nothing
+************************************************************************/
+void Set_Same_Color_Single_Device(BYTE A, BYTE B, BYTE C)
+{
+    int i;
+    Buffer1[0]    = 17;
+    Buffer1[1]    = 0x82;
+    for (i = 0; i < 5; i++)
+    {
+        Buffer1[3*i+2] = A;
+        Buffer1[3*i+3] = B;
+        Buffer1[3*i+4] = C;
+    }
+    Buffer1[17] = A;
+}
+
+
+void delay(int dd)
+{
+ms_timer.reset();
+ms_timer.start();
+while(ms_timer.read_ms() <= (dd));
+ms_timer.stop();
+}
+
+void i2cfail(void)
+{
+int c = 0;
+while(1) {
+    set_my_LED(c++);
+    delay(50);
+    }
+}
+
+void I2C_Write(I2C_MESSAGE *mp)
+{
+if(i2c.write(mp->address, (char *) &mp->buf[1], mp->buf[0])) i2cfail();
+}
+
+/***********************************************************************
+DESCRIPTION:    Set the I2C address to the ALL CALL Address and
+                    send the I2C_Write command
+INPUT(S):        None
+RETURNS:            Nothing
+************************************************************************/
+void Write_All_Devices(void)
+{
+    I2C_Message.address         = ALL_CALL_I2C_ADDRESS;
+    I2C_Write(&I2C_Message);
+}
+
+
+/***********************************************************************
+DESCRIPTION:    Set the I2C address to the required address and
+                    send the I2C_Write command
+INPUT(S):        I2C Address of the targetted device (LSB = 0)
+RETURNS:            Nothing
+************************************************************************/
+void Write_To_Device(BYTE I2C_Address)
+{
+    I2C_Message.address         = I2C_Address;
+    I2C_Write(&I2C_Message);
+}
+
+
+/***********************************************************************
+DESCRIPTION:    Set the I2C address to the required address and
+                    send the I2C_Write command
+                    Wait (delay) before moving to the next step
+INPUT(S):        I2C Address of the targetted device (LSB = 0)
+                    Delay = delay in ms / 10
+RETURNS:            Nothing
+************************************************************************/
+void Write_To_Device_And_Wait(BYTE I2C_Address, BYTE Delay_Value)
+{
+    I2C_Message.address         = I2C_Address;
+    I2C_Write(&I2C_Message);
+    delay(Delay_Value);
+}
+
+
+/***********************************************************************
+DESCRIPTION:    Swtich of ALL the LEDs using the ALL CALL address
+INPUT(S):        None
+RETURNS:            Nothing
+************************************************************************/
+void ALL_LED_OFF(void)        // Switch off all the LEDs
+{
+    I2C_Message.buf             = LED_ALL_OFF; 
+    Write_All_Devices();
+}
+
+
+void LED_INTENSITY(void)
+{
+    //GLOBAL_INTENSITY[2] = global_i;
+    I2C_Message.buf = GLOBAL_INTENSITY;
+    Write_All_Devices();
+}
+
+
+void update_LED(void)
+{
+  I2C_Message.buf = Buffer1;
+  Write_To_Device(0x80);
+  I2C_Message.buf = Buffer2;
+  Write_To_Device(0x86);
+  I2C_Message.buf = Buffer3;
+  Write_To_Device(0x82);
+  I2C_Message.buf = Buffer4;
+  Write_To_Device(0x88);
+  I2C_Message.buf = Buffer5;
+  Write_To_Device(0x84);
+  I2C_Message.buf = Buffer6;
+  Write_To_Device(0x8A);
+}
+
+void read_LED( int LEDn, BYTE *R, BYTE *G, BYTE *B)
+{
+    *R = RGB_LED[LEDn].RED.buf[RGB_LED[LEDn].RED.n];
+    *G = RGB_LED[LEDn].GREEN.buf[RGB_LED[LEDn].GREEN.n];
+    *B = RGB_LED[LEDn].BLUE.buf[RGB_LED[LEDn].BLUE.n];
+}
+
+void rainbow_LED( void)
+{
+int i;
+    for(i=0;i<32;i++) set_LED( i, Rainbow[i].r, Rainbow[i].g, Rainbow[i].b );
+}
+
+void ripple_LED( void )
+{
+uint32_t  m;
+uint8_t LEDn, R, G, B, tR, tG, tB;
+if( dflag) {   // Ripple LEDs to the right
+    read_LED( 0, &tR, &tG, &tB);    // Save the first LED value
+    for(LEDn = 0 , m = 1; LEDn < 31; LEDn++) {
+       read_LED( LEDn+1, &R, &G, &B);
+       set_LED(  LEDn, R, G, B); 
+        m = m << 1;
+        }
+    set_LED(  31, tR, tG, tB);
+    } else {  // Ripple LEDs to the left
+    read_LED( 31, &tR, &tG, &tB);
+    for(LEDn = 31, m = 0x80000000 ; LEDn > 0; LEDn--) {
+       read_LED( LEDn - 1, &R, &G, &B);
+       set_LED(  LEDn, R, G, B);
+        m = m >> 1;
+        }
+    set_LED(  0, tR, tG, tB);
+    }
+}    
+        
+        
+void test_pattern(void)
+{
+int l, r, g, b;
+// Dim Blue Color (from min to max)
+Init_Buffers();
+set_my_LED(1);
+for (r = 0, g = 0, b = 0; b < 0xFF; b++) {
+    for(l = 0; l < 32; l++) {
+        set_LED( l, r, g, b);
+        }              
+    update_LED();    
+    }
+set_my_LED(2);
+// Mix from Only Blue (Max going to off) to Only Green (off to Max) 
+for (r = 0, g = 0, b = 0xFF; b >= 0x00; b--) {
+    for(l = 0;l < 32; l++) {
+       set_LED( l, r, g, b);
+       }
+    update_LED();          
+    g++;                  
+    }        
+set_my_LED(4);
+// Mix from Only Green (Max going to off) to Only Red (off to Max) 
+for (r = 0, g = 0xFF, b = 0; g >= 0x00; g--)  {
+    for (l = 0;l < 32; l++) {
+        set_LED( l, r, g, b);
+        }
+    update_LED();
+    r++;                
+    }
+set_my_LED(8);
+// Mix from Only Red (Max going to off) to Only Blue (off to Max) 
+for (r = 0xFF, g = 0, b = 0; r >= 0x00; r--) {
+    for (l = 0;l < 32; l++) {
+        set_LED( l, r, g, b);
+        }
+    update_LED();
+    b++;
+    }
+set_my_LED(0);
+rainbow_LED();
+update_LED();  
+}
+
+void SetOutReport (void)
+{
+int LEDn;
+uint32_t    led, m;
+uint8_t        R, G, B, seq;
+
+    /* Check the bits of the "OutReport" data from the PC
+     * and set the output port status. */
+seq = recv_report.data[0];
+//LED_Report = (LED_Report_type *) &recv_report.data[1];
+GLOBAL_INTENSITY[2] = recv_report.data[8];
+if(seq) {
+    tflag = 2;
+    dflag = seq & 1;
+    dval = (seq & 0xFC) >> 1; // sets a range from 0x00 to 0x7E
+    } else {
+    led = recv_report.data[4];
+    led <<= 8;
+    led |= recv_report.data[3];
+    led <<= 8;
+    led |= recv_report.data[2];
+    led <<= 8;
+    led |= recv_report.data[1];
+    
+    set_my_LED(led & 0xf);
+    R = recv_report.data[5];
+    G = recv_report.data[6];
+    B = recv_report.data[7];
+    for(LEDn=0, m=1;LEDn < 32; LEDn++, m <<= 1) {
+        if(led & m) {
+            RGB_LED[LEDn].RED.buf[RGB_LED[LEDn].RED.n] = R;
+            RGB_LED[LEDn].GREEN.buf[RGB_LED[LEDn].GREEN.n] = G;
+            RGB_LED[LEDn].BLUE.buf[RGB_LED[LEDn].BLUE.n] = B;
+            }
+        }
+    tflag = 1;
+    }
+}
+
+
+
+
+
+
+/***********************************************************************
+DESCRIPTION:    Main function
+INPUT(S):        None
+RETURNS:            Nothing
+************************************************************************/
+int main (void)
+{
+int l = 1;
+led_en = 0;
+set_my_LED(1);
+// Perform Software Reset - Set the PCA9635 in a known state
+I2C_Message.buf = SW_RESET; 
+Write_To_Device(SW_RESET_I2C_ADDRESS);
+
+// Wake up and Init the PCA9635 using ALL CALL address
+I2C_Message.buf             = WAKE_UP_AND_INIT; 
+Write_All_Devices();
+Init_Buffers();
+
+// Program all LED outputs to Individual PWM + Global PWM using ALL CALL address
+I2C_Message.buf = LED_ALL_INDVDL_PLUS_GLOBL_PWM_CTRL;
+Write_All_Devices();
+if(!SW6) test_pattern(); 
+dflag = 0;
+dval = 10;
+tflag = 0;
+set_my_LED(l++);
+send_report.length = 1;
+while (1) {
+      send_report.data[0] = SW5;
+      hid.send(&send_report);
+      if(hid.readNB(&recv_report)) SetOutReport();
+      if(tflag == 2) {
+          ripple_LED();
+          update_LED();
+          LED_INTENSITY();
+          delay(dval);
+          }
+        
+      if(tflag == 1) {
+          update_LED();
+          LED_INTENSITY();
+          tflag = 0;
+          }
+    }
+}
\ No newline at end of file