WS2811 Led Strip Code for mBed

Dependencies:   mbed WS2811_RY_A

Dependents:   WS2811_RY_A WS2811_RY_32x48_ConwayA

main.cpp

Committer:
ohararp
Date:
2013-08-15
Revision:
1:1b91ef74cc9c
Parent:
0:f19c80146d55

File content as of revision 1:1b91ef74cc9c:

#include "mbed.h"
#include "matrix.h"
Serial pc(USBTX, USBRX);
DigitalOut dat(p5);
DigitalOut bLed(LED1);

//*******************************************************************************    
// DEFINE WS2811 Strip Parameters
#define numLEDs 1536 
#define BrightMax 64
#define BrightMin 0

#define ROWS_LEDs 32  // LED_LAYOUT assumed 0 if ROWS_LEDs > 8
#define COLS_LEDs 48  // all of the following params need to be adjusted for screen size


uint8_t RandRed;
uint8_t RandGrn;
uint8_t RandBlu;

uint8_t pixels[numLEDs*3];
Timer guardtime;
uint32_t bogocal;
//*******************************************************************************
//Byte val 2PI Cosine Wave, offset by 1 PI 
//supports fast trig calcs and smooth LED fading/pulsing.
uint8_t cos_wave[256] =  
{0,0,0,0,1,1,1,2,2,3,4,5,6,6,8,9,10,11,12,14,15,17,18,20,22,23,25,27,29,31,33,35,38,40,42,
45,47,49,52,54,57,60,62,65,68,71,73,76,79,82,85,88,91,94,97,100,103,106,109,113,116,119,
122,125,128,131,135,138,141,144,147,150,153,156,159,162,165,168,171,174,177,180,183,186,
189,191,194,197,199,202,204,207,209,212,214,216,218,221,223,225,227,229,231,232,234,236,
238,239,241,242,243,245,246,247,248,249,250,251,252,252,253,253,254,254,255,255,255,255,
255,255,255,255,254,254,253,253,252,252,251,250,249,248,247,246,245,243,242,241,239,238,
236,234,232,231,229,227,225,223,221,218,216,214,212,209,207,204,202,199,197,194,191,189,
186,183,180,177,174,171,168,165,162,159,156,153,150,147,144,141,138,135,131,128,125,122,
119,116,113,109,106,103,100,97,94,91,88,85,82,79,76,73,71,68,65,62,60,57,54,52,49,47,45,
42,40,38,35,33,31,29,27,25,23,22,20,18,17,15,14,12,11,10,9,8,6,6,5,4,3,2,2,1,1,1,0,0,0,0
};


//Gamma Correction Curve
uint8_t exp_gamma[256] =
{0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,3,3,3,
4,4,4,4,4,5,5,5,5,5,6,6,6,7,7,7,7,8,8,8,9,9,9,10,10,10,11,11,12,12,12,13,13,14,14,14,15,15,
16,16,17,17,18,18,19,19,20,20,21,21,22,23,23,24,24,25,26,26,27,28,28,29,30,30,31,32,32,33,
34,35,35,36,37,38,39,39,40,41,42,43,44,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,
61,62,63,64,65,66,67,68,70,71,72,73,74,75,77,78,79,80,82,83,84,85,87,89,91,92,93,95,96,98,
99,100,101,102,105,106,108,109,111,112,114,115,117,118,120,121,123,125,126,128,130,131,133,
135,136,138,140,142,143,145,147,149,151,152,154,156,158,160,162,164,165,167,169,171,173,175,
177,179,181,183,185,187,190,192,194,196,198,200,202,204,207,209,211,213,216,218,220,222,225,
227,229,232,234,236,239,241,244,246,249,251,253,254,255
};
//*******************************************************************************
void setup () {
    /*if ((pixels = (uint8_t *)malloc(numLEDs * 3))) {
        memset(pixels, 0x00, numLEDs * 3); // Init to RGB 'off' state
    }*/
    
    for (int j=0; j<numLEDs*3; j++) {
        pixels[j]=0x00;
    }
    
    // calibrate delay loops for NRZ 
    int i;
    guardtime.start();
    for (i=0; i<1000; i++)
        /* do nothing */;
    i=guardtime.read_us();
    printf("ws2811:  1000 iters took %d usec.\n", i);
    bogocal = (1000 / (i*10)); // iterations per bitcell (417 nsec)
    bogocal = 1;
    printf("ws2811:  calibrating to %d bogojiffies.\n", bogocal);
}
//*******************************************************************************
inline void celldelay(void) {
    for (int i = 0; i<bogocal; i++)
        /* do nothing */ ;
}
//*******************************************************************************
void writebit(bool bit) {
    // first cell is always 1
    dat = 1;
    celldelay();
    if (bit) {
        celldelay();
    } else {
        dat=0;
        celldelay();
    }
    // last cell is always 0
    dat=0;
    celldelay();
}
//*******************************************************************************
void write(uint8_t byte) {
    __disable_irq();
    for (int i=0; i<8; i++) {
        if (byte & 0x80)
            writebit(1);
        else
            writebit(0);
        byte <<= 1;
    }
    __enable_irq();
}

uint16_t numPixels(void) {
    return numLEDs;
}

//*******************************************************************************
void show(void) {
    uint16_t i, nl3 = numLEDs * 3; // 3 bytes per LED
    while (guardtime.read_us() < 50)
        /* spin */;
    for (i=0; i<nl3; i++ ) {
        write(pixels[i]);
    }
    guardtime.reset();
}
//*******************************************************************************
void blank(void) {
    for (int i=0; i<numLEDs*3; i++) {
        pixels[i]=0x00;
    }
    show();
}
//*******************************************************************************
void blankDelay(int n) {
    for (int i=0; i<numLEDs*3; i++) {
        pixels[i]=0x00;
    }
    show();
    wait_ms(n);
}
//*******************************************************************************
uint32_t total_luminance(void) {
    uint32_t running_total;
    running_total = 0;
    for (int i=0; i<numLEDs*3; i++)
        running_total += pixels[i];
    return running_total;
}
//*******************************************************************************
// Convert R,G,B to combined 32-bit color
uint32_t Color(uint8_t r, uint8_t g, uint8_t b) {
    // Take the lowest 7 bits of each value and append them end to end
    // We have the top bit set high (its a 'parity-like' bit in the protocol
    // and must be set!)
    return ((uint32_t)g << 16) | ((uint32_t)r << 8) | (uint32_t)b;
}
//*******************************************************************************
// store the rgb component in our array
void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b) {
    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
    pixels[n*3  ] = g;
    pixels[n*3+1] = r;
    pixels[n*3+2] = b;
    //pc.printf("setPixelColor-4 inputs\n");   
}
//*******************************************************************************
void setPixelR(uint16_t n, uint8_t r) {
    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
    pixels[n*3+1] = r;
}
//*******************************************************************************
void setPixelG(uint16_t n, uint8_t g) {
    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
    pixels[n*3] = g;
}
//*******************************************************************************
void setPixelB(uint16_t n, uint8_t b) {
    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
    pixels[n*3+2] = b;
}
//*******************************************************************************
void setPixelColor(uint16_t n, uint32_t c) {
    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
    pixels[n*3  ] = (c >> 16);
    pixels[n*3+1] = (c >>  8);
    pixels[n*3+2] =  c;
    //pc.printf("setPixelColor-2 inputs\n");   
}
//*******************************************************************************
// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<numPixels(); i++) {
      setPixelColor(Matrix[i], c);      
      show();
      wait_ms(wait);
  }
}
//*******************************************************************************
// Fill the dots one after the other with a color
void colorAll(uint32_t c, uint16_t wait) {
  for(uint16_t i=0; i<numPixels(); i++) {
      setPixelColor(Matrix[i], c);
  }
  show();
  wait_ms(wait);
}

//*******************************************************************************
// Fill the dots one after the other with a color
void RandOne(uint8_t MaxRand, uint16_t wait) {
  for(uint16_t i=0; i<numPixels(); i++) {
        setPixelColor(Matrix[rand() % numLEDs-1], rand() % MaxRand,rand() % MaxRand,rand() % MaxRand);
        show();
        wait_ms(wait);
  }

}
//*******************************************************************************
// Fill the dots one after the other with a color
void RandAll(uint8_t MaxRand, uint16_t wait) {
  for(uint16_t i=0; i<numPixels(); i++) {
        setPixelColor(Matrix[i], rand() % MaxRand,rand() % MaxRand,rand() % MaxRand);
  }
  show();
  wait_ms(wait);
}
//*******************************************************************************
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(int WheelPos) {
  if(WheelPos < 85) {
   return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   return Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170;
   return Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}
//*******************************************************************************
void rainbow(uint8_t rwait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<numPixels(); i++) {
      setPixelColor(i, Wheel((i+j) & 255));
    }
    show();
    wait_ms(rwait);
  }
}
//*******************************************************************************
// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t rwait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< numPixels(); i++) {
      setPixelColor(i, Wheel(((i * 256 / numPixels()) + j) & 255));
    }
    show();
    wait_ms(rwait);
  }
}
//*******************************************************************************
void Ring(int RingArray[], uint8_t r, uint8_t g, uint8_t b, uint8_t RingWait) {
   
    for (int i=1;i<RingArray[0];++i) {
        setPixelColor(RingArray[i], r, g, b);
        //pc.printf("RingArray[%d,%d]\n",RingArray[i],RingArray[0]);
    }
    show();
    wait_ms(RingWait);
}
//*******************************************************************************
void RingFadeUp(int RingArray[], uint8_t r, uint8_t g, uint8_t b, uint8_t FadeSteps, uint8_t FadeTime, uint16_t RingWait) {
    uint8_t rBump, gBump, bBump;
    uint8_t rStep, gStep, bStep;
    
    rStep = r/FadeSteps; if(rStep == 0) {rStep = 1;}
    gStep = g/FadeSteps; if(gStep == 0) {gStep = 1;}
    bStep = b/FadeSteps; if(bStep == 0) {bStep = 1;}
        
    rBump = 0;
    gBump = 0;
    bBump = 0;
    
    for (int j=0;j<FadeSteps;++j) {
        rBump += rStep; if(rBump > BrightMax) {rBump = 0;} //Account for Int rollover
        gBump += gStep; if(gBump > BrightMax) {gBump = 0;} //Account for Int rollover
        bBump += bStep; if(bBump > BrightMax) {bBump = 0;} //Account for Int rollover
        for (int i=1;i<RingArray[0];++i) {
            setPixelColor(RingArray[i], rBump, gBump, bBump);
            pc.printf("UP [%d,%d %d]\n",rBump, gBump, bBump);
        }
        show();
    wait_ms(FadeTime);    
    };
    wait_ms(RingWait);
}
//*******************************************************************************
void RingFadeDn(int RingArray[], uint8_t r, uint8_t g, uint8_t b, uint8_t FadeSteps, uint8_t FadeTime, uint16_t RingWait) {
    uint8_t rBump, gBump, bBump;
    uint8_t rStep, gStep, bStep;
    
    rStep = r/FadeSteps; if(rStep == 0) {rStep = 1;}
    gStep = g/FadeSteps; if(gStep == 0) {gStep = 1;}
    bStep = b/FadeSteps; if(bStep == 0) {bStep = 1;}
    
    rBump = r;
    gBump = g;
    bBump = b;
    
    for (int j=0;j<FadeSteps;++j) {
        rBump -= rStep; if(rBump > BrightMax) {rBump = 0;} //Account for Int rollover
        gBump -= gStep; if(gBump > BrightMax) {gBump = 0;} //Account for Int rollover
        bBump -= bStep; if(bBump > BrightMax) {bBump = 0;} //Account for Int rollover
        for (int i=1;i<RingArray[0];++i) {
            setPixelColor(RingArray[i], rBump, gBump, bBump);
            pc.printf("DN [%d,%d %d]\n",rBump, gBump, bBump);
        }
        show();
    wait_ms(FadeTime);    
    };
    wait_ms(RingWait);
}
//*******************************************************************************
uint8_t ColorRand(void) {
    return (rand()%(BrightMax-BrightMin)+BrightMin);
}
//*******************************************************************************
inline uint8_t fastCosineCalc( uint16_t preWrapVal)
{
  uint8_t wrapVal = (preWrapVal % 255);
  if (wrapVal<=0){
  wrapVal=255+wrapVal;
  }
  return cos_wave[wrapVal]; 
}
//*******************************************************************************
void Plasma()
{
    unsigned long frameCount=25500;  // arbitrary seed to calculate the three time displacement variables t,t2,t3
    while(1) {
        frameCount++ ; //42 35 38
        uint16_t t = fastCosineCalc((128 * frameCount)/100);  //time displacement - fiddle with these til it looks good...
        uint16_t t2 = fastCosineCalc((128 * frameCount)/100); 
        uint16_t t3 = fastCosineCalc((128 * frameCount)/100);
        
        for (uint8_t y = 0; y < ROWS_LEDs; y++) {
          int left2Right, pixelIndex;
          if (((y % (ROWS_LEDs/8)) & 1) == 0) {
            left2Right = 1;
            pixelIndex = y * COLS_LEDs;
          } else {
            left2Right = -1;
            pixelIndex = (y + 1) * COLS_LEDs - 1;
          }
          for (uint8_t x = 0; x < COLS_LEDs ; x++) {
            //Calculate 3 seperate plasma waves, one for each color channel
            uint8_t r = fastCosineCalc(((x << 3) + (t >> 1) + fastCosineCalc((t2 + (y << 3)))));
            uint8_t g = fastCosineCalc(((y << 3) + t + fastCosineCalc(((t3 >> 2) + (x << 3)))));
            uint8_t b = fastCosineCalc(((y << 3) + t2 + fastCosineCalc((t + x + (g >> 2)))));
            //uncomment the following to enable gamma correction
            r=exp_gamma[r];  
            g=exp_gamma[g];
            b=exp_gamma[b];
            setPixelColor(Matrix[pixelIndex],r,g,b);
            //pc.printf("Plasma [%d,%d,%d %d]\n",pixelIndex,r,g,b);
            pixelIndex += left2Right;
          }
        }
        show();
    }
}

//*******************************************************************************
//http://onehourhacks.blogspot.com/2012/03/conways-game-of-life-on-arduino.html
const int ROWS = 48;
const int COLS = 32;
int boardnum = 0; // number of boards run by the game
int iteration = 0; // current round in the current board
int numberAround(int row, int col);

// The "Alive" cells on the board.
uint32_t alive[ROWS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

//*******************************************************************************
bool isAlive(int row, int col)
{
return alive[row] & (1<<(col));
}
//*******************************************************************************
void setAlive(int row, int col)
{
alive[row] |= 1 << col;
}
//*******************************************************************************
/*
 * Sets the alive array to all falses.
 */
void blank_alive()
{
for(int i = 0; i < ROWS; ++i)
 alive[i] = 0;
}
//*******************************************************************************
/**
 * Writes output to the console.
 */
 
void do_output()
{
 //blank();
 //pc.printf("Board: %d",boardnum);
 //pc.printf(" Iteration: %d\n",iteration);
    for(int i = 0; i < ROWS; i++)
    {
     for(int j = 0; j < COLS; j++)
     {
      // WIDTH, HEIGHT
      if(isAlive(i,j))
       {
       setPixelColor(Matrix[i+RowIdx[j]],rand() % BrightMax,rand() % BrightMax,rand() % BrightMax);
       //pc.printf("Alive: %d %d\n",i,j);
       }
      else
       setPixelColor(Matrix[i+RowIdx[j]],0,0,0);
     }
    }
}

/**
 * Randomly fills the grid with alive cells after blanking.
 */
void random_fill()
{
blank_alive();

// Fill up 10-30% of the cells
int numToFill = (ROWS * COLS) * (rand() % 30+10) / 100 ;

for(int r = 0; r < numToFill; r ++)
{
 int row = rand() % ROWS;
 int col = rand() % COLS;
 
 setAlive(row,col);
}
}

/**
 * Returns the index of the row below the current one.
 */
int rowBelow(int row)
{
return (row + 1 < ROWS) ? row + 1 : 0;
}

/**
 * Returns the index of the row above the given one
 */
int rowAbove(int row)
{
return (row > 0) ? row - 1 : ROWS - 1;
}

/** Returns the index of the col to the right of this one */
int colRight(int col)
{
return (col + 1 < COLS) ? col + 1 : 0;
}

/** Returns the index of the col to the left of this one */
int colLeft(int col)
{
return (col > 0) ? col - 1 : COLS -1;
}

/** true if the cell to the left is alive*/
bool left(int row, int col)
{
col = colLeft(col);
return isAlive(row,col);
}

/** true if the cell to the right is alive*/
bool right(int row, int col)
{
col = colRight(col);
return isAlive(row,col);
}

/** true if the cell above is alive*/
bool above(int row, int col)
{
row = rowAbove(row);
return isAlive(row,col);
}

/** true if the cell below is alive*/
bool below(int row, int col)
{
row = rowBelow(row);
return isAlive(row,col);
}

/** true if the cell NE is alive*/
bool aboveright(int row, int col)
{
row = rowAbove(row);
col = colRight(col);
return isAlive(row,col);
}

/** true if the cell SE is alive*/
bool belowright(int row, int col)
{
row = rowBelow(row);
col = colRight(col);
return isAlive(row,col);
}

/** true if the cell NW is alive*/
bool aboveleft(int row, int col)
{
row = rowAbove(row);
col = colLeft(col);
return isAlive(row,col);
}

/** true if the cell SW is alive*/
bool belowleft(int row, int col)
{
row = rowBelow(row);
col = colLeft(col);
return isAlive(row,col);
}

/**Returns the number of living cells sorrounding this one.*/
int numberAround(int row, int col)
{
int around = 0;
if(left(row,col))
 around++;

if(right(row,col))
 around++;

if(above(row,col))
 around++;

if(below(row,col))
 around++;

if(aboveright(row,col))
 around++;

if(aboveleft(row,col))
 around++;

if(belowright(row,col))
 around++;

if(belowleft(row,col))
 around++;

return around;
}

/**
 * Moves all of the cells
 */
void move()
{
uint32_t nextRows[ROWS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0};

for(int i = 0; i < ROWS; i++)
{
 for(int j = 0; j < COLS; j++)
 {
  int na = numberAround(i,j);
  if((na == 2 && isAlive(i,j)) || na == 3)
   nextRows[i] |= 1 << j;
 }
}
for(int i = 0; i < ROWS; i++)
 alive[i] = nextRows[i];
}

//*******************************************************************************
int main() {
    pc.baud(38400);
    setup();
    while (1) {
        pc.printf("Top of the Loop\n");
        bLed = !bLed;
        blankDelay(0);
  
        boardnum++;
        random_fill();
        
        for(iteration = 0;iteration < 500; iteration++)
        {
         do_output();
         show();
         move(); 
         wait_ms(0);
        }
    }
}