Neopixel and SD card

Hi all,

I have been trying to get this code to work this whole morning with no success. It is supposed to read LED values stored in a test.txt file on a sd card. And I do get the output on the Serial monitor, but for some reason it just doesnt light up the LEDs.

I have also tried just lighting up one LED with given values rather than the ones in the file, no success. The strip does work, i have tested it with the neo pixel demo library. I just don't understand what is wrong.

Here is my code, any help will be greatly appreciated.

#include <Time.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif
#include <SPI.h>
#include <SD.h>

Sd2Card card;
SdVolume volume;
SdFile root;

const int chipSelect = 4;

#define PIN            6
#define NUMPIXELS      400

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

char inputString[5000];         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete
boolean readarray=false;
String inString = "";
int c=0;
int cc=0;
int led=0;
int i=0;
int j=0;
int pixel_n=0;
unsigned long start;
unsigned long endd;

//char* ledd[]={"", "", ""};
int ledd[3]={0,0,0};

File myFile;

void setup() {
  Serial.begin(115200);
  SD.begin(4);

  pixels.begin(); // This initializes the NeoPixel library.

  myFile = SD.open("test.txt");

  while (myFile.available()) {
    
      char inChar = myFile.read();
      
      if (isDigit(inChar)) {
        inString += (char)inChar;
      }

      if (inChar == '(') {
      led=led+1;

    }
    
    if (inChar == ',') {
      ledd[c]=inString.toInt();
      inString="";
      c=c+1;
    }

    if (inChar == ')') {

      ledd[c]=inString.toInt();
      inString="";

      pixels.setPixelColor(led, pixels.Color(ledd[0],ledd[1],ledd[2])); // THIS DOES NOT SEEM TO WORK
      pixels.show(); // THIS EITHER. IT DOESNT LIGHT UP THE LEDS
      
      Serial.println(ledd[0]);
      Serial.println(ledd[1]);
      Serial.println(ledd[2]);
    
      Serial.println("END OF LED ");
      Serial.println(led);
      c=0;
      
    }

    if (inChar=='*') {
      Serial.write("NEXT FRAME");
      
      myFile.close();
      break;
    }   
  }
}

void loop() {

}
pixels.setPixelColor(led, pixels.Color(ledd[0],ledd[1],ledd[2])); // THIS DOES NOT SEEM TO WORK
      pixels.show(); // THIS EITHER. IT DOESNT LIGHT UP THE LEDS

Because it is not how the call works.
The first parameter is the LED number, the second is the colour. What you have written is a nonsense.

I hear you but how is this a nonsense?

the variable led is a number, and the array ledd[] contains the led rgb values as ints. How is this a nonsense?

I have tried with the following as well:

pixels.setPixelColor(i, (250,250,250));

It just doesn't work. The data LED doesn't even light up the Arduino.

the variable led is a number, and the array ledd[] contains the led rgb values as ints. How is this a nonsense?

Because that call expects ONE number not an array of numbers.

Yes, ledd[0], ledd[1], ledd[2] all contain an individual number, do they not?

I thought maybe the problem was in the minimal code, with my variables declarations and libraries.

I tried this:

#include <Time.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define PIN            6
#define NUMPIXELS      400

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);


void setup() {
  Serial.begin(9600);
  pixels.begin(); // This initializes the NeoPixel library.
      for (int i=0; i<NUMPIXELS;i++) {
    pixels.setPixelColor(i, (0,0,0));
  }
  pixels.show();

  delay(2000);
}

void loop() {

  for (int i=0; i<NUMPIXELS;i++) {
    pixels.setPixelColor(i, (25,250,250));
  }

  pixels.show();

  delay(20000);
  
}

Works like a charm. But if I add this extra code at the top, it doesn't work anymore. The LEDs don't respond.

#include <Time.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif
#include <SPI.h>
#include <SD.h>

Sd2Card card;
SdVolume volume;
SdFile root;

const int chipSelect = 4;

#define PIN            6
#define NUMPIXELS      400

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

boolean stringComplete = false;  // whether the string is complete
boolean readarray=false;
String inString = "";
int c=0;
int cc=0;
int led=0;
int i=0;
int j=0;
int pixel_n=0;
unsigned long start;
unsigned long endd;

//char* ledd[]={"", "", ""};
int ledd[3]={0,0,0};

File myFile;


void setup() {
  Serial.begin(9600);
  pixels.begin(); // This initializes the NeoPixel library.
      for (int i=0; i<NUMPIXELS;i++) {
    pixels.setPixelColor(i, (0,0,0));
  }
  pixels.show();

  delay(2000);
}

void loop() {

  for (int i=0; i<NUMPIXELS;i++) {
    pixels.setPixelColor(i, (25,250,250));
  }

  pixels.show();

  delay(20000);
  
}

Can it be a library/variable conflict?

I have tried the following simple code and it works, so it's not that @Grumpy_Mike:

  for (int i=0; i<NUMPIXELS;i++) {
    pixels.setPixelColor(i, (ledd[0],ledd[1],ledd[2]));
  }

It's when I include the SD libraries that it doesn't respond anymore. This is driving me crazy.

Maybe the Arduino cannot communicate with the SD card and the LED strip at the same time. So I tried storing each frame in a frame array matrix[400][3], then go through the array and light up the leds, and then flush the array at the end of each frame, but I get a memory error of course.

My problem seems related to this issue here:

The SPI bus apparently messes with the pins. So I need to close it after reading, except I need to send data to the strip while reading on the sd card.

But your code is not using pin 13 is it?

It's not, but it is clearly affecting my code. I am using pin 4 for SD card reading, and pin 6 for LED strip data line. When I do not include the libraries or initiate the SD card, everything is smooth. When I do include the SD libraries or try to interact with the SD card, I cannot send data to the LED strip anymore.

So it is the SD library for sure.

If at least I could first read the array on the SD card, close the SPI, store the array temporarily and use it, but I can't, my matrix is 400 x 3 rgb values.

This is really problematic. I have read about SDFat.h which apparently contains update for better SPI behavior. Any info on that? This is extremely inconvenient and problematic.

Just try and read one LEDs worth of data in, then shut down the SD card and try and write to the LEDs. It will tell you if that is the possibility of a fix.

Ok, thank you for your help again Grumpy_Mike,

I will try that tomorrow morning, for now I'm working on my animations!

I just tried. No luck. Even with SPI.end(). I just cannot access the strip anymore.

#include <Time.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif
#include <SPI.h>
#include <SD.h>

Sd2Card card;
SdVolume volume;
SdFile root;

const int chipSelect = 4;

#define PIN            6
#define NUMPIXELS      400

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

boolean stringComplete = false;  // whether the string is complete
boolean readarray=false;
String inString = "";
int c=0;
int cc=0;
int led=0;
int i=0;
int j=0;
int pixel_n=0;
unsigned long start;
unsigned long endd;

//char* ledd[]={"", "", ""};
int ledd[3]={0,0,0};

File myFile;

void setup() {


  pixels.begin(); // This initializes the NeoPixel library.
  pixels.show();

    Serial.begin(9600);
  SD.begin(4);


  myFile = SD.open("test.txt");

  while (myFile.available()) {
    
      char inChar = myFile.read();
      
      if (isDigit(inChar)) {
        inString += (char)inChar;
      }

      if (inChar == '(') {
      led=led+1;

    }
    
    if (inChar == ',') {
      ledd[c]=inString.toInt();
      inString="";
      c=c+1;
    }

    if (inChar == ')') {

      ledd[c]=inString.toInt();
      inString="";
      
      Serial.println(ledd[0]);
      Serial.println(ledd[1]);
      Serial.println(ledd[2]);
    
      Serial.println("END OF LED ");
      Serial.println(led);
      c=0;
      
    }

    if (inChar=='*') {
      Serial.write("NEXT FRAME");

      myFile.close();
      SPI.end();
      Serial.println("Ok we're done");
      delay(2000);

      pixels.setPixelColor(5, (200,200,200));
      pixels.show();
      break;
    }   
  }
  
}

void loop() {

}

Tried with the SdFat.h, no luck either.

It's really odd, this is a very common way of doing. I'm trying to find animation scripts.

pixels.setPixelColor(5, (200,200,200));

No that's not right how about

pixels.setPixelColor(5, pixels.Color (200,200,200));

Any option or help is greatly appreciated.

I posted here: neopixel - LED strip and SD card - Arduino Stack Exchange

This guy is advising me to go for this: Adafruit Assembled Data Logging shield for Arduino : ID 1141 : $13.95 : Adafruit Industries, Unique & fun DIY electronics and kits

Except I am not positive this will actually solve my problem. Is there not an option with a regular sd card reader? I have this one: here

EDIT: Sorry GrumpyMike didn't see your message. No this is not changing anything, either way the data led on the arduino doesn't even light up. It's just not sending anything, I believe the SPI.h allocates all the pins making them unusable for something else than the sd card.
There's gotta be a way to cope with that.

I believe the SPI.h allocates all the pins making them unusable for something else than the sd card.

No that is not true. I have used an SD card and A/D bit banged on pins and two things on the I2C bus, so it is possible to use other pins with the SD card.

Your reply said:-

I had the same problem with using the SD reader with a SPI SRAM. It turns out that the very cheap SD reader cards do not like multiple SPI components on the same port.

This is nothing like the problem you described, you have not got two devices on the SPI bus. Getting that card will not help you.

What Arduino are you using? You are using 5K as an input buffer, you might be running out of memory.

I am using the latest available Arduino Uno.

The animations I store on the sd card are stored as follows:

FRAME delimiter
400 rgb values as follows: (250,250,250)
END FRAME delimiter

There can be up to 500 frames per animation, and I need a lot of animations (dozens). My micro sd is 16gb so the issue is not the storage memory, but as you say maybe the input buffer.

In which case, what would the solution be?

Thanks for all your help.

I am using the latest available Arduino Uno.

The Uno only has 2K of memory. You use 1.5K for your led array and then want 5.1K as a buffer for the SD card. Can you see why it is not working?
You need to cut down on the buffers. Why do you need to read the whole of the frame array in and in ASCII? Do not have an SD buffer, simply have the frame data in hex in the SD card, read the SD card and then store it in the pixel buffer ( pixel.set ). You might get away with that but even then it will be touch and go.

If you get a Mega that has 8K of memory, if you need more then you will have to go for an Arduino Zero.