Skip to content

Commit ce09da4

Browse files
authored
Merge pull request #9 from projf/no-async-timings
No async display timings
2 parents 3e81c3c + c06df70 commit ce09da4

18 files changed

+178
-178
lines changed

README.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Project F Display Controller
1+
# Project F Display Controller
22

33
The Project F display controller makes it easy to add video output to FPGA projects. It's written in Verilog and supports VGA, DVI, and HDMI displays. It includes full configuration for 640x480, 800x600, 1280x720, and 1920x1080, as well as the ability to define custom resolutions. This design and its documentation are licensed under the MIT License.
44

@@ -22,12 +22,12 @@ This design supports displays using VGA, DVI, and HDMI.
2222

2323
**VGA** support is straightforward; you can see an example in the [VGA demo](hdl/demo/display_demo_vga.v). If you're building your own hardware, then [Retro Ramblings](http://retroramblings.net/?p=190) has a good example of creating a register ladder DAC. If you're looking for a ready-made VGA output, then the [VGA Pmod](https://reference.digilentinc.com/reference/pmod/pmodvga/start) is a good option for around $10.
2424

25-
**DVI** & **HDMI** use [transition-minimized differential signalling](https://en.wikipedia.org/wiki/Transition-minimized_differential_signaling) (TMDS) to transmit video over high-speed serial links. HDMI provides extra functionality over DVI, including audio support, but all HDMI displays should accept a standard DVI signal without issue.
25+
**DVI** & **HDMI** use [transition-minimized differential signalling](https://en.wikipedia.org/wiki/Transition-minimized_differential_signaling) (TMDS) to transmit video over high-speed serial links. HDMI provides extra functionality over DVI, including audio support, but all HDMI displays should accept a standard DVI signal without issue.
2626

27-
The display controller offers two types of TMDS generation:
27+
The display controller offers two types of TMDS generation:
2828

2929
* Direct generation on FPGA
30-
* [Black Mesa Labs DVI Pmod](https://blackmesalabs.wordpress.com/2017/12/15/bml-hdmi-video-for-fpgas-over-pmod/)
30+
* [Black Mesa Labs DVI Pmod](https://blackmesalabs.wordpress.com/2017/12/15/bml-hdmi-video-for-fpgas-over-pmod/)
3131

3232
Direct TMDS generation on FPGA requires high-frequency clocks (742.5 MHz for 720p60) and SerDes but allows full control of the signal including HDMI features. HDMI support is currently via backwards compatibility with DVI: any standard HDMI display should accept DVI signals. However, this display controller lacks support for audio or advanced HDMI features at present.
3333

@@ -36,14 +36,14 @@ The Black Mesa Labs (BML) Pmod is based on the Texas Instruments [TFP410](http:/
3636

3737
## Display Resolution Support
3838
The following four display resolutions are tested and included by default (all at 60 Hz refresh rate):
39-
40-
Resolution Ratio Clock
39+
40+
Resolution Ratio Clock
4141
640 x 480 4:3 25.20 MHz [1]
4242
800 x 600 4:3 40.00 MHz
43-
1280 x 720 16:9 74.25 MHz
44-
1920 x 1080 16:9 148.50 MHz [2]
43+
1280 x 720 16:9 74.25 MHz
44+
1920 x 1080 16:9 148.50 MHz [2]
4545

46-
You can easily add timings for other resolutions; see [demos](#demos) for how to do this.
46+
You can easily add timings for other resolutions; see [demos](#demos) for how to do this.
4747

4848
_[1] The canonical clock for 640x480 60Hz is 25.175 MHz, but 25.2 MHz is within VESA spec and easier to generate._
4949

@@ -91,9 +91,9 @@ We haven't formally verified the design yet, but plan to do this for the display
9191

9292

9393
## TMDS Encoder Model
94-
The display controller includes a simple [Python model](model/tmds.py) to help with TMDS encoder development.
94+
The display controller includes a simple [Python model](model/tmds.py) to help with TMDS encoder development.
9595

96-
There are two steps to TMDS encoding: applying XOR or XNOR to the bits to minimize transitions and keeping the overall number of 1s and 0s similar to ensure DC balance. The first step depends only on the current input value, so it is easy to test. However, balancing depends on the previous values, which makes testing harder; this is where the model is particularly useful.
96+
There are two steps to TMDS encoding: applying XOR or XNOR to the bits to minimize transitions and keeping the overall number of 1s and 0s similar to ensure DC balance. The first step depends only on the current input value, so it is easy to test. However, balancing depends on the previous values, which makes testing harder; this is where the model is particularly useful.
9797

9898
By default, the Python model encodes all 256 possible 8-bit values in order, but it's easy to change the script to handle other combinations. `A0, A1, B0, or B1` show which of the four balancing options was taken: you can see what they do in the [Python source](model/tmds.py) or [Verilog design](hdl/tmds_encoder_dvi.v).
9999

@@ -115,7 +115,7 @@ You can also see the full output from the [Python model](model/tmds-test-python.
115115

116116

117117
## Resource Utilization
118-
The display controller is lightweight, fitting into even the smallest FPGA:
118+
The display controller is lightweight, fitting into even the smallest FPGA:
119119

120120
Artix-7
121121
Demo LUT FF

doc/modules.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ See [README](/README.md) for more documentation.
1010
## Contents
1111

1212
- **[Architecture](#architecture)**
13-
- **[Display Clocks](#display-clocks)** ([hdl](/hdl/display_clocks.v)) - pixel and high-speed clocks for TMDS
13+
- **[Display Clocks](#display-clocks)** ([hdl](/hdl/display_clocks.v)) - pixel and high-speed clocks for TMDS
1414
- **[Display Timings](#display-timings)** ([hdl](/hdl/display_timings.v)) - generates display timings, including horizontal and vertical sync
1515
- **[DVI Generator](#dvi-generator)** ([hdl](/hdl/dvi_generator.v)) - uses `serializer_10to1` and `tmds_encode_dvi` to generate a DVI signal
1616

@@ -84,7 +84,7 @@ The display timings generator turns timing parameters into appropriately timed s
8484
* `i_pixclk` - pixel clock
8585
* `i_rst` - reset (active high)
8686

87-
The pixel clock must be suitable for the timings given in the parameters (see display clocks, above).
87+
The pixel clock must be suitable for the timings given in the parameters (see display clocks, above).
8888

8989
### Outputs
9090

@@ -97,7 +97,7 @@ The pixel clock must be suitable for the timings given in the parameters (see di
9797
* `o_x [15:0]` - horizontal screen position (active pixels)
9898
* `o_y [15:0]` - vertical screen position (active pixels)
9999

100-
The positional outputs `(h,v)` and `(x,y)` allow you to determine the current pixel AKA "beam position". The values provided by `h` & `v `include the blanking interval, while `x` & `y` only include valid on-screen positions. For simple drawing or bitmap display you can use `(x,y)` and safely ignore `(h,v)`. However, if you're doing calculations in real time "racing the beam", then you'll want to perform actions in the blanking interval, which is where (h,v) comes in.
100+
The positional outputs `(h,v)` and `(x,y)` allow you to determine the current pixel AKA "beam position". The values provided by `h` & `v `include the blanking interval, while `x` & `y` only include valid on-screen positions. For simple drawing or bitmap display you can use `(x,y)` and safely ignore `(h,v)`. However, if you're doing calculations in real time "racing the beam", then you'll want to perform actions in the blanking interval, which is where (h,v) comes in.
101101

102102
Project F considers blanking intervals to occur _before_ active pixels. At the start of a frame (indicated by the `o_frame` signal), you have the blanking intervals in which to work before active pixel drawing occurs. The following sketch this for 1280x720p60 (other resolutions work in the same way):
103103

@@ -109,8 +109,8 @@ Horizontal and vertical sync may be active high or low depending on the display
109109

110110
### Parameters
111111

112-
* `H_RES` - active horizontal resolution in pixels
113-
* `V_RES` - active vertical resolution in lines
112+
* `H_RES` - active horizontal resolution in pixels
113+
* `V_RES` - active vertical resolution in lines
114114
* `H_FP` - horizontal front porch length in pixels
115115
* `H_SYNC` - horizontal sync length in pixels
116116
* `H_BP` - horizontal back porch length in pixels
@@ -138,7 +138,7 @@ DVI generator instantiates two other modules to do the actual work: one for [TMD
138138
* `i_data_ch0 [7:0]` - 8-bit blue colour data (TMDS channel 0)
139139
* `i_data_ch1 [7:0]` - 8-bit green colour data (TMDS channel 1)
140140
* `i_data_ch2 [7:0]` - 8-bit red colour data (TMDS channel 2)
141-
* `i_ctrl_ch0 [1:0]` - channel 0 control data; set to `{v_sync, h_sync}` from [display timings](#display-timings)
141+
* `i_ctrl_ch0 [1:0]` - channel 0 control data; set to `{v_sync, h_sync}` from [display timings](#display-timings)
142142
* `i_ctrl_ch1 [1:0]` - channel 1 control data; set to `2'b00`
143143
* `i_ctrl_ch2 [1:0]` - channel 2 control data; set to `2'b00`
144144

@@ -153,7 +153,7 @@ The output is the four TMDS encoded serial channels ready for output as differen
153153

154154
You can use these signals with `OBUFDS`, for example:
155155

156-
OBUFDS #(.IOSTANDARD("TMDS_33"))
156+
OBUFDS #(.IOSTANDARD("TMDS_33"))
157157
tmds_buf_ch0 (.I(tmds_ch0_serial), .O(hdmi_tx_p[0]), .OB(hdmi_tx_n[0]));
158158

159159
Where `hdmi_tx_p[0]` and `hdmi_tx_n[0]` are the differential output pins for TMDS channel 0.

doc/porting.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Porting the Display Controller
1+
# Porting the Display Controller
22

33
We strive to create generic HDL designs where possible. However, vendor-specific components are critical to certain functionality, such as high-speed clock generation. The display controller uses three Xilinx-specific components: all display options use the `MMCM` for clock generation, while TMDS encoding on the FPGA requires `OSERDESE2` and `OBUFDS`. Expanded hardware support will be available in future, but in the meantime, we offer the following advice:
44

hdl/demo/display_demo_dvi.v

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
// Learn more at https://projectf.io
77

88
// This demo requires the following Verilog modules:
9-
// * display_clocks
10-
// * display_timings
11-
// * dvi_generator
12-
// * serializer_10to1
13-
// * test_card
14-
// * tmds_encoder_dvi
9+
// * display_clocks
10+
// * display_timings
11+
// * dvi_generator
12+
// * serializer_10to1
13+
// * test_card
14+
// * tmds_encoder_dvi
1515

1616
module display_demo_dvi(
1717
input wire CLK, // board clock: 100 MHz on Arty/Basys3/Nexys
@@ -22,13 +22,13 @@ module display_demo_dvi(
2222
inout wire hdmi_tx_rsda, // DDC bidirectional
2323
output wire hdmi_tx_clk_n, // HDMI clock differential negative
2424
output wire hdmi_tx_clk_p, // HDMI clock differential positive
25-
output wire [2:0] hdmi_tx_n, // Three HDMI channels differential negative
25+
output wire [2:0] hdmi_tx_n, // Three HDMI channels differential negative
2626
output wire [2:0] hdmi_tx_p // Three HDMI channels differential positive
2727
);
2828

2929
wire rst = ~RST_BTN; // reset is active low on Arty & Nexys Video
3030
// wire rst = RST_BTN; // reset is active high on Basys3 (BTNC)
31-
31+
3232
// Display Clocks
3333
wire pix_clk; // pixel clock
3434
wire pix_clk_5x; // 5x clock for 10:1 DDR SerDes
@@ -43,9 +43,9 @@ module display_demo_dvi(
4343
)
4444
display_clocks_inst
4545
(
46-
.i_clk(CLK),
47-
.i_rst(rst),
48-
.o_clk_1x(pix_clk),
46+
.i_clk(CLK),
47+
.i_rst(rst),
48+
.o_clk_1x(pix_clk),
4949
.o_clk_5x(pix_clk_5x),
5050
.o_locked(clk_lock)
5151
);
@@ -69,12 +69,12 @@ module display_demo_dvi(
6969
.V_BP(20), // 33 23 20 36
7070
.H_POL(1), // 0 1 1 1
7171
.V_POL(1) // 0 1 1 1
72-
)
73-
display_timings_inst (
72+
)
73+
display_timings_inst (
7474
.i_pixclk(pix_clk),
7575
.i_rst(rst),
76-
.o_hs(h_sync),
77-
.o_vs(v_sync),
76+
.o_hs(h_sync),
77+
.o_vs(v_sync),
7878
.o_de(de),
7979
.o_frame(frame),
8080
.o_h(),
@@ -86,17 +86,17 @@ module display_demo_dvi(
8686
// Test Card Generation
8787
wire red, green, blue;
8888
test_card #(
89-
.H_RES(1280),
89+
.H_RES(1280),
9090
.V_RES(720)
91-
)
91+
)
9292
test_card_inst (
9393
.i_x(x),
9494
.i_y(y),
9595
.o_red(red),
9696
.o_green(green),
9797
.o_blue(blue)
9898
);
99-
99+
100100
// TMDS Encoding and Serialization
101101
wire tmds_ch0_serial, tmds_ch1_serial, tmds_ch2_serial, tmds_chc_serial;
102102
dvi_generator dvi_out (
@@ -116,18 +116,18 @@ module display_demo_dvi(
116116
.o_tmds_ch2_serial(tmds_ch2_serial),
117117
.o_tmds_chc_serial(tmds_chc_serial) // encode pixel clock via same path
118118
);
119-
119+
120120
// TMDS Buffered Output
121-
OBUFDS #(.IOSTANDARD("TMDS_33"))
121+
OBUFDS #(.IOSTANDARD("TMDS_33"))
122122
tmds_buf_ch0 (.I(tmds_ch0_serial), .O(hdmi_tx_p[0]), .OB(hdmi_tx_n[0]));
123-
OBUFDS #(.IOSTANDARD("TMDS_33"))
123+
OBUFDS #(.IOSTANDARD("TMDS_33"))
124124
tmds_buf_ch1 (.I(tmds_ch1_serial), .O(hdmi_tx_p[1]), .OB(hdmi_tx_n[1]));
125-
OBUFDS #(.IOSTANDARD("TMDS_33"))
125+
OBUFDS #(.IOSTANDARD("TMDS_33"))
126126
tmds_buf_ch2 (.I(tmds_ch2_serial), .O(hdmi_tx_p[2]), .OB(hdmi_tx_n[2]));
127-
OBUFDS #(.IOSTANDARD("TMDS_33"))
128-
tmds_buf_chc (.I(tmds_chc_serial), .O(hdmi_tx_clk_p), .OB(hdmi_tx_clk_n));
129-
130-
assign hdmi_tx_cec = 1'bz;
127+
OBUFDS #(.IOSTANDARD("TMDS_33"))
128+
tmds_buf_chc (.I(tmds_chc_serial), .O(hdmi_tx_clk_p), .OB(hdmi_tx_clk_n));
129+
130+
assign hdmi_tx_cec = 1'bz;
131131
assign hdmi_tx_rsda = 1'bz;
132132
assign hdmi_tx_rscl = 1'b1;
133133
endmodule

hdl/demo/display_demo_dvi_pmod3.v

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
// Learn more at https://projectf.io
77

88
// This demo requires the following Verilog modules:
9-
// * display_clocks
10-
// * display_timings
11-
// * test_card
9+
// * display_clocks
10+
// * display_timings
11+
// * test_card
1212

1313
module display_demo_dvi_pmod3(
1414
input wire CLK, // board clock: 100 MHz on Arty/Basys3/Nexys
@@ -24,7 +24,7 @@ module display_demo_dvi_pmod3(
2424

2525
wire rst = ~RST_BTN; // reset is active low on Arty & Nexys Video
2626
// wire rst = RST_BTN; // reset is active high on Basys3 (BTNC)
27-
27+
2828
// Display Clocks
2929
wire pix_clk; // pixel clock
3030
wire clk_lock; // clock locked?
@@ -38,10 +38,10 @@ module display_demo_dvi_pmod3(
3838
)
3939
display_clocks_inst
4040
(
41-
.i_clk(CLK),
42-
.i_rst(rst),
43-
.o_clk_1x(pix_clk),
44-
.o_clk_5x(), // 5x clock not needed for VGA
41+
.i_clk(CLK),
42+
.i_rst(rst),
43+
.o_clk_1x(pix_clk),
44+
.o_clk_5x(), // 5x clock not needed for DVI Pmod
4545
.o_locked(clk_lock)
4646
);
4747

@@ -64,12 +64,12 @@ module display_demo_dvi_pmod3(
6464
.V_BP(33), // 33 23 20 36
6565
.H_POL(0), // 0 1 1 1
6666
.V_POL(0) // 0 1 1 1
67-
)
68-
display_timings_inst (
67+
)
68+
display_timings_inst (
6969
.i_pixclk(pix_clk),
7070
.i_rst(rst),
71-
.o_hs(h_sync),
72-
.o_vs(v_sync),
71+
.o_hs(h_sync),
72+
.o_vs(v_sync),
7373
.o_de(de),
7474
.o_frame(frame),
7575
.o_h(),
@@ -81,23 +81,23 @@ module display_demo_dvi_pmod3(
8181
// Test Card Generation
8282
wire red, green, blue;
8383
test_card #(
84-
.H_RES(640),
84+
.H_RES(640),
8585
.V_RES(480)
86-
)
86+
)
8787
test_card_inst (
8888
.i_x(x),
8989
.i_y(y),
9090
.o_red(red),
9191
.o_green(green),
9292
.o_blue(blue)
9393
);
94-
94+
9595
// 3-bit DVI Output
9696
assign DVI_HS = h_sync;
9797
assign DVI_VS = v_sync;
9898
assign DVI_CLK = pix_clk;
9999
assign DVI_DE = de;
100-
assign DVI_R = de & red;
100+
assign DVI_R = de & red;
101101
assign DVI_G = de & green;
102102
assign DVI_B = de & blue;
103103
endmodule

0 commit comments

Comments
 (0)