I am currently in the middle of creating a Persistence of Vision Display project using an Arduino Nano; The POV display code would access the color values held in an array and send them to the LEDs. Using an SD card to store the bitmap images converted into a 24bits array due to the limited storage of the Arduino Nano, the only issue now is getting the main POV display code to use the 24bits array in the SD file. Any ideas or inputs on how I could approach this idea is greatly appreciated as I am still relatively new in the coding language Arduino uses.
Below is the POV display code:
/*
*This sketch outputs images to persistence of vision led strips
*It uses FastLed to drive APA102 leds, sending colour values from
*arrays held in flash memory (designated by 'const'). You need to
*set the number of slices you have made your image into,
*e.g. bmp image of 60 pixels high by 150 wide
* would give 60 num_leds and
* 150 slices (number of slices you have made your image into)
*/
#include "FastLED.h"
#include <SD.h>
#include <SPI.h>
#define NUM_LEDS 72 //number of leds in strip length on one side
#define DATA_PIN 2 //7 = second hardware spi data
#define CLOCK_PIN 13 //D13; was supposed to be second hardware spi clock, WS2812B doesn't have one so we combine it instead and hope for the best
CRGB leds[NUM_LEDS];
int numberOfSlices = 150;
int CS_PIN = 10;
File dataFile = SD.open("ImageArrayHeader.h", FILE_WRITE);
void setup() {
Serial.begin(9600);
pinMode (CS_PIN, OUTPUT);
delay(200);
// access the image array file
if (dataFile) {
while (dataFile.available()) {
Serial.write(dataFile.read());
}}
// FastLED.addLeds<WS2812B, DATA_PIN, CLOCK_PIN>(leds, NUM_LEDS); was used in the initial example but again, our LED strip only features a data slot and two voltage slots.
FastLED.addLeds <WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
}
void loop() {
PoiSonic(2000, dataFile); //call method, with duration to show (2sec) and array name.
}
void PoiSonic(int long time, int array0[]) {
int long currentTime = millis();
while (millis() < currentTime + (time)) {
int f = numberOfSlices;
int z; //a counter
int j = NUM_LEDS;
for (int x = 0; x < f; x++) {
for (z = NUM_LEDS; z > 0; z--) {
leds[z - 1] = array[x + ((j - z) * f)];
}
FastLED.show();
delayMicroseconds(40); //may need to increase / decrease depending on spin rate
}
delayMicroseconds(1000); //may need to increase / decrease depending on spin rate
}
}
With my current code I get these errors:
POV_Display_Code1.ino: In function 'void loop()':
POV_Display_Code1.ino:36:28: error: cannot convert 'SDLib::File' to 'int*' for argument '2' to 'void PoiSonic(long int, int*)'
POV_Display_Code1.ino: In function 'void PoiSonic(long int, int*)':
POV_Display_Code1.ino:49:25: error: 'array' was not declared in this scope
Error compiling.
I suggest to start by learning to read the datafile, using a small, dedicated program. There are many examples in the SD library to help you get started.
For informed help, please describe the contents of the file "ImageArrayHeader.h" and explain how it was written.
The first and most obvious mistake is opening a file to WRITE when you intend to READ.
Depending on the size of this file, is it the sort of thing that could live in a new Arduino tab or maybe just move to PROGMEM or do you think reading from SD cards is simpler, ultimately?
Oh, not sure if it's clear, this is a question I have for @jremington
It would take quite a bit of code and work to parse that text file (header code) and convert to a binary array of data in memory, to send to the display.
It is possible to read and write files in binary, or in much simpler-to-parse text formats, like .csv (comma separated values).
It would be a good idea to rethink how to put the data onto the SD card in a format that would be easy to read.
Easiest to read would likely be to store the data as binary, in the same Red/Green/Blue order as is used by FastLED in the led array, then directly write to the led array, bypassing the FastLED functions. That would be faster than any method requiring parsing or conversion from ASCII to binary.
How many patterns do you have? With 72 LEDs, each pattern would take 216 bytes, giving you room to store about 120 patterns with the current code (once the SD commands are removed).
ok, so no chance of just shifting the whole thing to another place in Arduino memory? How large is the file?
I ask because I like the Nano Every, it has extra memory and my projects use lots of Strings for printing to the serial monitor, lots of String objects that would probably make the real gurus here (I am not one) cringe and I have managed to never need an SD card unless I was calling .wav files. (I'm gradually working through better arrays and pointers, @Delta_G ! I'm trying, honest!)
instead of storing code in the file on the SD card
store only the values, may be one per line, in ASCII and force the leading 0s (if any) to be there
1c1b1c
1b1a1b
1a1a1b
012345 <== make sure to have the leading 0
. . .
5f0c06
5e0c05
650b04
98261c
then this way each line has the exact same length (6 characters and a CR LF) and it's easy to access the file either sequentially or jump to a specific index
By patterns do you mean the converted bitmap images? If so, as of right now I only have one prepared as I planned on preparing more once I've properly got the POV display code working.
In regards to storing the data as binary, any idea on how I can directly write to the LED array with the binary data? I recall seeing other examples of POV projects that used single color LEDs with the code manually set to instruct each LEDs based on a given binary data but I initially didn't look too much into it as I thought I needed something more convenient as I am using RGB LEDs. Could it be the same concept?
The overall size of the "ImageArrayHeader.h" file is 292KB. Unfortunately I am running on a limited time scale so as much as possible I'm trying to work with what I have available currently. The Nano Every does seem interesting, at the very least I'll keep it in mind for when I have the time to properly fine tune certain parts in my POV project!
That could be roughly 90K bytes of actual data, too much for program memory on a Nano. It might be possible to compress the data, if you are only using a limited number of colors for the LEDs.
You should not open the file in the global variables, the SD.begin() function needs to be called first.
The SD library uses filenames in the 8.3 format, up to 8 characters for the filename and up to 3 characters for the extension.
The SD card data is normally accessed sequentially, if you want random access then you can use seek(), but that requires a very strict file format so that you can calculate positions correctly.
The time needed to read from the SD card will not be consistent for each set of LED data, depending on whether the data crosses the boundary of the SD library's 512 byte buffer. Adding random access to this will greatly increase the read time.
I have my doubts about achieving your desired results when I see the 40uS delay. Updating the LED strip alone will take 2.16mS for 72 LEDs.
Could I use some kind of method wherein I split the data into series and feed it to the Nano sequentially?
I initially opened the file in the global variables because it is used in both the void setup and void loop functions. In regards to needing the SD.begin() function, do you mean something like this?
I am unaware of the filename format for the SD library, I'll change it.
I think I'll let the SD card data be accessed sequentially. My current goal is figuring out how to get the array onto the POV code. I might try using a different image array meant for 34 LEDs just so that I can test the POV display code properly without the potential issue of size, before moving on the current issue with the 24bit array I have prepared that's meant for 72 LEDs.
Currently I am trying to redo the "ImageArrayHeader.h" file so that the converted 24bit array is stored as binary, but besides that I remain unsure on how I can approach the issue of the size of the 24bits array meant for 72 LEDs I have for the image.
Arduino Due has 512KB flash memory. I just had another look. Now, I'm not saying you should listen to me because my Arduino project architecture is what you might call, the "Brutal" style, but I would be looking to getting this off an SD card to begin with. I have used these for audio with Adafruit Wave shield: there's always a bit of a read delay (that doesn't matter for my purposes). Will it matter for yours? I don't know.
I'm a goal oriented guy though. I don't care for elegance if my way gets the job done. What I can say is that my Arduino projects work, year after year and my Arduino projects are way more elaborate than my education or skill have any business building.
Can I ask a pro? @Delta_G is it possible to stuff all the SD card data in @heatherscornnuts ' project into PROGMEM on say, an Arduino Due and access it fast enough for a POV LED project? I'm not asking you to stoop to my level of debauchery but is it possible?
Again, I don't know. I'm just saying that's the approach my knuckledragging style would pursue, especially if time was tight.