Tuesday, 24 April 2018

Using SPI to interface the ESP-12E to the MAX7219 LED display

From top: ESP-12E Nodemcu, middle: Level Converter, bottom: MAX7219 8-digit 7-segment display
You will need an ESP-12E NodeMCU ESP8266, a 4-channel level converter and a MAX7219 7-segment LED display.

 Wire up as follows:
   GPIO    NodeMCU   Name  |   MAX7219
   ===================================
     15       D8                SS       |   CS
     13       D7                MOSI  |   DIN
     12       D6                MISO  |   Not connected
     14       D5                SCK    |   CLK

Since the MAX7219 is a 5V device and the ESP-12E a 3.3V you will need a level converter in between. I used one based on 4 MOSFETs, covered in some detail here.

The MAX7219 draws quite a bit of power so it is advisable to have a separate power source from the ESP-12E. I used a 3A D-Link USB 3.0 hub.

I based my program on the sample code in the NodeMCU Lua sample code 'SPISlave_SafeMaster'  that came with the Arduino IDE.

With the level converter connected, the ESP-12E would not program, so I ended up having to unplug the 3.3V side of the level converter before programming.

The program merely initializes the MAX7219, displays '12345678', then triggers the MAX7219's built-in test function (lights up everything with maximum brightness). The built-in test requires a relatively high-ampere 5V supply.

The program is a Lua sketch, and requires the Arduino IDE. I used a custom-built Slackware Linux version, but there are stock Linux and Windoes versions that work the same.

The program is:

    SPI Safe Master Demo Sketch
    Connect the SPI Master device to the following pins on the esp8266:

    GPIO    NodeMCU   Name  |   Uno
   ===================================
     15       D8       SS   |   D10
     13       D7      MOSI  |   D11
     12       D6      MISO  |   D12
     14       D5      SCK   |   D13

    Note: If the ESP is booting at a moment when the SPI Master has the Select line HIGH (deselected)
    the ESP8266 WILL FAIL to boot!
    This sketch tries to go around this issue by only pulsing the Slave Select line to reset the command
    and keeping the line LOW all other time.

*/
#include <SPI.h>

class ESP_MAX7219
{
private:
    uint8_t _ss_pin;
    void SS_High()
    {
        digitalWrite(_ss_pin, HIGH);
    }
    void SS_Low()
    {
        digitalWrite(_ss_pin, LOW);
    }
 
public:
    ESP_MAX7219(uint8_t pin):_ss_pin(pin) {}
    void begin()
    {
        pinMode(_ss_pin, OUTPUT);
        SS_High(); // Default to high
    }

    void writeData(const uint8_t MSB, const uint8_t LSB)
    {
        SS_Low();
        SPI.transfer(MSB);      
        SPI.transfer(LSB);
        SS_High();
    }
};

ESP_MAX7219 esp(SS);

 
void send(const uint8_t msb, const uint8_t lsb)
{
    esp.writeData(msb, lsb);
    delay(10);
    // Serial.print("Slave: ");
    // Serial.println(esp.readData());
    // Serial.println();
}

void setup()
{
    Serial.begin(115200);
    SPI.begin();
    esp.begin();
    delay(1000);
    send(0x0C, 0x01); // Normal Operation
}

void loop()
{
    delay(1000);
    send(0x0C, 0x01); // Normal Operation
    Serial.println("Shutdown off");
    delay(1000);
    send(0x09, 0xFF);
    Serial.println("BCD Mode all 8 digits");
    delay(1000);
    send(0x0A, 0x03);
    Serial.println("Quarter brightness");
    delay(1000);
    send(0x0B, 0x07);
    Serial.println("8 Digit Scan");
    delay(1000);
    send(0x0F, 0x01);
    Serial.println("Test mode on");
    delay(1000);
    send(0x0F, 0x00);
    Serial.println("Test mode off");
    delay(1000);
    send(0x01, 0x08);
    Serial.println("Digit 8");
    send(0x02, 0x07);
    Serial.println("Digit 7");
    send(0x03, 0x06);
    Serial.println("Digit 6");
    send(0x04, 0x05);
    Serial.println("Digit 5");
    send(0x05, 0x04);
    Serial.println("Digit 4");
    send(0x06, 0x03);
    Serial.println("Digit 3");
    send(0x07, 0x02);
    Serial.println("Digit 2");
    send(0x08, 0x01);
    Serial.println("Digit 1");

    /* send(0x0C, 0x00);
    delay(3000);
    Serial.println("Shutdown on"); */
 
    send(0x0C, 0x01);
    Serial.println("Shutdown off");
    delay(3000);
}

There are plenty of other projects out there using the MAX7219, but I could not find one that uses the ESP-12E (or ESP8266). The MAX7219 uses SPI which seems to be gradually being replaced by I2C. This has been tested and worked for me, but turned out to be harder than I thought, but that is another blog post.

Happy Trails.

No comments:

Post a Comment