I am trying to create a large-dish array with three dimensions. It is declared as follows:
byte LED [20] [2] [20]={{},{},{}};
I want to fill in the values by reading them from an SD text file and stuffing the numbers in via nested loops. x and y are the loop values that run from 0 to 19 each. Inside the loops I use the following code:
byte red = dataFile.parseInt();
byte green = dataFile.parseInt();
byte blue = dataFile.parseInt();
LED[y][0][x] = red;
LED[y][1][x] = green;
LED[y][2][x] = blue;
I then output the values to the serial monitor. The program stops reading values from the dataFile after about 69 values, and just starts reading zeros. The program slows to a crawl at that point too, as if the parsInt() is timing out.
If I comment out the LED[y][0][x] = red, green and blue lines, the program runs fine and reads all values from the SD file and prints them to the Serial Monitor.
AND, if I define the ARRAY like this:
byte LED [1] [2] [1]={{},{},{}}; //way too small to hold all the data
The behavior is identical. It reads from the file and writes to the array up to about 69 numbers and then starts writing zeros. So it is writing beyond the bounds of the defined array.
I am using a mega board, so there is lots of flash available. Am I overwriting memory some how? Is the definition of the array not reserving memory for the values? Very confused...
// Adafruit SPI Flash FatFs Simple Datalogging Example
// Author: Tony DiCola
//
// This is a simple example that opens a file and prints its
// entire contents to the serial monitor. Note that
// you MUST have a flash chip that's formatted with a flash
// filesystem before running, and there should be some sort
// of text file on it to open and read. See the fatfs_format
// example to perform this formatting, and the fatfs_datalogging
// example to write a simple text file.
//
// Usage:
// - Modify the pins and type of fatfs object in the config
// section below if necessary (usually not necessary).
// - Upload this sketch to your M0 express board.
// - Open the serial monitor at 115200 baud. You should see the
// example start to run and messages printed to the monitor.
// If you don't see anything close the serial monitor, press
// the board reset buttton, wait a few seconds, then open the
// serial monitor again.
#include <SPI.h> #include <SD.h>
const int chipSelect = 10;
const String filename ="test.txt"; //name of file to read
//for NeoPixels: #include <Adafruit_NeoPixel.h> #ifdefAVR #include <avr/power.h> #endif
// Which pin on the Arduino is connected to the NeoPixels? #define PIN 4
// How many NeoPixels are attached to the Arduino?
// door is 2 meters tall = 120 LEDs or 180 LED (if rt angle strip) #define NUMPIXELS 20
int delayval = 50; // delay
//uint32_t array [10][10][10]={}; // a check to see if this multi-diemsional 32 bit array was valid-YES
const int FloorCount = 1;
const int NUMROWS = NUMPIXELS * FloorCount;
const int NUMLAYERS = 20; //depth of annimation layers
long P = -1; // pointer to starting place in array (gets incremented by 1 each loop)
//double np = NUMPIXELS;
// double index = FloorCount;
Adafruit_NeoPixel pixel = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_RGB + NEO_KHZ800);
//int LED [NUMROWS] [2] [NUMLAYERS]={{},{},{}};
byte LED [20] [2] [20]={{},{},{}};
void setup() {
pixel.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
pixel.show(); // Turn OFF all pixels ASAP
char delimiter = ','; // this char stops the file read for a number
// Initialize serial port and wait for it to open before continuing.
Serial.begin(115200);
while (!Serial) {
delay(100);
}
//Here we read from the file on the SD card
Serial.println("Initializing SD card...");
delay(1000);
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
while (1);
}
Serial.println("card initialized.");
delay(1000);
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
File dataFile = SD.open(filename);
//loop here to read flash values into LED matrix
//if the file is available, write to it:
if (dataFile) {
while (dataFile.available()){
for (int x=0; x < NUMLAYERS; x++){ //number of annimation layers or frames
Serial.print("new column ");
Serial.println(x);
for (int y=0; y < NUMROWS; y++){ //number of rows (leds * floors)
Serial.print("reading from SD file ");
byte red = dataFile.parseInt();
byte green = dataFile.parseInt();
byte blue = dataFile.parseInt();
void loop() {
Serial.println("we made it to Void Loop()");
// P = P+1; //index starting point to load colors
// if (P > NUMPIXELS*(FloorCount)) P=-1; //go back to top floor //Serial.println("Next Loop:");
for (int j=0; j < NUMLAYERS; j++){ //number of annimation layers or frames
for(int i=0;i<NUMPIXELS;i++){ //loop through pixels in first annimation frame
pixel.setPixelColor(i,LED[i][0][j], LED[i][1][j], LED[i][2][j]); //load in the colors
Serial.print(j);
Serial.print(", ");
Serial.print(i);
Serial.print(", ");
Serial.println(LED[i][0][j]);
//delay(20);
}
pixel.show();
delay(delayval);
}
}
'blue' gets stored somewhere, but not in a location that doesn't exist. if the 2nd dimension has a size of 2, that means it can have either '0' or '1' as an index, but not '2'
And what is requested in reply #6 so we can read the rest of your code properly. Please remove excess comments and use ctrl-T to auto-format the code.
// Initialize serial port and wait for it to open before continuing.
Serial.begin(115200);
while (!Serial) {
delay(100);
}
It might help if you used more common names for things.
What model of Arduino are you using? When I compiled for an UNO I couldn't have more than 7 frames of animation before I got the "Low Memory" warning. 20 frames used 110% of available memory.
If you run out of memory you could try loading each frame from the file. That way you only need one frame in memory at a time. I don't know if the SD card is fast enough but if it is you could get unlimited frames and more pixels in your animations.
#include <SD.h>
const int SDChipSelect = 10;
const String filename = "test.txt"; //name of file to read
//for NeoPixels:
#include <Adafruit_NeoPixel.h>
const byte StripPin = 4;
const int NUMFRAMES = 7; // Number of animation frames
const int NUMPIXELS = 20; // Pixels per frame
byte LED[NUMFRAMES][NUMPIXELS][3]; // Three colors per pixel
const unsigned long TIME_BETWEEN_FRAMES = 50;
Adafruit_NeoPixel pixel = Adafruit_NeoPixel(NUMPIXELS, StripPin, NEO_RGB + NEO_KHZ800);
void setup()
{
pixel.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
pixel.show(); // Turn OFF all pixels ASAP
// Initialize serial port and wait for it to open before continuing.
Serial.begin(115200);
while (!Serial)
{
delay(100);
}
//Here we read from the file on the SD card
Serial.println("Initializing SD card...");
// see if the card is present and can be initialized:
if (!SD.begin(SDChipSelect))
{
Serial.println("Card failed, or not present");
// don't do anything more:
while (1);
}
Serial.println("card initialized.");
delay(1000);
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
File dataFile = SD.open(filename);
//loop here to read values into LED matrix
//if the file is available, write to it:
if (dataFile)
{
for (int f = 0; f < NUMFRAMES; f++) //number of annimation frames
{
Serial.print("new frame ");
Serial.println(f);
for (int p = 0; p < NUMPIXELS; p++) //number of pixels per frame
{
Serial.print("reading from SD file ");
if (!dataFile.available())
{
Serial.print("Error: Out of file data at Frame ");
Serial.print(f);
Serial.print(", Pixel ");
Serial.println(p);
while (1) {}
}
LED[f][p][0] = dataFile.parseInt(); // Red
LED[f][p][1] = dataFile.parseInt(); // Green
LED[f][p][2] = dataFile.parseInt(); // Blue
Serial.print("Frame ");
Serial.print(f);
Serial.print(", Pixel ");
Serial.print(p);
Serial.print(": ");
Serial.print(LED[f][p][0]);
Serial.print(", ");
Serial.print(LED[f][p][1]);
Serial.print(", ");
Serial.println(LED[f][p][2]);
}
}
dataFile.close();
}
//dataFile.close();
else
{
Serial.println("error opening data file.");
while (1) {}
}
}
void loop()
{
Serial.println("we made it to Void Loop()");
for (int f = 0; f < NUMFRAMES; f++) //number of annimation frames
{
for (int p = 0; p < NUMPIXELS; p++) //loop through pixels in first annimation frame
{
pixel.setPixelColor(p, LED[f][p][0], LED[f][p][1], LED[f][p][2]); //load in the colors
}
pixel.show();
delay(TIME_BETWEEN_FRAMES);
}
}
That's it! I was mistakenly thinking because the array is zero based, "2" meant there entries. When I changed it to "3", the program behave as expected. Thanks!
John, Sound like we are doing similar things. I am using the Arduino mega, and am now running out of space for the array as you suggested.
The project is a little strange. It's an art installation in our guest powder room that simulates an elevator experience (as if you were inside it). There is a control panel with buttons, a display, and sounds (run by a Rasperry pi). There are a pair of sliding doors in the powder room (for access to our water heater and heater). I want a strip of neopixels to illuminate the gap between the doors to simulate what you might see when going from floor to floor through the crack. Of course I want to animate each floor as it "goes by". For example a disco party on floor 2 with lights flashing.
I have 5 floors total. The gap is illuminated by 180 right angle neo-pixels. If I want the animation to be 40 frames, then that's 5 X 180 X 40 x 3 colors is array elements = 108,000 That's not going to fit in ram. It might fit if there was a way to store the array to flash (256k flash on the Mega), but I don't know how to to that, or even if it is possible. Would the "const" definition work? The array never changes once filled...
Otherwise I will need to load smaller bits of numbers from the file which might be to slow (16mhz clock) and might be a pain to figure out as the file is not random access.
Any help is greatly appreciated, as I am a mechanical engineer, not a programmer.
If it works on a Mega now, to your satisfaction, then i wouldn't change it. PROGMEM Is an option that will probably fit. I need to suggest to use a board that has more resources though, like a nodeMCU with which you can expand easily and can create a user friendly UI, and can store everything in SPIFFS and the whole animation in RAM. Still if you are not really a programmer, this would mean quite a bit of work.
If your data extends beyond the first 64k of FLASH you will need to use pgm_read_byte_far(address) to read each byte. For 'address' you can let the compiler do the math:
byte red = pgm_read_byte_far(&LED[f][p][0]);
byte green = pgm_read_byte_far(&LED[f][p][1]);
byte blue = pgm_read_byte_far(&LED[f][p][2]);