Max7219 and Common Anode Displays

How to drive common anode displays with the Max7219 and an Arduino

Finding myself with a bunch of common anode 7 segment displays and some left over max7219s, I was soon scratching my head wondering why I couldn’t get anything working. I eventually realised that the max7219 is designed for common cathode displays only, it doesn’t work at all with common anode displays.

Or does it? With a little effort and some mind-bending thinking the max7219 can be persuaded to control these common anode displays too.

Reverse the wiring

Simple right? Just flip anode and cathode connections on the IC. All segment pins on the max7219 now connect to the common anode pins on the display and all digit pins on the max7219 connect to the segment cathode pins on the display.

A little something like :

reverse

Turn off BCD mode

Goes without saying as each segment will need to be addressed individually. BCD mode will be turned off. Set the max7219 decode mode register 0x09 to 0.

Turn addressing on its head

Normally (with bcd mode off) to turn on, say, segment C on digit 1 you would just send 0b00000100 to digit 1.

A simple spi transfer command might be :

 MAX7219Send(1,0b00000100);  // sends bit 3 / seg C, to digit 1

or, to digit 2 :

MAX7219Send(2,0b00001000);  // sends bit 4 / seg D, to digit 2

Clearly this isn't going to work with the new wiring. As the segments are now connected to the digit pins on the max7219. I need to send the 8 bit segment data across all digit pins, so :

Bit 3 / segment C to digit 1 :

 
MAX7219Send(1,0b0000000); // seg A
MAX7219Send(2,0b0000000); // seg B
MAX7219Send(3,0b0000001); // seg C 
MAX7219Send(4,0b0000000); // seg D
MAX7219Send(5,0b0000000); // seg E
MAX7219Send(6,0b0000000); // seg F
MAX7219Send(7,0b0000000); // seg G
MAX7219Send(8,0b0000000); // seg dp

All segments on, digit 2 :


MAX7219Send(1,0b0000010); // seg A
MAX7219Send(2,0b0000010); // seg B
MAX7219Send(3,0b0000010); // seg C 
MAX7219Send(4,0b0000010); // seg D
MAX7219Send(5,0b0000010); // seg E
MAX7219Send(6,0b0000010); // seg F
MAX7219Send(7,0b0000010); // seg G
MAX7219Send(8,0b0000010); // seg dp

I've written some basic code for the Arduino (but the same principle will work with the Raspberry Pi) to send numbers to each digit position on my 4 digit module.


// Controlling a common anode 4 digit 7seg display with the Max7219
// David Barton, 2016

#include <SPI.h>

// The Max7219 Registers :

#define DECODE_MODE   0x09                       
#define INTENSITY     0x0a                        
#define SCAN_LIMIT    0x0b                        
#define SHUTDOWN      0x0c                        
#define DISPLAY_TEST  0x0f       

byte chip_select=10;  // spi chip select pin

byte display_num[4];  // array to hold our 4 digits

// standard 7 seg display numbers
byte number_seg[]=
{
  0b00111111,  // 0 
  0b00000110,  // 1
  0b01011011,  // 2
  0b01001111,  // 3
  0b01100110,  // 4
  0b01101101,  // 5  
  0b01111101,  // 6
  0b00000111,  // 7
  0b01111111,  // 8
  0b01100111   // 9
};


void MAX7219Send(uint8_t address, uint8_t value) 
{
  // Ensure LOAD/CS is LOW
  digitalWrite(chip_select, LOW);

  // Send the register address
  SPI.transfer(address);

  // Send the value
  SPI.transfer(value);

  // Tell chip to load in data
  digitalWrite(chip_select, HIGH);
}
  
 
void setup() 
{
  pinMode(chip_select,OUTPUT); // chip select
  
  SPI.begin();

  // set up max7219

  // Disabled BCD mode
  MAX7219Send(DECODE_MODE, 0x00);
  
  // brightness
  MAX7219Send(INTENSITY, 0x14);
  
  // Scan
  MAX7219Send(SCAN_LIMIT, 0x07);
  
  // Turn on chip
  MAX7219Send(SHUTDOWN, 0x01);

 // fill with 4 numbers
 display_num[0]=1;
 display_num[1]=2;
 display_num[2]=3;
 display_num[3]=4;

 for (byte each_segment=1;each_segment<=8;each_segment++)
 {
     // build the byte to send 
     byte output=0b00000000;

    // 4 digits 
    for (byte digits = 0; digits < 4; digits++)
    {
      
    byte number_to_display = display_num[digits];  
  
   // for out chosen number to display get it's segment bit at the position current position of 'each_segment'
    bool seg= number_seg[number_to_display] & (0b00000001 << (each_segment-1) );
 
    //set this bit in our output byte   
     output = output | (seg << digits);
      
    }

     MAX7219Send( each_segment, output);
  }
   
}

void loop() {
  
}

It's possible to address up to 8 digits with one max7219. Here's my final setup controlling 8 common anode digits :

Common Anode and the Max7219

12 thoughts on “Max7219 and Common Anode Displays

  1. 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.

    1. Sorry @Giorgio Croci Candiani, but this is not true. A Max7219 Controller can also controll one 8×8 matrix. 8×8 matrix contains both: common annodes (8) und common cathodes (8). You only have to adjust your sketch a little bit.
      There are NO current or brightness limitations!
      8×8 Matrix or two 4-Digit 7 seg common cathode Displays doesn?t matter. Its all a bunch of 64 LED?s they are just placed in a different pattern…

      1. I think the original comment makes a lot of sense instead. I think your understanding of what a common anode or cathode is, is a bit off. A 8×8 matrix is either common anode or cathode, not both. And of course there are current limitation. Pay attention or you are going to fry something.

      2. Even if you have an 8×8 matrix, a segment pin of MAX7219 feeds only one digit at a time, and only its own segment. To show another digit, you turn the previous one off (to GND) and then turn on the other digit pin.

        In other words, in a common anode display, each digit pin (anode) may feed all 8 segments. But in common cathode, each segment pin (anode) feeds only that segment at once normally. Of course, you can turn all cathodes on (every segment will be lit), but that’s not how it should work.

      3. You’re dead wrong.

        While it’s true that an 8×8 display has 8 cathodes and 8 anodes, it is operated in MULTIPLEXED fashion. The original commentor is precisely correct in their statement.

    1. Thanks for sharing your code David, I was working on something very similar to make use of some white LED 7-segment CA displays I got hold of for free and your code has some nice bit manipulation trick that saved me some time. I would agree that there is no reason for the current to excessive as in effect this is the same as driving an 8X8 LED matrix, which was my starting point when looking into this. I have a prototype Internet clock running now on an ESP8266 connected to a MAX7219 with one of the displays. Thanks again, great work.

  2. You saved my day. I got exactly the same problem and though of how to write this control code. I had a PCB project ready to be ordered, but decided to just make a final check, and was also puzzled with the circuit behavior. How wise that decision was!

  3. I am sorry Giorgio, but the brightness of the 7219 is not controlled by current, yes for PWM control. So, no matter how you connect the LEDs or segments, the PWM will control brightness and the current during the PWM is high enough to lit all the LEDs really bright. The datasheet states about the PWM.

  4. I solve the same problem by just adding a PNP transistor (BC557) for each digit and connect it with MAX7219 this way :
    E with VCC 5v
    B with MAX7219 outputs D0 to D7 (using 1k resistor)
    C with CA for eash digit
    then from the code reverse all signals
    for examble to display the number 7 at segment 2 :
    mx.setRow(2, 0b11110001);
    instead of
    mx.setRow(2, 0b00001110);

    for more informations or help
    [email protected]

Leave a Reply to HartCad Cancel reply

Your email address will not be published. Required fields are marked *