Guidance for Arduino Controlled Multi- LED Radial Matrix

Hi All -

I just got my Arduino yesterday and I’ve gone through a few basic exercises and think I have a pretty good grasp on the concepts. Got some lights and switches working while playing w/ the included starter kit examples. Gone through a ton of youtube videos and learned a lot researching prior posts. I’m just not sure how to proceed.

I’d like to create a radial matrix of 36 LEDs - attached a diagram. The ones I’m currently using have 3 diodes per module, so I guess that’d be 36 modules - attached a photo of that too. Each module pulls .72W (.24W per diode). I have a separate power supply for the LEDs if necessary. (That’s a whole setup that confuses me - how I can control power via the Arduino, but it need not be coming from the board itself? I think my setup would require more power than the board could handle.)

I’m not sure what would be the best circuit design and offer me the most options for sequencing. Ideally I’m hoping to implement switches to allow for a few different sequences, pulsing, fading, following, etc…

I’ve also found some slick looking programs like Glediator but I don’t think I have the right kind of LEDs to use it. Finding a solution like this seems ideal.

I think I have a grasp on multiplexing, just not sure if going that route would make it more difficult to implement pre-existing libraries/code.

I currently have an Arduino Uno and a 2560 Mega Sunfounder Super Starter Kit. Open to adding more hardware should that prevent me from trying to reinvent the wheel code wise.

I’m sure I left out some valuable info - still learning all this stuff but excited!

Thank you in advance for any guidance or advice you could offer -

Jonathan

Alright - I figured out I can use a MOSFET as a switch to activate the LEDs from a power source higher than an Arduino can handle, this youtube video helped me understand the concept better.

I also found these pixel WS2812B LEDs (couldn’t find the manufacturer’s page). If I switched to these LEDs, I could eliminate 2/3 the power (only one .25W diode per module) and I’d be able to control them a bunch of different ways.

Considering I want to create radial patterns (light and fade concentric rings - image attached). Is there a smart way to organize this circuit that’ll let me take advantage of the libraries/software that’ll control WS2818 LEDs?

This post had some good advice about individually addressing each LED: http://forum.arduino.cc/index.php?topic=136993.0#quickreply

Not sure I can apply the spoke and ring code since I’d be using individual pixel LEDS vs the strips.

Chipping away…

Not sure I can apply the spoke and ring code since I'd be using individual pixel LEDS vs the strips.

You can't address those LEDs individually, to do that you need the WS2812b LED strips sold as Neopixels.

I did something similar before Neopexiels were out, the PDF manual downloadable from the site tells you a lot more about the API that I built up to talk to an array in this manner.

http://www.thebox.myzen.co.uk/Hardware/Hexome.html

Thanks for that. Got it, I was confusing those with NeoPixel LEDs from Adafruit:
https://www.adafruit.com/products/1558. I thought they were just a knockoff w/ the same chips, but I guess they just use the same LED. So many details…

I’m pretty sure the adafruit ones can be addressed individually and called out as a strip when connected.

Tho they recommend only 6" between them, which is a bummer. But it looks like I could snake it to 12" if I use heavier gauge wire: Adafruit customer service forums • View topic - Neopixels - Any way to guarentee operation 12" apart?

The design of this project prevents me from using an actual strip - I attached an image of it overlayed w/ a potential circuit. The LEDs will be mounted up, underneath the floating panels and some radii have gaps, so a strip wouldn’t hide very well.

So if I continue in this fashion, am I in good shape?

So if I continue in this fashion, am I in good shape?

Sounds like it.

Do you know you can get Neopixels in "normal" 5mm packages? That is not mounted on a PCB at all. You have to add your own decoupling capacitors on them and use wire runs. However, you can use a bit of a star wiring arrangement on both power rails. That is where the power all meets at one point.
You can also run many Neopixel strips from an Arduino each with it's own driver pin, there is no need to put it all into one long snake. I think that might be better for you.

Alright! So I’ve come a long way since my last post. Thanks a ton for your help. Got a working circuit and a code solution that’s giving me the control over the lights. I ended up running 12 strips, each w/ a 470ohm resistor, directly into 12 digital pins of my Arduino Mega. This theoretically lets me control each radial arm of the matrix independently. Here’s a video of the project so far - this one’s just running a 6 second loop with 2 patterns split between the 12 strips: [ https://youtu.be/rNjK68Wl8sY](http:// https://youtu.be/rNjK68Wl8sY)

I’ve worked it out so I can use images I create in photoshop to populate data sets, this is an ideal solution process wise - since I don’t know very much about programming and I get to keep the design largely visual. It has drawbacks though. The short loop is one of my restrictions. If I try to include 3 different 20 second data sets (like the code below), I run out of memory and can compile/upload the code.

This is pulled from my error message:

Sketch uses 25,566 bytes (10%) of program storage space. Maximum is 253,952 bytes.
Global variables use 21,819 bytes (266%) of dynamic memory, leaving -13,627 bytes for local variables. Maximum is 8,192 bytes.

I guess my questions are:

  • Would getting a QuadRam shield from Rugged Circuits fix my problem?
  • or is there another solution you’d recommend?

I’m betting the blocks of data aren’t very efficient in the way I’m using them, but unless I can find another way to build these patterns from images, I’d like to stick with this and find a work around for the memory issue.

My code was too big to include, so I attached it as a text file.

code.txt (52.9 KB)

Try storing your data in program memory.

Oh man, I was hoping that I was done w/ code…

So, after reading about progmem, it looks like I’ll need an array for my 12 LED strips. From what I can see there are 3 steps I need to take:

  1. Store my data in program memory
const char string_0[] PROGMEM = "x, x, x, x....";
const char string_1[] PROGMEM = "x, x, x, x....";
const char string_2[] PROGMEM = "x, x, x, x....";
const char string_3[] PROGMEM = "x, x, x, x....";
const char string_4[] PROGMEM = "x, x, x, x....";
const char string_5[] PROGMEM = "x, x, x, x....";
const char string_6[] PROGMEM = "x, x, x, x....";
const char string_7[] PROGMEM = "x, x, x, x....";
const char string_8[] PROGMEM = "x, x, x, x....";
const char string_9[] PROGMEM = "x, x, x, x....";
const char string_10[] PROGMEM = "x, x, x, x....";
const char string_11[] PROGMEM = "x, x, x, x....";
  1. Setup a table:
const char* const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7, string_8, string_9, string_10, string_11};
  1. Retrieve the data from program memory

This is where I can’t wrap my head around the implementation. I can see where my data sets are in the void loop, but I don’t understand how to add the strcpy_P function to my code:

void loop() {
    for (int i=0; i<LENGTH; i++) {
        int cpixel = i % pixels;
        int index = cframe*pixels*3 + cpixel*3;
        strip_1.setPixelColor(i,data2[index],data2[index+1],data2[index+2]);
        strip_2.setPixelColor(i,data3[index],data3[index+1],data3[index+2]);
        strip_3.setPixelColor(i,data1[index],data1[index+1],data1[index+2]);
        strip_4.setPixelColor(i,data1[index],data1[index+1],data1[index+2]);
        strip_5.setPixelColor(i,data3[index],data3[index+1],data3[index+2]);
        strip_6.setPixelColor(i,data2[index],data2[index+1],data2[index+2]);
        strip_7.setPixelColor(i,data2[index],data2[index+1],data2[index+2]);
        strip_8.setPixelColor(i,data3[index],data3[index+1],data3[index+2]);
        strip_9.setPixelColor(i,data1[index],data1[index+1],data1[index+2]);
        strip_10.setPixelColor(i,data1[index],data1[index+1],data1[index+2]);
        strip_11.setPixelColor(i,data3[index],data3[index+1],data3[index+2]);
        strip_12.setPixelColor(i,data2[index],data2[index+1],data2[index+2]);
    }
    strip_1.show();
    strip_2.show();
    strip_3.show();
    strip_4.show();
    strip_5.show();
    strip_6.show();
    strip_7.show();
    strip_8.show();
    strip_9.show();
    strip_10.show();
    strip_11.show();
    strip_12.show();
    cframe ++;
    if (cframe >= frames) cframe = 0;
    delay(1000/fps);

Oh man, I was hoping that I was done w/ code...

Not the code you just posted you were not.

Before you start delving into using 12 strips just get one working first, then worry about the other 11.

  1. Store my data in program memory

Why are you using strings for this? Why not bytes?
There are two approaches to storing a fixed pattern in memory:-

  1. Store the three bytes needed for every LED in the strip.
  2. Store the three bytes and a byte number for every LED that changes from the last pattern you showed.

You might see that on most occasions there is a huge memory saving with the second approach although it does take one byte more. Looking at the data most of it is sparse ( lots of zeros in it ) so compressing the data with reference to all LEDs being off is probably a good idea.

With your strips being so short only 4 LEDs you do not need much SRAM, but your fixed patterns take up a lot of space.

  1. Retrieve the data from program memory

No that is not the way you access data stored in program memory. You use:-

value = pgm_read_byte_near(&patternStore[point]);

But just get one working with a limited number of frames first.

Thanks Mike!

Why are you using strings for this? Why not bytes?

Ha. Because I know very little about this and I’m using examples I find online to guide me. It’s pretty wild I’ve made this this far. At the time I hadn’t found examples storing bytes in progmem, but now looking specifically for that.

Before you start delving into using 12 strips just get one working first, then worry about the other 11.

Yeah, baby steps…I know in the past using multiple instances lead me to rework the code, and change direction so I was hoping this would be simple enough to do all together. I can start small tho…

Store the three bytes and a byte number for every LED that changes from the last pattern you showed

That pattern was pretty arbitrary and might not make it into my final program, so using it as a baseline to factor changes might not be the best idea…unless you were just talking about a byte number specific to each LED regardless of the last pattern, in that case there would be 32.

value = pgm_read_byte_near(&patternStore[point]);

So, if that’s how you access stored data, and I need to add that stored data to my code, after I establish that value, would it look something like this? I’ve just swapped out “data” for “value”

void loop() {
    for (int i=0; i<LENGTH; i++) {
        int cpixel = i % pixels;
        int index = cframe*pixels*3 + cpixel*3;
        strip_1.setPixelColor(i,value[index],value[index+1],value[index+2]);
        
    }
    strip_1.show();
    
    cframe ++;
    if (cframe >= frames) cframe = 0;
    delay(1000/fps);

would it look something like this?

No.

Do not define variable in a for loop, this leaves lots of identically named variables on the stack and you are short of memory.

I don't see the call pgm_read_byte_near in your code, you need it to recover stuff in program memory.

Ohhhh, ok. I found this conversation and I think it’s helping me understand it better:

I think I got it! The code below sends the color information correctly to a single strip (I’ve omitted the actual data in favor of “x,x,x,x…” to conserve space). Is this actually sending the data to PROGMEM and solving my problem?

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

//IMPORTANT: Update the pin and length to match your LED strip!
#define PIN1 2 


#define LENGTH 4

Adafruit_NeoPixel strip_1 = Adafruit_NeoPixel(LENGTH, PIN1, NEO_GRB + NEO_KHZ800);

int pixels = 4;
int frames = 600;
int fps = 30;

const byte data1[] PROGMEM = {x,x,x,x....};



void setup() {
  strip_1.begin();
  strip_1.show();
 
}

int cframe = 0;
void loop() {
    for (int i=0; i<LENGTH; i++) {
        int cpixel = i % pixels;
        int index = cframe*pixels*3 + cpixel*3;
        int red = pgm_read_byte_near(&data1[index]);
        int green = pgm_read_byte_near(&data1[index+1]);
        int blue = pgm_read_byte_near(&data1[index+2]);
        strip_1.setPixelColor(i,red,green,blue);}
       
    strip_1.show();

    cframe ++;
    if (cframe >= frames) cframe = 0;
    delay(1000/fps);

}

Is this actually sending the data to PROGMEM

No but it could be GETTING data from the program memory.
However what did I say about declaring variables inside a for loop?

As to the indexing I suppose it would work like that but you are going round the houses on that way.

No but it could be GETTING data from the program memory.

I'm sorry I phrased that poorly. Is this approach solving my problem of running out of memory?

However what did I say about declaring variables inside a for loop?

OK, I guess I don't understand how to format these variables outside the for loop. Every instance I've tried errors out.

int red = pgm_read_byte_near(&data1[index]);
        int green = pgm_read_byte_near(&data1[index+1]);
        int blue = pgm_read_byte_near(&data1[index+2]);

If I declare red, green, blue as integers at the beginning of my sketch with that code, the functions pull an error. How do I format it properly?

As to the indexing I suppose it would work like that but you are going round the houses on that way.

I'm so happy it works, but I'm open to a better way if you could point me in that direction.

If I declare red, green, blue as integers at the beginning of my sketch with that code, the functions pull an error.

No it doesn’t.

Well read the error and what does it say? Re-declaration of variable perhaps?
By having the int in front of a variable name you are declaring it. This tells the compiler to set aside some memory for the variable EVERY time round the loop. You are pissing your memory away.

Use this.

void loop() {
int cframe, index, red, green, blue; // this declares the variables 
    for (int i=0; i<LENGTH; i++) {
          cpixel = i % pixels; // this sets the value of the variable
          index = cframe*pixels*3 + cpixel*3; // this sets the value of the variable
          red = pgm_read_byte_near(&data1[index]); // this sets the value of the variable
          green = pgm_read_byte_near(&data1[index+1]); // this sets the value of the variable
          blue = pgm_read_byte_near(&data1[index+2]); // this sets the value of the variable
          strip_1.setPixelColor(i,red,green,blue);
}

I see what you did!

I declared cframe outside of the loop as 0, so when I changed "cframe" to "cpixel" in the line where you declared everything it worked perfectly! Thank you! With that initial code it wasn't advancing through the loop.

So I was trying to declare and set the value in one line and that pulled the error when I placed it in setup - got it! It was the "statement-expressions are not allowed outside functions nor in template-argument lists" error.

So, now - I think I can filter through the changes to add a different pattern to each strip. This all makes more sense.

If I wanted to add an input device, like a button to allow a user to cycle through different loops - do you recommend a certain approach?

Putting the word
static
Infront of that definition in the code I posted would have done the same thing for cframe and cpixel.

The problem with a button is you have to read it often enough for it to seem responsive. If your patten is changing fast enough this is fine. Otherwise you have to write the code as a state machine and not use for loops in advancing the pattern.

MoreRobotsPlease:
If I wanted to add an input device, like a button to allow a user to cycle through different loops - do you recommend a certain approach?

Pro Mini’s are dirt cheap. Just dedicate a board to the display and another one to handle I/O and RTC/time functions.

The problem with using two processors is that the communications between the two is just as intrusive to the software as reading a push button anyway. So you gain little and just swap one problem for another.

Ahhh - I saw the static command in my research - that makes sense.

Yeah, I could see response being a big problem, with a minute long pattern and no immediate response from the button, a user is likely to hit it multiple times waiting for a change.

Would it be a matter of changing my code to use use if/than statements and pinging the button enough to get a decent response time? Would the code need to be drastically different if I wanted to implement a small LCD display? That could at least let the user know what pattern they're currently set to, even if the LEDs response isn't immediate. This could be my answer since I'm leaning towards having these LED patterns only hit every once in a while and the piece will be static w/ the lights off most of the time.

And is all of this gonna get more difficult since the Arduino can only do 1 thing at a time?