Skip to contentSkip to author details

FPGA

A 10-post collection

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.

Here is the Lucid code (the Mojo-specific HDL):

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

Solving the Stable Marriage problem on an FPGA (Part 2)

Written by Michael Earls
 Mathematics  FPGA  electronics  programming

In part 1, I introduced the Stable Marriage problem and proposed implementing it on an FPGA.

In this post, I will define the approach I am taking to define the preferences in binary form.

Series entries:

Note: Blog title image used without permission (pending) from numberphile.com

Since we're only dealing with eight people (four women and four men), I decided to use a 2-bit number to define the Id number of the person within their gender.

With a 2-bit number, that gives us the following Id's to work with (per gender):

  • Person #1 - 00
  • Person #2 - 01
  • Person #3 - 10
  • Person #4 - 11

To define the preferences for each person, we can take advantage of the fact that we're only using 2-bits per id and only have four preferences. That means we can use a single byte to define the preferences, with the most significant 2 bits being the first choice.

Here is a table to illustrate some sample preferences:

Proposal Table (Decimal)

Females
Id 1st 2nd 3rd 4th
1 2 1 4 3
2 2 4 3 1
3 2 1 4 3
4 4 3 2 1
Males
Id 1st 2nd 3rd 4th
1 4 3 2 1
2 3 1 2 4
3 4 3 1 2
4 2 4 3 1

So, let's take a look at our proposal cycles using this table:

First cycle

Here are the proposals:

  • Woman 1: Man 2
  • Woman 2: Man 2
  • Woman 3: Man 2
  • Woman 4: Man 4

So, Man 2 now has 3 proposals (Woman 1, Woman 2, and Woman 3). If we look at his preferences (3, 1, 2, 4), we see that he prefers Woman 3 over Women 1 and 2, so he declines them and accepts a tentative proposal from Woman 3 (since this is the first match and they both are top of each other's list, they won't be matched with another person, but that is a fact that we can deduce as humans that we can't expect the machine to know).

Woman 4 is tentatively engaged to Man 4.

Women 1 and 2 are left out because they were declined, so they'll propose to their second choice on the second cycle.

At the end of the cycle we have the following state for the Women:

  • Woman 1: unmatched
  • Woman 2: unmatched
  • Woman 3: tentatively engaged to Man 2
  • Woman 4: tentatively engaged to Man 4

Second cycle

Here are the choices

  • Woman 1: Man 1
  • Woman 2: Man 4
  • Woman 3: N/A (tentatively engaged)
  • Woman 4: N/A (tentatively engaged)

Woman 1 proposes to her 2nd choice, Man 1. Man 1 has not been proposed to yet, so he'll accept.

Woman 2 proposes to Man 4, but he is tentatively engaged to Woman 4. However, since Woman 2 is his first choice, he declines Woman 4 and "trades up" to accept the new proposal from Woman 2.

This leaves Woman 4 alone to propose in the third cycle.

At the end of the cycle we have the following state for the Women:

  • Woman 1: tentatively engaged to Man 1
  • Woman 2: tentatively engaged to Man 4
  • Woman 3: tentatively engaged to Man 2
  • Woman 4: unmatched

Third cycle

Here are the choices

  • Woman 1: N/A (tentatively engaged)
  • Woman 2: N/A (tentatively engaged)
  • Woman 3: N/A (tentatively engaged)
  • Woman 4: Man 2

So, Woman 4 proposes to Man 2, but he prefers his current fiance, so he declines her.

At the end of the cycle we have the following state for the Women:

  • Woman 1: tentatively engaged to Man 1
  • Woman 2: tentatively engaged to Man 4
  • Woman 3: tentatively engaged to Man 2
  • Woman 4: (still) unmatched

Fourth cycle

Here are the choices

  • Woman 1: N/A (tentatively engaged)
  • Woman 2: N/A (tentatively engaged)
  • Woman 3: N/A (tentatively engaged)
  • Woman 4: Man 1

Woman 4 proposes to Man 1, but he is tentatively engaged to Woman 1. However, Woman 4 is is top choice, so he declines Woman 1's proposal and "trades up" to accept Woman 4's proposal.

This leaves Woman 1 alone again, forcing her to propose in the next cycle.

At the end of the cycle we have the following state for the Women:

  • Woman 1: unmatched
  • Woman 2: tentatively engaged to Man 4
  • Woman 3: tentatively engaged to Man 2
  • Woman 4: tentatively engaged to Man 1

Fifth cycle

Here are the choices

  • Woman 1: Man 4
  • Woman 2: N/A (tentatively engaged)
  • Woman 3: N/A (tentatively engaged)
  • Woman 4: N/A (tentatively engaged)

Woman 1 proposes to Man 4, but he is already engaged to his top preference, so he declines her proposal. This leaves her alone again for the next cycle.

At the end of the cycle we have the following state for the Women:

  • Woman 1: (still) unmatched
  • Woman 2: tentatively engaged to Man 4
  • Woman 3: tentatively engaged to Man 2
  • Woman 4: tentatively engaged to Man 1

Sixth cycle

Here are the choices

  • Woman 1: Man 3
  • Woman 2: N/A (tentatively engaged)
  • Woman 3: N/A (tentatively engaged)
  • Woman 4: N/A (tentatively engaged)

Woman 1 proposes to Man 3, who is currently free, so he accepts her proposal.

At the end of the cycle we have the following state for the Women:

  • Woman 1: tentatively engaged to Man 3
  • Woman 2: tentatively engaged to Man 4
  • Woman 3: tentatively engaged to Man 2
  • Woman 4: tentatively engaged to Man 1

We now have no more unmatched Women, so our cycles are complete and we have stable marriages.

Here are the final results:

  • Woman 1: engaged to Man 3
  • Woman 2: engaged to Man 4
  • Woman 3: engaged to Man 2
  • Woman 4: engaged to Man 1

Here is the proposal table in binary (with 2-bit Id's)

Females
Id 1st 2nd 3rd 4th
00 01 00 11 10
01 01 11 10 00
10 01 00 11 10
11 11 10 01 00
Males
Id 1st 2nd 3rd 4th
00 11 10 01 00
01 10 00 01 11
10 11 10 00 01
11 01 11 10 00

So to represent the preferences of the Women, we simply create a byte containing their preferences.

Here they are for each woman:

  • Woman 1 (00) - 01001110
  • Woman 2 (01) - 01111000
  • Woman 3 (10) - 01001110
  • Woman 4 (11) - 11100100

Note: It's important to notice that I'm referring to them in 1-based decimal (Woman 1, 2, 3, 4), but 0-based binary (Woman 00, Woman 01, Woman 10, Woman 11).

So, to represent these preferences we simply need four sets of 4-bit numbers representing the matching for the women. So, our final results would look like this in binary:

0010 0111 1001 1100

I'm not considering how to scale this out, yet, so I'm making some assumptions on the feasibility of using 2-bit id's rather than full bytes. In the end, a full byte will give us more people, but I wanted to keep this simple. I hope by starting this way I don't adversely effect the overall solution.

Now that I've established the preferences and a way to represent them in binary, I need to figure out the best way to store them and run the cycles on the FPGA.

Next up, defining our finite state machines (FSMs).

Solving the Stable Marriage problem on an FPGA (Part 1)

Written by Michael Earls
 Mathematics  FPGA  programming

At my last client, there was an issue that came up that required matching between two groups. It had to be a fair matching based on preferences of both sides. I first started by writing my own algorithm, but I quickly realized that someone has to have come up with something to do this already. I was right. Not only had someone(s) figured the problem out, they received a Nobel Prize for their work (good thing I didn't try to tackle it on my own).

Note: Blog title image used without permission (pending) from numberphile.com

Series entries:

The algorithm is named after the two mathematicians who discovered it: the Gale–Shapley algorithm, or commonly called the Stable Marriage Problem (or stable matching problem - SMP). I'll let you read about it on Wikipedia as I don't just want to repeat what's already there. Basically, it's also used in the National Resident Matching Program to help match medical students to residency programs, so it has real-world applications beyond the classroom.

Here is a great video describing the algorithm in layman's terms:

And for some deeper math, here is the follow-up to that video:

I became obsessed with this algorithm while working with the client because they had some unique ways of determining preferences beyond just saying "I like guy 2". There had to be more to it. "I like guy 2 because...".

My work obsession happened to coincide with my home obsession of learning how to utilize and develop on FPGAs. Again, I'll let you read the details, but the best way to describe an FPGA (compared to a microcontroller like the Arduino or Raspberry Pi) is as follows (I read this somewhere on the Internet and it stuck in my head):

  • You tell a microcontroller what to do.
  • You tell an FPGA what to be

There's a nuance there that has enormous implications on the differences between the two. FPGAs are much faster than microcontrollers because all of the logic runs in parallel, whereas a microcontroller has to run a program in a tight loop and constantly check and update the status of its IO pins. Every time you add a new task to a microcontroller's program, you slow it down.

Here is a video from Microsoft's Channel 9 discussing research they are doing on using FPGAs in the data center (Bing specifically) to increase performance and save energy:

Since the SMB algorithm can be so processor-intensive, I thought it might be cool to implement it on FPGA hardware to see if I can pull it off.

To keep things simpler for me, my initial approach is only going to deal with 8 total people: 4 women, and 4 suitors. I will take the "women propose" approach as discussed in the video above.

Next: Establishing the preferences...

Using Notepad++ as the default editor for Xilinx ISE

Written by Michael Earls
 FPGA  electronics

I was having difficulties working with the built in text editor for the ISE FPGA tool from Xilinx. I was missing some of the things I've come to depend on in the editors that I use every day (Visual Studio, VSCode, Notepad++, etc.) I noticed in the preferences that I could choose an external text editor. I decided to see if I could get Notepad++ working.

I was able to get it to work, but I first had to add the path to Notepad++ to my PATH environment variable in Windows.

Update: If you use Notepad++ as the default text editor, then the test benches do not execute correctly. Le Sigh!

Open control panel and edit system environment variables. Add the path to Notepad++ to the PATH variable (mine was "C:\Program Files(x86)\Notepad++").

Then, choose Edit->Preferences from the Xilinx ISE editor.

Xilinx ISE Custom Text Editor Dialog

As you can see, once you have the Notepad++ path set, you simply need to add notepad++.exe $1 to the command line syntax and choose Custom from the Editor drop down.

I was pleasantly surprised to find out that Notepad++ already has language settings for Verilog and VHDL, so all of my code is formatted and colored.

When ISE opens the custom text editor, it does it in another window. I have docked my ISE and Notepad++ windows side-by-side for an easier workflow.

ISE and Notepad++ docked side-by-side

I love working with Notepad++, so this is a welcome improvement as I work more with Xilinx ISE.