
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.

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.
First, I started by wiring the Max 7219 to the Mojo.

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

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

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.
There are 13 registers on the Max7219 module including a no-op.

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

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

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/)