Checkoff 01: Test Patterns

Pretty Pictures on the Screen

The questions below are due on Wednesday October 02, 2024; 11:59:00 PM.
 
You are not logged in.

Please Log In for full access to the web site.
Note that this link will take you to an external site (https://shimmer.mit.edu) to authenticate, and then you will be redirected back to this page.

Alright time to build. Create a new project like before. Grab the standard xdc file here. By studying the top_level module inputs and outputs, make sure to uncomment all the necessary lines in the XDC file (new ones today include the hdmi signals).

Set up the rest of your project directory like before. For files you will want in your hdl:

  • top_level.sv: A skeleton of which is provided below.
  • video_sig_gen.sv that you already made here. Put that in its own file!
  • tmds_encoder.sv: The TMDS that you wrote in the previous section. Put that in its own file! The tm_choice module can either also be in that file or a separate one...your choice.
  • hdmi_clk_wiz.v: A "clock wizard" module that creates the appropriate 74.25 MHz and 371.25 MHz clock signals (don't edit it)
  • tmds_serializer.sv: A module to serialize the TMDS signal (don't edit it)
  • block_sprite.sv: A module performing the logic for a block "sprite" (don't edit it)

The starting code for top_level.sv is found below. As always, make sure to really actually read the comments.

`default_nettype none // prevents system from inferring an undeclared logic (good practice)

module top_level(
  input wire clk_100mhz, //crystal reference clock
  input wire [15:0] sw, //all 16 input slide switches
  input wire [3:0] btn, //all four momentary button switches
  output logic [15:0] led, //16 green output LEDs (located right above switches)
  output logic [2:0] rgb0, //rgb led
  output logic [2:0] rgb1, //rgb led
  output logic [2:0] hdmi_tx_p, //hdmi output signals (positives) (blue, green, red)
  output logic [2:0] hdmi_tx_n, //hdmi output signals (negatives) (blue, green, red)
  output logic hdmi_clk_p, hdmi_clk_n //differential hdmi clock
  );

  assign led = sw; //to verify the switch values
  //shut up those rgb LEDs (active high):
  assign rgb1= 0;
  assign rgb0 = 0;

  //have btn[0] control system reset
  logic sys_rst;
  assign sys_rst = btn[0]; //reset is btn[0]
  logic game_rst;
  assign game_rst = btn[1]; //reset is btn[1]

  logic clk_pixel, clk_5x; //clock lines
  logic locked; //locked signal (we'll leave unused but still hook it up)

  //clock manager...creates 74.25 Hz and 5 times 74.25 MHz for pixel and TMDS
  hdmi_clk_wiz_720p mhdmicw (
      .reset(0),
      .locked(locked),
      .clk_ref(clk_100mhz),
      .clk_pixel(clk_pixel),
      .clk_tmds(clk_5x));

  logic [10:0] hcount; //hcount of system!
  logic [9:0] vcount; //vcount of system!
  logic hor_sync; //horizontal sync signal
  logic vert_sync; //vertical sync signal
  logic active_draw; //ative draw! 1 when in drawing region.0 in blanking/sync
  logic new_frame; //one cycle active indicator of new frame of info!
  logic [5:0] frame_count; //0 to 59 then rollover frame counter

  //written by you previously! (make sure you include in your hdl)
  //default instantiation so making signals for 720p
  video_sig_gen mvg(
      .pixel_clk_in(clk_pixel),
      .rst_in(sys_rst),
      .hcount_out(hcount),
      .vcount_out(vcount),
      .vs_out(vert_sync),
      .hs_out(hor_sync),
      .ad_out(active_draw),
      .nf_out(new_frame),
      .fc_out(frame_count));

  logic [7:0] red, green, blue; //red green and blue pixel values for output
  logic [7:0] tp_r, tp_g, tp_b; //color values as generated by test_pattern module
  logic [7:0] pg_r, pg_g, pg_b;//color values as generated by pong game(part 2)

  //comment out in checkoff 1 once you know you have your video pipeline working:
  //these three colors should be a nice pink (6.205 sidebar) color on full screen .
  assign tp_r = 8'hFF;
  assign tp_g = 8'h40;
  assign tp_b = 8'h7A;

  //uncomment the test pattern generator for the latter portion of part 1
  //and use it to drive tp_r,g, and b once you know that your video
  //pipeline is working (by seeing the 6.205 pink color)
  /*
  test_pattern_generator mtpg(
      .sel_in(sw[1:0]),
      .hcount_in(hcount),
      .vcount_in(vcount),
      .red_out(tp_r),
      .green_out(tp_g),
      .blue_out(tp_b));
  */

  //uncomment for last part of lab!:
  /*
  pong my_pong (
      .pixel_clk_in(clk_pixel),
      .rst_in(game_rst),
      .control_in(btn[3:2]),
      .puck_speed_in(sw[15:12]),
      .paddle_speed_in(sw[11:8]),
      .nf_in(new_frame),
      .hcount_in(hcount),
      .vcount_in(vcount),
      .red_out(pg_r),
      .green_out(pg_g),
      .blue_out(pg_b));
  */

  always_comb begin
    if (~sw[2])begin //if switch 3 switched use shapes signal from part 2, else defaults
      red = tp_r;
      green = tp_g;
      blue = tp_b;
    end else begin
      red = pg_r;
      green = pg_g;
      blue = pg_b;
    end
  end

  logic [9:0] tmds_10b [0:2]; //output of each TMDS encoder!
  logic tmds_signal [2:0]; //output of each TMDS serializer!

  //three tmds_encoders (blue, green, red)
  //MISSING two more tmds encoders (one for green and one for blue)
  //note green should have no control signal like red
  //the blue channel DOES carry the two sync signals:
  //  * control_in[0] = horizontal sync signal
  //  * control_in[1] = vertical sync signal

  tmds_encoder tmds_red(
      .clk_in(clk_pixel),
      .rst_in(sys_rst),
      .data_in(red),
      .control_in(2'b0),
      .ve_in(active_draw),
      .tmds_out(tmds_10b[2]));

  //three tmds_serializers (blue, green, red):
  //MISSING: two more serializers for the green and blue tmds signals.
  tmds_serializer red_ser(
      .clk_pixel_in(clk_pixel),
      .clk_5x_in(clk_5x),
      .rst_in(sys_rst),
      .tmds_in(tmds_10b[2]),
      .tmds_out(tmds_signal[2]));

  //output buffers generating differential signals:
  //three for the r,g,b signals and one that is at the pixel clock rate
  //the HDMI receivers use recover logic coupled with the control signals asserted
  //during blanking and sync periods to synchronize their faster bit clocks off
  //of the slower pixel clock (so they can recover a clock of about 742.5 MHz from
  //the slower 74.25 MHz clock)
  OBUFDS OBUFDS_blue (.I(tmds_signal[0]), .O(hdmi_tx_p[0]), .OB(hdmi_tx_n[0]));
  OBUFDS OBUFDS_green(.I(tmds_signal[1]), .O(hdmi_tx_p[1]), .OB(hdmi_tx_n[1]));
  OBUFDS OBUFDS_red  (.I(tmds_signal[2]), .O(hdmi_tx_p[2]), .OB(hdmi_tx_n[2]));
  OBUFDS OBUFDS_clock(.I(clk_pixel), .O(hdmi_clk_p), .OB(hdmi_clk_n));

endmodule // top_level
`default_nettype wire

What needs to be done first with this code is to complete the HDMI pipeline. Specifically we are aiming for a system that looks like this:

The basic starting HDMI pipeline. Complete the wiring/implementation of this in the `top_level`.

  • video_sig_gen you already wrote. That creates all the necessary signals for our 720p existence.
  • tmds_encoder you already wrote. That will generate the appropriately encoded TMDS data for HDMI.
  • tmds_serializer is a special module we wrote using Vivado primitives found on the FPGA. The module takes in the 10 bit TMDS-encoded pixel from your tmds_encoder module and then uses the faster 371.25 MHz clock to double-pump the data out at 742.5 MHz.
  • OBUFDS is another Xilinx primitive that links to a special piece of hardware on the FPGA. It takes in this very high speed data stream and generates a differential signal which is then fed to the HDMI output on the board.

Study the code and fill in the gaps using the comments. There are missing instances of the tmds_serializer and tmds_encoder. Take special care to make sure that the blue channel of the TMDS pipeline gets the vertical and horizontal sync values. These are used to generate the control patterns in the TMDS encoding during the blanking and sync periods!

If created correctly, when controlling an HDMI monitor you should see the screen full of pink kinda like the sidebar on our website. This is coming from the following three lines:

  assign tp_r = 8'hFF;
  assign tp_g = 8'h77;
  assign tp_b = 8'hAA;

The 6.205 pink color is the default here since it is rarely used as a "default" color of a monitor and involves non-negligible amounts of all three color channels. If you're not getting the color shown below (or any signal), then there's likely an issue with your module wiring!

If you don't have access to all three color sensors with your human eyes, no worries! Feel free to ask a staff member to ensure that it looks right. We just need to make sure you have proper RGB control and then after that we don't really care about color in any specific sense!

If everything is wired up correctly, you should be getting a screen full of this color.

If you've got a screen that is the right color, you can move on. Congrats you have a functioning HDMI pipeline that you (mostly) wrote! Excellent job.

Now that you've verified your video pipeline is working, write a test pattern generator module that takes in hcount and vcount as well as a two-bit selector switch sel_in and based on sel_in generates values for the red, green, and blue channels that will result in the following patterns:

  • sel_in==2'b00: All pixels are your favorite color. I like orange a lot, but you should choose one you like and be prepared to defend it. You cannot choose black, white, or pink since we already used those.
  • sel_in==2'b01: Pixels make a cross-hair pattern where a pixel is full-white if either vcount=360 or hcount=640 else it is black.
  • sel_in==2'b10: A white-to-black horizontal gray repeating pattern. The red, green, and blue values should be just be the lower 8 bits of hcount only.
  • sel_in==2'b11: A beautiful, loud argyle-like pattern where:
    • red is the lower 8 bits of hcount.
    • green is the lower 8 bits of vcount.
    • blue is the lower 8 bits of the sum of hcount and vcount.

The four patterns should look like the following:

If everything is wired up correctly, then you should see these test pattern on your display. Study its colors

The module should be combinational only! We do not want to introduce a delay into our signal pipeline!

module test_pattern_generator(
  input wire [1:0] sel_in,
  input wire [10:0] hcount_in,
  input wire [9:0] vcount_in,
  output logic [7:0] red_out,
  output logic [7:0] green_out,
  output logic [7:0] blue_out
  );
  //your code here.
  //logic should be purely combinational
endmodule

When finished, uncomment the instantiation of the module in your top_level module, remove/comment-out the hard-coded pink values. This will update your video pipeline to look something like the following:

Your video pipeline with the test pattern generator in place.

Build the entire project and make sure the test patterns are working!

All four test patterns from the FPGA. You can even hear the switches clicking in the background as I flip them.

When ready, you can ask for the checkoff. Be prepared to discuss the following:

  • The signals you generate from the video_sig_gen module. Specifically:
    • What is the back porch and front porch? What is the sync?
    • What are the dimensions of a complete frame?
    • What fraction of the frame is actually drawn on screen?
  • TMDS:
    • What is it?
    • How does it work?
    • What were any issues you ran into while developing this module?
  • How did you generate the test patterns?
  • What do the following modules do:
    • tmds_encoder
    • tmds_serializer
    • OBUFDS

Checkoff 1:
For checkoff 1, show your video pipeline working with all four basic test patterns. See questions above.

Once you're done, move onto Pong in Checkoff 02 :D