8x8 MAX7219 Updating Slowly/Not At All

Hi guys, hoping to narrow down why my project is performing a bit unpredictably. Any suggestions and help is greatly appreciated.

I have two NodeMCU ESP8266s. One is a transmitter/client ESP with an array of hall effect sensors, which transmits their state over wifi (UDP) to a receiver/server ESP, that displays a number (that represents the magnet state) on a MAX7219 8x8 LED matrix. This was working very well when the receiver/server had a TM1637 7-segment LED display (I2C), but upon changing to the MAX7219 (SPI), the display does not always update/receive the transmitted packet. When moving a magnet near or away from a sensor, sometimes (probably 50% of the time) the display does not update, and stays on the current number.

I've tried troubleshooting, but am a bit confused as to why the display has made such a difference (I assume it's the change to SPI). Any help is greatly appreciated, as always. Below code is transmitter/client, followed by the receiver/server.

(the receiver/server code has a lot of TM1637 code commented out, as it's a work in progress)

Transmitter/Client Side


// NodeMCU ESP8266-based manual gear shifter detector & display using the MAX7219 8x8 LED Matrix 
// module. 3x A3144 Hall Effect Sensors are connected via pins 2, 3 & 12, and when a magnet/s is 
// present, will display gear One (pin 2), Gear Two (pin 3), Gear Three (pin 12), Gear Four (Pins 
// 2 & 12), Gear Five (Pins 3 & 12), and Reverse (pins 2 & 3) - otherwise Neutral is displayed.

//Hall effect sensor coding is a modified example as provided by Arduino Forum member johnwasser.
//https://forum.arduino.cc/t/my-codes-inefficiency/851135/9

//UDP server/client scripts heavily modified based upon Siytek.com example.
//https://siytek.com/communication-between-two-esp8266/

// ***********Sensor/Transmitter/Client Side************

#include "TM1637Display.h"
#include "ESP8266WiFi.h"
#include "WiFiUdp.h"

#define WIFI_SSID "E36GearShifter"                 // Set WiFi credentials
#define WIFI_PASS "owwmyfrickenexpansiontank"

WiFiUDP UDP;                                       // UDP
IPAddress remote_IP(192,168,4,1);
#define UDP_PORT 4210

const int CLK = D1;                                // Set the CLK pin connection to the display
const int DIO = D2;                                // Set the DIO pin connection to the display
const uint8_t blank[] = {0x00, 0x00, 0x00, 0x00};  // Declares the value of "blank"
const uint8_t data[] = {0xff, 0xff, 0xff, 0xff};   // Declares "data" as all segments on
const uint8_t n[] =                                // Required segments to display the character "n"
{
  SEG_C | SEG_E | SEG_G
};
const uint8_t r[] =
{
  SEG_E | SEG_G
};                                    // Required segments to display the character "r"

TM1637Display display(CLK, DIO);                 //set up the 4-Digit Display.

// int TM1637Display(CLK, DIO);
const int FirstGearPin = D0;
const int SecondGearPin = D3;
const int UpperGearsPin = D4;
const int ledPinD5 = D5;
const int ledPinD6 = D6;
const int ledPinD7 = D7;

const char * GearNames[8] =
{
  "Neutral",     // 0
  "First Gear",  // 1 (FirstGearPin)
  "Second Gear", // 2 (SecondGearPin)
  "Reverse",     // 3 (FirstGearPin + SecondGearPin)
  "Third Gear",  // 4 (UpperGearsPin alone)
  "Fourth Gear", // 5 (FirstGearPin + UpperGearsPin)
  "Fifth Gear",  // 6 (SecondGearPin + UpperGearsPin)
  "INVALID"      // 7 (FirstGearPin + SecondGearPin + UpperGearsPin)
};

enum Gears {Neutral, First, Second, Reverse, Third, Fourth, Fifth};

int counter = 0;

void setup()
{
  Serial.begin(115200);                              // Setup serial monitor
  pinMode(FirstGearPin, INPUT);
  pinMode(SecondGearPin, INPUT);
  pinMode(UpperGearsPin, INPUT);
  pinMode(ledPinD5, OUTPUT);
  pinMode(ledPinD6, OUTPUT);
  pinMode(ledPinD7, OUTPUT);

  WiFi.begin(WIFI_SSID, WIFI_PASS);                // Begin WiFi
  WiFi.mode(WIFI_STA);
  
  //Serial.print("Connecting to ");                  // Connecting to WiFi...
  //Serial.print(WIFI_SSID);
  
  //while (WiFi.status() != WL_CONNECTED)            // Loop continuously while WiFi is not connected
  //{
   // delay(100);
    //Serial.print(".");
  //}
  
  //Serial.println();                                // Connected to WiFi
  //Serial.print("Connected! IP address: ");
  //Serial.println(WiFi.localIP());
 
  UDP.begin(UDP_PORT);                             // Begin UDP port
  Serial.print("Opening UDP port ");
  Serial.println(UDP_PORT);

  display.clear();                                 // Clear display
  display.setBrightness(7);                        // Set the diplay to maximum brightness
  display.setSegments(blank);                      // Clear display
}

void DisplayGear(enum Gears gear)
{
  // Set the LEDs to match the sensor inputs.
  digitalWrite(ledPinD5, gear & 1);
  digitalWrite(ledPinD6, gear & 2);
  digitalWrite(ledPinD7, gear & 4);

  printMessage(GearNames[gear]);

  display.clear();

  switch (gear)
  {
    case Neutral:
      display.setSegments(n, 1, 3);
      break;

    case First:
    case Second:
      display.showNumberDec(gear, false, 4);
      break;

    case Reverse:
      display.setSegments(r, 1, 3);
      break;

    case Third:
    case Fourth:
    case Fifth:
      display.showNumberDec(gear - 1, false, 4);
      break;

    default:
      break;
  }
}

void loop()
{
  static byte previousGear = 7;

  byte currentGear = (digitalRead(FirstGearPin) == LOW)
                     + ((digitalRead(SecondGearPin) == LOW) << 1)
                     + ((digitalRead(UpperGearsPin) == LOW) << 2);

  if (currentGear == previousGear)
    return;  // Nothing to do if the gear has not changed

  previousGear = currentGear;

  DisplayGear((enum Gears)currentGear);
  
  UDP.beginPacket(remote_IP, UDP_PORT);               // Send packet
  UDP.write(currentGear);
  UDP.endPacket();
  delay(100);
}

void printMessage(String message)
{
  counter++;
  Serial.print(counter);
  Serial.print(" ");
  Serial.println(message);
  //delay(200);
}

Receiver/Server Side


// NodeMCU ESP8266-based manual gear shifter detector & display using the MAX7219 8x8 LED Matrix 
// module. 3x A3144 Hall Effect Sensors are connected via pins 2, 3 & 12, and when a magnet/s is 
// present, will display gear One (pin 2), Gear Two (pin 3), Gear Three (pin 12), Gear Four (Pins 
// 2 & 12), Gear Five (Pins 3 & 12), and Reverse (pins 2 & 3) - otherwise Neutral is displayed.

//Hall effect sensor coding is a modified example as provided by Arduino Forum member johnwasser.
//https://forum.arduino.cc/t/my-codes-inefficiency/851135/9

//UDP server/client scripts heavily modified based upon Siytek.com example.
//https://siytek.com/communication-between-two-esp8266/

// ***********Receiver/Display/Server Side***********

#include "ESP8266WiFi.h"
#include "WiFiUdp.h"
#include "LedControl.h"
//#include "TM1637Display.h"

int DIN = D0;                                         //Set the DIN/?Didigtal IN pin
int CS = D1;                                          //Set the CS/?Chip Select pin
int CLK = D2;                                         //Set the CLK/Clock pin
LedControl lc=LedControl(DIN, CLK, CS, 0);

//Set gear numbers as bytes for the display
int One[8] ={B00000000,B00011000,B00111000,B00011000,B00011000,B00011000,B00111100,B00000000};
byte Two [8]={B00000000,B00011000,B00100100,B00000100,B00001000,B00010000,B00111100,B00000000};
byte Three [8]={B00000000,B00111000,B00000100,B00011000,B00001100,B00000100,B00111000,B00000000};
byte Four [8]={B00000000,B00000100,B00001100,B00010100,B00100100,B01111110,B00000100,B00000000};
byte Five [8]={B00000000,B01111110,B01000000,B00111100,B00000010,B01000010,B00111100,B00000000};
byte Reverse [8]={B00000000,B01111100,B01000010,B01000010,B01111100,B01000010,B01000010,B00000000};
byte Neutral [8]={B00000000,B01000010,B01100010,B01010010,B01001010,B01000110,B01000010,B00000000};

//const int CLK = D1;                                 // Set the CLK pin connection to the display
//const int DIO = D2;                                 // Set the DIO pin connection to the display
//const uint8_t blank[] = {0x00, 0x00, 0x00, 0x00};   // Declares the value of "blank"
//const uint8_t data[] = {0xff, 0xff, 0xff, 0xff};    // Declares "data" as all segments on
//const uint8_t n[] =                                 // Required segments to display the character "n"
//{
//  SEG_C | SEG_E | SEG_G
//};
//const uint8_t r[] =                                 // Required segments to display the character "r"
//{
//  SEG_E | SEG_G
//};

//TM1637Display display(CLK, DIO);                     //set up the 4-Digit Display

// Set AP credentials
#define AP_SSID "E36GearShifter"
#define AP_PASS "owwmyfrickenexpansiontank"

// UDP
WiFiUDP UDP;
IPAddress local_IP(192, 168, 4, 1);
IPAddress gateway(192, 168, 4, 1);
IPAddress subnet(255, 255, 255, 0);
#define UDP_PORT 4210

// UDP Buffer
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];

void setup() {

  // Setup TM1637 Display
  //display.clear();
  //display.setBrightness(7);       // Set the diplay to maximum brightness
  //display.setSegments(blank);     // Clear display
  lc.shutdown(0,false);
  lc.setIntensity(0,4);
  lc.clearDisplay(0);

  // Setup LED pin
  pinMode(2, OUTPUT);

  // Setup serial port
  Serial.begin(115200);
  Serial.println();

  // Begin Access Point
  Serial.println("Starting access point...");
  WiFi.softAPConfig(local_IP, gateway, subnet);
  WiFi.softAP(AP_SSID, AP_PASS);
  Serial.println(WiFi.localIP());

  // Begin listening to UDP port
  UDP.begin(UDP_PORT);
  Serial.print("Listening on UDP port ");
  Serial.println(UDP_PORT);

}

void loop()
{
  // Receive packet
  UDP.parsePacket();
  UDP.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);

  if (packetBuffer[0] == 0) {
    Serial.println("Neutral");
    for(int i=0;i<8;i++) lc.setRow(0,i,Neutral[i]);
    //lc.setRow(Neutral);
    //display.setSegments(n, 1, 3);
  }

  if (packetBuffer[0] == 1) {
    Serial.println("One");
    for(int i=0;i<8;i++) lc.setRow(0,i,One[i]);
    //lc.setRow(One);
    //display.showNumberDec(1, false, 1, 3);
  }

  if (packetBuffer[0] == 2) {
    Serial.println("Two");
    for(int i=0;i<8;i++) lc.setRow(0,i,Two[i]);
    //lc.setRow(Two);
    //display.showNumberDec(2, false, 1, 3);
  }

  if (packetBuffer[0] == 3) {
    Serial.println("Reverse");
    for(int i=0;i<8;i++) lc.setRow(0,i,Reverse[i]);
    //lc.setRow(Reverse);
    //display.setSegments(r, 1, 3);
  }

  if (packetBuffer[0] == 4) {
    Serial.println("Three");
    for(int i=0;i<8;i++) lc.setRow(0,i,Three[i]);
    //lc.setRow(Three);
    //display.showNumberDec(3, false, 1, 3);
  }

  if (packetBuffer[0] == 5) {
    Serial.println("Four");
    for(int i=0;i<8;i++) lc.setRow(0,i,Four[i]);
    //lc.setRow(Four);
    //display.showNumberDec(4, false, 1, 3);
  }

  if (packetBuffer[0] == 6) {
    Serial.println("Five");
    for(int i=0;i<8;i++) lc.setRow(0,i,Five[i]);
    //lc.setRow(Five);
    //display.showNumberDec(5, false, 1, 3);
  }
}

First, try some example sketches that come with the LEDControl library to verify that you have wired the esp and max chip correctly.

Thanks PaulRB.

I initially tried some demo sketches and it seemed to work well. The 8x8 matrix is on a PCB with a MAX7219 and SPI pins (common eBay module), so I only have to connect 5 wires.

OK, good.

I can think of no reason why the change to SPI would cause the intermittent problem. Actually, you are not even using SPI as such, only a software emulation, so this is really no different to using the TM1637 display.

Have you tried switching back to the TM1637 display, with no other changes to the circuit, to check that nothing else has changed which could be causing the problem?

You could also try connecting the matrix, but commenting out the lines of code in loop() that update it, leaving only the Serial.println() to allow you to check that the packets are received.

Post a Schematic, not a frizzy thing, it sounds like I/O conflict or grounding problems.

Thanks for the additional suggestions. I've created this schematic; apologies for it being an MS Paint attempt. The pin assignments are correct, and it does work as expected with a TM1637 on the receiver/display/server side (which is where switching to the 8x8 causes issues).

You could also try connecting the matrix, but commenting out the lines of code in loop() that update it, leaving only the Serial.println() to allow you to check that the packets are received.

I will try that next, thanks.

A small update. I tried switching back to a TM1637 display (I2C), no change. And paired with the serial output, it seems that sometimes the packets aren't received (or sent). I also changed out to another ESP, no difference. I also reviewed the project prior to the addition to of the 8x8 matrix, and it seems the problem was there before that - so definitely not related to SPI.

I'm not really sure how to troubleshoot it from here, because I don't know which side is letting the team down. My only thought is to find a way to have the sensor state ("currentGear") be written to a packet and sent continuously.

Packets that are not sent cannot be received! Your first task is to figure out if the packets are being sent or not. Can't you tell, by what you see on the sending circuit's display? Looking at the structure of the code, I can't see how it could avoid sending the packet when the display gets updated. There is no conditional code between those two actions.

I suggest creating a simple-as-possible sketch for the receiver in order to test that the packets are being sent/received. Nothing else except receiving a packet and printing it to serial monitor. Then give the whole thing a thorough test, on the bench, with no metal or other dense items between the sender and receiver antennae (but keep them about a metre apart, in case the signal is so strong that it's overwhelming the receiver).

How about posting a real schematic. You have a 5V device connected to a 3V3 device. Show all connections. If your picture is correct you will need a level converter.

Hi gilshultz, I'm sorry my schematic has upset you so much by it not being a "real" schematic. I'm not an electrical engineer, this is my hobby, and I learn by doing. I'm not sure what exactly you expect, but this diagram is drawn in MS Paint (not Fritzing, which is what I assume you mean), although it shows all connections as they are in the project.

I actually hadn't realised that I had mixed 5V and 3.3V devices, whoops. Thanks for pointing that out. I'll look into a logic level converter.

Probably not necessary. So far I have found that max7219 responds ok to the 3.3V signals from an esp8266. However, you should power the max7219 with 5V, it's not rated to work down to 3.3V.

Works fine for me too - so far. :grin:

Hi,
Can you post link to data/specs of your Hall Effect devices?

Thanks.. Tom.. :grinning: :+1: :coffee: :australia:

1 Like

I've ordered a couple of level convertors anyway, as they're quite cheap. Can't hurt to try. I will also try powering the MAX7219 seperately to the ESP8266 off of 5V.

TomGeorge, have a look at this link. Everything you could want to know about them, including datasheet. They are A3144 hall effect sensors, non-latching, 5V, very reaponsive, really cheap. I got 5x for $6.30 AUD delivered.

Do be careful! If we are talknig about level conversion between ESP8266 and MAX7219, a "level converter" is not one of those "Bi-Directional I²C Logic Level Converter"s

They are only for I²C. For simple 3.3 to 5 V boosting - which is most unlikely to be your present problem, you would use a 74HCT14 (Jaycar does not seem to stock them - not entirely surprising) with two cascaded gates for each of the three MAX7219 control pins.

Thanks Paul_B. I had bought a couple of those, although they were labelled as being capable of doing I2C, UART and SPI. But it looks identical.

Now you understand why I asked for a schematic, the frizzy things do not show power and ground.

They probably can, for slow data rates. But probably not faster rates. The default data rate for i2c is 100KHz, but most Arduinos also support 400KHz, I wonder if these level converters would work at that speed. They might, I guess. But i know they don't work reliably at 800KHz, I tried using one once to level shift a ws2812 led data line. It seemed to work ok, until I put my hand too close to the circuit! UART will go up to 2MHz and SPI up to 8MHz on most Arduino, I'm pretty sure it won't work at those kinds of speeds.