MAX7219 SPI Chain Length

Hello all,

I could use some help from somebody with good SPI experience. I am building a rather large LED matrix display comprised of many MAX7219 matrix drivers daisy chained in a row. These drivers are controlled from my Arduino Uno using SPI and the SPI.h library.

The MAX7219 chips have a 16bit shift register, and all of them are connected to each other with less than 2 inches of SPI wires. When I turn everything on and send it data, the SPI seems to stop working after a certain distance/# of MAX7219s. I have a feeling the problem is due to 1 of two things:

  1. Timing/synchronization between CLK and DATA becomes degraded as the DATA is shifted through more and more MAX7219's.
  2. The voltage level of CLK or SS drops too much over the length of conductor (wire + pcb traces of all connected MAX7219s).

But those two scenarios are just my best guess. I'm a mechanical engineer, not an EE so I'm just speculating :slight_smile: Anyways, I have 60 MAX7219's daisy chained together, and I am only able to control the first 8-12 of MAX7219's in the daisy chain reliably.

Anybody have any insight on how many MAX7219's can be daisy chained, how far SPI can be successfully achieved, or if a logic level shifter configured as a logic booster would help?

Also, just to note, I have tried increasing the SPI clock divider (and thus decreasing the CLK frequency) to see if that would help the synchronization issues. It seems to have a minor positive effect, but does not get the whole chain working.

Thanks a bunch guys, looking forward to your suggestions.

I have had up to 20 connected together as part of testing my Parola project and others have many more than that, so the 10-12 limitation is probably not coming from the chips but somewhere else in your circuits. The links for Parola and the forum are in my footer below.

You could add a buffer for the SCK & SS lines, so arduino drives several buffer inputs and then the buffer drives 10 or chips per output. Data line then buffered by the MAX7219 chip.

marco_c:
I have had up to 20 connected together as part of testing my Parola project and others have many more than that, so the 10-12 limitation is probably not coming from the chips but somewhere else in your circuits. The links for Parola and the forum are in my footer below.

In terms of just the SPI communication, does the Parola code do anything special that the Arduino SPI library doesn't? My test code is very simple, and uses the hardware SPI:

#include "SPI.h"

void setup()
{
    // Set pin 10 as SS pin.
    pinMode(10, OUTPUT);
    digitalWrite(10, HIGH);
    // Start SPI.
    SPI.setBitOrder(MSBFIRST);
    SPI.begin();
    
    // Write "On" to the "Display Test" register in each of the 30 connected MAX7219s.
    digitalWrite(10, LOW);
    for(int i = 0; i < 30; i++)
    {
        // Transfer register byte followed by data byte.
        SPI.transfer(0x0F);
        SPI.transfer(0x01);
    }
    digitalWrite(10, HIGH);
}

void loop()
{
    // Do nothing, test code lies in setup.
}

This code works for the first 8-12 MAX7219s in the chain, and the rest after that are iffy/corrupt/unresponsive. Thoughts?

Got enough power available? Display test tells MAX7219 to turn on all LEDs.
Could be a lot of power used depending on your current settings per device.
8 LEDs on at each could be 160-240mA.

I would also do more to setup the 5 control registers:

Initial Power-Up
On initial power-up, all control registers are reset, the
display is blanked, and the MAX7219/MAX7221 enter
shutdown mode. Program the display driver prior to
display use. Otherwise, it will initially be set to scan one
digit, it will not decode data in the data registers, and
the intensity register will be set to its minimum value.

In terms of just the SPI communication, does the Parola code do anything special that the Arduino SPI library doesn't?

The control of the hardware is in the MD_MAX72xx library. No special things are done except the initialization is by the book according to the spec sheets, as mentioned by CrossRoads. You could download the library and see if it works better for you.

With lots of modules you should be using external power. The Arduino power supply won't be enough. Also make sure that the capacitors are as per the sample design on the spec sheet as that does make a difference.

What does you circuit for one module look like? Are you using standard module so your own circuits?

I'm using a standard module. Each module has CLK, CS, and DATA wires feeding to the next module with <2in wires. I have 14awg power and ground wires that run across the length of all of the modules. Each module's power and ground pins are connected directly to this 14awg wire bundle, which is powered from a separate 9A power supply.

I've had a few discussions on other places in the forum that suggest my problem is due to "fan-out" of the CLK and SS pins... meaning that the CLK/CS output pins of the Arduino cannot supply enough current to drive the logic circuits for CLK and CS on all 60 connected modules. Thoughts?

Buffering the CS & SCK signals has already been brought up.

Definitely buffer the SCK signal, that's the one that will be suffering most.

Add termination resistors at the far end, say about 270 ohms to GND and 270 ohms to +5V,
that'll quell reflections (but won't reduce the capacitance of all those chips.)

Alternatively just repeat the signals with standard logic gates every 8 chips or so.

Good decoupling and signal routing should be used.

pcdangio:
I could use some help from somebody with good SPI experience. I am building a rather large LED matrix display comprised of many MAX7219 matrix drivers daisy chained in a row. These drivers are controlled from my Arduino Uno using SPI and the SPI.h library.

All that typing and you left out the only important detail:

How many is "many"?

fungus:
How many is "many"?

He says 60 later on in his message and that he can only get 8-12 to work.

One thing I will ask is - are these genuine chips or are they possibly clones? I have heard that the clones are not as reliable when used with longer strings of chips. The dead giveaway is the half-pins on the edges. Look here:

http://tronixstuff.com/2013/05/16/the-max7219-led-display-controller-real-or-fake/

Yea I'm definitely using the knock-off ones... didn't feel like spending $600+ just on ICs haha. I guess I'll be paying up anyway with the amount of extra time I have to put in to get the knock-offs to work right.

I'm going to start doing some testing tonight to see if the fan-out is the culprit. The real MAX7219 data sheet says the max input current for CLK and CS are 1 micro-amp... and the arduino uno has a max output current of 40 milli-amps. Using the real chip, the arduino CLK pin should have no trouble here. I wonder if the knock-off chips are way off spec.

Also, one weird thing I noticed is that the MAX7219 chips pull power from the CLK, CS, and/or DATA pins. If I don't have VCC hooked up to the MAX7219, the LEDs still function (just very dimly)... wonder why that is happening?

Anyways tonight I will take some voltage/current measurements along the CLK and CS lines, and will also try a transistor and a buffer.

It's usually capacitance of the extended wiring that degrades the signal, not just the chips themselves.

Leakage current thru the input protection diodes is what allows the chips to run from the high control signals. That's why IO pins are not supposed to exceed Vcc +0.5V. If no power is applied, don't allow the control lines to be driven high.

pcdangio:
Yea I'm definitely using the knock-off ones... didn't feel like spending $600+ just on ICs haha. I guess I'll be paying up anyway with the amount of extra time I have to put in to get the knock-offs to work right.

I've done the same thing. You can get like 50 of the knockoff chips on eBay for $25 or even a little less. For a hobbyist trying to make a cheap display, using the genuine chips is really a cost shock. Anyway, if it does turn out to be SPI length, there is really no huge performance penalty breaking that chain of 60 displays up into to 10 chains of 6 displays and using some logic to select one chain to dump data to at a time, possibly using six 74HC138 (two each for a 1-of-10 selection for each of the 3 control signals).

First, thanks Crossroads for answering my question about the SPI lines powering the chips without VCC, gave you some karma for that!

Second, I did some more testing tonight. Here's what I found:

With 30 chips plugged in, I checked the voltage level on both the CLK and CS lines at the end of the chain driving both of them high manually. There was negligible voltage drop, 5.2v at the beginning of the chain and 5.16v at the end of the chain. Don't make fun of me since im not an EE haha, but doesn't that mean the chips are getting enough current and this isn't a fan-out problem?

With a short chain (24 units), I was able to accurately control the Display Test register for all connected units. One thing I noticed though was that 4-5 units at the end were turning their display test on in the middle of a transfer. First, let me show you the code. It simply runs a loop that turns Display Test to OFF for all units except for one, which basically scrolls a display test On across all connected elements in the loop() method:

#include "SPI.h"

int N = 24;
int j = 0;

void setup()
{
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);
  
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV4);
  SPI.begin();
  
  digitalWrite(10, LOW);
  for(int i = 0; i < N; i++)
  {
    SPI.transfer(0x0C);
    SPI.transfer(0x00);
  }
  digitalWrite(10, HIGH);
  
  delay(10);
  
  digitalWrite(10, LOW);
  for(int i = 0; i < N; i++)
  {
    SPI.transfer(0x0F);
    SPI.transfer(0x00);
  }
  digitalWrite(10, HIGH);
  
  delay(100);
}

void loop()
{  
  digitalWrite(10, LOW);
  for(int i = 0; i < N; i++)
  {
    SPI.transfer(0x0F);
    SPI.transfer(byte(i==j));
  }
  digitalWrite(10, HIGH);
  
  if(j++ == N)
  {
    j = 0;
  }
  
  delay(100);
}

Now what I noticed was happening was that the last few elements would turn their display test on while CS(pin 10) is still low! CS goes low, and new data is shifted into all the units. The DisplayTest=On bits that were previously in the registers get shifted out as new data is shifted in, all while CS is low. However, in the last few connected units, the display test actually gets set to On while the data is shifting through, even though its CS is low. I was able to find this by putting a delay(100) inside of the for loop in the loop() method. Why would this be happening?

Once I connected 30 units together, everything just died instantly, and all I got was garbage across the whole chain.

I also read somewhere that long SPI chains should be tied to ground with a termination resistor. Is this a good idea, and how do I decide what size termination resistor to use?

Thanks so much for all the help so far you guys, you have been really awesome. Hopefully my explanations above are clear enough for you to understand... if not let me know and I will try to break it down better.

I also forgot to mention... I had 1 element that was powered with the same rail as all of the other elements, but its CS, CLK, and DIN lines were completely disconnected. When sending Display Test commands to the other connected elements, I noticed at one point that the disconnected element had somehow also received a Display test command and turned itself on... what the heck?

Update:

Found a partial fix: My ground wiring scheme was bad. Had mini-chains of 6 MAX7219s that daisy-chained power+ground off of a main power wire. I connected the last element back to the main ground wire and this helped a ton.

Possible complete fix: After doing a bunch of research and speaking with Maxim support, I think my true problem is a lack of termination on the CLK and CS/LOAD lines. These wires are long enough to be considered a transmission line, and they must be terminated (not left open circuit or short circuited at the end). Without proper termination, signals reach the end of the wire and are reflected back, distorting the signal that is read by the MAX7219s. To minimize these reflections, I have to put a resistor at the end of the wire that matches the wire's resistance. I'm going to do this for both CLK and CS/LOAD tonight, will let you guys know the results.

Note that in the datasheet it specifies the DIN setup time to be 25 ns. In a daisy-chained (series) configuration, this time is cumulative. If there's 30 ICs, then the total setup time required would be 750 ns plus whatever extra delays due to wire connections and capacitance.

In your code, try inserting delayMicroseconds(1); just before digitalWrite(10, HIGH);.

Except DIN comes from the chip prior, so it would have changed when the chip prior changed its output from the common clock.
What's the propagation delay from clock going high to the output changing?

Oops... its "tDO" (output data propagation delay), specified at 25 ns that's cumulative. The 25 ns DIN setup time is non-cumulative.

A small delay prior to setting CS high could help ... easy to test.