Johan Kritzinger
/
FRDMKL25Z-ShiftBrite
A few classes to interface one or more ShiftBrite module to the FRDM KL25Z.
Diff: sbDriver.cpp
- 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 + } +} + +//-------------------- + + +//=============================================================================================