Johan Kritzinger
/
FRDMKL25Z-ShiftBrite
A few classes to interface one or more ShiftBrite module to the FRDM KL25Z.
sbDriver.cpp
- Committer:
- JoKer
- Date:
- 2014-08-22
- Revision:
- 7:a0f62fc80de0
- Parent:
- 5:aa0424f31fa1
File content as of revision 7:a0f62fc80de0:
//Low level driver for shiftbrite modules #include <iostream> #include "mbed.h" #include "sbDriver.h" //#define ERRORPRINT //Comment out 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 shiftBriteDisplay::shiftBriteDisplay (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; 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){ 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 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 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 } spi.write(byt); byt = (unsigned char)( 0X000000FF & (temp >> 16)); spi.write(byt); byt = (unsigned char)( 0X000000FF & (temp >> 8)); spi.write(byt); byt = (unsigned char)( 0X000000FF & temp); spi.write(byt); } //-------------------- 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 } } void shiftBriteDisplay::rotateLeft(){ rgbLed temp; //temporary object to hold data unsigned int i; temp.setRgbLed(module_p[0].getRed(),module_p[0].getGreen(),module_p[0].getBlue()); for(i=0; i != moduleCount-1; i++){ setLed(i,module_p[i+1].getRed(),module_p[i+1].getGreen(),module_p[i+1].getBlue()); } setLed(moduleCount-1,temp.getRed(),temp.getGreen(),temp.getBlue()); } void shiftBriteDisplay::shiftLeft(unsigned short int inR,unsigned short int inG,unsigned short int inB){;//info shifted out is lost, unsigned int i; for(i=0; i != moduleCount-1; i++){ setLed(i,module_p[i+1].getRed(),module_p[i+1].getGreen(),module_p[i+1].getBlue()); } if(inR==0 && inG==0 && inB==0) setLed(moduleCount-1,0,0,0); else setLed(moduleCount-1,inR,inG,inB); } void shiftBriteDisplay::rotateRight(){; rgbLed temp; //temporary object to hold data unsigned int i; temp.setRgbLed(module_p[moduleCount-1].getRed(),module_p[moduleCount-1].getGreen(),module_p[moduleCount-1].getBlue()); for(i=moduleCount; i != 0; i--){ setLed(i-1,module_p[i-2].getRed(),module_p[i-2].getGreen(),module_p[i-2].getBlue()); } setLed(0,temp.getRed(),temp.getGreen(),temp.getBlue()); } void shiftBriteDisplay::shiftRight(unsigned short int inR,unsigned short int inG,unsigned short int inB){;//info shifted out is lost unsigned int i; for(i=moduleCount; i != 0; i--){ setLed(i-1,module_p[i-2].getRed(),module_p[i-2].getGreen(),module_p[i-2].getBlue()); } if(inR==0 && inG==0 && inB==0) setLed(0,0,0,0); else setLed(0,inR,inG,inB); } void shiftBriteDisplay::turnOn(){; priv_SBEnable(); } void shiftBriteDisplay::turnOff(){; priv_SBDisable(); } void shiftBriteDisplay::flip(){; //swop positions rgbLed temp; //temporary object to hold data unsigned int i; for(i=0; i != moduleCount/2; i++){ temp.setRgbLed(module_p[i].getRed(),module_p[i].getGreen(),module_p[i].getBlue()); setLed(i,module_p[moduleCount-1-i].getRed(),module_p[moduleCount-1-i].getGreen(),module_p[moduleCount-1-i].getBlue()); setLed(moduleCount-i-1,temp.getRed(),temp.getGreen(),temp.getBlue()); } } void shiftBriteDisplay::invert(){; //invert colours unsigned int i; for(i=0; i != moduleCount; i++){ //module_p[i].getRed(); setLed(i,1023-module_p[i].getRed(),1023-module_p[i].getGreen(),1023-module_p[i].getBlue()); } } //=============================================================================================