Spidey Wall is the name for a physical wall lit up by multiple addressable LED strips. This program is an LPC1768 web server to control the wall from a browser.

Dependencies:   EthernetInterfacePlusHostname RdWebServer mbed-rtos mbed

This project is part of a Light-Wall using addressable LED strips (WS2801). I have published a few posts on my blog about the construction of the wall and building a game to play on it (PacMan). I have also had a guest post from a friend who has set his children the task of producing some interesting animations. The original post is http://robdobson.com/2015/07/spidey-wall/ /media/uploads/Bobty/20130722_112945_img_9674_62895-1184x1579.jpg

So far, however, I hadn't fully connected the physical (and electronic) wall with the web-browser creations to drive it. This project is hopefully the final link. A fast and reliable web server using REST commands to drive the 1686 LEDs in the Spidey Wall from code running in a browser (say on an iPad while you are playing a game).

The approach taken here results in the ability to control the RGB values of all 1686 LEDs at a rate of 20 frames per second.

A blog post describing the whole thing is here:

http://robdobson.com/2015/08/a-reliable-mbed-webserver/

Committer:
Bobty
Date:
Mon Aug 31 09:03:15 2015 +0000
Revision:
3:e5ea80fae61d
Parent:
2:99eb4c6e9ea4
Child:
4:b521815f2657
Made ShowLeds an explicit command rather than automatic; Allow hostname to be set; Made sure HTTP response has keep-alive in it; Moved http_server into main loop (was in a separate thread); Added HSV fill command

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Bobty 1:362331cec9b7 1 // LED Strip using WS2801 with two ISRs for two SPI connected
Bobty 1:362331cec9b7 2 // LED strips running in parallel
Bobty 1:362331cec9b7 3 // Rob Dobson 2013-2014
Bobty 1:362331cec9b7 4
Bobty 0:887096209439 5 #include "ledstrip.h"
Bobty 0:887096209439 6 #include "colourconverters.h"
Bobty 0:887096209439 7 #include "stddef.h"
Bobty 0:887096209439 8
Bobty 0:887096209439 9 #define SPIF 0 // SPI interrupt flag bit
Bobty 0:887096209439 10 #define SSP_IMSC_TX_RDY 3
Bobty 0:887096209439 11 #define SSP_IMSC_BITMASK 0x0f
Bobty 0:887096209439 12
Bobty 1:362331cec9b7 13 volatile int mCurPos0 = 0;
Bobty 1:362331cec9b7 14 int mEndPos0 = 0;
Bobty 1:362331cec9b7 15 volatile bool isr0Busy = false;
Bobty 1:362331cec9b7 16 unsigned char* pLedValues0 = NULL;
Bobty 0:887096209439 17
Bobty 0:887096209439 18 extern "C" void spi0_isr()
Bobty 0:887096209439 19 {
Bobty 0:887096209439 20 if (mCurPos0 < mEndPos0)
Bobty 0:887096209439 21 {
Bobty 1:362331cec9b7 22 LPC_SSP0->DR = pLedValues0[mCurPos0]; // write to FIFO data register
Bobty 0:887096209439 23 mCurPos0++;
Bobty 0:887096209439 24 }
Bobty 0:887096209439 25 else
Bobty 0:887096209439 26 {
Bobty 0:887096209439 27 // Turn off interrupts
Bobty 0:887096209439 28 LPC_SSP0->IMSC = 0;
Bobty 1:362331cec9b7 29 isr0Busy = false;
Bobty 0:887096209439 30 }
Bobty 0:887096209439 31 }
Bobty 0:887096209439 32
Bobty 1:362331cec9b7 33 volatile int mCurPos1 = 0;
Bobty 1:362331cec9b7 34 int mEndPos1 = 0;
Bobty 1:362331cec9b7 35 volatile bool isr1Busy = false;
Bobty 1:362331cec9b7 36 unsigned char* pLedValues1 = NULL;
Bobty 1:362331cec9b7 37
Bobty 0:887096209439 38 extern "C" void spi1_isr()
Bobty 0:887096209439 39 {
Bobty 0:887096209439 40 if (mCurPos1 < mEndPos1)
Bobty 0:887096209439 41 {
Bobty 1:362331cec9b7 42 LPC_SSP1->DR = pLedValues1[mCurPos1]; // write to FIFO data register
Bobty 0:887096209439 43 mCurPos1++;
Bobty 0:887096209439 44 }
Bobty 0:887096209439 45 else
Bobty 0:887096209439 46 {
Bobty 0:887096209439 47 // Turn off interrupts
Bobty 0:887096209439 48 LPC_SSP1->IMSC = 0;
Bobty 1:362331cec9b7 49 isr1Busy = false;
Bobty 0:887096209439 50 }
Bobty 0:887096209439 51 }
Bobty 0:887096209439 52
Bobty 0:887096209439 53 ledstrip::ledstrip(int length, int splitPoint)
Bobty 0:887096209439 54 {
Bobty 1:362331cec9b7 55 mpLedValuesA = NULL;
Bobty 1:362331cec9b7 56 mpLedValuesB = NULL;
Bobty 1:362331cec9b7 57 mpCurLedValues = NULL;
Bobty 0:887096209439 58
Bobty 0:887096209439 59 // SPI0 (using SSP 0 in 1768 chip)
Bobty 0:887096209439 60 mpSPI0 = new SPI(p11, NC, p13);
Bobty 0:887096209439 61 mpSPI0->format(8,0);
Bobty 0:887096209439 62 mpSPI0->frequency(500000);
Bobty 0:887096209439 63 LPC_SSP0->IMSC = 0; // initially no interrupts requested
Bobty 0:887096209439 64 NVIC_SetVector(SSP0_IRQn,( uint32_t ) spi0_isr);
Bobty 0:887096209439 65 NVIC_ClearPendingIRQ(SSP0_IRQn);
Bobty 0:887096209439 66 NVIC_SetPriority(SSP0_IRQn, 2);
Bobty 0:887096209439 67 NVIC_EnableIRQ(SSP0_IRQn);
Bobty 0:887096209439 68
Bobty 0:887096209439 69 // SPI1 (using SSP 1 in 1768 chip)
Bobty 0:887096209439 70 mpSPI1 = new SPI(p5, NC, p7);
Bobty 0:887096209439 71 mpSPI1->format(8,0);
Bobty 0:887096209439 72 mpSPI1->frequency(500000);
Bobty 0:887096209439 73 LPC_SSP1->IMSC = 0; // initially no interrupts requested
Bobty 0:887096209439 74 NVIC_SetVector(SSP1_IRQn,( uint32_t ) spi1_isr);
Bobty 0:887096209439 75 NVIC_ClearPendingIRQ(SSP1_IRQn);
Bobty 0:887096209439 76 NVIC_SetPriority(SSP1_IRQn, 2);
Bobty 0:887096209439 77 NVIC_EnableIRQ(SSP1_IRQn);
Bobty 1:362331cec9b7 78
Bobty 0:887096209439 79 // Resize the string length
Bobty 0:887096209439 80 Resize(length, splitPoint);
Bobty 0:887096209439 81 }
Bobty 0:887096209439 82
Bobty 0:887096209439 83 ledstrip::~ledstrip()
Bobty 0:887096209439 84 {
Bobty 0:887096209439 85 delete mpLedValuesA;
Bobty 0:887096209439 86 delete mpLedValuesB;
Bobty 0:887096209439 87 }
Bobty 0:887096209439 88
Bobty 0:887096209439 89 bool ledstrip::Resize(int length, int splitPoint)
Bobty 0:887096209439 90 {
Bobty 1:362331cec9b7 91 if (isr0Busy || isr1Busy)
Bobty 0:887096209439 92 return false;
Bobty 1:362331cec9b7 93 if (mpLedValuesA != NULL)
Bobty 0:887096209439 94 delete mpLedValuesA;
Bobty 1:362331cec9b7 95 if (mpLedValuesB != NULL)
Bobty 0:887096209439 96 delete mpLedValuesB;
Bobty 0:887096209439 97 mLedsBufSize = length*mColoursPerLed;
Bobty 0:887096209439 98 mpLedValuesA = new unsigned char[mLedsBufSize];
Bobty 0:887096209439 99 mpLedValuesB = new unsigned char[mLedsBufSize];
Bobty 0:887096209439 100 mpCurLedValues = mpLedValuesA;
Bobty 0:887096209439 101 mLedsInStrip = length;
Bobty 0:887096209439 102 mSplitPoint = splitPoint;
Bobty 0:887096209439 103 Clear();
Bobty 0:887096209439 104 return true;
Bobty 0:887096209439 105 }
Bobty 0:887096209439 106
Bobty 0:887096209439 107 void ledstrip::Clear()
Bobty 0:887096209439 108 {
Bobty 0:887096209439 109 /* Timer timr;
Bobty 0:887096209439 110 timr.start();
Bobty 0:887096209439 111 for (int i = 0; i < mLedsInStrip*mColoursPerLed; i++)
Bobty 0:887096209439 112 mpCurLedValues[i] = 0;
Bobty 0:887096209439 113 timr.stop();
Bobty 0:887096209439 114 printf("ClearTime loop %d\n", timr.read_us()); // Result is 863uS for 2500 x 3colour LEDS
Bobty 0:887096209439 115 timr.reset();
Bobty 0:887096209439 116 timr.start();
Bobty 0:887096209439 117 */
Bobty 0:887096209439 118 memset(mpCurLedValues, 0, mLedsBufSize);
Bobty 0:887096209439 119 /* timr.stop();
Bobty 0:887096209439 120 printf("ClearTime memset %d\n", timr.read_us()); // Result is 35uS for 2500 x 3 colour LEDS
Bobty 0:887096209439 121 */
Bobty 0:887096209439 122 }
Bobty 0:887096209439 123
Bobty 0:887096209439 124 unsigned char* ledstrip::GetBuffer()
Bobty 0:887096209439 125 {
Bobty 0:887096209439 126 return mpCurLedValues;
Bobty 0:887096209439 127 }
Bobty 0:887096209439 128
Bobty 0:887096209439 129 int ledstrip::GetBufferSizeinBytes()
Bobty 0:887096209439 130 {
Bobty 0:887096209439 131 return mLedsBufSize;
Bobty 0:887096209439 132 }
Bobty 0:887096209439 133
Bobty 0:887096209439 134 bool ledstrip::IsBusy()
Bobty 0:887096209439 135 {
Bobty 1:362331cec9b7 136 return isr0Busy || isr1Busy;
Bobty 0:887096209439 137 }
Bobty 0:887096209439 138
Bobty 1:362331cec9b7 139 void ledstrip::RawFill(int startLed, int numLeds, const unsigned char* pLedVals)
Bobty 1:362331cec9b7 140 {
Bobty 1:362331cec9b7 141 if ((startLed < 0) || (startLed >= mLedsInStrip))
Bobty 1:362331cec9b7 142 return;
Bobty 1:362331cec9b7 143 if (numLeds >= mLedsInStrip - startLed)
Bobty 1:362331cec9b7 144 numLeds = mLedsInStrip - startLed;
Bobty 1:362331cec9b7 145 int pos = startLed * mColoursPerLed;
Bobty 1:362331cec9b7 146 unsigned char* pBuf = GetBuffer() + pos;
Bobty 1:362331cec9b7 147 memcpy(pBuf, pLedVals, numLeds * mColoursPerLed);
Bobty 1:362331cec9b7 148 }
Bobty 3:e5ea80fae61d 149
Bobty 3:e5ea80fae61d 150 void ledstrip::HsvFill(int startLed, int numLeds, const unsigned char* pLedVals)
Bobty 3:e5ea80fae61d 151 {
Bobty 3:e5ea80fae61d 152 if ((startLed < 0) || (startLed >= mLedsInStrip))
Bobty 3:e5ea80fae61d 153 return;
Bobty 3:e5ea80fae61d 154 if (numLeds >= mLedsInStrip - startLed)
Bobty 3:e5ea80fae61d 155 numLeds = mLedsInStrip - startLed;
Bobty 3:e5ea80fae61d 156 int pos = startLed * mColoursPerLed;
Bobty 3:e5ea80fae61d 157 unsigned char* pBuf = GetBuffer() + pos;
Bobty 3:e5ea80fae61d 158
Bobty 3:e5ea80fae61d 159 // Copy over the values converting each to RGB
Bobty 3:e5ea80fae61d 160 for (int i = 0; i < numLeds; i++)
Bobty 3:e5ea80fae61d 161 {
Bobty 3:e5ea80fae61d 162 RgbColor colrVal = HsvToRgb(HsvColor(pLedVals[0],pLedVals[1] & 0xf0, (pLedVals[1] << 4) & 0xf0));
Bobty 3:e5ea80fae61d 163 pBuf[pos] = colrVal.r;
Bobty 3:e5ea80fae61d 164 pBuf[pos+1] = colrVal.g;
Bobty 3:e5ea80fae61d 165 pBuf[pos+2] = colrVal.b;
Bobty 3:e5ea80fae61d 166 // 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);
Bobty 3:e5ea80fae61d 167 pos += mColoursPerLed;
Bobty 3:e5ea80fae61d 168 pLedVals += 2;
Bobty 3:e5ea80fae61d 169 }
Bobty 3:e5ea80fae61d 170 }
Bobty 1:362331cec9b7 171
Bobty 0:887096209439 172 // Fill - solid colour
Bobty 0:887096209439 173 void ledstrip::Fill(int startLed, int numLeds,
Bobty 0:887096209439 174 int r1, int g1, int b1)
Bobty 0:887096209439 175 {
Bobty 0:887096209439 176 /* Timer timr;
Bobty 0:887096209439 177 timr.start();
Bobty 0:887096209439 178 */
Bobty 0:887096209439 179 if ((startLed < 0) || (startLed >= mLedsInStrip))
Bobty 0:887096209439 180 return;
Bobty 0:887096209439 181 if (numLeds >= mLedsInStrip - startLed)
Bobty 0:887096209439 182 numLeds = mLedsInStrip - startLed;
Bobty 0:887096209439 183 int pos = startLed * mColoursPerLed;
Bobty 0:887096209439 184 unsigned char* pBuf = GetBuffer();
Bobty 0:887096209439 185 for (int i = 0; i < numLeds; i++)
Bobty 0:887096209439 186 {
Bobty 0:887096209439 187 pBuf[pos] = (unsigned char) r1;
Bobty 0:887096209439 188 pBuf[pos+1] = (unsigned char) g1;
Bobty 0:887096209439 189 pBuf[pos+2] = (unsigned char) b1;
Bobty 0:887096209439 190 pos += mColoursPerLed;
Bobty 0:887096209439 191 }
Bobty 0:887096209439 192 /* timr.stop();
Bobty 0:887096209439 193 printf("Fill solid %d\n", timr.read_us()); // Fill 50 LEDS solid colour = 11uS
Bobty 0:887096209439 194 */
Bobty 0:887096209439 195 }
Bobty 0:887096209439 196
Bobty 0:887096209439 197 // Fill - with interpolation of colours using HSV colour space
Bobty 0:887096209439 198 void ledstrip::Fill(int startLed, int numLeds,
Bobty 0:887096209439 199 int r1, int g1, int b1,
Bobty 0:887096209439 200 int r2, int g2, int b2)
Bobty 0:887096209439 201 {
Bobty 0:887096209439 202 /* Timer timr;
Bobty 0:887096209439 203 timr.start();
Bobty 0:887096209439 204 */
Bobty 0:887096209439 205 if ((startLed < 0) || (startLed >= mLedsInStrip))
Bobty 0:887096209439 206 return;
Bobty 0:887096209439 207 if (numLeds >= mLedsInStrip - startLed)
Bobty 0:887096209439 208 numLeds = mLedsInStrip - startLed;
Bobty 0:887096209439 209 int pos = startLed * mColoursPerLed;
Bobty 0:887096209439 210 RgbColor startRGB(r1,g1,b1);
Bobty 0:887096209439 211 HsvColor startHsv = RgbToHsv(startRGB);
Bobty 0:887096209439 212 RgbColor endRGB(r2,g2,b2);
Bobty 0:887096209439 213 HsvColor endHsv = RgbToHsv(endRGB);
Bobty 0:887096209439 214 int curH = startHsv.h << 16;
Bobty 0:887096209439 215 int curS = startHsv.s << 16;
Bobty 0:887096209439 216 int curV = startHsv.v << 16;
Bobty 0:887096209439 217 int interpSteps = numLeds - 1;
Bobty 0:887096209439 218 if (interpSteps < 1)
Bobty 0:887096209439 219 interpSteps = 1;
Bobty 0:887096209439 220 int incH = ((endHsv.h - startHsv.h) << 16) / interpSteps;
Bobty 0:887096209439 221 int incS = ((endHsv.s - startHsv.s) << 16) / interpSteps;
Bobty 0:887096209439 222 int incV = ((endHsv.v - startHsv.v) << 16) / interpSteps;
Bobty 0:887096209439 223 // Since H is a polar value we need to find out if it is best to go clockwise or anti-clockwise
Bobty 0:887096209439 224 if (endHsv.h > startHsv.h)
Bobty 0:887096209439 225 {
Bobty 0:887096209439 226 if (endHsv.h-startHsv.h > 128)
Bobty 0:887096209439 227 incH = ((startHsv.h-endHsv.h) << 16) / interpSteps;
Bobty 0:887096209439 228 }
Bobty 0:887096209439 229 else
Bobty 0:887096209439 230 {
Bobty 0:887096209439 231 // Go "round the top" using modulo result
Bobty 0:887096209439 232 if (startHsv.h-endHsv.h > 128)
Bobty 0:887096209439 233 incH = ((endHsv.h + 255 - startHsv.h) << 16) / interpSteps;
Bobty 0:887096209439 234 }
Bobty 0:887096209439 235
Bobty 0:887096209439 236 // 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);
Bobty 0:887096209439 237 unsigned char* pBuf = GetBuffer();
Bobty 0:887096209439 238 for (int i = 0; i < numLeds; i++)
Bobty 0:887096209439 239 {
Bobty 0:887096209439 240 RgbColor colrVal = HsvToRgb(HsvColor((curH>>16)&0xff,curS>>16,curV>>16));
Bobty 0:887096209439 241 pBuf[pos] = colrVal.r;
Bobty 0:887096209439 242 pBuf[pos+1] = colrVal.g;
Bobty 0:887096209439 243 pBuf[pos+2] = colrVal.b;
Bobty 0:887096209439 244 // printf("HSV %d %d %d RGB %d %d %d\n", curH>>16, curS>>16, curV>>16, colrVal.r, colrVal.g, colrVal.b);
Bobty 0:887096209439 245 pos += mColoursPerLed;
Bobty 0:887096209439 246 curH = curH + incH;
Bobty 0:887096209439 247 curS = curS + incS;
Bobty 0:887096209439 248 curV = curV + incV;
Bobty 0:887096209439 249 }
Bobty 0:887096209439 250 /*
Bobty 0:887096209439 251 timr.stop();
Bobty 0:887096209439 252 printf("Fill gradient %d\n", timr.read_us()); // Fill gradient 50 LEDS = 64uS
Bobty 0:887096209439 253 */
Bobty 0:887096209439 254 }
Bobty 0:887096209439 255
Bobty 0:887096209439 256 void ledstrip::ShowLeds()
Bobty 0:887096209439 257 {
Bobty 0:887096209439 258 // Check if busy
Bobty 1:362331cec9b7 259 while (isr0Busy || isr1Busy)
Bobty 1:362331cec9b7 260 wait_us(2000);
Bobty 3:e5ea80fae61d 261 // wait_us(2000);
Bobty 0:887096209439 262
Bobty 0:887096209439 263 // Set up start points
Bobty 0:887096209439 264 mCurPos0 = 0;
Bobty 0:887096209439 265 mEndPos0 = mSplitPoint*mColoursPerLed;
Bobty 0:887096209439 266 mCurPos1 = mSplitPoint*mColoursPerLed;
Bobty 0:887096209439 267 mEndPos1 = mLedsInStrip*mColoursPerLed;
Bobty 0:887096209439 268
Bobty 0:887096209439 269 // Set the buffer for the ISRs
Bobty 1:362331cec9b7 270 pLedValues0 = mpCurLedValues;
Bobty 1:362331cec9b7 271 pLedValues1 = mpCurLedValues;
Bobty 1:362331cec9b7 272
Bobty 0:887096209439 273 // Flip the current buffer to the alternate one for interleaved writing
Bobty 0:887096209439 274 if (mpCurLedValues == mpLedValuesA)
Bobty 1:362331cec9b7 275 {
Bobty 1:362331cec9b7 276 memcpy(mpLedValuesB, mpLedValuesA, mLedsBufSize);
Bobty 0:887096209439 277 mpCurLedValues = mpLedValuesB;
Bobty 1:362331cec9b7 278 }
Bobty 0:887096209439 279 else
Bobty 1:362331cec9b7 280 {
Bobty 1:362331cec9b7 281 memcpy(mpLedValuesA, mpLedValuesB, mLedsBufSize);
Bobty 0:887096209439 282 mpCurLedValues = mpLedValuesA;
Bobty 1:362331cec9b7 283 }
Bobty 0:887096209439 284
Bobty 0:887096209439 285 // Enable interrupts
Bobty 1:362331cec9b7 286 isr0Busy = true;
Bobty 1:362331cec9b7 287 if (mSplitPoint < mLedsInStrip)
Bobty 1:362331cec9b7 288 isr1Busy = true;
Bobty 0:887096209439 289
Bobty 0:887096209439 290 // Check if second strip is used
Bobty 1:362331cec9b7 291 LPC_SSP0->IMSC = (1 << SSP_IMSC_TX_RDY) & SSP_IMSC_BITMASK;
Bobty 2:99eb4c6e9ea4 292 if (mSplitPoint < mLedsInStrip && mSplitPoint > 0)
Bobty 0:887096209439 293 LPC_SSP1->IMSC = (1 << SSP_IMSC_TX_RDY) & SSP_IMSC_BITMASK;
Bobty 0:887096209439 294 }