Skip to content
Go back

FPGA for Fun #1 (Part 1) - Driving the MAX 7219 LED Display Module

By Michael Earls

Edit page

FPGA for Fun #1 (Part 1) - Driving the MAX 7219 LED Display
Module

I recently ordered a few LED display modules based on the MAX7219 chip. When they arrived, I immediately began putting together projects to use them. The first project was to wire one up to my Raspberry Pi and use C to bitbang some numbers to display. I wrote about this in a [previous post](https://cerkit.com/2017/11/25/driving-the-max-7219-7-segment-display- module-from-asp-net-core-on-the-raspberry-pi/).

The Lucid HDL “code” can be found on GitHub - FPGA for Fun on GitHub

Blog posts in this series:

This time, I’d like to talk about how I wired the MAX7219 LED display module up to my Mojo FPGA.

The Module

FPGA for Fun #1 (Part 1) - Driving the MAX 7219 LED Display
Module

Here is a module on eBay similar to the ones that I purchased:

[Red MAX7219 8-Digit LED Display SPI Control Module Digital Tube For Arduino](https://www.ebay.com/itm/Red-MAX7219-8-Digit-LED-Display-SPI-Control- Module-Digital-Tube-For- Arduino/232597763398?epid=2163908124&hash=item3627e83546:g:6OQAAOSw6hNZiVAF)

If this link is dead (or the sale has ended), search for the above text on eBay and you should find one.

Wiring the MAX7219 to the Mojo

First, I started by wiring the Max 7219 to the Mojo.
FPGA for Fun #1 (Part 1) - Driving the MAX 7219 LED Display
Module

I wired RAW from the Mojo to VCC, GND to GND, Pin 50 to Data In (DIN), Pin 51 to CLK, and Pin 40 to CS (Load).

MAX7219 Datasheet (PDF)

Timing Considerations

The timing diagram for the MAX7219 module is fairly straight forward. It only covers four of the interface pins. We won’t be using the data out pin (DOUT), so we can ignore that one.

We’re interested in the behavior of the Load, Clock, and the data in pins and how they interact.

FPGA for Fun #1 (Part 1) - Driving the MAX 7219 LED Display
Module

Since we are working with an FPGA clock that runs too fast for our display module, we’ll need to use an SPI component to manage our communication and synchronize with that clock instead of the FPGA. In addition, we’ll use a d-flip-flop to manage the state of the load pin between clock cycles.

After creating a new Mojo project, I added the SPI Master component to it (it’s one of the available components in the Mojo IDE).

The load pin must be low to clock data in, so that’s our first step when sending data. Once the load pin is low, we start our clock pulses to the CLK pin. As you can see in the timing diagram, we need to send one bit of data at roughly the same time as our clock pulse. The Max 7219 uses a 16-bit word for each message that it processes, so we need to keep up with how many clock cycles have passed since we started (we’ll use a d-flip-flop to do this in the implementation).

Once we get to 16 clock pulses on the CLK pin, the data is then latched into either the digit or control registers by pulsing LOAD/CS.

LOAD/CS must go high concurrently with or after the 16th rising clock edge, but before the next rising clock edge or data will be lost. This is very important to remember and was the source of a great deal of trouble for me when first building this project. I spent a few hours debugging this (I don’t yet have the wave capture utility setup in my Mojo IDE and the logic probe that I ordered hasn’t arrived from Hong Kong, yet).

Finite State Machines

I’ve found that planning my logic out in terms of finite state machines really helps me get my head around the problem. The Max7219 component is driven by three main states: Idle, Transfer Address, and Transfer Data. It requires a little setup to synchronize the clocks and manage the state of the load pin.

MAX7219 Component FSM

FPGA for Fun #1 (Part 1) - Driving the MAX 7219 LED Display
Module

We need to make an assumption about the overall state of the component; there is an SPI Clock counter with its clock input set to the SCK output of the SPI component.

IDLE
TRANSFER_ADDR
TRANSFER_DATA

Register Map

There are 13 registers on the Max7219 module including a no-op.

FPGA for Fun #1 (Part 1) - Driving the MAX 7219 LED Display
Module

For example, if I wanted to turn on all of the segments on the display (test mode), I would send 0x0F as the first 8 bits of the message (the address), and then 0x01 as the next 8 bits (the data). I would then pulse the Load pin to latch the message into the Max7219.

Let’s go over the order of operations that I’ll use in my test component:

Main Component (Mojo Top) FSM

The main component is a little more complicated because it is the one that drives the MAX7219 component. It keeps up with the characters that are being sent, as well as the states required to initialize the MAX7219 module.

This particular component was written as an initial test to see if I could get data to display. It does not handle any sort of number conversion or true display driver functionality. It merely outputs “DEADBEEF” to the display. The segment index is simply a d-flip-flop that I use to keep up with which segment we’re sending the data for. Since there is more than one segment, we have to send them one at a time. We use the index to determine which one to send.

FPGA for Fun #1 (Part 1) - Driving the MAX 7219 LED Display
Module

IDLE
SEND_SHUTDOWN

Remember that all actions shown are simultaneous and happen for each clock cycle. That’s why we have to wait until the Max7219 component has completed sending its message and is no longer busy before moving on to the next state. Otherwise, we’d overload the module and nothing would be displayed. It’s a careful balancing act of clock, data, and load.

SEND_RESET
SEND_NO_DECODE
SEND_ALL_DIGITS
SEND_WORD
HALT

Segment Lines

Programming the 7-segments is done by sending an 8-bit number representing the state of the segments in order from A-G with the decimal point being the most significant bit.

FPGA for Fun #1 (Part 1) - Driving the MAX 7219 LED Display
Module

I coded the 16 hexadecimal digits and added a few characters so that the word “Error” could be displayed, as well as a minus sign and a blank space.

0 = 01111110
1 = 00110000
2 = 01101101
3 = 01111001
4 = 00110011
5 = 01011011
6 = 01011111
7 = 01110000
8 = 01111111
9 = 01111011
A = 01110111
B = 00011111
C = 01001110
D = 00111101
E = 01001111
F = 01000111
O = 00011101
R = 00000101
MINUS = 01000000
BLANK = 00000000

That’s the basic state workflow for the module on the FPGA. I had a great time figuring this out and I hope this has helped you understand how you might wire a MAX7219 module to your FPGA.

In the [next post](https://cerkit.com/2017/12/27/fpga-for- fun-1-part-2-driving-the-max-7219-led-display-module/), we’ll take a look at the implementation in the Lucid Hardware Description Language. Lucid is the HDL used by the Mojo. It is a simpler HDL than Verilog or VHDL, but transpiles to Verilog for synthesis onto the hardware.

Video:

Read [Part 2](https://cerkit.com/2017/12/27/fpga-for-fun-1-part-2-driving-the- max-7219-led-display-module/)


Edit page
Share this post on:

Previous Post
FPGA for Fun #1 (Part 2) - Driving the MAX 7219 LED Display Module
Next Post
Driving the Max 7219 7-Segment Display Module from ASP.NET Core on the Raspberry Pi