digital light wand sketch / triggering different files to different led strips

Hi people!

I am working on a sketch published by mr Ross that allows us to send bmp files to addresable LED strips. It is normally used for “light painting”. you can check detailed info about it in the following link: http://mrossphoto.com/wordpress32/lpd8806-dlw/

There are a couple of different versions, that work with different led strips. I am using a version that controls a WS2801 led strip for a light installation.

The code is done in a way that allows us to navigate through different files stored in a SD card with the keypad from the LCD shield, to finally send the desired file to the led strip + the option to change the frame rate.

I modified the code in order to be able to send the file automatically when the arduino board turns on. Changing the frame rate has to be done then by code. I also edited the code in order to send the same file to 2 different led strips, and it is working fine.

What I would like to do next, is to be able to send different files to different LED strips, and I have been checking it out but I think it is a little bit more complex than what I know how to do, so if somebody would like to give it a try, it would be lovely!!

:slight_smile:

pd. you will se that in the code there is plenty of data that refers to the lcd and to auxiliary buttons. I am not using either the lcd or the auxiliary buttons, but trying to get rid of this codes, I messed it up several times, so I simply gave up and left it there…

ws2811_2strips_9px_1set.ino (14.1 KB)

There was a lot of code related to the LCD Shield, the backlight of the LCD and auxiliary buttons, that was no longer in use, since the sketch I want to have needs no LCD and no buttons to select any file. the file is selected in the code. So I cleaned up the code and deleted (I think) all the code related to these funtionalities.

here goes the code

hope somebody can take a look at it!

ws2811_2strips_9px_1set_no_lcd_no_backlight_no_buttons.ino (5.8 KB)

if I write

void loop()
{
   SendFile1("set01.bmp");
   SendFile2("set02.bmp");
}

set01.bmp is going to be "sent", and when it finishes, set02.bmp is going to be sent. they are not sent simultaneously but one after the other.

how do I write this to send both file simultaneously?

cheers

If you are sending them both out the same serial port, you can't easily.
You could write some code to send a few bytes of one, then the other, and repeat. The receiver would have to handle that as well. Probably need to add some control bytes so the receiver knows which is which - in the end resulting in more data to send and an overall slower transfer rate.
If the data is going to two places you could use a device with 2 serial ports, likely easier to send data to both at the same time.

You create a rift in the time/space continuum and get your other self to send one while you send the other.

duplicating a lot of the code, and numbering the commands 1 and 2, I am able now to send file1 to strip1 and file2 to strip2, but not simultaneously.

Is there a way to send them simultaneously?

I attach the new code

ws2811_2strips_9px_2sets.ino (9.62 KB)

ok. I didn´t expect it to be that complicated, bassically because I still do not understand the whole picture.

I would ask you then @CrossRoads if you could check another post where I present the issue in a little bit more detail.

thanks!

Please don't start multiple topics on the same subject.
Topic Locked.

You have 1 processor, you have 2 interfaces that need to run in parallel, using a chip with a somewhat complicated timing interface.
You’d need to write your own code that could duplicate the timing created while sending out separate data on each.

WS2811-preliminary.pdf (320 KB)

With WS2801, there is a separate clock line, so you can more readily control which strip is getting data, and at a much higher rate.
Still, you only have 1 processor, so you have to select which strip is getting data at any time.
So send 3 bytes to 1, 3 bytes to the other, alternating until all bytes for that frame are done.

WS2801.pdf (423 KB)

Something like this:

#include <Adafruit_NeoPixel.h>
#include <SD.h>
#include <SPI.h>


#define SDssPin 53
int frameDelay = 20;


#define STRIP_LENGTH 9
uint16_t length = 9;

Adafruit_NeoPixel strip1 = Adafruit_NeoPixel(9, 37, NEO_RGB + NEO_KHZ400);
Adafruit_NeoPixel strip2 = Adafruit_NeoPixel(9, 39, NEO_RGB + NEO_KHZ400);


File root;
File dataFile;
String m_CurrentFilename = "";
int m_FileIndex = 0;
int m_NumberOfFiles = 0;
String m_FileNames[200];

long buffer[STRIP_LENGTH];

void setup()
{
  Serial.begin(115200);
  setupLEDs();
  setupSDcard();
}


void setupLEDs()
{
  strip1.begin();
  strip1.show();
  strip2.begin();
  strip2.show();
}


void setupSDcard()
{
  pinMode(SDssPin, OUTPUT);
  while (!SD.begin(SDssPin)) {
  }
}


void loop()
{
  SendFile("set01.bmp", 1);
  SendFile("set02.bmp", 2);
}


void SendFile(String Filename, int strip)
{
  char temp[14];
  Filename.toCharArray(temp,14);
  dataFile = SD.open(temp);

  // if the file is available send it to the LED's
  if (dataFile)
  {
    ReadTheFile(strip);
    dataFile.close();
    ClearStrip(100);
  }  
  else
  {
    delay(1000);
    setupSDcard();
    return;
  }
}


void latchanddelay(int dur)
{
  strip1.show();
  strip2.show();
  delay(dur);
}


void ClearStrip(int duration)
{
  int x;
  for(x=0;x<STRIP_LENGTH;x++)
  {
    strip1.setPixelColor(x, 0);
    strip2.setPixelColor(x, 0);
  }
  strip1.show();
  strip2.show();
  latchanddelay(duration);

}

uint32_t readLong()
{
  uint32_t retValue;
  byte incomingbyte;

  incomingbyte=readByte();
  retValue=(uint32_t)((byte)incomingbyte);

  incomingbyte=readByte();
  retValue+=(uint32_t)((byte)incomingbyte)<<8;

  incomingbyte=readByte();
  retValue+=(uint32_t)((byte)incomingbyte)<<16;

  incomingbyte=readByte();
  retValue+=(uint32_t)((byte)incomingbyte)<<24;

  return retValue;
}

uint16_t readInt()
{
  byte incomingbyte;
  uint16_t retValue;

  incomingbyte=readByte();
  retValue+=(uint16_t)((byte)incomingbyte);

  incomingbyte=readByte();
  retValue+=(uint16_t)((byte)incomingbyte)<<8;

  return retValue;
}

int readByte()
{
  int retbyte=-1;
  while(retbyte<0) retbyte= dataFile.read();
  return retbyte;
}


void ReadTheFile(int strip)
{
#define MYBMP_BF_TYPE           0x4D42
#define MYBMP_BF_OFF_BITS       54
#define MYBMP_BI_SIZE           40
#define MYBMP_BI_RGB            0L
#define MYBMP_BI_RLE8           1L
#define MYBMP_BI_RLE4           2L
#define MYBMP_BI_BITFIELDS      3L



  uint16_t bmpType = readInt();
  uint32_t bmpSize = readLong();
  uint16_t bmpReserved1 = readInt();
  uint16_t bmpReserved2 = readInt();
  uint32_t bmpOffBits = readLong();
  bmpOffBits = 54;

  Serial.println("bmpType = ");
  Serial.println(bmpType,HEX);

  Serial.println("bmpSize");
  Serial.println(bmpSize,DEC);

  Serial.println("bmpReserved1");
  Serial.println(bmpReserved1,DEC);

  Serial.println("bmpReserved2");
  Serial.println(bmpReserved2,DEC);

  Serial.println("bmpOffBits");
  Serial.println(bmpOffBits,DEC);

  /* Check file header */
  if (bmpType != MYBMP_BF_TYPE || bmpOffBits != MYBMP_BF_OFF_BITS)
  {
    delay(1000);
    return;
  }

  /* Read info header */
  uint32_t imgSize = readLong();
  uint32_t imgWidth = readLong();
  uint32_t imgHeight = readLong();
  uint16_t imgPlanes = readInt();
  uint16_t imgBitCount = readInt();
  uint32_t imgCompression = readLong();
  uint32_t imgSizeImage = readLong();
  uint32_t imgXPelsPerMeter = readLong();
  uint32_t imgYPelsPerMeter = readLong();
  uint32_t imgClrUsed = readLong();
  uint32_t imgClrImportant = readLong();


  Serial.println("bitmap height");
  Serial.println(imgHeight,DEC);
  Serial.println("bitmap Width");
  Serial.println(imgWidth,DEC);
  Serial.println("bitmap bpp");
  Serial.println(imgBitCount,DEC);

  /* Check info header */
  if( imgSize != MYBMP_BI_SIZE || imgWidth <= 0 ||
    imgHeight <= 0 || imgPlanes != 1 ||
    imgBitCount != 24 || imgCompression != MYBMP_BI_RGB ||
    imgSizeImage == 0 )
  {
    delay(1000);
    return;
  }

  int displayWidth = imgWidth;
  if (imgWidth > STRIP_LENGTH)
  {
    displayWidth = STRIP_LENGTH;//only display the number of led's we have
  }


  /* compute the line length */
  uint32_t lineLength = imgWidth * 3;
  if ((lineLength % 4) != 0)
    lineLength = (lineLength / 4 + 1) * 4;

  Serial.println("Line Length");
  Serial.println(lineLength,DEC);

  int x = 0;
  for(int y=imgHeight;y>0 ;y--) {

    int bufpos=0;    


    {
      for(int x=0;x <displayWidth  ;x++) {

        uint32_t offset = (MYBMP_BF_OFF_BITS + (((y-1)* lineLength) + (x*3))) ;

        dataFile.seek(offset);

        int g=gamma(readByte());
        int b=gamma(readByte());
        int r=gamma(readByte());

        if (strip == 1) {
          strip1.setPixelColor(x,r,b,g);
        } 
        else {
          strip2.setPixelColor(x,r,b,g);
        }

      }
      latchanddelay(frameDelay);
    }


  }
  Serial.println("Finished");
  ClearStrip(100);
}



PROGMEM prog_uchar const gammaTable[]  = {
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  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,  2,  2,  2,  2,
  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,
  4,  4,  4,  4,  5,  5,  5,  5,  5,  6,  6,  6,  6,  6,  7,  7,
  7,  7,  7,  8,  8,  8,  8,  9,  9,  9,  9, 10, 10, 10, 10, 11,
  11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16,
  16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 21, 21, 21, 22, 22,
  23, 23, 24, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30,
  30, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 37, 37, 38, 38, 39,
  40, 40, 41, 41, 42, 43, 43, 44, 45, 45, 46, 47, 47, 48, 49, 50,
  50, 51, 52, 52, 53, 54, 55, 55, 56, 57, 58, 58, 59, 60, 61, 62,
  62, 63, 64, 65, 66, 67, 67, 68, 69, 70, 71, 72, 73, 74, 74, 75,
  76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
  92, 93, 94, 95, 96, 97, 98, 99,100,101,102,104,105,106,107,108,
  109,110,111,113,114,115,116,117,118,120,121,122,123,125,126,127
};


inline byte gamma(byte x) {
  return pgm_read_byte(&gammaTable[x]);
}

must work, but not simultaneously.

@Luis. Thanks ! It does work and it is actually much simpler that all the mess I have done to make it work.

@CrossRoads: thank you very much for the information you provided. I am certanly not in a level in which I can face this programming. Moreover (and I appreciate your point of view here), sending 2 different files to 2 different led strips is what I am trying to do now to verify its feasibility, but my final idea is to be able to send 10 different files to 10 different strips, or even more. Is this quite preposterous then?

if so, which is the way to control 10 led strips with different information each?

I am personally enjoying very much the possibility of controlling them with a bmp file, since I consider it to be very intuitive. It allows me to imagine what I want, and very easily carry it out.

I have to say also that I have already a solution in my mind, that is sending 1 file to 10mts of led strip, but treating the led strip as 10 separate parts of 1mt.

Then I deal with the information throught the bitmap instead of the code, and instead of connecting the led strips in parallel, I would have them in series.

but, what I was aiming before gives me other possibilities....

and do you think it is perhaps possible to send the same file but with a different frame delay?

I did a tryout, and it didnt work…

#include <Adafruit_NeoPixel.h>
#include <SD.h>
#include <SPI.h>


#define SDssPin 53
int frameDelay1 = 2;
int frameDelay2 = 1;


#define STRIP_LENGTH 9
uint16_t length = 9;

Adafruit_NeoPixel strip1 = Adafruit_NeoPixel(100, 37, NEO_RGB + NEO_KHZ400);
Adafruit_NeoPixel strip2 = Adafruit_NeoPixel(100, 39, NEO_RGB + NEO_KHZ400);


File root;
File dataFile;
String m_CurrentFilename = "";
int m_FileIndex = 0;
int m_NumberOfFiles = 0;
String m_FileNames[200];

long buffer[STRIP_LENGTH];

void setup()
{
  Serial.begin(115200);
  setupLEDs();
  setupSDcard();
}


void setupLEDs()
{
  strip1.begin();
  strip1.show();
  strip2.begin();
  strip2.show();
}


void setupSDcard()
{
  pinMode(SDssPin, OUTPUT);
  while (!SD.begin(SDssPin)) {
  }
}


void loop()
{
  SendFile("set01.bmp");
}


void SendFile(String Filename)
{
  char temp[14];
  Filename.toCharArray(temp,14);
  dataFile = SD.open(temp);

  // if the file is available send it to the LED's
  if (dataFile)
  {
    ReadTheFile();
    dataFile.close();
    ClearStrip(100);
  }  
  else
  {
    delay(1000);
    setupSDcard();
    return;
  }
}


void latchanddelay1(int dur)
{
  strip1.show();
  delay(dur);
}

void latchanddelay2(int dur)
{
  strip2.show();
  delay(dur);
}


void ClearStrip(int duration)
{
  int x;
  for(x=0;x<STRIP_LENGTH;x++)
  {
    strip1.setPixelColor(x, 0);
    strip2.setPixelColor(x, 0);
  }
  strip1.show();
  strip2.show();
  latchanddelay1(duration);
  latchanddelay2(duration);

}

uint32_t readLong()
{
  uint32_t retValue;
  byte incomingbyte;

  incomingbyte=readByte();
  retValue=(uint32_t)((byte)incomingbyte);

  incomingbyte=readByte();
  retValue+=(uint32_t)((byte)incomingbyte)<<8;

  incomingbyte=readByte();
  retValue+=(uint32_t)((byte)incomingbyte)<<16;

  incomingbyte=readByte();
  retValue+=(uint32_t)((byte)incomingbyte)<<24;

  return retValue;
}

uint16_t readInt()
{
  byte incomingbyte;
  uint16_t retValue;

  incomingbyte=readByte();
  retValue+=(uint16_t)((byte)incomingbyte);

  incomingbyte=readByte();
  retValue+=(uint16_t)((byte)incomingbyte)<<8;

  return retValue;
}

int readByte()
{
  int retbyte=-1;
  while(retbyte<0) retbyte= dataFile.read();
  return retbyte;
}


void ReadTheFile()
{
#define MYBMP_BF_TYPE           0x4D42
#define MYBMP_BF_OFF_BITS       54
#define MYBMP_BI_SIZE           40
#define MYBMP_BI_RGB            0L
#define MYBMP_BI_RLE8           1L
#define MYBMP_BI_RLE4           2L
#define MYBMP_BI_BITFIELDS      3L



  uint16_t bmpType = readInt();
  uint32_t bmpSize = readLong();
  uint16_t bmpReserved1 = readInt();
  uint16_t bmpReserved2 = readInt();
  uint32_t bmpOffBits = readLong();
  bmpOffBits = 54;

  Serial.println("bmpType = ");
  Serial.println(bmpType,HEX);

  Serial.println("bmpSize");
  Serial.println(bmpSize,DEC);

  Serial.println("bmpReserved1");
  Serial.println(bmpReserved1,DEC);

  Serial.println("bmpReserved2");
  Serial.println(bmpReserved2,DEC);

  Serial.println("bmpOffBits");
  Serial.println(bmpOffBits,DEC);

  /* Check file header */
  if (bmpType != MYBMP_BF_TYPE || bmpOffBits != MYBMP_BF_OFF_BITS)
  {
    delay(1000);
    return;
  }

  /* Read info header */
  uint32_t imgSize = readLong();
  uint32_t imgWidth = readLong();
  uint32_t imgHeight = readLong();
  uint16_t imgPlanes = readInt();
  uint16_t imgBitCount = readInt();
  uint32_t imgCompression = readLong();
  uint32_t imgSizeImage = readLong();
  uint32_t imgXPelsPerMeter = readLong();
  uint32_t imgYPelsPerMeter = readLong();
  uint32_t imgClrUsed = readLong();
  uint32_t imgClrImportant = readLong();


  Serial.println("bitmap height");
  Serial.println(imgHeight,DEC);
  Serial.println("bitmap Width");
  Serial.println(imgWidth,DEC);
  Serial.println("bitmap bpp");
  Serial.println(imgBitCount,DEC);

  /* Check info header */
  if( imgSize != MYBMP_BI_SIZE || imgWidth <= 0 ||
    imgHeight <= 0 || imgPlanes != 1 ||
    imgBitCount != 24 || imgCompression != MYBMP_BI_RGB ||
    imgSizeImage == 0 )
  {
    delay(1000);
    return;
  }

  int displayWidth = imgWidth;
  if (imgWidth > STRIP_LENGTH)
  {
    displayWidth = STRIP_LENGTH;//only display the number of led's we have
  }


  /* compute the line length */
  uint32_t lineLength = imgWidth * 3;
  if ((lineLength % 4) != 0)
    lineLength = (lineLength / 4 + 1) * 4;

  Serial.println("Line Length");
  Serial.println(lineLength,DEC);

  int x = 0;
  for(int y=imgHeight;y>0 ;y--) {

    int bufpos=0;    


    {
      for(int x=0;x <displayWidth  ;x++) {

        uint32_t offset = (MYBMP_BF_OFF_BITS + (((y-1)* lineLength) + (x*3))) ;

        dataFile.seek(offset);

        int g=gamma(readByte());
        int b=gamma(readByte());
        int r=gamma(readByte());
        strip1.setPixelColor(x,r,b,g);
        strip2.setPixelColor(x,r,b,g);

      }
      latchanddelay1(frameDelay1);
      latchanddelay2(frameDelay2);
    }


  }
  Serial.println("Finished");
  ClearStrip(100);
}



PROGMEM prog_uchar const gammaTable[]  = {
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  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,  2,  2,  2,  2,
  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,
  4,  4,  4,  4,  5,  5,  5,  5,  5,  6,  6,  6,  6,  6,  7,  7,
  7,  7,  7,  8,  8,  8,  8,  9,  9,  9,  9, 10, 10, 10, 10, 11,
  11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16,
  16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 21, 21, 21, 22, 22,
  23, 23, 24, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30,
  30, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 37, 37, 38, 38, 39,
  40, 40, 41, 41, 42, 43, 43, 44, 45, 45, 46, 47, 47, 48, 49, 50,
  50, 51, 52, 52, 53, 54, 55, 55, 56, 57, 58, 58, 59, 60, 61, 62,
  62, 63, 64, 65, 66, 67, 67, 68, 69, 70, 71, 72, 73, 74, 74, 75,
  76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
  92, 93, 94, 95, 96, 97, 98, 99,100,101,102,104,105,106,107,108,
  109,110,111,113,114,115,116,117,118,120,121,122,123,125,126,127
};


inline byte gamma(byte x) {
  return pgm_read_byte(&gammaTable[x]);
}