A few classes to interface one or more ShiftBrite module to the FRDM KL25Z.

Dependencies:   mbed

Revision:
0:f76850de7b57
Child:
3:9376bf1f1bbd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sbDriver.cpp	Tue Aug 19 07:09:20 2014 +0000
@@ -0,0 +1,296 @@
+//Low level driver for shiftbrite modules
+#include <iostream>
+#include "mbed.h"
+#include "sbDriver.h"
+
+//#define DEBUGPRINT //Uncoment to see various debug output
+
+//#define SENDPRINT //Uncomment to see what is being sent to the SB's
+
+#define ERRORPRINT //Comment to not see any error message on STD::
+
+
+//NOTES ON THE SHIFTBRITE MODULES
+/*
+ The modules are daisy chained and they buffer data, clock, latch and enable signals from in to out.
+ Imagine the chain of leds as a VERY long shift register, growing by 32 bits (4 bytes) for each LED. 
+ Each LED is 10 bits and the complete RGB set is
+Bit #31                                 #0
+      00010101  01010101 01010101 01010101
+ (msb)xC\--LED1----/\--LED2---/\--LED3---/(lsb)
+          BLUE         GREEN      RED
+ Two most msb bits are not used except to enter COMMAND mode by setting bit 30
+ In COMMAND mode set a value of 0 to 127 for each led that adjust the max current from 30% to 100%
+ Manual recommends red120, green100 and blue100.
+ 
+ Data is moved out startgin with MSB.
+ Data is latched into the *WHOLE* chain with a *SINGLE* latch pulse.
+ I.E, if you have 2 leds you clock in 64 bits followed by *one* latch pulse
+ The first 32 bits will be latched into the LED on the very end of the chain. 
+ Thus the last 32 bit will be latched into the LED closest to the MCU.
+ 
+ There is no RESET command for the A6281's. They are only reset at power up.
+ Thus, if they loose synchronization with the clock/data you have to cycle the power.
+ I have a FET/Transisor circuit that allows me to do this using the reset() member function
+ 
+ There needs to be a delay from the last bit to the positive edge of the latch pulse (see datasheet).
+ 
+ */
+ 
+ 
+//=============================================================================================    
+// colour class to hold a led colour value
+colour colour::operator=(unsigned short int v){
+    setColour(v); // this will also range check
+    return *this;
+}
+//--------------------
+
+colour colour::operator=(colour c){
+    value = c.value;
+    return *this;
+}
+
+
+//=============================================================================================    
+//rgbLed class to manupilate RGB colours as one object
+
+rgbLed::rgbLed(unsigned long int rgbValue){ // constructor for RGB value e.g. 0xFFFFFF. Will expand 0XFF to 0x3FF as per colour range. Remember to update packet
+    setRgbLed(rgbValue); // this way all the other house keeping chores will be done
+}
+//--------------------
+rgbLed::rgbLed(unsigned short int red, unsigned short int green, unsigned short int blue){ //overload for  seperate r,g,b arguments. Remember to updatepacket
+    this->red=red;
+    this->green = green;
+    this->blue = blue;
+}
+//--------------------
+
+rgbLed::rgbLed(){//no arguments given so default to 0
+    //red.setColour(0); //red is an colour object, not just a value
+    red=0;//use overloaded operator
+    //green.setColour(0);
+    green = 0;
+    //blue.setColour(0);
+    blue = 0;
+    //packet = 0; 
+    
+}
+//--------------------
+unsigned long int rgbLed::getPacket(){
+    //Convert R, G and B values into one 4 byte packet ready for trnsmittion to SB
+    //TO DO : Confirm that unsigned long int is 4 bytes long.......
+    //NOTE, This compensates for SB being GRB and nor RGB
+    unsigned long int temp;
+    temp = 0; // initialize - DATA MODE
+    //temp = 0x01; //init - COMMAND MODE
+    temp <<=2; //shift in mode
+    temp |= (blue.getColour()& 0X3FF);
+    //ser_p->printf("BLUE: 0x%lx",temp);
+    temp <<= 10;
+    temp |= (red.getColour() & 0X3FF);
+    temp <<=10;
+    temp |= (green.getColour() & 0X3FF);
+    return temp;
+}
+//--------------------
+
+void rgbLed::setRgbLed(unsigned long int rgbValue){ // RGB value e.g. 0xFFFFFF. Will expand 0XFF to 0x3FF as per colour range
+// THIS IS NOT THE BEST AS IT WILL EXPAND
+// First, pull each colour out and set accordingly in rgbLed
+    blue.setColour(4*((unsigned short int)(rgbValue & 0X0000FF)));//blue
+    //But, remember, the range is 0-0x3FF, not 0-0xFF
+    green = 4*((unsigned short int)((rgbValue >> 8) & 0X0000FF));//This uses the overloaded = operator
+    red = 4*((unsigned short int)((rgbValue >> 16) & 0X0000FF));
+}
+//--------------------
+
+void rgbLed::setRgbLed(unsigned short int red, unsigned short int green, unsigned short int blue){ //overload for  seperate r,g,b arguments
+//THIS IS THE BEST WAY AS YOU CAN SPECIFY THE FULL 0-0X3FF RANGE
+    this->red=red;//This should kick in the operator overloaded f() and do a range check
+    this->green = green;
+    this->blue = blue;
+}
+
+
+
+//=============================================================================================
+// Display object tracking/controlling multiple rgbLed objects    
+shiftBriteDisplay::shiftBriteDisplay (Serial *port,DigitalOut &latch, DigitalOut &enable, DigitalOut &reset, SPI &spiPort, unsigned int moduleCount):/*PC(port),*/sb_latch(latch), sb_enable(enable), sb_reset(reset), spi(spiPort){ //constructor
+// OK, so the sb control/data lines have been setup via references
+//Allocate memory for moduleCount* sb modules
+    serial_p = port;
+#ifdef DEBUGPRINT
+    serial_p->printf("Construct shiftBriteDisplay\r\n");
+#endif
+    spi.format(8,0);//8 bit, mode 0
+    spi.frequency(100000);//100kHz clk
+
+
+    this->moduleCount = moduleCount;
+    module_p = new rgbLed[moduleCount];//
+    if(!module_p){
+        //to do : WHAT TO DO WITH ERRORS?
+#ifdef ERRORPRINT
+        serial_p->printf("Unable to allocate memory for RGB led array\r\n");
+#endif
+        while(1);// for now just get stuck here
+    }
+    
+    priv_reset(); //assuming cct connected, remove power for a short time to reset the chips
+    priv_SBEnable();
+    
+    setCurrentCorr(0x78,0x64,0x64);//setup default rgb values
+    f_update = 0;
+}
+//--------------------
+
+void shiftBriteDisplay::setCurrentCorr(unsigned short int red, unsigned short int green, unsigned short int blue){
+        //Now, for each module, set a command packet with
+        //appropriately loaded current control values
+        //and send
+        //Uses same module_p as normal operations
+        //This saves and restores the current colour values
+        unsigned short int i, r,g,b;//storage for temporary colour memory
+        
+        //save user selected value for current correction reg values with some range checking
+        rCorr = red & 0X7F; // ensure that it is no larger than 0x7F
+        gCorr = green & 0x7F;
+        bCorr= blue & 0x7F;
+        
+        if(f_update == 0){
+#ifdef DEBUGPRINT
+    serial_p->printf("Current adj\r\n");
+#endif
+        f_update=1; //prevent the ISR from messing this up
+        //Backup the colours
+        
+        //do it
+        //As per recommenation, set red=120, green and blue = 100
+        for(i=0; i != moduleCount; i++){
+            r=module_p[i].getRed();
+            g=module_p[i].getGreen();
+            b=module_p[i].getBlue();
+            setLed(i,red,green,blue);
+            send(module_p[i],1);
+            setLed(i,r,g,b); //restore colours
+        }
+ /*       for(i=0; i != moduleCount; i++){
+            send(module_p[i],1);
+        }*/
+        priv_SBLatch();
+        f_update=0;
+#ifdef ERRORPRINT
+        } 
+        else {
+            serial_p->printf("Current adj packet lost\r\n");
+#endif
+        }
+
+}
+
+//Overloaded member f()
+void shiftBriteDisplay::setCurrentCorr(){
+    setCurrentCorr(rCorr,gCorr,bCorr); // call the setter with the correct values
+}
+//--------------------
+
+shiftBriteDisplay::~shiftBriteDisplay(){//Destructor
+    delete [] module_p;//Be nice, clean the house. Not strictly required as this should never be called as we never reach the end of the program
+}
+//--------------------
+
+void shiftBriteDisplay::setLed(unsigned int moduleNum, unsigned long int rgbValue){
+    //Set the colour of a specific LED in the array
+#ifdef DEBUGPRINT
+   serial_p->printf("SetLed %u:%lx\r\n",moduleNum,rgbValue);
+#endif
+    moduleCount >= moduleNum ? module_p[moduleNum].setRgbLed(rgbValue): /*TO DO - set some sort of error? For now, mess up the LAST moodule setting*/ module_p[moduleCount-1].setRgbLed(rgbValue);
+    }
+//--------------------
+void shiftBriteDisplay::setLed(unsigned int moduleNum, unsigned short int red, unsigned short int green, unsigned short int blue){
+    module_p[moduleNum].setRgbLed(red,green,blue);
+}  
+//--------------------
+
+void shiftBriteDisplay::send(rgbLed M, unsigned short int commandStatus){
+    unsigned long int temp;
+    unsigned char byt;
+    temp = M.getPacket();//Will pull in the 4 bytes of RGB data
+    //Now, massage the hardware to send the data bits for this particular led module
+    //Remember, spi writes 8 bits at a time so I need to access the packet a byte at a time
+    //but I also need to start at the MSB
+#ifdef DEBUGPRINT
+    serial_p->printf("send 0x%0x\r\n",temp);
+   serial_p->printf("Red: 0x%x | Grn: 0x%x  |  Blue: 0x%x\r\n",M.getRed(),M.getGreen(),M.getBlue());
+#endif
+    byt = (unsigned char)( 0X000000FF & (temp >> 24));//msb
+    if(commandStatus == 1){//i.e. adjust current control registers
+        byt |= 0x40;//Add in the control flag to tell the shift Brite LED module that we are talking to the control registers
+#ifdef SENDPRINT
+        serial_p->printf("C");
+    } //i.e. going to write current control registers
+    else {
+        serial_p->printf("N");
+#endif
+    }
+    spi.write(byt);
+#ifdef SENDPRINT
+   serial_p->printf("*0x%02x",byt);
+#endif
+    byt = (unsigned char)( 0X000000FF & (temp >> 16));
+    spi.write(byt);
+#ifdef SENDPRINT
+    serial_p->printf("%02x",byt);
+#endif
+    byt = (unsigned char)( 0X000000FF & (temp >> 8));
+    spi.write(byt);
+#ifdef SENDPRINT
+   serial_p->printf("%02x",byt);
+#endif
+    byt = (unsigned char)( 0X000000FF & temp);
+    spi.write(byt);
+#ifdef SENDPRINT
+    serial_p->printf("%02x\r\n",byt);
+#endif    
+}
+
+//--------------------
+
+void shiftBriteDisplay::priv_reset(){
+        sb_reset=0;
+        wait(0.1);
+        sb_reset=1;
+        /*TO DO - init SB current control registers ? */
+        wait(0.1); //allow power to settle
+}
+
+//--------------------
+
+void shiftBriteDisplay::displayFrame(){
+unsigned int i;
+    if(f_update == 0){//Prevents doing this if an update is already in progress. This is b/c this member f() is called by an ISR etup in main
+        f_update = 1;
+        //TO DO - do any harware init e.g., reset the whole chain or enable the display or whatever
+        for(i=0; i != moduleCount; i++){
+         //do something with module_p[i]
+            send(module_p[i]); // transmit the rgb info of this led to the chain
+        }
+        //Complete the hardware handshaking etc
+        priv_SBLatch(); // Latch the complete string of LED data, i.e. the frame
+        f_update = 0;
+        
+        setCurrentCorr();//force a reload of the current correction register values
+        
+    }else {
+       //Do nothing if we are alreay in an update cycle. In fact, for now, destructively chuck the update away.
+#ifdef ERRORPRINT
+        serial_p->printf("Data Packet Lost\r\n");
+#endif
+    }
+}
+
+//--------------------
+
+
+//=============================================================================================