Treating an array of Matrices as a single Matrix [WS2812]

I’ve been working on a project where I’m using a program (LEDMatrixStudio by Paul Freshney) to generate HEX colour code to address WS2812 LEDs in a matrix.

The purpose of this is to create frames of an animated display which I can trigger frame by frame through DMX, I’m trying to structure my code in a way that allows it to act as a framework where all I have to do in order to run a new animation is generate new HEX code and replace the old colour code.

So far this has all been working fine on an individual matrix but now I’m moving towards using an array of tiles and I’ve hit a roadblock.

What I want to happen: Ideally I’d like to treat my array as if it were a single matrix, as a starting point I’m using 3 8x8 matrices which are arranged in progressive rows.
Where I have for example 3 tiles in series I’d like that to act as 8 rows of 24 pixels rather than 3 tiles of 64. So pixel 0 of Tile 2 should be pixel 8, pixel 0 of Tile 3 should be pixel 16 and so on.

What is actually happening: Using LEDMatrixStudio I’m setting a grid of 24x8, generating the colour code then attempting to display it on an array of 3 8x8 tiles. My code is treating pixel 0 of Tile 2 as pixel 64, pixel 0 of Tile 3 as 128 and so on, this leads to an incorrect display. I can work around this by separating my designs into 8x8 chunks and generating the code for each tile individually but its pretty cumbersome and at some point I’m going to want to make some much larger arrays.

So what am I asking? Is there some function where when x passes beyond the tile width it moves to the adjacent row of the next tile and when x passes the width of the array it moves to the row below? Will this even help given how I’m currently inputting my colour code? Basically is there a better way than what I’m currently doing?

Code I’m using to fill the display;

#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>

#define PIN 9

/Colour Code*********/
uint32_t ledarray = {
0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000,
0x00F00000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00F00000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00F00000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00F00000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00F00000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00F00000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000,
0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000,
0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00F00000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00F00000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00F00000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00F00000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00F00000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00F00000,
0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, 0x00F00000, };

/*********initial matrix layout (to get matrix index by x/y)/

Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(8, 8, 3, 1, PIN,
NEO_TILE_TOP + NEO_TILE_LEFT + NEO_TILE_ROWS + NEO_TILE_PROGRESSIVE +
NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE,
NEO_RGB + NEO_KHZ800);

/*************************************************************************************************/

void setup() {
matrix.begin();
matrix.setBrightness(40);
matrix.show();
}

void loop() {
RenderFrame_01();
delay(100);
}

void RenderFrame_01()
{
for (int t = 0; t <192 ; t++){
matrix.setPixelColor(t, ledarray[t]);
}
matrix.show();
delay(100);
}

The shape the colour code here represents is a simple red hollow rectangle, I’m aware I could use draw.rectangle instead but in practice the shapes will be more complex images, this is just a shape I use as a test to check everything lines up. This is also a barebones version with the DMX-enabled code removed as I just want to focus on getting the display to work with tile arrangement.

My instinct tells me "> for (int t = 0; t <192 ; t++){ " is where I need to make some changes.

I’m an electrician who messes around with LEDs a lot, my code knowledge isn’t great, go easy on me!

So that I can understand your question I have taken some liberties with the array contents to make it visually more obvious what you want . Before anyone asks, yes, I know the contents are now wrong

uint32_t ledarray =
{
  00FFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF,
  08FFFFFF, ________, ________, ________, ________, ________, ________, ________,
  16FFFFFF, ________, ________, ________, ________, ________, ________, ________,
  24FFFFFF, ________, ________, ________, ________, ________, ________, ________,
  32FFFFFF, ________, ________, ________, ________, ________, ________, ________,
  40FFFFFF, ________, ________, ________, ________, ________, ________, ________,
  48FFFFFF, ________, ________, ________, ________, ________, ________, ________,
  56FFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF,
  
  64FFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF,
  72______, ________, ________, ________, ________, ________, ________, ________,
  80______, ________, ________, ________, ________, ________, ________, ________,
  88______, ________, ________, ________, ________, ________, ________, ________,
  96______, ________, ________, ________, ________, ________, ________, ________,
  104_____, ________, ________, ________, ________, ________, ________, ________,
  112_____, ________, ________, ________, ________, ________, ________, ________,
  120FFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF,
  
  128FFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF,
  136_____, ________, ________, ________, ________, ________, ________, FFFFFFFF,
  144_____, ________, ________, ________, ________, ________, ________, FFFFFFFF,
  152_____, ________, ________, ________, ________, ________, ________, FFFFFFFF,
  160_____, ________, ________, ________, ________, ________, ________, FFFFFFFF,
  168_____, ________, ________, ________, ________, ________, ________, FFFFFFFF,
  176,_____, ________, ________, ________, ________, ________, ________, FFFFFFFF,
  184FFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF,
};

If I understand what you want it is to read through the array in the order 0, 1, 2, 3, 4, 5, 6, 7, 64, 65, 66, 67, 68, 69, 70, 71, 128, 129, 130, 131, 132, 133, 134, 135, 8, 9, 10, 11 and so on

If not, then what order do you want them in ?

Yes you’ve understood me correctly! As row 1 of tile 1 ends id like for the path to continue on row 1 of tile 2 etc.
Someone has mentioned to me it might be easier to create a sort of excel sheet that rearranges the colour code generated by LEDMatrixStudio rather than try to change the order of how Arduino is plotting that colour code, I’m open to any suggestion though!

It made more sense once I had mangled your array and the pattern stood out

Is there any reason why you don’t use a 2 dimensional array with 24 columns and 8 rows

That is actually quite easy to do. Create an array that maps the pixel to the actual LED position.

const byte ledMap[192] = {
    0,   1,   2,   3,   4,   5,   6,   7,
   64,  65,  66,  67,  68,  69,  70,  71,
  128, 129, 130, 131, 132, 133, 134, 135,
    8,   9,  10,  11,  12,  13,  14,  15,
   72,  73,  74,  75,  76,  77,  78,  79,
  136, 137, 138, 139, 140, 141, 142, 143,
   16,  17,  18,  19,  20,  21,  22,  23,
   80,  81,  82,  83,  84,  85,  86,  87,
  144, 145, 146, 147, 148, 149, 150, 151,
   24,  25,  26,  27,  28,  29,  30,  31,
   88,  89,  90,  91,  92,  93,  94,  95,
  152, 153, 154, 155, 156, 157, 158, 159,
   32,  33,  34,  35,  36,  37,  38,  39,
   96,  97,  98,  99, 100, 101, 102, 103,
  160, 161, 162, 163, 164, 165, 166, 167,
   40,  41,  42,  43,  44,  45,  46,  47,
  104, 105, 106, 107, 108, 109, 110, 111,
  168, 169, 170, 171, 172, 173, 174, 175,
   48,  49,  50,  51,  52,  53,  54,  55,
  112, 113, 114, 115, 116, 117, 118, 119,
  176, 177, 178, 179, 180, 181, 182, 183,
   56,  57,  58,  59,  60,  61,  62,  63,
  120, 121, 122, 123, 124, 125, 126, 127,
  184, 185, 186, 187, 188, 189, 190, 191
};

Then use that array to get the LED number for the setPixelColor function.

void RenderFrame_01()
{
  for (int t = 0; t < 192 ; t++) {
    matrix.setPixelColor(ledMap[t], ledarray[t]);
  }
  matrix.show();
  delay(100);
}

Could also be done with calculations using nested for loops using the row, column, and tile position, that would be more suitable when changing the number of tiles.

Had a few minutes to look at using an equation, this should work for any number of tiles in a horizontal row. Will need to be modified if you also want to stack tiles vertically.

const byte rowsPerTile = 8;
const byte colsPerTile = 8;
const byte numTiles = 3;

void RenderFrame_01()
{
  for (int row = 0; row < rowsPerTile; row++) {
    for (int tile = 0; tile < numTiles; tile++) {
      for (int col = 0; col < colsPerTile; col++) {
        int source = (row * colsPerTile * numTiles) + (tile * colsPerTile) + col;
        int destination = (row * colsPerTile) + (tile * rowsPerTile * colsPerTile) + col;
        matrix.setPixelColor(destination, ledarray[source]);
      }
    }
  }
  matrix.show();
  delay(100);
}

Really appreciate the help from you both, this looks very promising! Been a busy day at work but I’m gonna try this out as soon as I get a chance and I’ll let you know how it goes. Haven’t seen this method before but it looks exactly like what I’m looking for. Exciting!

And probably more efficient.

Have had a good chance to play with this today. Got the 3x1 setup working as it should with both your methods, thanks for that. I love learning about this stuff.
Will be having a go at a 3x2 setup next, 2 rows of 3 tiles.

Posting the working code for both methods below;

SETUP 1

#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>

#define PIN 9

/Colour Code*********/
uint32_t ledarray = {
0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00FF0000, 0x00FF0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00FF0000, 0x00FF0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00FF0000, 0x00FF0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00FF0000, 0x00FF0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00FF0000, 0x00FF0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000,
};
/*********initial matrix layout (to get matrix index by x/y)/

Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(8, 8, 3, 1, PIN,
NEO_TILE_TOP + NEO_TILE_LEFT + NEO_TILE_ROWS + NEO_TILE_PROGRESSIVE +
NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE,
NEO_RGB + NEO_KHZ800);

const byte rowsPerTile = 8;
const byte colsPerTile = 8;
const byte numTiles = 3;
/*************************************************************************************************/

void setup() {

matrix.begin();
matrix.setBrightness(30);
matrix.show();

}

void loop() {
RenderFrame_01();
delay(100);
}

void RenderFrame_01()
{
for (int row = 0; row < rowsPerTile; row++) {
for (int tile = 0; tile < numTiles; tile++) {
for (int col = 0; col < colsPerTile; col++) {
int source = (row * colsPerTile * numTiles) + (tile * colsPerTile) + col;
int destination = (row * colsPerTile) + (tile * rowsPerTile * colsPerTile) + col;
matrix.setPixelColor(destination, ledarray[source]);
}
}
}
matrix.show();
delay(100);
}

SETUP 2

#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>

#define PIN 9

/Colour Code*********/
uint32_t ledarray = {0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00FF0000, 0x00FF0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00FF0000, 0x00FF0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00FF0000, 0x00FF0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00FF0000, 0x00FF0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00FF0000, 0x00FF0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, // 1
};
/*********initial matrix layout (to get matrix index by x/y)/

Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(8, 8, 3, 1, PIN,
NEO_TILE_TOP + NEO_TILE_LEFT + NEO_TILE_ROWS + NEO_TILE_PROGRESSIVE +
NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE,
NEO_RGB + NEO_KHZ800);

/LED_MAP******/
const byte ledMap[192] = {
0, 1, 2, 3, 4, 5, 6, 7,
64, 65, 66, 67, 68, 69, 70, 71,
128, 129, 130, 131, 132, 133, 134, 135,
8, 9, 10, 11, 12, 13, 14, 15,
72, 73, 74, 75, 76, 77, 78, 79,
136, 137, 138, 139, 140, 141, 142, 143,
16, 17, 18, 19, 20, 21, 22, 23,
80, 81, 82, 83, 84, 85, 86, 87,
144, 145, 146, 147, 148, 149, 150, 151,
24, 25, 26, 27, 28, 29, 30, 31,
88, 89, 90, 91, 92, 93, 94, 95,
152, 153, 154, 155, 156, 157, 158, 159,
32, 33, 34, 35, 36, 37, 38, 39,
96, 97, 98, 99, 100, 101, 102, 103,
160, 161, 162, 163, 164, 165, 166, 167,
40, 41, 42, 43, 44, 45, 46, 47,
104, 105, 106, 107, 108, 109, 110, 111,
168, 169, 170, 171, 172, 173, 174, 175,
48, 49, 50, 51, 52, 53, 54, 55,
112, 113, 114, 115, 116, 117, 118, 119,
176, 177, 178, 179, 180, 181, 182, 183,
56, 57, 58, 59, 60, 61, 62, 63,
120, 121, 122, 123, 124, 125, 126, 127,
184, 185, 186, 187, 188, 189, 190, 191
};

/*************************************************************************************************/
void setup() {
matrix.begin();
matrix.setBrightness(30);
matrix.show();
}

void loop() {
RenderFrame_01();
delay(100);
}

void RenderFrame_01()
{
for (int t = 0; t < 192 ; t++) {
matrix.setPixelColor(ledMap[t], ledarray[t]);
}
matrix.show();
delay(100);
}