Rob Dobson / Mbed 2 deprecated SpideyWallWeb

Dependencies:   EthernetInterfacePlusHostname RdWebServer mbed-rtos mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ledstrip.cpp Source File

ledstrip.cpp

00001 
00002 // LED Strip using WS2801 with two ISRs for two SPI connected 
00003 // LED strips running in parallel
00004 // Rob Dobson 2013-2014
00005 
00006 #include "ledstrip.h"
00007 #include "colourconverters.h"
00008 #include "stddef.h"
00009 
00010 #define SPIF 0              // SPI interrupt flag bit
00011 #define SSP_IMSC_TX_RDY 3
00012 #define SSP_IMSC_BITMASK 0x0f
00013 
00014 volatile int mCurPos0 = 0;
00015 int mEndPos0 = 0;
00016 volatile bool isr0Busy = false;
00017 unsigned char* pLedValues0 = NULL;
00018 
00019 extern "C" void spi0_isr()
00020 {
00021     if (mCurPos0 < mEndPos0)
00022     {
00023         LPC_SSP0->DR = pLedValues0[mCurPos0];  // write to FIFO data register
00024         mCurPos0++;
00025     }
00026     else
00027     {
00028         // Turn off interrupts
00029         LPC_SSP0->IMSC = 0;
00030         isr0Busy = false;
00031     }
00032 }
00033 
00034 volatile int mCurPos1 = 0;
00035 int mEndPos1 = 0;
00036 volatile bool isr1Busy = false;
00037 unsigned char* pLedValues1 = NULL;
00038 
00039 extern "C" void spi1_isr()
00040 {
00041     if (mCurPos1 < mEndPos1)
00042     {
00043         LPC_SSP1->DR = pLedValues1[mCurPos1];  // write to FIFO data register
00044         mCurPos1++;
00045     }
00046     else
00047     {
00048         // Turn off interrupts
00049         LPC_SSP1->IMSC = 0;
00050         isr1Busy = false;
00051     }
00052 }
00053 
00054 ledstrip::ledstrip(int length, int splitPoint)
00055 {
00056     mpLedValuesA = NULL;
00057     mpLedValuesB = NULL;
00058     mpCurLedValues = NULL;
00059 
00060     // SPI0 (using SSP 0 in 1768 chip)
00061     mpSPI0 = new SPI(p11, NC, p13);
00062     mpSPI0->format(8,0);
00063     mpSPI0->frequency(500000);    
00064     LPC_SSP0->IMSC = 0; // initially no interrupts requested
00065     NVIC_SetVector(SSP0_IRQn,( uint32_t ) spi0_isr);
00066     NVIC_ClearPendingIRQ(SSP0_IRQn);
00067     NVIC_SetPriority(SSP0_IRQn, 2);
00068     NVIC_EnableIRQ(SSP0_IRQn);
00069 
00070     // SPI1 (using SSP 1 in 1768 chip)
00071     mpSPI1 = new SPI(p5, NC, p7);
00072     mpSPI1->format(8,0);
00073     mpSPI1->frequency(500000);    
00074     LPC_SSP1->IMSC = 0; // initially no interrupts requested
00075     NVIC_SetVector(SSP1_IRQn,( uint32_t ) spi1_isr);
00076     NVIC_ClearPendingIRQ(SSP1_IRQn);
00077     NVIC_SetPriority(SSP1_IRQn, 2);
00078     NVIC_EnableIRQ(SSP1_IRQn);
00079 
00080     // Resize the string length
00081     Resize(length, splitPoint);
00082 }
00083 
00084 ledstrip::~ledstrip()
00085 {
00086     delete mpLedValuesA;
00087     delete mpLedValuesB;
00088 }
00089 
00090 bool ledstrip::Resize(int length, int splitPoint)
00091 {
00092     if (isr0Busy || isr1Busy)
00093         return false;
00094     if (mpLedValuesA != NULL)
00095         delete mpLedValuesA;
00096     if (mpLedValuesB != NULL)
00097         delete mpLedValuesB;
00098     mLedsBufSize = length*mColoursPerLed;
00099     mpLedValuesA = new unsigned char[mLedsBufSize];
00100     mpLedValuesB = new unsigned char[mLedsBufSize];
00101     mpCurLedValues = mpLedValuesA;
00102     mLedsInStrip = length;
00103     mSplitPoint = splitPoint;
00104     Clear();
00105     return true;
00106 }
00107 
00108 void ledstrip::Clear()
00109 {
00110 /*    Timer timr;
00111     timr.start();
00112     for (int i = 0; i < mLedsInStrip*mColoursPerLed; i++)
00113         mpCurLedValues[i] = 0;
00114     timr.stop();
00115     printf("ClearTime loop %d\n", timr.read_us());  // Result is 863uS for 2500 x 3colour LEDS
00116     timr.reset();
00117     timr.start();
00118  */
00119     memset(mpCurLedValues, 0, mLedsBufSize);
00120  /*   timr.stop();
00121     printf("ClearTime memset %d\n", timr.read_us());  // Result is 35uS for 2500 x 3 colour LEDS
00122 */
00123 }
00124 
00125 unsigned char* ledstrip::GetBuffer()
00126 {
00127     return mpCurLedValues;
00128 }
00129 
00130 int ledstrip::GetBufferSizeinBytes()
00131 {
00132     return mLedsBufSize;
00133 }
00134 
00135 bool ledstrip::IsBusy()
00136 {
00137     return isr0Busy || isr1Busy;
00138 }
00139 
00140 void ledstrip::RawFill(int startLed, int numLeds, const unsigned char* pLedVals)
00141 {
00142     if ((startLed < 0) || (startLed >= mLedsInStrip))
00143         return;
00144     if (numLeds >= mLedsInStrip - startLed)
00145         numLeds = mLedsInStrip - startLed;
00146     int pos = startLed * mColoursPerLed;
00147     unsigned char* pBuf = GetBuffer() + pos;
00148     memcpy(pBuf, pLedVals, numLeds * mColoursPerLed);
00149 }
00150 
00151 void ledstrip::HsvFill(int startLed, int numLeds, const unsigned char* pLedVals)
00152 {
00153     if ((startLed < 0) || (startLed >= mLedsInStrip))
00154         return;
00155     if (numLeds >= mLedsInStrip - startLed)
00156         numLeds = mLedsInStrip - startLed;
00157     int pos = startLed * mColoursPerLed;
00158     unsigned char* pBuf = GetBuffer() + pos;
00159     
00160     // Copy over the values converting each to RGB
00161     for (int i = 0; i < numLeds; i++)
00162     {
00163         RgbColor colrVal(0,0,0);
00164         HsvToRgb(HsvColor(pLedVals[0],pLedVals[1] & 0xf0, (pLedVals[1] << 4) & 0xf0), colrVal);
00165         pBuf[pos] = colrVal.r;
00166         pBuf[pos+1] = colrVal.g;
00167         pBuf[pos+2] = colrVal.b;
00168 //        printf("HSV %d %d %d RGB %d %d %d\r\n", pLedVals[0],pLedVals[1] & 0xf0, (pLedVals[1] << 4) & 0xf0, colrVal.r, colrVal.g, colrVal.b);
00169         pos += mColoursPerLed;
00170         pLedVals += 2;
00171     }
00172 }
00173     
00174 // Fill - solid colour
00175 void ledstrip::Fill(int startLed, int numLeds, 
00176                 int r1, int g1, int b1)
00177 {
00178 /*    Timer timr;
00179     timr.start();
00180 */
00181     if ((startLed < 0) || (startLed >= mLedsInStrip))
00182         return;
00183     if (numLeds >= mLedsInStrip - startLed)
00184         numLeds = mLedsInStrip - startLed;
00185     int pos = startLed * mColoursPerLed;
00186     unsigned char* pBuf = GetBuffer();
00187     for (int i = 0; i < numLeds; i++)
00188     {
00189         pBuf[pos] = (unsigned char) r1;
00190         pBuf[pos+1] = (unsigned char) g1;
00191         pBuf[pos+2] = (unsigned char) b1;
00192         pos += mColoursPerLed;
00193     }
00194 /*    timr.stop();
00195     printf("Fill solid %d\n", timr.read_us()); // Fill 50 LEDS solid colour = 11uS
00196     */
00197 }
00198 
00199 // Fill - with interpolation of colours using HSV colour space
00200 void ledstrip::Fill(int startLed, int numLeds, 
00201                 int r1, int g1, int b1, 
00202                 int r2, int g2, int b2)
00203 {
00204 /*    Timer timr;
00205     timr.start();
00206     */
00207     if ((startLed < 0) || (startLed >= mLedsInStrip))
00208         return;
00209     if (numLeds >= mLedsInStrip - startLed)
00210         numLeds = mLedsInStrip - startLed;
00211     int pos = startLed * mColoursPerLed;
00212     RgbColor startRGB(r1,g1,b1);
00213     HsvColor startHsv(0,0,0);
00214     RgbToHsv(startRGB, startHsv);
00215     RgbColor endRGB(r2,g2,b2);
00216     HsvColor endHsv(0,0,0);
00217     RgbToHsv(endRGB, endHsv);
00218     int curH = startHsv.h << 16;
00219     int curS = startHsv.s << 16;
00220     int curV = startHsv.v << 16;
00221     int interpSteps = numLeds - 1;
00222     if (interpSteps < 1)
00223         interpSteps = 1;
00224     int incH = ((endHsv.h - startHsv.h) << 16) / interpSteps;
00225     int incS = ((endHsv.s - startHsv.s) << 16) / interpSteps;
00226     int incV = ((endHsv.v - startHsv.v) << 16) / interpSteps;
00227     // Since H is a polar value we need to find out if it is best to go clockwise or anti-clockwise
00228     if (endHsv.h > startHsv.h)
00229     {
00230         if (endHsv.h-startHsv.h > 128)
00231             incH = ((startHsv.h-endHsv.h) << 16) / interpSteps;
00232     }
00233     else
00234     {
00235         // Go "round the top" using modulo result
00236         if (startHsv.h-endHsv.h > 128)
00237             incH = ((endHsv.h + 255 - startHsv.h) << 16) / interpSteps;
00238     }
00239     
00240 //    printf("StartHSV %d %d %d EndHSV %d %d %d IncHSV %d %d %d\n", startHsv.h, startHsv.s, startHsv.v, endHsv.h, endHsv.s, endHsv.v, incH, incS, incV);
00241     unsigned char* pBuf = GetBuffer();
00242     for (int i = 0; i < numLeds; i++)
00243     {
00244         RgbColor colrVal(0,0,0);
00245         HsvToRgb(HsvColor((curH>>16)&0xff,curS>>16,curV>>16), colrVal);
00246         pBuf[pos] = colrVal.r;
00247         pBuf[pos+1] = colrVal.g;
00248         pBuf[pos+2] = colrVal.b;
00249 //        printf("HSV %d %d %d RGB %d %d %d\n", curH>>16, curS>>16, curV>>16, colrVal.r, colrVal.g, colrVal.b);
00250         pos += mColoursPerLed;
00251         curH = curH + incH;
00252         curS = curS + incS;
00253         curV = curV + incV;
00254     }
00255     /*
00256     timr.stop();
00257     printf("Fill gradient %d\n", timr.read_us());  // Fill gradient 50 LEDS = 64uS
00258     */
00259 }
00260 
00261 void ledstrip::ShowLeds()
00262 {
00263     // Check if busy
00264     while (isr0Busy || isr1Busy)
00265         wait_us(2000);
00266 //    wait_us(2000);
00267     
00268     // Set up start points
00269     mCurPos0 = 0;
00270     mEndPos0 = mSplitPoint*mColoursPerLed;
00271     mCurPos1 = mSplitPoint*mColoursPerLed;
00272     mEndPos1 = mLedsInStrip*mColoursPerLed;
00273     
00274     // Set the buffer for the ISRs
00275     pLedValues0 = mpCurLedValues;
00276     pLedValues1 = mpCurLedValues;
00277 
00278     // Flip the current buffer to the alternate one for interleaved writing
00279     if (mpCurLedValues == mpLedValuesA)
00280     {
00281         memcpy(mpLedValuesB, mpLedValuesA, mLedsBufSize);
00282         mpCurLedValues = mpLedValuesB;
00283     }
00284     else
00285     {
00286         memcpy(mpLedValuesA, mpLedValuesB, mLedsBufSize);
00287         mpCurLedValues = mpLedValuesA;
00288     }
00289     
00290     // Enable interrupts
00291     isr0Busy = true;
00292     if (mSplitPoint < mLedsInStrip)
00293         isr1Busy = true;
00294     
00295     // Check if second strip is used
00296     LPC_SSP0->IMSC = (1 << SSP_IMSC_TX_RDY) & SSP_IMSC_BITMASK;
00297     if (mSplitPoint < mLedsInStrip && mSplitPoint > 0)
00298         LPC_SSP1->IMSC = (1 << SSP_IMSC_TX_RDY) & SSP_IMSC_BITMASK;
00299 }