Go Down

Topic: MAX7219 and Common Anode displays with LedControl (Read 6301 times) previous topic - next topic

Sep 02, 2012, 09:57 am Last Edit: Sep 02, 2012, 10:32 am by LordPants Reason: 1
I'm working on a project that uses lots of 7-segment LED displays, and I'm using the MAX7219 IC for its wonderful multiplexing and constant current features. Since the displays I found were common anode (not the common cathode the MAX7219 datasheet specifies), I had to modify the LedControl library a bit to accommodate them. I will share my methods and code here to get feedback before I upload any updated libraries.

The 7219 can be easily used with common anode displays, as long as things are wired up "backwards." In other words, since the pins for DIG-0 through DIG-7 are current sinks and the pins for SEG-DP through SEG-G are current sources, they can be swapped to provide appropriate power to a common anode display. Wiring should be:
Code: [Select]

Wiring for Common anode display

MAX7219 | Display
DIG-0   | SEG-DP
DIG-1   | SEG-A
DIG-2   | SEG-B
...     | ...
DIG-7   | SEG-G
SEG-DP  | Anode of Digit 0
SEG-A   | Anode of Digit 1
...     | ...
SEG-G   | Anode of Digit 7


Now since the 7219 scans digit-by-digit, and we've swapped digits with segments, it's now going to scan segment-by-segment on the common anode displays, unless we modify the data we're sending to it. The data for the entire display is represented by an 8-byte array, with each byte corresponding to one digit and each bit corresponding to one segment. To get it to work to our wiring scheme, we have to flip it: we transpose the bit matrix.

Here are the two matrices for displaying "01234567" with no decimal points on an 8-digit display (in NO DECODE mode, which LedControl uses). Each row of the matrix is stored as a byte in an array (in LedControl, it's in the status[] array).
Code: [Select]

Common cathode (standard)   Common anode (transposed)
    DP A B C D E F G            DP A B C D E F G
   +----------------           +----------------
 0 | 0 1 1 1 1 1 1 0         0 | 0 0 0 0 0 0 0 0
 1 | 0 0 1 1 0 0 0 0         1 | 1 0 1 1 0 1 1 1
 2 | 0 1 1 0 1 1 0 1         2 | 1 1 1 1 1 0 0 1
 3 | 0 1 1 1 1 0 0 1         3 | 1 1 0 1 1 1 1 1
 4 | 0 0 1 1 0 0 1 1         4 | 1 0 1 1 0 1 1 0
 5 | 0 1 0 1 1 0 1 1         5 | 1 0 1 0 0 0 1 0
 6 | 0 1 0 1 1 1 1 1         6 | 1 0 0 0 1 1 1 0
 7 | 0 1 1 1 0 0 0 0         7 | 0 0 1 1 1 1 1 0


My patch for LedControl is attached. It's completely backwards compatible with existing code. To use it with common anode displays, you only have to add a boolean option to the object creation. The transposition is handled completely by the library.
Code: [Select]

#include "LedControl.h"
LedControl lc=LedControl(12,11,10,1,true); // lc is our object
// pin 12 is connected to the MAX7219 pin 1
// pin 11 is connected to the CLK pin 13
// pin 10 is connected to LOAD pin 12
// 1 as we are only using 1 MAX7219
// true since this is a common anode display setup
void setup() {
 lc.shutdown(0,false); // turn off power saving, enables display
 lc.setIntensity(0,5); // sets brightness (0~15 possible values)
 lc.clearDisplay(0); // clear screen
}
void loop() {
 // display 0-7, cascading on the 8 displays
 for(int i=0; i<8; i++) {
   lc.setDigit(0,i,i,false);
   delay(250);
   lc.clearDisplay(0);
 }
}


Comments, questions, and critiques are welcome.

rhawbert

#1
Mar 10, 2013, 02:46 am Last Edit: Mar 10, 2013, 02:49 am by rhawbert Reason: 1
Hi LordPants,

Any idea if I can use this same technic with my LED matrices (datasheet: http://www.eled.com/data/spec/EBC20-12EGWB.PDF)?

The matrices are 5x7, common-anode and bicolor.

I have 40 of them and 10 MAX7219 and unfortunately I'm struggling to create a big (approximately 26cm2) LED display like the image below:



The image shows only 35 matrices in use due to the LedControl's library limit of 8 daisy-chained MAX7219 per connection, and the amount of ports on Arduino. So I was thinking of outputting just one color of the matrices and to use one MAX7219 to control each module (35 LEDs per module).

Everywhere I look there's only information for 7-segments displays... and I have no idea of how to wire it in a way that I could use the MAX7219 to control.

Also any input on how to power the whole thing would be greatly appreciated.






--
Rhawbert Costa

You could absolutely use a MAX7219 to run a matrix display, but the 10 you have will not be nearly enough for your 40-display project.

A 7-segment display has 8 LEDs in it (7 segments and the decimal point), and a MAX7219 can run 8 of those multiplexed... That's a total of 64 LEDs per chip. Each of your 5x7 matrices has 35 LEDs, so each 7219 chip can run almost two matrices. For a 40 matrix display like you describe, you could conceivably use 22 chips to run the whole thing, but the software would be a pain, since there would be no correlation between chip number and matrix number.

For now I'll assume one chip is running one matrix display. You wire it up like each row of LEDs is a digit, and each column is segment. So column 1 is segment A, column 2 is segment B, and so on. You'll probably have to either write the LEDs individually or pass a 1-byte binary value to turn LEDs in the row ("digit") on or off, because the built-ins won't do much for you.

I'm also not sure that the 8-digit limit in LedControl is a limit of the 7219... you may want to check the data sheet. You could conceivably modify the library to allow more, if the chip supports it.


rhawbert

Quote
A 7-segment display has 8 LEDs in it (7 segments and the decimal point), and a MAX7219 can run 8 of those multiplexed... That's a total of 64 LEDs per chip. Each of your 5x7 matrices has 35 LEDs, so each 7219 chip can run almost two matrices. For a 40 matrix display like you describe, you could conceivably use 22 chips to run the whole thing, but the software would be a pain, since there would be no correlation between chip number and matrix number.


You're right. For simplicity's sake I was thinking of using one MAX7219 for each matrix... but multiplexing for one color only (red), since the MAX7219 can't control all 70 LEDs in it.

Thanks for the tips on making the connections... I'll now try to create some sort of breakout board and connect it to my breadboard for testing the connections between the driver and the matrix. If I manage to control a couple of matrices than it'll be just a matter of writing the sketch appropriately.

Meanwhile in this other thread http://arduino.cc/forum/index.php/topic,117102.msg881138.html#msg881138 other user says that it can't be done because the number of row pins is not the same as the number of column pins, so no interchange can happen. Which I disagree but without firm ground since my matrix isn't squared (5x7) and the fact I haven't quite understood current sinking and sourcing concepts yet.

Quote
I'm also not sure that the 8-digit limit in LedControl is a limit of the 7219... you may want to check the data sheet. You could conceivably modify the library to allow more, if the chip supports it.


I'll check on that in the meantime...

--
Rhawbert Costa

Yeah, I didn't realize that the matrix was bi-color... you'd need 2 chips per display, one for each color.

And yes, you can do this on a non-square matrix. Matrix transposition doesn't have to be done on a square matrix (I use my library to light up only two digits, and that's 2x8). In fact, in this case, you might not have to do any transposition at all, since you get to decide whether the "digit" represents a row or a column. Looking at the data sheet, your 5 rows are current sinks (cathodes), and therefore should be wired to the 7219 digit pins, and your 7 columns are current sources (anodes) and should therefore be wired to the 7219 segment pins. So instead of worrying about matrix math (which adds a performance penalty), you just send signals to the chip to light each row as if it was a digit, which you can do with the original LedControl library.

These pages may also be of help:
http://playground.arduino.cc/Main/MAX72XXHardware
http://playground.arduino.cc/Main/LedControl

I also looked through the 7219 data sheet again, and there doesn't seem to be a limit on the number of chips you can cascade together on the same serial bus (i.e., the same three pins on the Arduino), but using more than 8 may require modifying a library to allow it. At some point the transmission speed becomes an issue for animations, depending on your clock speed and the efficiency of your library. Each chip requires 17 clock cycles to get the data, so assuming a clock speed of 10 kHz (not unreasonable) and a 10x10 matrix of chips on the same serial bus, a full refresh would take (1700 cycles)/(10,000 cycles per second)=0.17s=170ms. Your maximum framerate would be just under 6 Hz, and that doesn't include any computation time on the frames themselves, just raw data transmission.

mjkzz

I think you can clock SPI at higher rate, like 200Khz even using software.

If you are going to do animations, I have a library here:

https://github.com/mjkzz/LedMatrix.git

It is buffer based, only one update to hardware is needed to dump memory image to cascaded led matrix, so it is rather fast.

Search for "mjkzz" on eBay :-)

CrossRoads

MAX7219 runs with no problem at default SPI rate of 4 MHz,
A full refresh of 10 chips, needing 2 bytes/register * 8 registers/chip * 10 chips can be done something like this:
Code: [Select]

for (registerLoop = 1; registerLoop<9; registerLoop = registerLoop +1){ // cycle thru 8 data registers, #1-8 (not 0-7)

digitalWrite(ssPin, LOW);  // replace with  PORTB = PORTB & B11111011;  // clear SS pin for example
   // now 16 SPI transfers: address & data pair for each chip
   for (chipLoop = 0; chipLoop<10; chipLoop = chipLoop +1){   // send to data to RegisterX, then x+1, x+2 ...x+1
   SPI.transfer(registerArray[registerLoop]);  // register address, 1 to 9
   SPI.transfer(dataArray[((registerLoop-1)*10)+chipLoop]); // so every 10th byte goes to next chip. subtract 1 since since column0 is register1
   } // done writing to same register for all chips
digitalWrite(ssPin, HIGH); // update the outputs  // replace with  PORTB = PORTB | B00000100;  // set SS pin for example

} // ready for next register


I did some timing testing over the weekend sending 41 bytes at 8 MHz SPI, got it down to 46uS, and 58uS when the outer loop was used and the inner loop was 41 discrete SPI.transfer commands
If you had 20 discrete SPI.transfer commands, you could spit those out in ~23uS, and ~35/uS for a pass thru the outerloop.
35uS * 8 register = 280uS to refresh the display. (or 560uS, 0.56mS if you stayed with 4MHz SPI)
30Hz frame rate is a full refresh every 33,000uS (33mS), seems like you'd have plenty of time to manipulate your data between frame update unless my math is off.


   


and I believe you could even go to 8 MHz.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

rhawbert

Thanks CrossRoads and mjkzz for these great info on the software optimization side... I'll sure refer to it once I figure out the hardware and wiring.


... you might not have to do any transposition at all, since you get to decide whether the "digit" represents a row or a column. Looking at the data sheet, your 5 rows are current sinks (cathodes), and therefore should be wired to the 7219 digit pins, and your 7 columns are current sources (anodes) and should therefore be wired to the 7219 segment pins.


In the image below (according to the matrix's datasheet in the top right) the rows are common-anodes and the columns the cathodes? Did I wired it correctly?



Not sure about the order neither if it's needed at all... but I connected the rows from the matrix to the SEG pins on the driver in crescent order, i.e:

    Matrix                 MAX7219
    • row1 (pin16) -> SEG A (14)
    • row2 (pin15) -> SEG B (16)
    • ...

Other topic I'm not so sure is the power supply solution in the image... I tried to separate the Arduino's power from the Source that will feed the drivers and respective matrices (preparing to connect more drivers and matrices), but read somewhere that the drivers must share the GRD with the Arduino... why?

If you feel like giving a closer look, the fritz file is here:
https://www.dropbox.com/s/c4qppnkl6fcx5tj/my-max7219.fzz
--
Rhawbert Costa

CrossRoads

Yes, all grounds must connect together so  all signals have common reference point.
I connected 4 8x8 matrixes & 4 MAX7219s powered by a Duemilanove.
Worked fine from 9V power supply, regulator overheated with 12V.
So you may or may not need to seperate the supplies.

Post a schematic - fritzing files are wlres & black boxes, no help at all.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

rhawbert

#9
Mar 12, 2013, 07:26 pm Last Edit: Mar 12, 2013, 07:41 pm by rhawbert Reason: 1
Ok... I managed to create some sort of schematic below:



Since I'd like to daisy-chain more than 10 drivers/matrices (35 to 40 actually) without worrying about overloading the Arduino, I tried to separate the power input but I'm not sure if I can connect both GRD lines - Arduino's and PSU - together like I've done (circled in red). Also not sure if I can connect the capacitors mixing the V+ from the PSU and the GRD from Arduino as shown.

But my main concern stills the same... if the current direction (sink/source) and the pins' connections order (from the matrix to the MAX7219) are correct or not.
--
Rhawbert Costa

CrossRoads

I can't see the drawing from here, but:
All Grounds MUST connect together. Connecting them at the source - the power supply - is fine.
Decoupling caps on the MAX7219 would ideally be from its Vcc pin to its Gnd pin.
Same for the '328P. Vcc & AVCC should both have caps from the pin to Gnd.
AREF also, cap from the pin to Gnd (do not connect to 5V, that's done internally) if you are doing any analog measurements. I add one always in case I want to add analog stuff later.
Segment pins source current (to anodes):
"Seven Segment Drives and Decimal Point Drive that source current to the display."
Digit pins sink current (from cathodes):
"Eight-Digit Drive Lines that sink current from the display common cathode."
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

rhawbert

I tested the schematic last night and the wiring was correct.

Now I'll try to connect the next matrices and start to write some funny animations  :D

I even made a video of it:
http://youtu.be/e5CdZwcm3xE


Thank you guys!
--
Rhawbert Costa

d82k

Dear All,

I am following this thread since I have a 8x8 bicolor matrix common anode which I would like to manage with two MAX7219, one for green and one for red.
I would like to remove the external psu, and get power from arduino. Is it enough to take of the psu and connect the V+ with the arduino 5v? I leave the resistor and capacitor as it is, right?
Thank you
dk



michinyon

No.  the arduino cannot supply enough current to run a whole lot of LED's.

d82k

Ops, I just read the answer now.. actually I'm a total beginner and I just tried this:

I have connected my bicolor matrix LE-MM103 (http://shop.boxtec.ch/pub/sure/LE-MM103_1.pdf) to the MAX7219 (only red color). Following rhawbert schematic.

Code: [Select]
Col Pin _______ Pin Row
DIN    1|o |24 DOUT
1 23 DIG 0  2| |23 SEG D 3   5
5 2 DIG 4  3|   M |22 SEG DP 22   1
GND    4|   A |21 SEG E 6   6
7 8 DIG 6  5|   X |20 SEG C 13   4
3 17 DIG 2  6|   7 |19 V+
4 14 DIG 3  7|   2 |18 ISET
8 11 DIG 7  8|   1 |17 SEG G 12   8
GND    9|   9 |16 SEG B 16   3
6 5 DIG 5 10| |15 SEG F 9   7
2 20 DIG 1 11|  RED |14 SEG A 19   2
LOAD  12|_______|13 CLK


Arduino pin 12 is connected to MAX7219 DIN pin 1
Arduino pin 11 is connected to MAX7219 CLK pin 13
Arduino pin 10 is connected to MAX7219 LOAD pin 12

I have also connected Arduino GND and VCC 5V.

Since I did not have a 28kOhm resistor I used a 22kOhm (does it affect anyhow?)

I applied the patch posted by LordPants to the LedControl and changed the loop function as follow to test everything:

Code: [Select]
void loop() {
  for(int i=0; i<8; i++) {
    for(int j=0; j<8; j++) {
      lc.setLed(0,j,i,true);
      delay(100);
      lc.clearDisplay(0);
    }
  }
}


It seems working.. Until now nothing exploded...

I cannot understand why rhawbert used two capacitor in parallel.. can't I just use the biggest one?

Next step is to connect a second MAX7219 for the GREEN part (only the left side is changed).

Code: [Select]
Col Pin _______ Pin Row
DIN    1|o |24 DOUT
1 24 DIG 0  2| |23 SEG D 3   5
5 1 DIG 4  3|   M |22 SEG DP 22   1
GND    4|   A |21 SEG E 6   6
7 7 DIG 6  5|   X |20 SEG C 13   4
3 18 DIG 2  6|   7 |19 V+
4 15 DIG 3  7|   2 |18 ISET
8 10 DIG 7  8|   1 |17 SEG G 12   8
GND    9|   9 |16 SEG B 16   3
6 4 DIG 5 10| |15 SEG F 9   7
2 21 DIG 1 11| GREEN |14 SEG A 19   2
LOAD  12|_______|13 CLK


The two MAX7219 RED and GREEN will have the DOUT connected together and share, in addition to the 8 rows (SEG X) the same CLK, LOAD, GND and VCC.

Am I about to burn something?

Thank you,
dk

Go Up