Tuesday, March 28, 2017

Arduino Powered WS2812 LED Strips turned into 8x75 Array

I found out that there is a 512 LED limit on running continuous LED arrays from one output of the Arduino.  Then I discovered an alternate setup that can run 1200 addressable LED's from an Arduino.  The alternate method uses the parallel output mode to run 8 strings at the same time.  So far I am just testing the setup to see if it works.

This picture shows the  wiring, it is much easier than any other method of running the addressable LED strings.  Since I only have four strings of 150 LED's they are split in half to make 8 strings of 75 LED's each.

Here is my first test program running.  I changed the default array of patterns into some text.

I have improved the code to support longer strings:

It now has the ability to do 8 colors and use a character generator!

Here is the video on YouTube:


The sign now breaks down into sections that are each 40 inches long.  That is done with eight 3 pin plugs that are identical to what comes on the LED strips.

Here is the code so far:
// BOB Davis Enhanced Version for sending data to 8 Parallel WS2812 strings

// PORTD is Digital Pins 0-7 on the Uno change for other boards.
#define PIXEL_PORT  PORTD  // Port of the pin the pixels are connected to
#define PIXEL_DDR   DDRD   // Port of the pin the pixels are connected to

// These are the timing constraints taken mostly from the WS2812 datasheets
#define T0H  400    // Width of a 0 bit in ns
#define RES 6000    // Width of the low gap between bits to cause a frame to latch

// Here are some convience defines to generate actual CPU delays
#define NS_PER_SEC (1000000000L)  // Note that this has to be SIGNED
#define CYCLES_PER_SEC (F_CPU)
#define NS_PER_CYCLE ( NS_PER_SEC / CYCLES_PER_SEC )
#define NS_TO_CYCLES(n) ( (n) / NS_PER_CYCLE )

// Actually send the next set of 8 WS2812B encoded bits to the 8 pins.
// We must to drop to assembler to ensure proper timing
static inline __attribute__ ((always_inline)) void sendBitX8( uint8_t bits ) {
    const uint8_t onBits = 0xff;    // to send all bits on
    const uint8_t offBits = 0x00;   // to send all bits off
    asm volatile (
      "out %[port], %[onBits] \n\t"   // 1st step - send T0H high
      ".rept %[T0HCycles]     \n\t"   // Execute NOPs to delay
        "nop                  \n\t"
      ".endr                  \n\t"
      "out %[port], %[bits]   \n\t"   // Set the output bits to their values
      ".rept %[T0HCycles]     \n\t"   // Execute NOPs to delay
        "nop                  \n\t"
      ".endr                  \n\t"
      "out %[port], %[offBits]\n\t"   // last step set all bits low
      ::
      [port]    "I" (_SFR_IO_ADDR(PIXEL_PORT)),
      [bits]    "d" (bits),
      [onBits]   "d" (onBits),
      [offBits]   "d" (offBits),
      [T0HCycles] "I" (NS_TO_CYCLES(T0H) - 2)   // 1-bit width less overhead
    );
}

// Set default color for letters 1=red, 2=blue, 0=green
int color=0;

static inline void __attribute__ ((always_inline)) sendPixelRow( uint8_t row ) {
  // Send the bit 8 times down every row, each pixel is 8 bits each for R,G,B
  for (int c=0; c<3; c++) {
    for (int bit=0; bit<8; bit++){    
      if (color==c)sendBitX8( row );
      else sendBitX8( 0x00 );
    }
  }
}
 
byte cha[]={  // Can be hex or binary-easier to read
  0x80, 0x80, 0xff, 0x80, 0x80, 0x00, //T
  B11111111,  B10010001,  B10010001,  B10010001,  B10010001,  B00000000, //E
  B01100001,  B10010001,  B10010001,  B10010001,  B10001110,  B00000000, //S
  B10000000,  B10000000,  B11111111,  B10000000,  B10000000,  B00000000, //T
  B00000000,  B10000001,  B11111111,  B10000001,  B00000000,  B00000000, //I
  B11111111,  B01100000,  B00011000,  B00000110,  B11111111,  B00000000, //N
  B01111110,  B10000001,  B10000001,  B10000101,  B01100110,  B00000000, //G
  B00000000,  B01000001,  B11111111,  B00000001,  B00000000,  B00000000, //1
  B01000001,  B10000001,  B10000111,  B10011001,  B01100001,  B00000000, //2
  B10000001,  B10010001,  B10010001,  B10010001,  B01101110,  B00000000, //3
  B00011000,  B00101000,  B01001000,  B10001000,  B11111111,  B00000000, //4
  B11110001,  B10010001,  B10010001,  B10010001,  B10001110,  B00000000, //5
};

void setup() {
  PIXEL_DDR = 0xff;    // Set all row pins to output
}

void loop() {
  cli();           // No time for interruptions!
  for (int l=0; l<72; l++){  // 66 is number of bytes to send
    sendPixelRow(cha[l]);
  }
  sei();
  delay(10);      // Wait more than RESET timeout to latch into the LEDs
  return;
}

No comments: