I am attempting to drive a 4 digit, common cathode LED display with a MAX7219CNG display driver and a PIC16F690 MCU for SPI communication.

The LED display does not light up and appears to not be driven by the MAX7219.

I tested the LED display functionality by itself and it works and is in fact common cathode.

The PIC16F690 SPI pins CLK, SDO, and CS appear to be working properly as the signals are correct on the oscilloscope and on the correct pins.

When powered, pin voltages on the MAX7219 are: all digits high at 5V, all segments low at 0V, Dout (pin24) does mirror the Din (pin1) data. With all digits pins high and all segment pins low, this is very similar to the shutdown mode which it enters when initially powered up.

One thing is that when I initialize the MAX7219, I put it into test mode for 1 second, which is supposed to light up all digits and segments but this does NOT happen.

So I am not sure but it is almost like there is no communication between the PIC16F690 and the MAX7219, but again, the SPI on the PIC16F690 does appear to be working. I can see the bytes being sent correctly (MSB first, 2 bytes per instruction set).

So I have no idea why this is not working and would really appreciate if someone would look things over and help me understand what the problem is.

I have included the schematic, the code, and the relevant datasheets. I am using MPLAB X IDE with XC8 compiler and coding in embedded C.

PIC16F690 datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/41262A.pdf

MAX7219 datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX7219-MAX7221.pdf

5641AH datasheet: http://www.xlitx.com/datasheet/5641AH.pdf


Schematic: Please note, the U13 identifier is wrong. It is a 5641AH LED display. enter image description here


    //NOT working.  LED display does not light up.
    //PIC16F690 CLK, SDO, and CS appear to be working properly as the signal are correct on the oscilloscope and on the correct pins.
    //The pin voltages on the MAX7219 are: all digit pins high at 5V, all segment pins low at 0V, Dout (pin24) does have the Din (pin1) correct signal.
    // PIC16F690 Configuration Bit Settings
    //#pragma config FOSC = INTRCIO   // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
    #pragma config FOSC = INTRCCLK  // Oscillator Selection bits (INTOSC oscillator: CLKOUT function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
    #pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
    #pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
    #pragma config MCLRE = ON       // MCLR Pin Function Select bit (MCLR pin function is MCLR)
    #pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
    #pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
    #pragma config BOREN = ON       // Brown-out Reset Selection bits (BOR enabled)
    #pragma config IESO = ON        // Internal External Switchover bit (Internal External Switchover mode is enabled)
    #pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)
    #include <xc.h>
    #define _XTAL_FREQ 8000000
    //#define _XTAL_FREQ 1000000
    //MAX7219 control registers
    #define DECODE_REG          0x09
    #define INTENSITY_REG       0x0A
    #define SCANLIMIT_REG       0x0B
    #define SHUTDOWN_REG        0x0C
    #define TEST_REG            0x0F
    //MAX7219 register program values
    #define DECODE_ALL          0xFF    //All digits decoded
    #define INTENSITY_LEVEL_8   0x08    //Intensity 17/32nds of Max Value
    #define SCANLIMIT_4         0x03    //Digits 0-3 (4 digits)
    #define SHUTDOWN_MODE_ON    0x00    //Shutdown mode ON
    #define SHUTDOWN_MODE_OFF   0x01    //Shutdown mode OFF
    #define TEST_MODE_ON        0x01    //Test ON
    #define TEST_MODE_OFF       0x00    //Test OFF
    //MAX7219 digit addresses
    #define DIGIT1              0x01
    #define DIGIT2              0x02
    #define DIGIT3              0x03
    #define DIGIT4              0x04
    //MAX7219 character addresses
    #define CHAR0               0x00
    #define CHAR1               0x01
    #define CHAR2               0x02
    #define CHAR3               0x03
    #define CHAR4               0x04
    #define CHAR5               0x05
    #define CHAR6               0x06
    #define CHAR7               0x07
    //General use
    char dummy;
    int loop = 0;
    void SPI_Write(char reg, char data)
        PORTCbits.RC6 = 0;  //Set CS line low to transmit
        SSPBUF = reg;  //Register address
        while (SSPSTATbits.BF == 0){};
        dummy = SSPBUF;
        SSPBUF = data;  //Value to send to register 
        while (SSPSTATbits.BF == 0){};
        dummy = SSPBUF;
        PORTCbits.RC6 = 1;  //Set CS line high to latch sent data
    void main() 
        //All ports set to digital low
        PORTA = 0x00;
        PORTB = 0x00;
        PORTC = 0x00;
        //All analog ports disabled
        ANSEL  = 0x00;
        ANSELH = 0x00;
        //All ports set to output
        TRISA = 0x00;
        TRISB = 0x00;
        TRISC = 0x00;
    //Clock setup - clock set to 8MHz = 111
        OSCCONbits.IRCF0 = 1;
        OSCCONbits.IRCF1 = 1;
        OSCCONbits.IRCF2 = 1;
    //SPI port setup
        //CLK - RB6
        TRISBbits.TRISB6 = 0;
        //SS - RC6
        TRISCbits.TRISC6 = 0;
        //SDO - RC7
        TRISCbits.TRISC7 = 0;
        //SDI - RB4
        //TRISBbits.TRISB4 = 1;
    //SPI module setup
        SSPSTATbits.CKE = 0;    //transmit on rising edge
        SSPSTATbits.BF = 0;     //buffer clear
        SSPCONbits.CKP = 0;     //clock polarity - idle low
        SSPCONbits.SSPM0 = 0;   //SPI Master mode, clock = FOSC/4
        SSPCONbits.SSPM0 = 0;
        SSPCONbits.SSPM0 = 0;
        SSPCONbits.SSPM0 = 0;
        SSPCONbits.SSPEN = 1;   //enable SPI
        __delay_ms(10);         //allow to settle
            //Initialize MAX7219CNG
            SPI_Write(DECODE_REG, DECODE_ALL);
            SPI_Write(SCANLIMIT_REG, SCANLIMIT_4);
            SPI_Write(TEST_REG, TEST_MODE_ON);
            SPI_Write(TEST_REG, TEST_MODE_OFF);
            while (1)
                //Write the number 2 to digit 2
                SPI_Write(DIGIT2, CHAR2);
  • \$\begingroup\$ Break it up and test the parts in isolation. Use an Arduino that's working, and try using its SPI to drive the display. Get each piece working first, then integrate. You'll get to the finished line faster, too. \$\endgroup\$ Oct 2, 2023 at 18:29
  • \$\begingroup\$ Complexity is your #1 enemy! \$\endgroup\$ Oct 2, 2023 at 18:31
  • 1
    \$\begingroup\$ @MicroservicesOnDDD, thank you for your reply and your advice. I am not using an Arduino. I am using the SPI on a PIC16F690 to communicate with the MAX7219. I have already checked all the individual components as much as possible, everything seems OK. I also tested an 8 digit, max7219 driven pre-assembled LED display module with this setup and that did not work either. So it all points to either my code or something odd with how the PIC's SPI interfaces with the MAX7219. Can you see anything wrong with the code? \$\endgroup\$
    – Pat
    Oct 4, 2023 at 9:06
  • 1
    \$\begingroup\$ @MicroservicesOnDDD I also initially tried this setup with a PIC16F18446 but again got no result. I do not see any issues with the electrical specifications on any of the components that I am using but perhaps I have missed something. I feel that the problem is on my end but I can't find what I am doing wrong. Does everything look OK? I mean, as I have presented the setup, SHOULD this work? Should I be able to communicate via SPI with a MAX7219 and a Microchip PIC16 MCU? As for your advice, I agree completely, I will recheck everything again. \$\endgroup\$
    – Pat
    Oct 4, 2023 at 9:16
  • 1
    \$\begingroup\$ @MicroservicesOnDDD Oh! Sorry about that. I think you meant that I should use an Arduino to figure out if the MAX7219 is working or not. Yes, good suggestion. Unfortunately I have never used an Arduino nor do I have any. If all else fails though, I may do just that. \$\endgroup\$
    – Pat
    Oct 4, 2023 at 13:39

1 Answer 1


I have the solution to this problem with the help of some helpful people.

The PIC16F690 has a design limitation in that it does not use a latch register for read/write operations to a PORT. Instead it reads and writes directly to the PORT itself. This causes issues and under certain read/write conditions can cause certain micro-controller pins to go high when you don't want them to or to act erratically. It is known as the Read-Modify-Write problem for Microchip PIC16. I believe it can be worked around via software.

A good explanation can be found here: https://download.mikroe.com/documents/compilers/mikroc/pic/help/rmw.htm

Per this website and using PORTB as an example,

To correct the problem in the code, insert a delay after each PORTB.Bx = 1 line, or modify the entire PORTB register in a single line PORTB = 0b00000011.

This was a big issue for me as I could not figure out what on earth the MCU (or my oscilloscope) was doing. I also do not fully understand how this issue was causing that specific block of code to not execute, but it was responsible as I decided to use the PIC16F18446 and now everything works. I think the successive write operations I was performing for the initalization of the MAX via SPI was causing the pin values to invert. It was very confusing. Microchip fixed this issue with the PIC16F18xxx series MCU and I think more generally the PIC16F1xxxx series MCUs.

I would not use the PIC16F690 for this type of application where SPI in involved. Save yourself the headaches and use the updated MCUs.

I would also note that concerning SPI communication, one must be careful of when the host shifts data out and when the client shifts data in. The host needs to shift data out on the opposite clock edge to when the client shifts data in. The MAX7219/7221 shifts data in on the rising edge of the clock. The host then must shift data out on the falling clock edge. The correct CKE and CKP bit settings for the PIC16F690 communicating via SPI with the MAX7219/7221 is CKE=0, CKP=0. For the PIC16F18446, it is CKE=1, CKP=0.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.