Close

Finally FPGA!

A project log for Microhacks

A collection of small ideas

ted-yapoTed Yapo 01/27/2018 at 20:492 Comments

I wanted to get started with FPGAs for a long time.  Today, it finally happened.  I bought a #TinyFPGA A-Series (A1 specifically) on Tindie, and started coding.  After a few hours, I came up with a bouncing ball on a VGA monitor (starting from scratch).

I know there are simple VGA examples out there, but I resisted looking at them for the exercise. It's not super-complex, but a lot of things have to be right to get this to work.  There are a few issues, mainly about the clock.  I used the internal clock source on the FPGA, which isn't very accurate or stable.  Additionally, the closest I could get to the proper 25.175 MHz dot clock was 24.18 MHz.  The result is a little jitter on the display. I could solve this with an external oscillator, but this was just an exercise.

The hardware is simply the A1 board and six resistors to shift the RGB levels and provide a proper 75-ohm output impedance.  I didn't have any VGA connectors around, so I used BNC's and an old-school VGA-to-BNC cable.  There are a few in-progress projects in the picture, but you can locate the TinyFPGA and the BNCs.  The three LEDs from the example in the TinyFPGA documentation are still in the breadboard :-)

The verilog code could probably be prettied up a lot, but at this point, I'm just excited to have something going.  This is sure to give experienced RTL jockeys a good laugh:

module TinyFPGA_A1 (
  output pin4_mosi,
  output pin5,
  output pin6,
  output pin7_done,
  output pin8_pgmn
                    );
  
  wire clk;
   OSCH #(.NOM_FREQ("24.18") // should be 25.175 - close enough!
          ) internal_oscillator_inst (
                                      .STDBY(1'b0), 
                                      .OSC(clk)
                                      );
   
   parameter ball_size = 20;
   reg [9:0] horiz_ctr;
   reg       hsync;
   reg [9:0] vert_ctr;
   reg       vsync;
   reg       hblank;
   reg       vblank;
   reg [9:0] row;
   reg [9:0] col;
   reg       dr;
   reg       dc;
   reg [2:0] rgb;
   always @(posedge clk) begin
      horiz_ctr <= horiz_ctr + 1; 
      if (((vert_ctr-45) >= row) &&
          ((vert_ctr-45) <= (row+ball_size)) &&
          ((horiz_ctr-160) >= col) &&
          ((horiz_ctr-160) <= (col+ball_size)))
        rgb = 3'b100;
      else
        rgb = 3'b001;
     
      case (horiz_ctr)
        10'd16:  hsync <= 1;
        10'd112: hsync <= 0;
        10'd160: hblank <= 0;
        10'd800:
          begin
             horiz_ctr <= 0;
             hblank <= 1;
             vert_ctr <= vert_ctr + 1;
             case (vert_ctr)
               10'd10:  vsync <= 1;
               10'd12:  vsync <= 0;
               10'd45:  vblank <= 0;
               10'd525:
                 begin
                    vert_ctr <= 0;
                    vblank <= 1;
                    if (dr)
                      row <= row + 1;
                    else
                      row <= row - 1;
                    if (dc)
                      col <= col + 1;
                    else
                      col <= col - 1;
                    if (row < 1) begin
                       row <= 1;
                       dr <= ~dr;
                    end
                    if (col < 1) begin
                       col <= 1;
                       dc <= ~dc;
                    end
                    if (row > (479-ball_size)) begin
                       row <= 479-ball_size;
                       dr <= ~dr;
                    end                               
                    if (col > (639-ball_size)) begin
                       col <= 639-ball_size;
                       dc <= ~dc;
                    end           
                 end
             endcase
          end
      endcase
   end

   wire frame_active = !vblank & !hblank;

   assign pin8_pgmn = !hsync;
   assign pin7_done = !vsync;
   assign pin4_mosi = frame_active & rgb[0];
   assign pin5 = frame_active & rgb[1];
   assign pin6 = frame_active & rgb[2];      
endmodule

If I'm reading the output of the Lattice Diamond software correctly (doubtful), I've used 117 of the 256 available LUT's - less than half.  I didn't think about optimizing the code at all - at this point, I wouldn't know exactly where to start.

I am really impressed with how easy this all is. Kudos to @Luke Valenty  on a very nice project/product.

Discussions

Luke Valenty wrote 01/27/2018 at 20:57 point

This is great!  @Xark had previously attempted using the internal oscillator on the A2 for VGA but it seemed like his monitor didn't like it.  I'm happy to see that it will at least work with some VGA monitors.  Also fun to see what people can do with the teeny-tiny FPGA in the A1.  Thanks for sharing your project :)  

  Are you sure? yes | no

Ted Yapo wrote 01/27/2018 at 21:02 point

Thanks! It also worked at 26.60 MHz with this monitor, but appeared to tear a little more on the left edge.

  Are you sure? yes | no