16 x 16 LED Matrix Animation Limitations Using MAX7129 and ledControl Library

Hello all,

I have been experimenting using 4 x MAX7129's in series to drive 4 x (8x8) led matrices. Using the led control libraries I have successfully put together a few animations by splitting each 16 x 16 sprite "frame" into 4 x (8x8) matrices consecutively using states.

The issue I am running into however is that these 16 x 16 sprite bytes "frames" have to be global variables so that I can run them each separately through the function to split them into each 8x8 array.

To get more variability I have added additional functions to manipulate these frames by translating the array to the left / upwards to make the sprite move in those directions.

Is this the best method to do this? Would changing all these to local variables take up less space even though I would have to have many more arrays? Or is there somehow I can make my global variable matrices take up less space?

Here is my current code and photo of setup attached below:

crab.ino (10.4 KB)

geckoman101:
Is this the best method to do this? Would changing all these to local variables take up less space even though I would have to have many more arrays? Or is there somehow I can make my global variable matrices take up less space?

I see two possibilities:

a) you could store your data instead in RAM in the PROGMEM --> PROGMEM - Arduino Reference

b) Currently you need 16x16 byte = 256 Byte for each picture. You use one byte for each dot. Break it down and use bits for the dots.
If you us an array of uint16_t[16] it will take only 32 bytes. Each element/index represents one row, each bit one dot.

0b0000000000000000,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b1111111111111111

and so on. In this case you have a bitmask, wherein each bit represents one dot. You could even combine these two concepts and store the uint16_t[16] in PROGMEM.

Will i need to convert the bit arrays back into bytes within each function in order to still use the display and translate functions?

You have to adopt your function do handle the uint bitwise.

I think you should look into the "Parola" library in the library manager.

everything clear now?

I see you are using a function:

int rowValue(unsigned char address, byte i)

for your case 0 and 1 you need the 8 most significant bits. Therefore shift the bits by 8 to right:

result = A[i] >> 8;

for case 2 and 3 you need only the 8 less significant bits, therefore mask these 8 bits with and AND:

result = A[i] & 0b0000000011111111;

by the way: see also the description for the switch case: there is no reason to write duplicate code if you have cases which should do the same code.

Yes thank you for the help that makes the bit interpretation a lot clearer.

I see what you mean about the repeating cases for rowValue returns however I cannot see a way to assign the case case to two separate address values.

Actually I was able to simplify it by doing this:

switch (address) {

case 0: case 1: {

results = . . .
break;
}

Is that what you were referring to?

yes, that's a way you can use.

Alright I am very close to getting this working. Upon testing I've noticed that the bit arrays are being clipped down to 8 instead of 16 somewhere along the way.

The only other issue is Case 3 displaying mirrored vertically, however im sure that can be fixed with some array transpose.

Here is my current code:

#include "LedControl.h"

#define Width 16
#define Height 16

/*
   pin 12 is connected to the DATA
   pin 11 is connected to the CLK
   pin 10 is connected to CS
*/

LedControl lc = LedControl(12, 11, 10, 4);


byte t9[16]  =  {0b0000000000000000,
        0b0000111111110001,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b0000111111110001,
0b1111111111111111,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b1111111111111111
};

byte t10[16]  =  {0b0000000000000000,
0b0000111111110000,
0b0000111111110001,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b0000111111110010,
0b1111111111111111,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b1111111111111111
};

byte t11[16]  =  {0b0000000000000000,
0b1000111111110000,
0b0000111111110000,
0b0000111111110001,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b0000111111110100,
0b1111111111111111,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b1111111111111111
};

byte t12[16]  =  {0b0000000000000000,
0b0000111111110000,
0b1000111111110000,
0b0000111111110000,
0b0000111111110001,
0b0000111111110000,
0b0000111111110000,
0b0000111111110000,
0b0000111111111000,
0b1111111111111111,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b1111111111111111
};

unsigned long delayTime = 1000;
//byte t1[16][16];
byte t2[16];
byte A[16];

void setup() {
  int devices = lc.getDeviceCount();
  //we have to init all devices in a loop
  for (int address = 0; address < devices; address++) {
    delay(10);
    /*The MAX72XX is in power-saving mode on startup*/
    lc.shutdown(address, false);
    /* Set the brightness to a medium values */
    lc.setIntensity(address, 1);
    /* and clear the display */
    lc.clearDisplay(address);
    Serial.begin(9600);
  }
  //randomize(t1);
}

void loop() {
  
  display(t9);

  delay(delayTime);
  
  display(t10);

  delay(delayTime);
  
  display(t11);

  delay(delayTime);
  
  display(t12);

  delay(delayTime);


}



void display(byte t1[16]) {
  for (unsigned char matrixCount = 0; matrixCount < 4; matrixCount++) {
    //lc.clearDisplay(matrixCount);
    for (unsigned int i = 0; i < 8; i++) {
        switch (matrixCount) {
          case 1: {
              A[i] = t1[i];
              break;
            }
          case 0: {
              A[i] = t1[i];
              break;
            }
          case 2: {
              A[i] = t1[i+8];
              break;
            }
          case 3: {
              A[i] = t1[i+8];
              break;
            }
        }
    }
    updateDisplay(matrixCount);
  }
}


void updateDisplay(unsigned char address) {
  if (address < 2 ) {
    for (int i = 0; i < 8; i++) {
      lc.setRow(address, i, rowValue(address, i));
      //delay(100);
    }
  } else {
    for (int i = 0; i < 8; i++) {
      lc.setRow(address, i, rowValue(address, 7-i));
      //delay(100);
    }
  }
}

int rowValue(unsigned char address,byte i) {
  int result;
  switch (address) {
    case 2: case 1: {
                Serial.println(A[i]);
        result = A[i] & 0b1111111100000000;
        break;
      }
    case 3: case 0: {
        result = A[i] & 0b0000000011111111;
        break;
      }
  }
  return result;
}
byte t9[16]  =  {0b0000000000000000,

it's not a byte (holding one byte)... it should be uint16_t!

result = A[i] & 0b1111111100000000;

is wrong. You need to SHIFT like explained in #5

I guess you mixed up the combinations. In your Sketch form #1 case 0 and case 1 were the same. Now you combine case 1 and 2. I guess this needs a fix also.