Checkoff 01: Test Patterns
Pretty Pictures on the Screen
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! Thetm_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:
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 yourtmds_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'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 eithervcount=360
orhcount=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 ofhcount
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
andvcount
.
- red is the lower 8 bits of
The four patterns should look like the following:
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:
Build the entire project and make sure the test patterns are working!
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
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