Zum Inhalt

Drive Max7219/Max7221 with common anode displays

As you maybe already know, the max7219 and max7221 chips are serially interfaced (SPI) 8-bit LED drivers. These chips work perfect on 7 segment displays if they have common cathode pins, because they are designed for those display. If you have common cathode 7 segment display you get in touch with the benefit of these led drivers, because they handle the multiplexing in an easy way. They have built-in bcd decoder for easily displaying information and if you don’t want to use the decoder you can byte-wise set every digit of your display. For example, if you want to display the number „0“ without bcd decoding, you create the bit mask as follows:


The bit mask for number „0“ is: 0x0111111
To display this number you have to address (e.g.) digit1 and send your „number byte“ afterwards. That works perfectly.

While the max7219 is a great thing for driving 7 segment displays with common cathode I came to the point when multiplexing is a pain in the ass. That happened to me when I tried to drive 7 segment displays with common anode. First of all you have to wire your display backwards. That means you have to wire the common anode pins to the segment pins of your max7219 and the cathode pins to the digit pins.
As you can imagine, this backwards wiring has an impact for driving your display, because the imaginary multiplexing table is rotated by 90°.
For example: I have two 4 x 7 segment displays common anode (ltc-4620hg – 8 digits in total – maximum for max7219). If I want to display the number „0“ I cant address digit1, because digit1 is wired across all (from a max7219 perspective) digit pins. Now, what I have to do to display a „0“ on digit1 is splitting the byte (my 0x0111111) and scatter each bit to the right position of each digit ( 90° rotation & repositioning).


If you handle this right, that should do the trick to run your 7-segment common anode display with a max7219/max7221!

After we took a look at the multiplexing, lets write some code to implement this in software, to drive your digits with the ease of the max7219.We call our function Display with 2 parameters:

We store each byte for each line (digit 1a-8a) in an array like this:

As we know, there is no bcd decoding and we don’t want to use hex format for displaying numbers on our display I created a char array with all numbers corresponding to their position in the array itself. My array looks like this:

Every number[x] is the binary format for the number X (e.g. number[2] represents the binary format for displaying the number 2). First of all we have to shift all bits left, depending on the digit we want to display (keep figure 2 in mind, just shift everything from e.g. a to e -> from digit1 to digit5). We start with the default positioning on digit1, by creating a bit mask where bit1 is high:

If we want to draw our number onto a different digit, we have to shit this to the left, or leave it, where it is if we want to print to digit1

After we have set the correct position, we iterate through our numbers array and check if we have to set the bit of DigValues[x] at out bPosition location high or low.

That’s it. Now you can call Display(dig,number) to display every number to every dig on your display. At the moment I don’t need any characters, so I would stop at this point. I hope that helps you to understand how you can use a 7 segment display with common anode in combination with max7219.

Here is an example for a Atmega8 with internal 8Mhz osc

Veröffentlicht inAllgemeinAVR - MiscCodingHobby

22 Kommentare

  1. Frank Frank

    Great…thank you!

  2. Nice tutorial, i’ve make digital stopwatch – seven segment 4 inch ( CA ) with max7219 …to invert logic i use transistor TIP41….it work
    thank’s for your tutorials…

  3. Thx for sharing. My first Idea was a inverter as well but then stumbled across someone who wrote that it works without any additional hardware. That’s the main reason why I wrote this :).

  4. Felix Felix

    Hi Marco! Great tutorial! I’m trying to implement it in my own project. But for some reason I can get segment „a“ and „b“ to work. If I use the binary representation: 0b11111111 everything lights except those two. Their are wired to pin 11 (dig1) and pin 6 (dig2) of the MAX7219 respectively.

  5. Hi Felix,
    do you use your own code, or mine? How many digits do you have?
    Is it possible to take a picture and post a link at the comments?

    To test if everything is wired correctly try to set the max7219 to 255 at all digits, with SPI_SEND( from 0 – 9, 255). Your display should show all digits as 8.

    I spent hours to find a bug where I have mix up the seg wire and the dig wire.

  6. Felix Felix

    Hi Marco,

    Thanks for your reply. I’m adapted your code to work with my compiler (e.g. SPI_SEND = SPI1_WRITE).
    As a matter of fact I had a wiring problem! I solved it, and your code seems to work. I’m just wondering on how to light the ‚dp‘ using your code? Its connected to the DIG 7 pin on my MAX7219.

  7. Hi Felix,

    Check the Max7219 Datasheet. You can find the description, on how to light up dp at page 8. I think you have to extend my code. Try to add a new parameter (boolean maybe) to „void display“. Depending on this value (true / false) use binary AND to set the highest bit to 0 (dp=off) or 1 (dp=on) when you set DigValues[x].

  8. Felix Felix

    Hi Marco,

    Thanks for your help. I’ll look into that. And again, very nice piece of code!

  9. Thank you :). If you have any further question, write a comment.
    I’m moving to a new apartment, so I’m a bit affected to write and test code at the moment.

  10. slatan slatan

    i have a common annode with a dot. i connected the DP to Digit7 on the MAX7219 but how can i activate it?

  11. Very inspiring this helped me a lot to find the motivation,

    Thanks !

  12. Kelzan Kelzan

    This is brilliant, thanks for the example. This fits in perfectly with what I’m trying to do, I really wanted to use a MAX7221 with some existing common anode LED’s that were already mounted in a panel.

    Thank you so much for sharing!

  13. Celso Celso

    How can I use this code with arduino uno?
    I’m asking because I don’t see loop and setup functions.
    what are the SPI port numbres defined in this code?

  14. You can’t use it with Arduino, because it is written in C and for example, the SPI ports are defined by the the Chip (in this Case PB2)

  15. Kalpesh Patel Kalpesh Patel

    Hi dear,

    thanks for your code… but i just copied and run in proteus…instead of 8 it shows 0 and not showing 9…. have you checked fully your code ? or ?

    I am trying to solve the error…i just thought so put comment here… don’t mind… good work….

  16. Hey, thanks for your comment! Yes, the last and published version was running correctly I think, but I cant test it at them moment, because these displays are used in another project.
    Hope you can fix that error!

  17. Kalpesh Patel Kalpesh Patel

    Hi Marco…

    i have fixed the error…. but i need a Trick… how to turn of particular display if i have 4 Displays… i want to turn off 4th display when value is only 3 – digit…. any idea ? Please suggest….

  18. dtbaker dtbaker

    Hello & Help!

    I am trying to run this code on a NodeMCU in Lua. I have tried to convert it best I can but it’s not giving any meaningful results. Are you able to have a quick look over my conversion and see if I missed a bitwise operator or something like that?


  19. I think it doesn’t work, because a lot of funcions are not available in LUA. So maybe you have to rewrite everything by your own, sorry!
    Kind Regards Marco

  20. Giorgio Croci Candiani Giorgio Croci Candiani

    Hallo Marco,
    your solution is a clever trick software-wise, however I feel the need to draw attention to a pair of points that should not be overlooked.
    The digit (common cathode) pins and the segment pins on the MAX have two important differences:
    (a) digit pins are rated for the whole 8-segment current (at full-load, a digit pin carries current 8*Iseg for 1/8 of the time, while a segment pin carries Iseg for the whole time). This means that the segment pins are likely to be overloaded if one does not pay attention;
    (b) segment pins have a constant-current control. This means that, when they are used as common leads, the segment brightness will slightly depend on how many segments are active in the digit at hand.
    Of course, these limitations may be circumvented by severely limiting the total display current (max Iseg is about 30..40 mA according to the datasheet, which amounts to little more than 3..4 mA per segment) and being aware that the segment brightness will be a little variable and uneven.
    I hope that my observations may be useful.

  21. Hey Giorgio,

    thank you for your comment. You are right, these are points I didn’t mention or even thought about.
    I was so happy to drive these segments and publish a solution for it, without thinking about the current drawn. I think keeping this in mind and measuring and double check the data sheet should prevent burning your components. In the meantime I would buy the correct segments and drive them as designed, but back in 2013 I wanted to run them, no matter what it takes.
    Your comment will be usefull for all people who try to run it this way!

    Thanks again!

    Kind regards

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.