MAX7219 performance

Hi,

I've got 8 x 8x8 matrices chained all of which have a max7219 controller on board, I'm finding that the performance of updating all the pixels on all of these screens is very slow, probably takes 500ms to set the pixels of all 8 screens.

Just doing something as basic as this (purposefully simplistic example!):
for(int i=0;i<8;i++)
{
for(int y=0;y<8;y++)
{
lc.setRow(i,y,255);
}
}

Just wondering if this is an inherent problem with using matrices like this and if I wanted to do full screen animation across the 64x32 screen I'd need to be using a different controller that has more umph?

Obviously the Mega board I'm using has more than enough grunt to set the pixels fast enough so I can only assume the bottleneck is on the MAX7219 itself.

Thanks in advance.

No, the bottleneck is not the Arduino or the max chips. It's the library. Don't get me wrong, the LED Control library is great for a beginner taking their first steps with max7219 chips. But every time your code calls lc.setRow(), it is only intending to update 8 LEDs, but the data that is sent each time probably updates at least 64 LEDs, maybe all 512, I'm not sure. Also, it may not be using the Arduino's SPI hardware, but using software "bit-banged" SPI, which is at least an order of magnitude slower.

So to summarize, an ordinary Arduino and Max chips can be used to update a display much larger than 8 times 8x8 very smoothly. But you must either use the right library or eschew libraries and write code yourself that interacts with the max chips more closely.

Hopefully forum member Marco will respond and advise!

You don't mention what library you are using or whether you have your own code to do this. LedControl is mentioned by PaulRB.

The matrix hardware can be updated very quickly (look at the videos linked from the READ.ME at GitHub - MajicDesigns/MD_Parola: Library for modular scrolling LED matrix text displays).

Last time I looked (some time ago), LedControl was particularly inefficient, as mentioned above:

  1. It did not use the SPI hardware and 'bit banged' the interface. This is much much slower to execute the comms.
  2. It updated the while display every time one thing changed (eg, your call to setRow) rather than just the parts that changed.

Together these two aspects make it very clunky and slow for animations, or even just fast updates.

The MaxMatrix library works the same way, as far as I can tell.

You might want to try the MD_MAX72xx library to see if this works faster for you. If you are doing text animation (scrolling, etc) the MD_Parola would also be worth looking into. Links in the signature block below.

Yeah, using the led control library, sorry should have thought to mention that!

I've made a load of optimisations so it only updates the bytes it needs to but this is the best I've got.

I'll take a look into those libraries you mention.

Cheers!

And if you're interested here's a link to my whole project as it's developed...

Right, looks like you are using a panel of matrices for text/graphics. For this application I would suggest you look at MD_MAXPanel. I wrote this one specifically to support 'game' type applications.

Video: MD_MAXPanel Library Movie - YouTube
Link: GitHub - MajicDesigns/MD_MAXPanel: Arduino library to allow a panel of MAX72xx LED matrix modules to be used as a pixel display device.

Awesome, I'll give that a shot. The idea was to have pinball table type animations, so basically store the graphics for each animation frame (probably a byte array) and be able to cycle through.

OK, So I've finally got round to giving the MD_MAXPanel library a shot. Real life has been annoyingly getting in the way of this!

So rewired my 7219 matrices so they go bottom to top, right to left, loaded up the MD_MAXPanel_Test and updated the bit of code..

const MD_MAX72XX::moduleType_t HARDWARE_TYPE = MD_MAX72XX::FC16_HW;
const uint8_t X_DEVICES = 4;
const uint8_t Y_DEVICES = 2;

const uint8_t CLK_PIN = 10;   // or SCK
const uint8_t DATA_PIN = 12;  // or MOSI
const uint8_t CS_PIN = 11;    // or SS

So that should all be correct... And finally compiled and uploaded to my Ardunio.

The matrices flicker and then all go steady on, all pixels on all matrices. And in the serial monitor I get

⸮⸮C⸮⸮'e⸮⸮8⸮)⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮

And then the Arduino disconnects from the computer as if the it's hung...

Bit of a puzzle... I'm guessing I've missed something fundamental but what?! any suggestions welcomed.

RobFarley:
And in the serial monitor I get

⸮⸮C⸮⸮'e⸮⸮8⸮)⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮

And then the Arduino disconnects from the computer as if the it's hung...

Did you set serial monitor baud rate to match the baud rate set in the sketch?

How are you powering the circuit? Did you overload the usb power with too many matrices?

Obvious things first:

  1. From your SPI pins it looks like you are not using the hardware SPI the. Have you changed the library constructor to be the version where you supply the pins?

  2. Is your power supply separate from the Arduino? The Arduino board's power supply is not powerful enough for 8 matrices. You need a separate power supply and make sure the grounds are all connected together.

  3. Are you sure your wiring is right? No shorts or incorrect paths?

Did you set serial monitor baud rate to match the baud rate set in the sketch?

No sure, I'll need to check that.

How are you powering the circuit? Did you overload the usb power with too many matrices?

  1. Is your power supply separate from the Arduino? The Arduino board's power supply is not powerful enough for 8 matrices. You need a separate power supply and make sure the grounds are all connected together.

So the Matrices are all powered directly off the main board, this wasn't a problem before when I was using the LEDControl library, but I can certainly give it it's own power supply and test it again.

  1. From your SPI pins it looks like you are not using the hardware SPI the. Have you changed the library constructor to be the version where you supply the pins?

I didn't know there was a difference in which pins you use, which pins are the best to use, and the only thing I changed were the consts at the beginning of the Panel_Test to assign the pins.

  1. Are you sure your wiring is right? No shorts or incorrect paths?

It works perfectly with the LEDControl library, the wiring for the boards isn't identical to that in the documentation as this from what I understand just simplifies it for when you've got a lot of boards stacked up. I've only got two runs of 4 so the wiring comes out the end of one block of 4 and into the other end of the next block of 4.

Image of matrix wiring

Note: The boards are the other way round now as when I took this picture it went
3210
7654
and now it's
7654
3210

The other thing is I've been looking at what this library does and it seems a little overly complex for what I actually need.

I've already got my fonts as bytes (an 8x14 and 3x5 font), and I'm happy to bit shift the bytes to do the 10s and the units in the little font, this stuff isn't scary to me. So I'm really comfortable dealing in bytes (takes me back to my spectrum coding days!). So ideally all I want is a library that essentially has two commands:

SetByte([displayno],[RowNo],[Byte]); // Prepare the display bytes
-- This essentially would probably set bytes in an array (disp1) meanwhile an array (disp2) is what is currently displayed on the screens
and
RefreshDisplays(); //Apply all the changes made to the displays
-- So this could compare the bytes in disp1 and disp2 and update the elements of the displays that have changed. From here the SetByte commands would then update disp2 rather than disp1 and then the refresh displays would flip to the other disp array (if all this makes sense), again this goes back to my previous coding days where you'd draw the screen then "flip" to it, and then you'd continue drawing on the other screen, then flip again to display it. I appreciate I'm rambling on a bit now!

I don't know how much of a big ask this is, I'm happy to write it myself if I understood the communication to the 7219s, but that's currently a bit beyond my knowledge right now. I had a look at the LEDControl.cpp to see if I could mod that to make it work as I wanted but ended up just making it even more inefficient (still worked though! just even slower!!)

That aside, this help you guys are providing is massively appreciated.

Actually thinking about this a bit more... So this is written directly into the browser, more pseudo code than code! Completely untested, not run, nothing! Just thinking out loud!!

So really the main bit I can't do is the {DoCleverStuffToUpdateTheActualDisplay;} of course, I've no idea how this should work, or indeed if you can just punch a byte at a row of a display... Anyway...

int maxdisplay = 8;
int ActiveDisplay = 0;
byte disp[2][8][8];

void SetByte(int DisplayNo, int RowNo, byte Byte)
{
	disp[ActiveDisplay,DisplayNo,RowNo] = Byte;
}

void FlipDisplay(bool ClearDisplay)
{
	int AltDisplay = 1-ActiveDisplay;
	for(int d=0; d<maxdisplay; d++) {
		for(int r=0; r<8; r++) {
			if (disp[ActiveDisplay][d][r] != disp[AltDisplay][d][r] {DoCleverStuffToUpdateTheActualDisplay;}
		}
	}
	ActiveDisplay = AltDisplay;
	if (ClearDisplay == 1) {
		for(int d=0; d<maxdisplay; d++) {
			for(int r=0; r<8; r++) {
				disp[ActiveDisplay][d][r] = 0;
			}
		}
	}
}

RobFarley:
So the Matrices are all powered directly off the main board, this wasn't a problem before when I was using the LEDControl library, but I can certainly give it it's own power supply and test it again.

What does "powered directly off the main board" mean? What is this "main board"?

I am always suspicious of such statements. An Arduino is not in any respect whatsoever a "power supply"; you supply power - at 5 V - to it via the 5 V pin it does not supply power to anything else. :astonished:

I don't really want to argue this as I'm really not precious about how it's powered and happy to try it out on it's own power supply. However, it's connected as per the instructions I got with the starter kit, and subsequently I've now got the 8 matrices running off the same pin diagram which apparently isn't the greatest idea in the world and I'm happy to adjust what I'm doing accordingly...

Image from the documentation here

OK, I'm out.

If I'm doing something wrong tell me! I'm new to this and keen to learn from the more experienced members of this forum. I've simply wired stuff up as per the instructions I've got!

I'm fine with software, but very new to the hardware side of things.

I didn't know there was a difference in which pins you use, which pins are the best to use, and the only thing I changed were the consts at the beginning of the Panel_Test to assign the pins.

There is a hardware SPI interface that works really fast. This is on set pins, which depend on the type of Arduino you are using (normally marked MISO, MISO and SS pins). You can also do SPI by bit bashing any pins you like, but this will run slower. The MD_MAX72xx library allows you to use either type. If you use the constructor with no pins, then it will default to the hardware interface for your hardware, using the SPI library. If you specify the pins, then it will bit bash directly.

I don't know how much of a big ask this is, I'm happy to write it myself if I understood the communication to the 7219s, but that's currently a bit beyond my knowledge right now.

Not really that hard at all. You should be able to work it out from the two libraries you have. It will simplify things if you use the SPI library for the actual transmissions (with the default pins). There is lots out there describing how the SPI interface works and you can certainly use any of the generic code in MD_MAX72xx. The MAX72xx data sheet describes the command register codes you should use and how the supporting data byte is structured. Again, both libraries already do this, so I expect that if you read the data sheet and understand what SHOULD be done for comms, what the libraries ACTUALLY DO will become easier to understand.

Cool, I've have a look into it