行场信号
| 名称 | 本质 | 对应坐标 |
|---|---|---|
| 行(H) | 一行扫描 | x(横向) |
| 场(V) | 一帧逐行 | y(纵向) |
800x480屏逻辑等价1056x525屏幕
| 类别 | 名称 | 数值 | 计数区间 | 含义 | 是否显示 | 本质 |
|---|---|---|---|---|---|---|
| 计数器 | h_cnt |
--- | 0 ~ 1055 | 一行里第几个像素 | --- | 横向(x) |
| 计数器 | v_cnt |
--- | 0 ~ 524 | 当前第几行 | --- | 纵向(y) |
| 横向 | H_SYNC |
128 | [0, 128) | 行同步 | ❌ | 时序填充 |
| 横向 | H_BACK |
88 | [128, 216) | 行后沿 | ❌ | 黑边 |
| 横向 | H_DISP |
800 | [216, 1016) | 行有效显示 | ✅ | 可见像素 |
| 横向 | H_FRONT |
40 | [1016, 1056) | 行前沿 | ❌ | 黑边 |
| 横向 | H_TOTAL |
1056 | [0, 1056) | 行扫描周期 | --- | 一行总长度 |
| 纵向 | V_SYNC |
2 | [0, 2) | 场同步 | ❌ | 时序填充 |
| 纵向 | V_BACK |
33 | [2, 35) | 场后沿 | ❌ | 黑边 |
| 纵向 | V_DISP |
480 | [35, 515) | 场有效显示 | ✅ | 可见像素 |
| 纵向 | V_FRONT |
10 | [515, 525) | 场前沿 | ❌ | 黑边 |
| 纵向 | V_TOTAL |
525 | [0, 525) | 场扫描周期 | --- | 一帧总高度 |
扫描方向
bash
pclk ↑ ⟹ h_cnt++;
h_cnt 满 ⟹ v_cnt++
# 扫描展开:
v_cnt = 0 ⟹ → → → → →
v_cnt = 1 ⟹ → → → → →
v_cnt = 2 ⟹ → → → → →
... ⟹ → → → → →
v_cnt = V_TOTAL-1 ⟹ → → → → →
bash
行内计数h_cnt →
0 1055
│----------------------------------------------│
v_cnt ↓ │ H_SYNC │ H_BACK │ H_DISP │ H_FRONT │
│ 128 │ 88 │ 800 │ 40 │
0 ├────────┼────────┼──────────────────┼─────────┤
│ V_SYNC (2 行) │
2 ├──────────────────────────────────────────────┤
│ V_BACK (33 行) │
35 ├────────┬────────┬──────────────────┬─────────┤
│ │ │ │ │
│ │ │ 有效显示区 │ │
│ │ │ 800 × 480 │ │
│ │ │ │ │
515 ├────────┴────────┴──────────────────┴─────────┤
│ V_FRONT (10 行) │
524 └──────────────────────────────────────────────┘
LCD / FPS / 时钟计算
ffps=fpclkHtotal×Vtotalf_{fps} = \frac{f_{pclk}}{H_{total} \times V_{total}}ffps=Htotal×Vtotalfpclk (帧率 = 像素时钟 / 一帧像素总数)\quad \text{(帧率 = 像素时钟 / 一帧像素总数)}(帧率 = 像素时钟 / 一帧像素总数)
fpclk=ffps×Htotal×Vtotalf_{pclk} = f_{fps} \times H_{total} \times V_{total}fpclk=ffps×Htotal×Vtotal (像素时钟 = 帧率 × 一帧像素总数)\quad \text{(像素时钟 = 帧率 × 一帧像素总数)}(像素时钟 = 帧率 × 一帧像素总数)
lcd_rgb_colorbar.v
verilog
module lcd_rgb_colorbar(
input i_sys_clk, // 系统时钟输入(pixel clock / PLL源)
input i_sys_rst_n, // 系统复位(低有效)
//========================
// RGB LCD 控制接口输出
//========================
output o_lcd_de, // 数据有效使能(Data Enable)
output o_lcd_hs, // 行同步信号(HSYNC)
output o_lcd_vs, // 场同步信号(VSYNC)
output o_lcd_bl, // 背光控制(Back Light)
output o_lcd_clk, // LCD像素时钟输出
output o_lcd_rst, // LCD复位信号(低有效/高有效视屏而定)
output [23:0] o_lcd_rgb // RGB888像素数据输出(R[23:16] G[15:8] B[7:0])
);
//====================================================
// wire
//====================================================
wire w_lcd_pclk;
wire [10:0] w_pixel_xpos;
wire [10:0] w_pixel_ypos;
wire [10:0] w_h_disp;
wire [10:0] w_v_disp;
wire [23:0] w_pixel_data;
//====================================================
// clk
//====================================================
clk_div u_clk_div(
.i_clk (i_sys_clk),
.i_rst_n (i_sys_rst_n),
.o_pclk (w_lcd_pclk)
);
//====================================================
// display
//====================================================
lcd_display u_lcd_display(
.i_lcd_pclk (w_lcd_pclk),
.i_rst_n (i_sys_rst_n),
.i_x_pos (w_pixel_xpos),
.i_y_pos (w_pixel_ypos),
.i_h_disp (w_h_disp),
.i_v_disp (w_v_disp),
.o_pixel_data(w_pixel_data)
);
//====================================================
// driver
//====================================================
lcd_driver u_lcd_driver(
.i_lcd_pclk (w_lcd_pclk),
.i_rst_n (i_sys_rst_n),
.i_pixel_data(w_pixel_data),
.o_pixel_xpos(w_pixel_xpos),
.o_pixel_ypos(w_pixel_ypos),
.o_h_disp (w_h_disp),
.o_v_disp (w_v_disp),
.o_data_req (),
.o_lcd_de (o_lcd_de),
.o_lcd_hs (o_lcd_hs),
.o_lcd_vs (o_lcd_vs),
.o_lcd_bl (o_lcd_bl),
.o_lcd_clk (o_lcd_clk),
.o_lcd_rst (o_lcd_rst),
.o_lcd_rgb (o_lcd_rgb)
);
endmodule
clk_div.v
verilog
module clk_div #(
parameter DIV = 2
)(
input i_clk,
input i_rst_n,
output o_clk_en, // 时钟使能
output o_pclk // 可选:分频时钟
);
//====================================================
// 内部信号
//====================================================
reg [$clog2(DIV)-1:0] r_cnt;
reg r_clk_en;
reg r_pclk;
//====================================================
// 分频逻辑
//====================================================
always @(posedge i_clk or negedge i_rst_n) begin
if (!i_rst_n) begin
r_cnt <= 0;
r_clk_en <= 1'b0;
r_pclk <= 1'b0;
end else begin
if (r_cnt == DIV/2 - 1) begin
r_cnt <= 0;
r_clk_en <= 1'b1;
r_pclk <= ~r_pclk;
end else begin
r_cnt <= r_cnt + 1;
r_clk_en <= 1'b0;
end
end
end
//====================================================
// 输出
//====================================================
assign o_clk_en = r_clk_en;
assign o_pclk = r_pclk;
endmodule
lcd_driver.v
verilog
//*******************************************************
//** Module name: lcd_driver (Fixed 4.3' 800*480)
//*******************************************************
module lcd_driver(
input i_lcd_pclk, //时钟
input i_rst_n, //复位,低电平有效
input [23:0] i_pixel_data, //像素数据
output reg [10:0] o_pixel_xpos, //当前像素点横坐标
output reg [10:0] o_pixel_ypos, //当前像素点纵坐标
output reg [10:0] o_h_disp, //LCD屏水平分辨率 (固定输出)
output reg [10:0] o_v_disp, //LCD屏垂直分辨率 (固定输出)
output reg o_data_req, //数据请求信号
//RGB LCD接口
output reg o_lcd_de, //LCD 数据使能信号
output o_lcd_hs, //LCD 行同步信号
output o_lcd_vs, //LCD 场同步信号
output o_lcd_bl, //LCD 背光控制信号
output o_lcd_clk, //LCD 像素时钟
output o_lcd_rst, //LCD复位
output [23:0] o_lcd_rgb //LCD RGB888颜色数据
);
//*********** 4.3' 800*480 参数定义 (固定) ***********
// 这些参数直接取自原代码中的 H_SYNC_4384 等定义
parameter H_SYNC = 11'd128; //行同步
parameter H_BACK = 11'd88; //行显示后沿
parameter H_DISP = 11'd800; //行有效数据 (分辨率宽)
parameter H_FRONT = 11'd40; //行显示前沿
parameter H_TOTAL = 11'd1056; //行扫描周期
parameter V_SYNC = 11'd2; //场同步
parameter V_BACK = 11'd33; //场显示后沿
parameter V_DISP = 11'd480; //场有效数据 (分辨率高)
parameter V_FRONT = 11'd10; //场显示前沿
parameter V_TOTAL = 11'd525; //场扫描周期
//reg define
reg [10:0] h_cnt; //行计数器
reg [10:0] v_cnt; //场计数器
//**************************************************
//** main code
//**************************************************
//RGB LCD 采用DE模式时,行场同步信号需要拉高
assign o_lcd_hs = 1'b1;
assign o_lcd_vs = 1'b1;
assign o_lcd_bl = 1'b1;
assign o_lcd_clk = i_lcd_pclk;
assign o_lcd_rst = 1'b1;
//RGB888数据输出
assign o_lcd_rgb = o_lcd_de ? i_pixel_data : 24'd0;
//像素点x坐标
always@ (posedge i_lcd_pclk or negedge i_rst_n) begin
if(!i_rst_n)
o_pixel_xpos <= 11'd0;
else if(o_data_req)
// 计算当前像素在屏幕内的X位置
o_pixel_xpos <= h_cnt - H_SYNC - H_BACK;
else
o_pixel_xpos <= 11'd0;
end
//像素点y坐标
always@ (posedge i_lcd_pclk or negedge i_rst_n) begin
if(!i_rst_n)
o_pixel_ypos <= 11'd0;
else if(o_data_req)
o_pixel_ypos <= v_cnt - V_SYNC - V_BACK;
else
o_pixel_ypos <= 11'd0;
end
// 固定分辨率输出 (供外部模块使用)
always @(*) begin
o_h_disp = H_DISP;
o_v_disp = V_DISP;
end
//数据使能信号 (固定逻辑)
always@ (posedge i_lcd_pclk or negedge i_rst_n) begin
if(!i_rst_n)
o_data_req <= 1'b0;
else if( (h_cnt >= H_SYNC + H_BACK) && (h_cnt < H_SYNC + H_BACK + H_DISP) &&
(v_cnt >= V_SYNC + V_BACK) && (v_cnt < V_SYNC + V_BACK + V_DISP) )
o_data_req <= 1'b1;
else
o_data_req <= 1'b0;
end
//行计数器对像素时钟计数
always@ (posedge i_lcd_pclk or negedge i_rst_n) begin
if(!i_rst_n)
h_cnt <= 11'd0;
else begin
if(h_cnt == H_TOTAL - 1'b1)
h_cnt <= 11'd0;
else
h_cnt <= h_cnt + 1'b1;
end
end
//场计数器对行计数
always@ (posedge i_lcd_pclk or negedge i_rst_n) begin
if(!i_rst_n)
v_cnt <= 11'd0;
else begin
if(h_cnt == H_TOTAL - 1'b1) begin
if(v_cnt == V_TOTAL - 1'b1)
v_cnt <= 11'd0;
else
v_cnt <= v_cnt + 1'b1;
end
end
end
//数据使能信号延迟寄存(DE)
always@ (posedge i_lcd_pclk or negedge i_rst_n) begin
if(!i_rst_n)
o_lcd_de <= 1'b0;
else
o_lcd_de <= o_data_req;
end
endmodule
lcd_display.v
verilog
module lcd_display(
input i_lcd_pclk, //时钟
input i_rst_n, //复位,低电平有效
input [10:0] i_x_pos, //当前像素点横坐标
input [10:0] i_y_pos, //当前像素点纵坐标
input [10:0] i_h_disp, //LCD屏水平分辨率
input [10:0] i_v_disp, //LCD屏垂直分辨率
output reg [23:0] o_pixel_data //像素数据
);
//parameter define
parameter WHITE = 24'hFFFFFF; //白色
parameter BLACK = 24'h000000; //黑色
parameter RED = 24'hFF0000; //红色
parameter GREEN = 24'h00FF00; //绿色
parameter BLUE = 24'h0000FF; //蓝色
//*****************************************************
//** main code
//*****************************************************
//根据当前像素点坐标指定当前像素点颜色数据,在屏幕上显示彩条
always @(posedge i_lcd_pclk or negedge i_rst_n) begin
if(!i_rst_n)
o_pixel_data <= BLACK;
else begin
if((i_x_pos >= 11'd0) && (i_x_pos < i_h_disp/5*1))
o_pixel_data <= WHITE;
else if((i_x_pos >= i_h_disp/5*1) && (i_x_pos < i_h_disp/5*2))
o_pixel_data <= BLACK;
else if((i_x_pos >= i_h_disp/5*2) && (i_x_pos < i_h_disp/5*3))
o_pixel_data <= RED;
else if((i_x_pos >= i_h_disp/5*3) && (i_x_pos < i_h_disp/5*4))
o_pixel_data <= GREEN;
else
o_pixel_data <= BLUE;
end
end
endmodule
pin.xdc
bash
create_clock -period 20.000 -name i_sys_clk -waveform {0.000 10.000} [get_ports i_sys_clk]
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports i_sys_clk]
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports i_sys_rst_n]
set_property -dict {PACKAGE_PIN W18 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[0]}]
set_property -dict {PACKAGE_PIN W19 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[1]}]
set_property -dict {PACKAGE_PIN R16 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[2]}]
set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[3]}]
set_property -dict {PACKAGE_PIN W20 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[4]}]
set_property -dict {PACKAGE_PIN V20 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[5]}]
set_property -dict {PACKAGE_PIN P18 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[6]}]
set_property -dict {PACKAGE_PIN N17 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[7]}]
set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[8]}]
set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[9]}]
set_property -dict {PACKAGE_PIN T17 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[10]}]
set_property -dict {PACKAGE_PIN R18 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[11]}]
set_property -dict {PACKAGE_PIN Y18 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[12]}]
set_property -dict {PACKAGE_PIN Y19 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[13]}]
set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[14]}]
set_property -dict {PACKAGE_PIN P16 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[15]}]
set_property -dict {PACKAGE_PIN V16 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[16]}]
set_property -dict {PACKAGE_PIN W16 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[17]}]
set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[18]}]
set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[19]}]
set_property -dict {PACKAGE_PIN Y17 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[20]}]
set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[21]}]
set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[22]}]
set_property -dict {PACKAGE_PIN U17 IOSTANDARD LVCMOS33} [get_ports {o_lcd_rgb[23]}]
set_property -dict {PACKAGE_PIN N18 IOSTANDARD LVCMOS33} [get_ports o_lcd_hs]
set_property -dict {PACKAGE_PIN T20 IOSTANDARD LVCMOS33} [get_ports o_lcd_vs]
set_property -dict {PACKAGE_PIN U20 IOSTANDARD LVCMOS33} [get_ports o_lcd_de]
set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports o_lcd_bl]
set_property -dict {PACKAGE_PIN P19 IOSTANDARD LVCMOS33} [get_ports o_lcd_clk]
set_property -dict {PACKAGE_PIN L17 IOSTANDARD LVCMOS33} [get_ports o_lcd_rst]