Skip to contentSkip to author details

FPGA

A 13-post collection

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

Written by Michael Earls
 FPGA  electronics

In a previous post, I covered the wiring diagrams, finite state machines, and LED segment encoding for the MAX7219 display module wired up to the Mojo FPGA.

In this post, I will cover the Lucid HDL code used to implement the state machines.

All of this Lucid HDL (and the resulting Verilog) can be found on my GitHub page:

FPGA for Fun on GitHub

Blog posts in this series:

The first thing to do after creating the project is define the constraints file to setup our pinouts. See the wiring diagram for details.

NET "max7219_load" LOC = P40 | IOSTANDARD = LVTTL;  
NET "max7219_data" LOC = P50 | IOSTANDARD = LVTTL;  
NET "max7219_clock" LOC = P51 | IOSTANDARD = LVTTL;

The MAX7219 Component

After adding an SPI Master component to the project from within the Mojo IDE, we need to add a new max7219 component to handle our operation states.

Here are the states that we'll be implementing:

Max7219 Component FSM

module max7219 (  
    input clk,  // clock
    input rst,  // reset
    input addr_in[8],
    input din[8],
    input start,
    output cs,
    output dout,
    output sck,
    output busy
  ) {

addr_in is used for our address data (from the MAX7219 Register Map), din is used for the data values coming in, and cs, dout, and sck are all used to manage the SPI interface with the MAX7219. We use busy to indicate that we're not in the IDLE state. start is used to trigger our state transfer from IDLE to TRANSFER_ADDR.

Let's continue with the Lucid code.

.clk (clk) {  
  .rst(rst) { 
      fsm state(#INIT(IDLE)) = {IDLE, TRANSFER_ADDR, TRANSFER_DATA};
      spi_master spi(.miso(0));
      dff data[8];
      dff addr[8];
      dff load_state;
    }
  }

We're initializing the components that we'll use in this module with the clk and rst values coming from the Mojo.

We define our finite state machine (fsm) and initialize it to a default state of IDLE. We then initialize an spi_master component to manage our SPI clock and data transfers. We're using d-flip-flops (dff) to hold the values that we send to the address and data lines because we need to store those values between clock cycles. We're also using a d-flip-flip to store the current state of our load (cs) pin.

  sig data_out[8];  
  sig mosi;
  counter count;

  always  {
    sck = spi.sck;
    // synchronize our counter with the spi clock so we can keep up with where we are
    count.clk = spi.sck;
    count.rst = 0;

    data_out = 8b0;
    spi.start = 0;
    mosi = 0;
    busy = state.q != state.IDLE;  // busy when not idle
    dout = 0;

In lines 1-2, we define a few signals to deal with the output data (what we'll actually send to the MAX7219 display) and the MOSI (Master Out Slave In). We also define a counter to use to keep up with how many SPI clock cycles have passed. This will let us manage the load pin and toggle it at the right time to latch the input data.

It's important to notice that in line 8, we set the clock of the counter to our SPI component's sck value. This ensures that our counter only increments in sync with the SPI data clock. It will help us keep up with how much data has been sent to the MAX7219.

  case (state.q) {  
      state.IDLE:
        load_state.d = 1;
        if (start) { // if we should start a new transfer
          // save our data and address values to memory
          addr.d = addr_in;
          data.d = din;
          count.rst = 1;

          // Toggle the load pin (makes the 7219 start listening for data)
          load_state.d = 0;

          state.d = state.TRANSFER_ADDR;
        }
      state.TRANSFER_ADDR:
        spi.start = 1;
        data_out = addr.q;
        dout = spi.mosi;
        if (count.value == 8){
          state.d = state.TRANSFER_DATA;
        }
      state.TRANSFER_DATA:  
        spi.start = 1;
        data_out = data.q;
        dout = spi.mosi;
        if (count.value == 16){
          // latch the data by pulsing the load pin (cs)
          load_state.d = 1;
          count.rst = 1;
          state.d = state.IDLE;
        }
    }

    cs = load_state.q;
    spi.data_in = data_out;

The last section of code in this component is the state management case statement. During the IDLE state, we first set the load pin high. The load pin stays high until we wish to write data to the MAX7219 (see the Timing Diagram). Then, we check to see if the start value is high. If so, we set the d-flip-flop values for address and data to the values coming in to the component. We then reset the counter and set the load pin low (to start reading into the MAX7219). After all of this, we transfer to the next state.

In the TRANSFER_ADDR state, we start the SPI component, set our data_out signal to equal the value of the addr flip-flop and set the dout value to the spi component's mosi value. We repeat the process 8 times total so that the SPI component will send the 8 bits we need for our address value. After the 8 bits are sent, we change to the next state.

In the TRANSFER_DATA state, we start the SPI component and set the data_out signal to our data value stored in the data flip-flop. We set the dout to the SPI mosi value. We repeat this process 8 times to ensure that we send all 8 bits of the data to the MAX7219. After sending the 8th bit (our counter is now at 16), we pulse the load pin high to latch the address and data into the MAX7219. We then reset the counter and switch to the IDLE state.

In line 34, we set the cs output to the value of our load flip-flop. Line 35 shows how we send the value from our data_out signal to the SPI data input. This is a bit confusing because we're mixing in with out. Think of it like this, we're outputting data from this component into another component. That component has an input that we're matching to our output. Because we're always connecting the dout output to the SPI component's mosi output (lines 18 and 25), our MAX7219 is always receiving its data from the SPI component. It's also managing the serial clock, so everything is in sync.

That's everything for the max7219 component. By using this component, we can control the MAX7219 chip from our Mojo FPGA.

Main Module

The next HDL to cover is the main component (mojo_top). This is a bit more complicated, because it uses the component we just covered to display "DEADBEEF" on the display.

The flow of this is basically just state management to switch from states based on this state diagram:

Main FSM

module mojo_top (  
    input clk,              // 50MHz clock
    input rst_n,            // reset button (active low)
    output led [8],         // 8 user controllable LEDs
    input cclk,             // configuration clock, AVR ready when high
    output spi_miso,        // AVR SPI MISO
    input spi_ss,           // AVR SPI Slave Select
    input spi_mosi,         // AVR SPI MOSI
    input spi_sck,          // AVR SPI Clock
    output spi_channel [4], // AVR general purpose pins (used by default to select ADC channel)
    input avr_tx,           // AVR TX (FPGA RX)
    output avr_rx,          // AVR RX (FPGA TX)
    input avr_rx_busy,      // AVR RX buffer full
    output max7219_load,
    output max7219_data,
    output max7219_clock
  ) {

  sig rst;                  // reset signal

  .clk(clk) {
    // The reset conditioner is used to synchronize the reset signal to the FPGA
    // clock. This ensures the entire FPGA comes out of reset at the same time.
    reset_conditioner reset_cond;

    .rst(rst) {
      max7219 max;
      fsm state(#INIT(IDLE)) = {IDLE, SEND_SHUTDOWN, SEND_RESET, SEND_NO_DECODE, SEND_ALL_DIGITS, SEND_TEST_ON, SEND_TEST_OFF, SEND_WORD, HALT};
      dff segments[8][8];
      dff segment_index[3];
    }
  }

  sig max_addr[8];
  sig max_data[8];

In line 29, you can see where we use a two-dimensional d-flip-flop to hold the segment data. The first dimension is the segment to display the data on (1-8 on the MAX7219), the second dimension is used to store the binary values representing the actual segment display (defined below as constants). We use the segment_index to keep up with what segment we're currently displaying.

Segment Encodings

  const C0 = b01111110;  
  const C1 = b00110000;
  const C2 = b01101101;
  const C3 = b01111001;
  const C4 = b00110011;
  const C5 = b01011011;
  const C6 = b01011111;
  const C7 = b01110000;
  const C8 = b01111111;
  const C9 = b01111011;
  const A = b01110111;
  const B = b00011111;
  const C = b01001110;
  const D = b00111101;
  const E = b01001111;
  const F = b01000111;
  const O = b00011101; // O
  const R = b00000101; // R
  const MINUS = b01000000; // -
  const BLANK = b00000000; // BLANK

These are the binary values for the segments on the MAX7219. I added O and R so that I could display the word "Error".

always { 
segments.d[7] = D; segments.d[6] = E; segments.d[5] = A; segments.d[4] = D; segments.d[3] = B; segments.d[2] = E; segments.d[1] = E; segments.d[0] = F;

If you are a software engineer like I am, you may be tempted to read this like source code. Hardware Description Languages (like Lucid, Verilog, and VHDL) are not programming languages. We need to have some way of expressing when things take place in relation to other things. Everything in the always block runs all of the time, as the word suggests. That's why we have to manage these states like we do, because this "code" is "executing" every time the clock cycles on the FPGA (the Mojo has a 50 MHz clock). It is truly parallel processing. That's one of the great advantages of FPGAs over microcontrollers. It's also why it's more complicated to manage.

The segments are numbered from right to left, so we need to display the characters in reverse order. We do this starting on line 2. Basically, we need to set the data stored in the segments flip-flop to the binary values of the character we wish to display. So, in line 2, the 7th segment (which will be segment 8 on the MAX7219 module) is set to the values stored in the D constant (b00111101). We'll loop through all 8 of these values in the SEND_WORD state and send the value of the flip-flop as the data to the max component.

The rest is fairly self-explanatory. We just transition from one state to another, sending in the appropriate address and data values as required by that state to get the desired result. We're not using the SEND_TEST_ON or SEND_TEST_OFF states, so those can be ignored.

Main Module State Machine Implementation

    reset_cond.in = ~rst_n; // input raw inverted reset signal  
    rst = reset_cond.out;   // conditioned reset

    led = 8h00;             // turn LEDs off
    spi_miso = bz;          // not using SPI
    spi_channel = bzzzz;    // not using flags
    avr_rx = bz;            // not using serial port
    max_addr = 8b0;
    max_data = 8b0;
    max.start = 0;

    case(state.q) {
      state.IDLE:
        segment_index.d = 0;
        state.d = state.SEND_SHUTDOWN;
      state.SEND_SHUTDOWN:
        max.start = 1;
        max_addr = h0C;
        max_data = h00;
        if(max.busy != 1) {
          state.d = state.SEND_RESET;
        }
      state.SEND_RESET:
        max.start = 1;
        max_addr = h0C;
        max_data = h01;
        if(max.busy != 1) {
          state.d = state.SEND_NO_DECODE;
        }
      state.SEND_TEST_ON:
        max.start = 1;
        max_addr = h0F;
        max_data = h01;
        if(max.busy != 1) {
          state.d = state.SEND_NO_DECODE;
        }
      state.SEND_TEST_OFF:
        max.start = 1;
        max_addr = h0F;
        max_data = h00;
        if(max.busy != 1) {
          state.d = state.SEND_NO_DECODE;
        }
      state.SEND_NO_DECODE:
        max.start = 1;
        max_addr = h09;
        max_data = h00;
        if(max.busy != 1) {
          state.d = state.SEND_ALL_DIGITS;
        }
      state.SEND_ALL_DIGITS:
        max.start = 1;
        max_addr = h0B;
        max_data = h07;
        if(max.busy != 1) {
          state.d = state.SEND_WORD;
        }
      state.SEND_WORD:
        if(segment_index.q < 8)
        {
          max.start = h01;
          max_addr = segment_index.q + 1;
          max_data = segments.q[segment_index.q];
          if(max.busy != 1) {
            segment_index.d = segment_index.q + 1;
          }
        } 
        else {
          segment_index.d = 0;
          state.d = state.HALT;      
        }
      state.HALT:
        max_addr = 8b0;
        max_data = 8b0;
    }

    max.addr_in = max_addr;
    max.din = max_data;
    max7219_clock = max.sck;
    max7219_data = max.dout;
    max7219_load = max.cs;
  }

}

On line 59, we check to see if our segment index is less than 8. If so, we set the address to the value of the segment index +1 on line 62 (to account for the fact that index 0 should write to segment 1, index 1 to segment 2, etc.) We wait for the max component to finish by keeping these values until the busy flag goes low (line 64). When that happens, we simply increment our segment index by 1.

On line 69, we handle the case when the index is equal to 8 (well, technically, it's no longer less than 8, but it's 8 in our case). Then, we simply transition to the HALT state, which does nothing but send a no-op (data 0 at address 0).

Starting on line 79, we need to set the output values going to the actual module to the values that we generate in the max component. We set the clock, data, and load pins accordingly.

That's it! This will display "DEADBEEF" on the MAX7219 display.

DEADBEEF

Video:


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

Written by Michael Earls
 FPGA  electronics

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.

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

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

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.
MAX7219 Mojo wiring diagram

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.

MAX7219 Timing Diagram

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

MAX7219 Component FSM

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
  • Set Load (CS) to 1
  • If Start == 1
    • Save incoming address and data to memory
    • Reset the SPI clock counter (helps manage two clock domains)
    • Set Load to 0 (tells the MAX7219 to start listening)
    • Transition to next state
TRANSFER_ADDR
  • Start the SPI component
  • Send the address we have in memory to the SPI component’s input
  • Set the data out to the value of the SPI.MOSI
  • If the SPI clock counter == 8
    • Transfer to the next state.
TRANSFER_DATA
  • Start the SPI component
  • Send the data we have in memory to the SPI component’s input
  • Set the data out to the value of the SPI.MOSI
  • If the SPI clock counter == 16
    • Latch the data by pulsing the load pin high
    • Reset the SPI clock counter
    • Transition back to the IDLE state to await more input

Register Map

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

Max7219 Register Map

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:

  • Shutdown = 0
  • Shutdown = 1
  • Decode Mode = 0 (display segments instead of BCD data)
  • Scan Limit = 7 (use all 8 digits)
  • Send 8 characters
  • Halt (send all zeros - no-op)

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.

Main Component FSM

IDLE
  • Reset segment index to 0
  • Transition to next state
SEND_SHUTDOWN
  • Start the Max7219 component
  • Set the max7219 address to 0C (Shutdown)
  • Set the max7219 data to 00
  • When max is complete, transition to next state

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
  • Start the Max7219 component
  • Set the max7219 address to 0C (Shutdown)
  • Set the max7219 data to 01 (Normal operation)
  • When max is complete, transition to next state
SEND_NO_DECODE
  • Start the Max7219 component
  • Set the max7219 address to 09 (Decode Mode)
  • Set the max7219 data to 00
  • When max is complete, transition to next state
SEND_ALL_DIGITS
  • Start the Max7219 component
  • Set the max7219 address to 0B (Scan Limit)
  • Set the max7219 data to 07 (use all 8 digits)
  • When max is complete, transition to next state
SEND_WORD
  • Start the Max7219 component
  • If segment index < 8
    • Set the max7219 address to the segment index +1 (to account for a zero-based index and a 1 based segment count)
    • Set the max7219 data to segment array with the index of segment index (segments.q[segment_index.q])
    • When max is complete, increment the segment index by 1
  • If segment index = 8
    • Reset segment index to 0
    • Transition to the next state (HALT)
HALT
  • Set the max7219 address to 0
  • Set the max7219 data to 0

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.

7-Segment Layout

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


Armchair Engineering - Ignorance is bliss

Written by Michael Earls
 FPGA  electronics

I'm totally into my FPGA. Embedded Micro is supposed to be announcing a new FPGA based on the new Artix 7 FPGA chip that will allow me to run the new Vivado design suite from Xilinx. I'm currently using the very outdated ISE tool (it's like using Microsoft Front Page to do modern web development). ISE works (with modifications to the binaries to make it work on Windows 10), but I'd like to try out some new (to me) stuff like System Verilog (which is unsupported in ISE).

I love the idea of an FPGA and I'm about to dip my feet into writing my own CPU based on the Basic CPU example project on Embedded Micro's website. I'd like to expand the instruction set to larger than 4-bits. It's probably going to be completely bizarre to anyone who actually really knows what they're doing (real-life engineers), but I don't care, I'm doing it for fun.

I thought about having a register that would write its data directly to a MIDI interface so I could have instructions that would send MIDI signals. I'd also like to figure out the best way to interface with the CPU so I can load programs into it without uploading a new bin file each time. The example requires me to use a custom-built Assembler to make the Lucid code required for running my programs on the CPU. It would be cool to have a loader on the PC that could upload the program to the Mojo using the USB connection and the on-board microprocessor.

Update: November 21, 2017 - It seems that what I'm looking for is already out there. I was already aware of the OpenCores website, but I also found the PicoBlaze and MicroBlaze microcontroller cores from Xilinx for the FPGA. I'm going to start working with the PicoBlaze and see what I can do to extend it to interact with external peripherals. That's going to save me a lot of time trying to figure out how to extend the CPU sample from Embedded Micro.

I also thought about adding a 12-bit VGA connector and seeing if I could learn how to interface with it using a custom CPU. The main issue I'm running into is I am quickly hitting my wall of interest. The best way to describe it is that if the concepts are too deep (i.e. - they require an advanced degree of some sort to make sense of them), then I tend to veer away from the topic altogether and move on to something a bit more amateur. However, I keep getting drawn back to CPU design, even though it's a very complicated topic.

I've been watching Ben Eater's awesome series about his breadboard computer on YouTube and learning a lot about how computers work at the most basic level (logic gates, timer-driven clocks, and data buses).

Another topic I've been exploring is how to build a "pocket computer" or similar homebrew computer based on the Zilog Z-80 processor from the 80's (70's?). I have a big interest in this particular processor because it's relatively simple as far as CPU's go.

I'd like to take all of this knowledge and apply it to my custom CPU project. I think it would be cool to come up with an amalgamation of Ben Eater's breadboard computer and the Mojo CPU such that I can control and interact with the FPGA CPU using buttons, switches, 7-segment displays, and possibly even LCD displays.

It has taken me over a year to get comfortable enough with electronics to feel somewhat confident in my abilities to pull some of this off. It's a slow road because it is only a hobby, after all, and my day job takes priority. If there's a topic that I need to study at home to help me on the job, I tend to learn those things first, then spend my extra time learning the electronics and FPGA knowledge.

When I first got into this, it was so that I could play with making my own music "synthesizers" using CMOS logic chips, but that rapidly advanced to the idea of "chips on a chip" that the FPGA represents. I can never just do anything the easy way. I like to take my problems and abstract them away until they are almost unrecognizable, then find the solution that covers the most ground. It serves me well at work when solving large-scale enterprise computing problems, but it makes hobbies a bit more complicated than they should be.

Ultimately, I see myself doing a lot more playing around with the FPGA in the future and less time with actual silicon chips and discreet components. I might make plug-in boards for my FPGA to accomplish some task like making a VGA interface, but even that may not be necessary when Embedded Micro releases their HDMI shield for the Mojo.

When it comes down to it, I think that the fact that I don't really know what I'm doing when it comes to FPGA coding is a good thing. It's that kind of spirit that allowed the microprocessor and home computer movement to sprout from the garages and basements of amateurs back when room-sized computers ruled the computing world and IBM thought the home computer was a toy and (luckily) ignored it. I'm not going to cause any real damage and I might actually stumble upon something fun along the way. Sure, I'm doing this the hard way, but I think it's too late for me to go to a university and get a degree in electrical or electronics engineering. Besides, I think this is a lot more fun...


Strange VGA Effects on an FPGA

Written by Michael Earls
 electronics  FPGA

When I assembled my VGA implementation on my Mojo FPGA, I did so with only a single wire for each of the color signals (Red, Green, and Blue). This limited my color choices to 8 colors. I read about using Pulse width modulation to send other values to a wire, so I gave it a try. The results were interesting, but not what I was looking for.

Here is a video of the results:

Here is my VHDL code:

----------------------------------------------------------------------------------  
-- Company: 
-- Engineer: 
-- 
-- Create Date:    04:37:23 05/27/2017 
-- Design Name: 
-- Module Name:    img_gen - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;  
use IEEE.STD_LOGIC_1164.ALL;  
use IEEE.STD_LOGIC_ARITH.ALL;  
use IEEE.STD_LOGIC_UNSIGNED.ALL;


entity img_gen is  
     Port ( clk : in STD_LOGIC;
                x_control : in STD_LOGIC_VECTOR(9 downto 0);
                paddle : in STD_LOGIC_VECTOR(9 downto 0);
                y_control : in STD_LOGIC_VECTOR(9 downto 0);
                video_on : in STD_LOGIC;
                rgb : out STD_LOGIC_VECTOR(2 downto 0));
end img_gen;

architecture Behavioral of img_gen is

signal  PWM_R_Accumulator : std_logic_vector(8 downto 0);  
signal  PWM_G_Accumulator : std_logic_vector(8 downto 0);  
signal  PWM_B_Accumulator : std_logic_vector(8 downto 0);

--wall
constant wall_l:integer :=10;--the distance between wall and left side of screen  
constant wall_t:integer :=10;--the distance between wall and top side of screen  
constant wall_k:integer :=10;--wall thickness  
signal wall_on:std_logic;  
signal rgb_wall:std_logic_vector(23 downto 0); 

--bar
signal bar_l, bar_l_next: integer:=100;  
constant bar_t:integer :=420;--the distance between bar and top side of screen  
constant bar_k:integer :=10;--bar thickness  
constant bar_w:integer:=120;--bar width  
constant bar_v:integer:=10;--velocity of the bar  
signal bar_on:std_logic;  
signal rgb_bar:std_logic_vector(23 downto 0); 

--ball
signal ball_l,ball_l_next:integer :=100;--the distance between ball and left side of screen  
signal ball_t,ball_t_next:integer :=100; --the distance between ball and top side of screen  
constant ball_w:integer :=20;--ball Height  
constant ball_u:integer :=20;--ball width  
constant x_v,y_v:integer:=3;-- horizontal and vertical speeds of the ball  
signal ball_on:std_logic;  
signal rgb_ball:std_logic_vector(23 downto 0); 

--refreshing(1/60)
signal refresh_reg,refresh_next:integer;  
constant refresh_constant:integer:=830000;  
signal refresh_tick:std_logic;

--ball animation
signal xv_reg,xv_next:integer:=3;--variable of the horizontal speed  
signal yv_reg,yv_next:integer:=3;--variable of the vertical speed

--x,y pixel cursor
signal x,y:integer range 0 to 650;

--mux
signal vdbt:std_logic_vector(3 downto 0);

--buffer
signal rgb_reg:std_logic_vector(2 downto 0);  
signal rgb_next:std_logic_vector(23 downto 0);

begin

--x,y pixel cursor
x <=conv_integer(x_control);  
y <=conv_integer(y_control );

--refreshing
process(clk)  
begin  
     if clk'event and clk='1' then
          refresh_reg<=refresh_next;
     end if;
end process;  
refresh_next<= 0 when refresh_reg= refresh_constant else  
refresh_reg+1;  
refresh_tick<= '1' when refresh_reg = 0 else  
                           '0';
--register part
process(clk)  
begin  
     if clk'event and clk='1' then
         ball_l<=ball_l_next;
         ball_t<=ball_t_next;
         xv_reg<=xv_next;
         yv_reg<=yv_next;
         bar_l<=bar_l_next;
      end if;
end process;

--bar animation
process(refresh_tick,paddle)  
begin

    if refresh_tick= '1' then
       bar_l_next<= conv_integer(paddle);
    end if;
end process;

--ball animation
process(refresh_tick,ball_l,ball_t,xv_reg,yv_reg)  
begin  
     ball_l_next <=ball_l;
     ball_t_next <=ball_t;
     xv_next<=xv_reg;
     yv_next<=yv_reg;
     if refresh_tick = '1' then
        if ball_t> 400 and ball_l > (bar_l -ball_u) and ball_l < (bar_l +120) then --the ball hits the bar
           yv_next<= -y_v ;
       elsif ball_t< 35 then--The ball hits the wall
           yv_next<= y_v;
       end if;
       if ball_l < 10 then --The ball hits the left side of the screen
          xv_next<= x_v;
       elsif ball_l> 600 then 
          xv_next<= -x_v ; --The ball hits the right side of the screen
       end if; 
       ball_l_next <=ball_l +xv_reg;
       ball_t_next <=ball_t+yv_reg; 
    end if;
end process;

--wall object
wall_on <= '1' when x > wall_l and x < (640-wall_l) and y> wall_t and y < (wall_t+ wall_k) else  
                      '0'; 
rgb_wall<=x"010101";--Black  
--bar object
bar_on <= '1' when x > bar_l and x < (bar_l+bar_w) and y> bar_t and y < (bar_t+ bar_k) else  
                    '0'; 
rgb_bar<=x"0000F1";--blue

--ball object
ball_on <= '1' when x > ball_l and x < (ball_l+ball_u) and y> ball_t and y < (ball_t+ ball_w) else  
                     '0'; 
rgb_ball<=x"00F100"; --Green


--buffer
process(clk)  
begin  
    if clk'event and clk='1' then      
      PWM_R_Accumulator  <=  ("0" & PWM_R_Accumulator(7 downto 0)) + ("0" & rgb_next(23 downto 16));
        PWM_G_Accumulator  <=  ("0" & PWM_G_Accumulator(7 downto 0)) + ("0" & rgb_next(15 downto 8));
        PWM_B_Accumulator  <=  ("0" & PWM_B_Accumulator(7 downto 0)) + ("0" & rgb_next(7 downto 0));
    end if;
     if clk'event and clk='1' then
         --rgb_reg<=rgb_next;

     end if;
end process;

--mux
vdbt<=video_on & wall_on & bar_on &ball_on;  
with vdbt select  
     rgb_next <= x"FFAAAA" when "1000",--Background of the screen is red 
     rgb_wall when "1100",
     rgb_wall when "1101",
     rgb_bar when "1010",
     rgb_bar when "1011",
     rgb_ball when "1001",
      x"000000" when others;
--output

rgb<=PWM_R_Accumulator(8) & PWM_G_Accumulator(8) & PWM_B_Accumulator(8);

end Behavioral;

I added three new signals for the PWMs. One PWM per color. Those are defined starting on line 37. Once those were defined, I then set the colors on the objects on the screen (the wall, the ball, the paddle, and the background). That code starts on line 149 (colors are defined in hexadecimal).

I then defaulted the color to red for things that didn't have a setting (line 178).

On line 187, I set the output of the VGA wires to the most significant bit of the PWM accumulators.

The idea was that the PWM would send a different color to the monitor. I really don't know how (or even if) I can fix it, but the results are interesting.

After watching the video below, I learned that this is a hardware issue. I need to build out the different resistance values to handle each of the bits with a gpio pin on the FPGA.

Here is a 12-bit schematic that I'm going to try next.

12-bit color VGA schematic (image source: https://electronics.stackexchange.com/questions/228825/programming-pattern-to-generate-vga-signal-with-micro-controller)


A Saturday morning puzzle on my FPGA

Written by Michael Earls
 FPGA  electronics  hobbies

I woke up this morning with a desire to solve a puzzle. I decided that I'd make a simple LED chaser on a 7-segment LED display using my Mojo FPGA (now that I have everything working in Windows 10 again thanks to the awesome customer support from Justin at Embedded Micro).

Here's a video of the results:

Here is a breadboard image showing how I've wired up the circuit:

Mojo 7-segment chaser breadboard circuit

Here's my constraints file that shows the wiring of the 7-segment display:

NET "seg<0>" LOC = P51 | IOSTANDARD = LVTTL;  
NET "seg<1>" LOC = P50 | IOSTANDARD = LVTTL;  
NET "seg<2>" LOC = P41 | IOSTANDARD = LVTTL;  
NET "seg<3>" LOC = P40 | IOSTANDARD = LVTTL;  
NET "seg<4>" LOC = P35 | IOSTANDARD = LVTTL;  
NET "seg<5>" LOC = P34 | IOSTANDARD = LVTTL;

Update (8:00 PM): I was able to reach my goal and pull this off using VHDL instead of Lucid. Here is the entire program (no dependencies required). This is much more precise. I really like VHDL.

library IEEE;  
use IEEE.STD_LOGIC_1164.ALL;  
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity circle_chaser is  
    Port ( clk : in  STD_LOGIC;
             rst_n : in STD_LOGIC;            -- reset button (active low)
             led : out STD_LOGIC_VECTOR (7 downto 0); --8 user controllable LEDs
             cclk : in STD_LOGIC;             -- configuration clock, AVR ready when high
             spi_miso : out STD_LOGIC;       -- AVR SPI MISO
             spi_ss : in STD_LOGIC;           -- AVR SPI Slave Select
             spi_mosi : in STD_LOGIC;         -- AVR SPI MOSI
             spi_sck : in STD_LOGIC;          -- AVR SPI Clock
             spi_channel : in STD_LOGIC_VECTOR (3 downto 0); --AVR general purpose pins (used by default to select ADC channel)
             avr_tx : in STD_LOGIC;           -- AVR TX (FPGA RX)
             avr_rx : out STD_LOGIC;          -- AVR RX (FPGA TX)
             avr_rx_busy : in STD_LOGIC;
             seg : out  STD_LOGIC_VECTOR (5 downto 0)
     );
end circle_chaser;

architecture Behavioral of circle_chaser is

signal clk_div   : std_logic_vector(21 downto 0);  
signal shift_reg : std_logic_vector(5 downto 0) := "000001";

begin  
    led <= X"00";
    spi_miso <= '0';
    avr_rx <= '0';

    -- clock divider
    process (clk)
    begin
      if (clk'Event and clk = '1') then
            clk_div <= clk_div + '1';
      end if;
    end process;

    -- LED chaser
    process (clk_div(21))
    begin
      if (clk_div(21)'Event and clk_div(21) = '1') then
            shift_reg <= shift_reg(4 downto 0) & '0';
            if (shift_reg(5) = '1') then
                shift_reg <= "000001";
            end if;
      end if;
    end process;

    -- display the result on the LEDs
    seg <= shift_reg;

end Behavioral;  

Update (6/18 10:00 AM): I completed the HDL trilogy this morning and implemented this chaser in Verilog. Here is the code:

module mojo_top(  
    // 50MHz clock input
    input clk,
    // Input from reset button (active low)
    input rst_n,
    // cclk input from AVR, high when AVR is ready
    input cclk,
    // Outputs to the 8 onboard LEDs
    output[7:0]led,
    // AVR SPI connections
    output spi_miso,
    input spi_ss,
    input spi_mosi,
    input spi_sck,
    // AVR ADC channel select
    output [3:0] spi_channel,
    // Serial connections
    input avr_tx, // AVR Tx => FPGA Rx
    output avr_rx, // AVR Rx => FPGA Tx
    input avr_rx_busy, // AVR Rx buffer full
     output [5:0] seg
    );

wire rst = ~rst_n; // make reset active high  
reg [22:0] clk_div = 22'b0;

// these signals should be high-z when not used
assign spi_miso = 1'bz;  
assign avr_rx = 1'bz;  
assign spi_channel = 4'bzzzz;

assign led = 8'b0;

parameter REG_INIT = 7'b0000001;

    reg [6:0] shift_reg = REG_INIT; // register for led output

    always @ (posedge clk) 
    begin
        clk_div = clk_div + 1;
        if (clk_div[22] == 1) begin
            clk_div = 0;
            shift_reg = shift_reg << 1;
            if (shift_reg[6] == 1) begin
                shift_reg = REG_INIT;
            end
        end
    end

    assign seg = shift_reg[5:0]; // wire output and leds register

endmodule

I had to take a different approach with the shift register to allow for an additional bit to check to see when to reset the shift register (and mirrored LED segments) back to the start. I made the shift register 1 bit larger (line 36) than the LED segments so I could check to see when the MSB was high and then reset. When the shift register was the same size as the LED segments, it would skip lighting one because it got reset before it could be lit up.

Update: November 17, 2017: I got some feedback on the Embedded Micro (the makers of the Mojo FPGA) forums about my code. It seems I was assigning the value of the shift register incorrectly by using the = instead of the <= assignment operator (line 43). That's what was causing me to have to add the extra bit to the shift register to correctly trigger the reset.

I rewrote my Verilog code using what I learned from the forums and it works perfectly.

So, instead of:

shift_reg = shift_reg << 1;

line 43 would be

shift_reg <= shift_reg << 1

this causes the changes to all happen at once so that the evaluation of the shift happens at the same time as the output instead of the shift happening instantly (just before the output).

However, Justin had another shortcut that allowed me to do the shift at the same time as the assignment by using the following code:

shift_reg <= {shift_reg[4:0], shift_reg[5]};

Here's the optimized code based on the feedback that I received on the forums:

assign led = 8'b0;

reg [5:0] shift_reg = 6'b000001; // register for led output

always @ (posedge clk)  
begin  
  clk_div = clk_div + 1;
  if (clk_div[22] == 1) begin
        clk_div = 0;
        shift_reg <= {shift_reg[4:0], shift_reg[5]};
  end
end

assign seg = shift_reg[5:0]; // wire output and leds register

Justin from Embedded Micro is very responsive on his forums and I've learned as much on the forums as I did from the great tutorials on the Mojo website.

Here is the Lucid code (the Mojo-specific HDL) for the same LED chaser:

  
.clk(clk) {
  .rst(rst) {
    circleChase chase(#SPEED(22));
  }
}

always {  
  seg = chase.out;
}

The chaser was a lot easier to implement than I expected...

module circleChase #(  
    MAX_OUT = 6: MAX_OUT > 2,
    SPEED = 25: SPEED > 0 // the lower the SPEED, the faster the counter
  )(
    input clk,  // clock
    input rst,  // reset
    output out[6]
  ) {

  .clk(clk) {   
    .rst(rst) {    
      slowCount count(#SPEED(SPEED));
    }
  }

  const TOP = MAX_OUT;
  counter outCount(.rst(rst), .clk(count.q), #TOP(TOP - 1));

  always {

    out = 6h0; 

    if(count.q) {
        out[outCount.value] = 1;
    }
  }
}

Notice how the clock to the outCount module on line 17 is coming from the slowCount's .q trigger. This goes high each time the slowCount reaches it's limit (the code for this is at the bottom of this post).

I've covered it before, but for completeness, here is the code for the slowCount module (in Lucid, the Mojo-specific HDL):

module slowCount #(  
      SPEED = 25 : SPEED > 0
    )(
    input clk,  // clock
    input rst,  // reset
    output value[8],
    output q
  ) {

  .clk(clk), .rst(rst) {
    dff flip[SPEED];
  }

  const LIMIT = SPEED - 1;
  counter ctr(.rst(rst));

  always {
    ctr.clk = flip.q[LIMIT];

    // toggle the q bit when the counter reaches each end
    q = flip.q[LIMIT] == 0 ? 0 : 1;

    flip.d = flip.q + 1;
    value = ctr.value;
  }
}

Pong on the Mojo Revisited

Written by Michael Earls
 FPGA  electronics  programming

In my previous post, I briefly discussed the implementation of a pseudo-pong game on my Mojo FPGA developer board.

I was able to implement the VHDL version that I linked to later in the post and it works much better.

The biggest challenge I had with it was converting the two-button input to a potentiometer input. It turns out all I had to do was convert an array to an integer as input to the paddle's left position.

Here is a link to the article describing the implementation that I used:

FPGA Pong From FPGACenter.com.

The VHDL was a big challenge for me because I had to learn it as I went along. It works just like Verilog, but the syntax is so different.

Also, I modified my User Constraints File to make the RGB an array for compatibility with this particular implementation.

Here are the new custom constraints:

NET "hsync" LOC = P50 | IOSTANDARD = LVTTL;  
NET "vsync" LOC = P51 | IOSTANDARD = LVTTL;  
NET "rgb<2>" LOC = P41 | IOSTANDARD = LVTTL;  
NET "rgb<1>" LOC = P40 | IOSTANDARD = LVTTL;  
NET "rgb<0>" LOC = P35 | IOSTANDARD = LVTTL;

Here is the code containing my changes (in the vga_control and img_gen modules):

vga_control:

library IEEE;  
use IEEE.STD_LOGIC_1164.ALL;  
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity vga_control is  
     Port ( clk : in STD_LOGIC;
                start : in STD_LOGIC;
                reset : in STD_LOGIC;
                paddle : IN STD_LOGIC_VECTOR(9 downto 0);
                rgb : out STD_LOGIC_VECTOR (2 downto 0);
                h_s : out STD_LOGIC;
                v_s : out STD_LOGIC);
end vga_control;

architecture Behavioral of vga_control is

COMPONENT img_gen  
       PORT( clk : IN std_logic;
                     x_control : IN std_logic_vector(9 downto 0);
                     paddle : IN std_logic_vector(9 downto 0);
                     y_control : IN std_logic_vector(9 downto 0);
                     video_on : IN std_logic; 
                     rgb : OUT std_logic_vector(2 downto 0) );
END COMPONENT;

COMPONENT sync_mod  
       PORT( clk : IN std_logic;
                     reset : IN std_logic;
                     start : IN std_logic; 
                     y_control : OUT std_logic_vector(9 downto 0);
                     x_control : OUT std_logic_vector(9 downto 0);
                     h_s : OUT std_logic;
                     v_s : OUT std_logic;
                     video_on : OUT std_logic );
END COMPONENT;

signal x,y:std_logic_vector(9 downto 0);  
signal video:std_logic;

begin  
          U1: img_gen PORT MAP( clk =>clk , x_control => x, paddle => paddle , 
                                                         y_control => y, video_on =>video , rgb => rgb );

           U2: sync_mod PORT MAP( clk => clk, reset => reset, start => start, y_control => y, x_control =>x ,
                                                             h_s => h_s , v_s => v_s, video_on =>video );
end Behavioral;

My changes are on lines 9, 20, and 41. This sends the output from the potentiometer hooked up to the ADC on the Mojo to the img_gen module where it's converted to position data for the paddle control.

Here's the modified img_gen code:

library IEEE;  
use IEEE.STD_LOGIC_1164.ALL;  
use IEEE.STD_LOGIC_ARITH.ALL;  
use IEEE.STD_LOGIC_UNSIGNED.ALL;


entity img_gen is  
     Port ( clk : in STD_LOGIC;
                x_control : in STD_LOGIC_VECTOR(9 downto 0);
                paddle : in STD_LOGIC_VECTOR(9 downto 0);
                y_control : in STD_LOGIC_VECTOR(9 downto 0);
                video_on : in STD_LOGIC;
                rgb : out STD_LOGIC_VECTOR(2 downto 0));
end img_gen;

architecture Behavioral of img_gen is

--wall
constant wall_l:integer :=10;--the distance between wall and left side of screen  
constant wall_t:integer :=10;--the distance between wall and top side of screen  
constant wall_k:integer :=10;--wall thickness  
signal wall_on:std_logic;  
signal rgb_wall:std_logic_vector(2 downto 0); 

--bar
signal bar_l, bar_l_next: integer:=100;  
constant bar_t:integer :=420;--the distance between bar and top side of screen  
constant bar_k:integer :=10;--bar thickness  
constant bar_w:integer:=120;--bar width  
constant bar_v:integer:=10;--velocity of the bar  
signal bar_on:std_logic;  
signal rgb_bar:std_logic_vector(2 downto 0); 

--ball
signal ball_l,ball_l_next:integer :=100;--the distance between ball and left side of screen  
signal ball_t,ball_t_next:integer :=100; --the distance between ball and top side of screen  
constant ball_w:integer :=20;--ball Height  
constant ball_u:integer :=20;--ball width  
constant x_v,y_v:integer:=3;-- horizontal and vertical speeds of the ball  
signal ball_on:std_logic;  
signal rgb_ball:std_logic_vector(2 downto 0); 

--refreshing(1/60)
signal refresh_reg,refresh_next:integer;  
constant refresh_constant:integer:=830000;  
signal refresh_tick:std_logic;

--ball animation
signal xv_reg,xv_next:integer:=3;--variable of the horizontal speed  
signal yv_reg,yv_next:integer:=3;--variable of the vertical speed

--x,y pixel cursor
signal x,y:integer range 0 to 650;

--mux
signal vdbt:std_logic_vector(3 downto 0);

--buffer
signal rgb_reg,rgb_next:std_logic_vector(2 downto 0);

begin

--x,y pixel cursor
x <= conv_integer(x_control);  
y <= conv_integer(y_control );

--refreshing
process(clk)  
begin  
     if clk'event and clk='1' then
          refresh_reg<=refresh_next; 
     end if;
end process;  
refresh_next <= 0 when refresh_reg= refresh_constant else  
refresh_reg+1;  
refresh_tick <= '1' when refresh_reg = 0 else  
                           '0';
--register part
process(clk)  
begin  
     if clk'event and clk='1' then
         ball_l <= ball_l_next;
         ball_t <= ball_t_next;
         xv_reg <= xv_next;
         yv_reg <= yv_next;
         bar_l <= bar_l_next;
      end if;
end process;

--bar animation
process(refresh_tick,paddle)  
begin

    if refresh_tick= '1' then
       bar_l_next <= conv_integer(paddle);
    end if;
end process;

--ball animation
process(refresh_tick,ball_l,ball_t,xv_reg,yv_reg)  
begin  
     ball_l_next <=ball_l;
     ball_t_next <=ball_t;
     xv_next <= xv_reg;
     yv_next <= yv_reg;
     if refresh_tick = '1' then
        if ball_t > 400 and ball_l > (bar_l -ball_u) and ball_l < (bar_l +120) then --the ball hits the bar
           yv_next <= -y_v ;
       elsif ball_t < 35 then--The ball hits the wall
           yv_next <= y_v;
       end if;
       if ball_l < 10 then --The ball hits the left side of the screen
          xv_next <= x_v;
       elsif ball_l> 600 then 
          xv_next <= -x_v ; --The ball hits the right side of the screen
       end if; 
       ball_l_next <= ball_l + xv_reg;
       ball_t_next <= ball_t + yv_reg; 
    end if;
end process;

--wall object
wall_on <= '1' when x > wall_l and x < (640-wall_l) and y> wall_t and y < (wall_t+ wall_k) else  
                      '0'; 
rgb_wall <= "000";--Black  
--bar object
bar_on <= '1' when x > bar_l and x < (bar_l+bar_w) and y> bar_t and y < (bar_t+ bar_k) else  
                    '0'; 
rgb_bar <= "001";--blue

--ball object
ball_on <= '1' when x > ball_l and x < (ball_l+ball_u) and y> ball_t and y < (ball_t+ ball_w) else  
                     '0'; 
rgb_ball <= "010"; --Green

--buffer
process(clk)  
begin  
     if clk'event and clk = '1' then
         rgb_reg <= rgb_next;
     end if;
end process;

--mux
vdbt<=video_on & wall_on & bar_on &ball_on;  
with vdbt select  
     rgb_next <= "100" when "1000",--Background of the screen is red 
     rgb_wall when "1100",
     rgb_wall when "1101",
     rgb_bar when "1010",
     rgb_bar when "1011",
     rgb_ball when "1001",
      "000" when others;
--output
rgb <= rgb_reg;

end Behavioral;

My changes are on lines 10 and 95 to make the potentiometer control the paddle.


Creating PONG on the Mojo FPGA

Written by Michael Earls
 FPGA  electronics  programming

I recently found an old VGA monitor on the side of the road and it inspired me to see if I could get my Mojo FPGA board to output a VGA signal. I took the monitor apart and wired its VGA cable directly to my Mojo.

I read up on the VGA specification and learned that getting it to work was as easy as adding resistors to the Red, Green, and Blue outputs.

VGA Connector

I decided to try my hand at implementing the PONG game that is outlined on fpga4fun.com.

There were some differences between that FPGA that they were using and my Mojo board, so I had to go through some trial-and-error.

For instance, the Verilog code that they have on the site depends on a 25MHz clock and my Mojo uses a 50MHz clock. I tried various ways of dividing the clock without success.

I finally found a great example using a 50MHz clock, but it wasn't quite right because it used 8-bits to encode the RGB values, 3 bits for red and green, and 2 bits for blue. I couldn't get this to work, so I found the code that it was based on and found 1 bit per color implementation. I was finally able to get a signal.

The rest of the time was spent implementing the Pong code from the original article. However, the article used a mouse input. I wanted to use a regular potentiometer (dial) to make it more like the "good old days". So, I wired up a pot to the Mojo and altered the Verilog to use it.

Honestly, my code turned out to be spaghetti code because I haven't quite learned how to modularize Verilog to my satisfaction.

I was able to get the paddle working and responding to movement of the potentiometer, but for some reason, the code for the ball just didn't work in my implementation. I'm guessing it has to do with the timing. I still haven't been able to get the ball working, but I was pretty happy that the paddle works.

The Mojo wired to the VGA cable and the paddle The Mojo wired to the VGA cable and the paddle "controller"

The pong paddle The paddle "controller" - a simple 10k potentiometer

Here is the Verilog definition for the Pong module:

`timescale 1ns / 1ps  
module pong(clk, red, green, blue, hsync, vsync, pot_sample);

// Input clk, 50 MHz Oscillator
input clk;  
input [9:0]pot_sample;

// VGA outputs
output red;  
output green;  
output blue;  
output hsync;  
output vsync;     

reg [9:0] hcount;     // VGA horizontal counter  
reg [9:0] vcount;     // VGA vertical counter  
reg [2:0] data;          // RGB data

wire hcount_ov;  
wire vcount_ov;  
wire inDisplayArea;  
wire hsync;  
wire vsync;  
reg  vga_clk;

// VGA mode parameters
parameter hsync_end   = 10'd95,  
   hdat_begin  = 10'd143,
   hdat_end  = 10'd783,
   hpixel_end  = 10'd799,
   vsync_end  = 10'd1,
   vdat_begin  = 10'd34,
   vdat_end  = 10'd514,
   vline_end  = 10'd524;


always @(posedge clk)  
begin  
 vga_clk = ~vga_clk;
end

always @(posedge vga_clk)  
begin  
 if (hcount_ov)
  hcount <= 10'd0;
 else
  hcount <= hcount + 10'd1;
end

assign hcount_ov = (hcount == hpixel_end);

always @(posedge vga_clk)  
begin  
 if (hcount_ov)
 begin
  if (vcount_ov)
   vcount <= 10'd0;
  else
   vcount <= vcount + 10'd1;
 end
end  
assign  vcount_ov = (vcount == vline_end);

////////////////////////////////////////////////////////////////
// Pong
////////////////////////////////////////////////////////////////
// Handle paddle position
reg [9:0] PaddlePosition;

always @(posedge vga_clk) begin

        PaddlePosition <= hdat_begin + pot_sample;

    if(0)
    begin
      if(0)
      begin
         if(~&PaddlePosition)        // make sure the value doesn't overflow
            PaddlePosition <= PaddlePosition + 1;
      end 
      else
      begin
         if(|PaddlePosition)        // make sure the value doesn't underflow
            PaddlePosition <= PaddlePosition - 1;
      end
    end
end

wire paddle = (hcount >= PaddlePosition + 8) && (hcount <= PaddlePosition+120) && ((vcount <= vdat_end - 15) && (vcount > vdat_end - 25));

// Draw a border around the screen
wire border = ((hcount >=  hdat_begin) && (hcount <  hdat_begin + 10)) || ((hcount >  hdat_end - 10) && (hcount <=  hdat_end))  
    || ((vcount >= vdat_begin) && (vcount < vdat_begin + 10)) || ((vcount > vdat_end - 10) && (vcount <= vdat_end));

//////////////////////////////////////////////////////////////////
reg [9:0] ballX;  
reg [9:0] ballY;  
reg ball_inX, ball_inY;

always @(posedge vga_clk)  
if(ball_inX==0) ball_inX <= ((hcount>ballX) && (hcount<=ballX+16)) & ball_inY; else ball_inX <= 0;//!(hcount==ballX+16);

always @(posedge vga_clk)  
if(ball_inY==0) ball_inY <= ((vcount>ballY) && (vcount<=ballY+16)); else ball_inY <= 0;//!(vcount==ballY+16);

wire ball = ball_inX & ball_inY;

/////////////////////////////////////////////////////////////////
wire BouncingObject = border | paddle; // active if the border or paddle is redrawing itself

reg ResetCollision;  
always @(posedge vga_clk) ResetCollision <= (vcount==0) & (hcount==0);  // active only once for every video frame

reg CollisionX1, CollisionX2, CollisionY1, CollisionY2;  
always @(posedge vga_clk) if(ResetCollision) CollisionX1<=0; else if(BouncingObject & (hcount==ballX   ) & (vcount==ballY+ 8)) CollisionX1<=1;  
always @(posedge vga_clk) if(ResetCollision) CollisionX2<=0; else if(BouncingObject & (hcount==ballX+16) & (vcount==ballY+ 8)) CollisionX2<=1;  
always @(posedge vga_clk) if(ResetCollision) CollisionY1<=0; else if(BouncingObject & (hcount==ballX+ 8) & (vcount==ballY   )) CollisionY1<=1;  
always @(posedge vga_clk) if(ResetCollision) CollisionY2<=0; else if(BouncingObject & (hcount==ballX+ 8) & (vcount==ballY+16)) CollisionY2<=1;

/////////////////////////////////////////////////////////////////
wire UpdateBallPosition = ResetCollision;  // update the ball position at the same time that we reset the collision detectors

reg ball_dirX, ball_dirY;  
always @(posedge vga_clk)  
if(UpdateBallPosition)  
begin  
    if(~(CollisionX1 & CollisionX2))        // if collision on both X-sides, don't move in the X direction
    begin
        ballX <= ballX + (ball_dirX ? -1 : 1);
        if(CollisionX2) ball_dirX <= 1; else if(CollisionX1) ball_dirX <= 0;
    end

    if(~(CollisionY1 & CollisionY2))        // if collision on both Y-sides, don't move in the Y direction
    begin
        ballY <= ballY + (ball_dirY ? -1 : 1);
        if(CollisionY2) ball_dirY <= 1; else if(CollisionY1) ball_dirY <= 0;
    end
end 

/////////////////////////////////////////////////////////////////

// display area calculation
assign inDisplayArea = ((hcount >= hdat_begin) && (hcount < hdat_end))  
     && ((vcount >= vdat_begin) && (vcount < vdat_end));

assign hsync = (hcount > hsync_end);  
assign vsync = (vcount > vsync_end);

reg vga_R, vga_G, vga_B;

always @(posedge vga_clk)  
begin  
  vga_R <= BouncingObject | ball;
  vga_G <= BouncingObject | ball;
  vga_B <= BouncingObject | ball;
end

assign red = (inDisplayArea) ?  vga_R : 0;  
assign green = (inDisplayArea) ?  vga_G : 0;  
assign blue = (inDisplayArea) ?  vga_B : 0;      


// generate "image"
always @(posedge vga_clk)  
begin  
  data <= (vcount[2:0] ^ hcount[2:0]); 
end

endmodule

Line #6 is the direct input of the potentiometer from the Mojo's on-board Analog to Digital Converter (ADC). Here is the top file showing how it's all wired together:

module mojo_top(  
    // 50MHz clock input
     input clk,
    // Input from reset button (active low)
    input rst_n,
    // cclk input from AVR, high when AVR is ready
    input cclk,
    // Outputs to the 8 onboard LEDs
    output[7:0]led,
    // AVR SPI connections
    output spi_miso,
    input spi_ss,
    input spi_mosi,
    input spi_sck,
    // AVR ADC channel select
    output [3:0] spi_channel,
    // Serial connections
    input avr_tx, // AVR Tx => FPGA Rx
    output avr_rx, // AVR Rx => FPGA Tx
    input avr_rx_busy, // AVR Rx buffer full
     output  red,
    output  green,
    output  blue,
    output hsync, vsync
    );

wire rst = ~rst_n; // make reset active high

// these signals should be high-z when not used
assign spi_miso = 1'bz;  
assign avr_rx = 1'bz;  
assign spi_channel = 4'bzzzz;

assign led = 8'b0;

wire [3:0] channel;  
wire new_sample;  
wire [9:0] sample;  
wire [3:0] sample_channel;  
wire [9:0] pot_sample;

avr_interface avr_interface (  
 .clk(clk),
 .rst(rst),
 .cclk(cclk),
 .spi_miso(spi_miso),
 .spi_mosi(spi_mosi),
 .spi_sck(spi_sck),
 .spi_ss(spi_ss),
 .spi_channel(spi_channel),
 .tx(avr_rx),
 .rx(avr_tx),
 .channel(channel),
 .new_sample(new_sample),
 .sample(sample),
 .sample_channel(sample_channel),
 .tx_data(8'h00),
 .new_tx_data(1'b0),
 .tx_busy(),
 .tx_block(avr_rx_busy),
 .rx_data(),
 .new_rx_data()
);

 input_capture input_capture (
 .clk(clk),
 .rst(rst),
 .channel(channel),
 .new_sample(new_sample),
 .sample(sample),
 .sample_channel(sample_channel),
 .sample_out(pot_sample)
);

pong pongBoard(  
    .clk(clk), 
    .red(red),
    .green(green),
    .blue(blue),
    .hsync(hsync),
    .vsync(vsync),
    .pot_sample(pot_sample)
);

endmodule

And, finally, here are the custom user constraints that I used to wire the output pins up to the VGA connector:

NET "hsync" LOC = P50 | IOSTANDARD = LVTTL;  
NET "vsync" LOC = P51 | IOSTANDARD = LVTTL;  
NET "red" LOC = P41 | IOSTANDARD = LVTTL;  
NET "green" LOC = P40 | IOSTANDARD = LVTTL;  
NET "blue" LOC = P35 | IOSTANDARD = LVTTL;

I'd really like to get the ball working with this. My scoring will be different than traditional Pong as I am not yet ready to tackle the "AI" of the computer player. I'd like the player to score 1 point each time the ball hits the paddle and lose a point each time the ball hits the bottom wall. If the ball hits the bottom wall while the score is 0, then the game is over. I'll have to add in a reset button, but that shouldn't be much trouble.

I just found another implementation of Pong in VHDL that I may try later. It divides the 50MHz clock into a 25MHz clock using a mod 2 counter. I discuss my implementation of that code in another post.

I haven't written any VHDL, yet, so I'm still trying to wrap my head around it. It was hard enough switching from Mojo's Lucid language to Verilog as Lucid made things a bit easier. However, I felt that since there were a lot more people out there using Verilog that I would be better off learning that. Now I'm learning that there are even more people using VHDL.

Lucid, Verilog, and VHDL are a far cry from C#, C, and JavaScript; three languages I'm very familiar with. This has been a very beneficial lesson in parallel "programming".


Custom Fritzing part for Mojo v3

Written by Michael Earls
 electronics  FPGA  Illustrator

There is a great tool called Fritzing that allows you to create a breadboard view of circuits that you can use for documentation. I really wanted to use it to document the breadboard for my post on setting up a reversible counter, but no one had created a part for it yet. You can also use Fritzing to create schematic diagrams from your breadboard as well as create PC boards.

So, I took a side journey down a very deep rabbit hole. Here's what I learned along the way.

The final part is available on GitHub in my fritzing-parts repository.

Fritzing example with new Mojo part

Fritzing Community

The first thing I noticed immediately was how helpful everyone is in the Fritzing community. The online forums are full of helpful people willing to pitch in. In fact, my part would not have been completed without the enormous effort of @vanepp from the Fritzing forums. I had spent three weeks of my spare time getting everything laid out in Illustrator and Fritzing before I was brave enough to "release" the part onto the Fritzing site. As soon as I did, I received instant feedback on what needed improvement on my part. From there, I've had the assistance of a very experienced part maker working with my source files (which I had converted from the Eagle CAD software to SVG since Eagle is the format that the Mojo manufacturer used to create the board).

Fritzing does not like Adobe Illustrator SVG

Adobe illustrator has the ability to export to SVG. It retains the layer and group names, but some things just weren't translating correctly, so it kept causing trouble. It turns out that the community is mostly using Inkscape (an open-source (GPL) alternative to Illustrator) to make their SVG documents.

I am going to learn how to use Inkscape and I will likely cancel my Adobe Creative Cloud membership. I already know how to use GIMP (the open-source Photoshop alternative). I'm not a graphics professional, but I'm paying a pro price to keep these tools.

The only other product that I use from Creative Cloud is Premiere Pro, but I can just buy Premiere Elements to replace it. That will save me a lot of money each month.

Part creation is hard

I jumped into this thinking "this should be easy, there are so many online tutorials". I was wrong. Even with the tutorials, there were some things I had to learn about creating parts. I accidentally deleted the first part that I created after wiring up 110 pins to three different views (that was over 600 mouse clicks after it was all over).

There are lots of resources, but I'm a hard-knocks kind of learner, so my stubbornness cost me extra pain. The Illustrator part took me over two weeks of spare time to get right. I started with a high-resolution image of the board from the Embedded Micro website and edited it in Photoshop. I prepared it (changed color balance and contrast) for Illustrator. Once I had it in Illustrator, I used the image trace tool to create the beginnings of a long task. I replaced each individual component with hand drawn basic shapes (the image trace created complex paths that would have made an enormous SVG file).

Once I had exported it to SVG, I then had to make sure that the pins lined up. It took a lot of work between myself and @vanepp from the forums

Summary

I enjoyed the part creation overall and I'd do it again. I think Fritzing is a great tool and I hope more people add more parts to it.