| | |
| G9-G0 | |
| B9-B0 |
| R9-R0 |
| BLANK | |
| SYNC | |
| Vaa | |
| CLOCK | |
| GND | |
| IOB,IOG,IOR | |
| IOB,IOG,IOR | |
| COMP | |
| Vref | |
| Rset | |
| | |
三、VGA驱动的FPGA实现
lcd_driver模块的编写:
| | | |
| 1 | input | |
| 1 | input | |
| 24 | Input | |
| 1 | output | |
| 1 | output | |
| 1 | output | |
| 1 | output | |
| 1 | output | |
| 1 | output | |
| 24 | output | |
| 1 | output | |
| 11 | output | |
| 11 | output | |
(1) 设定640*480@60Hz分辨率的宏定义参数
//640*480@60HzVGA Timing
//这里定义为10位宽,因为记数到800,转换成16进制为320,即1100100000
`define H_FRONT 10'd16
`define H_SYNC 10'd96
`define H_BACK 10'd48
`define H_DISP 10'640
`define H_TOTAL 10'd800
`define V_FRONT 10'd10
`define V_SYNC 10'd2
`define V_BACK 10'd33
`define V_DISP 10'd480
`define V_TOTAL 10'd525
(2)行、场扫描记数单位:所有的信号包括使能信号、用户接口都以此参考生成的。
//h_synccounter
reg [9:0] h_cnt;
always@(posedgeclk or negedge rst_n)
begin
if(!rst_n)
h_cnt <=10'd0;
else
begin
if(h_cnt ==`H_TOTAL-1'b1)
h_cnt <=10'd0;
else
h_cnt <=h_cnt+1'b1;
end
end
assign lcd_hs=(h_cnt <=`H_SYNC-1'b1)?1'b0:1'b1;//生成行同步信号
//v_synccounter
reg [9:0] v_cnt;
always@(posedgeclk or negedge rst_n)
begin
if(!rst_n)
v_cnt <=10'b0;
else if(h_cnt==`H_TOTAL-1)
begin
if(v_cnt ==`V_TOTAL-1'b1)
v_cnt <=10'b0;
else
v_cnt<=v_cnt+1'b1;
end
else
v_cnt <=v_cnt;
end
assign lcd_vs=(v_cnt <=`V_SYNC-1'b1)?1'b0;1'b1;//生成场同步信号
(3)ADV7123控制信号
//ADV7123
assign lcd_dclk=clk;
assign lcd_blank=lcd_hs&lcd_vs;
assign lcd_sync=1'b0;
lcd_blank作为显示空白信号,低电平有效,此时RGB输入都将被忽略。设定为场同步之外的时刻。lcd_sync不需要,直接接地。
(4)数据的使能信号
//data out
assign lcd_en=(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)?1'b1:1'b0;
assign lcd_rgb=lcd_en?lcd_data:24'h000_000;
只有在行、场显示有效时间,数据才能有效的输出,当lcd_en有效时,接收外部输入的RGB数据作为VGA驱动模块的输出,同时作为ADV7123的数据输入。
(5)用户控制信号接口
//userinterface
localparam H_AHEAD=1;
assign lcd_request=(h_cnt>=`H_SYNC+`H_BACK-H_AHEAD&&
h_cnt<`H_SYNC+`H_BACK+`H_DISP-H_AHEAD)&&
(v_cnt>=`V_SYNC+`V_BACK&&
v_cnt<`V_SYNC+`V_BACK+`V_DISP)?1'b1:1'b0;
assign lcd_xpos=lcd_request?(h_cnt-(`H_SYNC+`H_BACK-H_AHEAD)):10'd0;
assign lcd_ypos=lcd_request?(v_cnt-(`V_SYNC+`V_BACK)):10'd0;
这里要深刻理解一下,lcd_request相当于提前了一个是时钟的lcd_en,在v_cnt中不能减去H_AHEAD,因为如果这样,lcd_request在场有效的前一个时钟内也会有高电平的出现,而这是不允许的。
以lcd_request信号为使能是为了保证lcd_xpos和lcd_ypos信号的正确时序,这样lcd_xpos最早只能在行显示期的前一时刻出现,同时也保证lcd_ypos是在场有效期内出现。lcd_xpos相对于h_cnt的对应坐标永远都提前了一个单位,这样通过非阻塞赋值,数据会在下一个时刻输出,刚好对应相应的lcd_en,也就是在相应的行显示期内。
这里同样lcd_ypos没有减去H_AHEAD,仔细想一想,记住场都是以行周期为单位的。
lcd_display模块的编写:
建立lcd_display模块,作为lcd_driver的图像输入源,通过对lcd_xpos和lcd_ypos坐标的判断,来实现固定区域图像的输入。
| | | |
| 1 | input | |
| 1 | input | |
| 10 | input | |
| 10 | input | |
| 24 | output | |
(1) 宏定义8种颜色
//definethe color
`define RED 24'hFF0000 /*11111111,00000000,00000000 */
`defineGREEN 24'h00FF00 /*00000000,11111111,00000000 */
`defineBLUE 24'h0000FF /*00000000,00000000,11111111 */
`defineWHITE 24'hFFFFFF /*11111111,11111111,11111111 */
`defineBLACK 24'h000000 /*00000000,00000000,00000000 */
`defineYELLOW 24'hFFFF00 /*11111111,11111111,00000000 */
`defineCYAN 24'hFF00FF /*11111111,00000000,11111111 */
`defineROYAL 24'h00FFFF /*00000000,11111111,11111111 */
(2) 根据输入的行、列地址,输出8色彩条
always@(posedgeclk or negedge rst_n)
begin
if(!rst_n)
lcd_data <=24'h0;
else
if(lcd_xpos>=0&&lcd_xpos<(`H_DISP/8)*1)
lcd_data <=`RED;
elseif(lcd_xpos>(`H_DISP/8)*1&&lcd_xpos<(`H_DISP/8)*2)
lcd_data <=`GREEN;
elseif(lcd_xpos>(`H_DISP/8)*2&&lcd_xpos<(`H_DISP/8)*3)
lcd_data <=`BLUE;
elseif(lcd_xpos>(`H_DISP/8)*3&&lcd_xpos<(`H_DISP/8)*4)
lcd_data <=`WHITE;
else if(lcd_xpos>(`H_DISP/8)*4&&lcd_xpos<(`H_DISP/8)*5)
lcd_data <=`BLACK;
elseif(lcd_xpos>(`H_DISP/8)*5&&lcd_xpos<(`H_DISP/8)*6)
lcd_data <=`YELLOW;
elseif(lcd_xpos>(`H_DISP/8)*6&&lcd_xpos<(`H_DISP/8)*7)
lcd_data <=`CYAN;
else
lcd_data <=`ROYAL;
end
`