• 重温FPGA开发32


    VGA成像原理与时序详解

    VGA、RGBTFT、HDMI 显示,VGA是最基础的

    在基于FPGA的数字系统设计中,VGA显示实验是一个大家绕不开的话题,毕竟使用FPGA就能驱动平常只有电脑才能驱动的大型显示器,相较于普通的MCU一般只能点亮普通的低分辨率小尺寸LCD液晶屏,驱动VGA显示器显得更加令人感兴趣。

    然而事实上,使用FPGA驱动VGA显示器在指定位置显示某一指定颜色并不难,一个具有基本的FPGA逻辑设计能力的人在了解了VGA驱动时序后,大概半个小时就能写出一个易用的VGA控制器,相较于使用小尺寸MCU接口的LCD液晶屏需要查阅一大堆的寄存器来配置其工作模式。显然VGA控制器的开发难度要小的很多。

    其次从功能应用来说,使用FPGA驱动VGA显示器显示复杂多变的图案就显得异常的麻烦了。不仅开发周期长,而且灵活性很低。不适合用来显示人机交互类的图案(所谓人机交互类图案就是指各种多变的文字信息,以及按钮信息等)。

    使用FPGA驱动VGA虽然不适合用来显示复杂多变的图像内容,但是却常用于显示实时图像内容,例如显示图像传感器实时采集到的图像。此种方式数据流由图像传感器实时提供,FPGA只需要控制好图像数据流的存储和传输即可,无需主动生成需要绘制的图像数据,所以实现相对简单。

    鉴于当前基于FPGA的图像处理是一个非常热门的应用方向,而在图像处理中,通过显示器实时查看显示内容属于必备功能,因此本节将详细介绍VGA时序及在FPGA中实现VGA控制器的方法。

    VGA显示器成像原理

    行消隐
    行同步
    场同步
    场消隐

    在这里插入图片描述
    在这里插入图片描述

    VGA控制器设计思路

    了解了整个VGA扫描时序的详细参数之后

    只需要输出 HS、VS、BLK、DATA (RGB三种颜色的分量)。
    需要找到各个信号或者数据的时间节点。
    行同步脉冲开始位置,HS_Begin = 0 (640*480 分辨率)
    行同步脉冲的结束位置 HS_End = 96 (pclk)
    行数据开始输出的位置 Hdata_begin = 96 + 40 + 8
    行数据停止输出的位置 Hdata_end = 96 + 40 + 8 + 640
    行同步信号的结束位置 Hsyns_End = 96 + 40 + 8 + 640 + 8 + 8

    场同步脉冲的开始位置 VS_Begin = 0
    场同步脉冲的结束位置 VS_End = 2(line )
    场数据开始输出的位置 Vdata_begin = 2 + 25 + 8
    场数据停止输出的位置 Vdata_end = 2 + 25 + 8 + 480
    场同步信号的结束位置 Vsyns_End = 2 + 25 + 8 + 480 + 2 + 8

    VGA_CTRL.v

    module VGA_CTRL(
    	Clk,
    	Reset,
    	VGA_HS,
    	VGA_VS,
    	VGA_BLK,
    	VGA_RGB,
    	Data
    	);
    
    	input Clk;
    	input Reset;
    	output reg VGA_HS;
    	output reg VGA_VS;
    	output VGA_BLK;
    	output [23:0]VGA_RGB; // R[7:0] G[7:0] B[7:0]
    
    	localparam Hsync_End = 800;
    	localparam HS_End = 96;
    	localparam Vsync_End = 525;
    	localparam VS_End = 2;
    	localparam Hdat_Begin = 144;
    	localparam Hdat_End = 784;
    
    	localparam Vdat_Begin = 35;
    	localparam Vdat_End = 515;
    	
    
    	reg [9:0]hcnt;
    	always@(posedge Clk or negedge Reset)
    	if(!Reset)
    		hcnt <= 0;
    	else if(hcnt == Hsync_End - 1)
    		hcnt <= 0;
    	else
    		hcnt <= hcnt + 1'b1;
    
    	// 对于我们的HS信号
    	// assign VGA_HS = (hcnt < HS_End - 1'd1)?0:1;
    	//  可以改成时序逻辑,更合理   VGA_VS 同理
    	always@(posedge Clk)
    		VGA_HS <= (hcnt < ES_End - 1'd1)?0:1;
    
    	reg [9:0]vcnt;
    	always@(posedge Clk or negedge Reset)
    	if(!Reset)
    		vcnt <= 0;
    	else if(hcnt == Hsync_End - 1) begin
    		if(vcnt >= Vsyns_End - 1)
    			vcnt <= 0;
    		else
    			vcnt <= vcnt + 1'd1;
    	end
    
    	assign VGA_VS = (vcnt < VS_End - 1'd1) ?0:1;
    
    	// Blk 信号,表示数据输出的时间段,也可以改成时序逻辑
    	assign VGA_BLK = (hcnt >= Hdat_begin - 1) && (hcnt < Hdat_End - 1) && (vcnt >= Vdat_Begin - 1 && (vcnt < Vdat_End))?1:0;
    
    	// 可以
    	assign VGA_RGB = VGA_BLK?Data:0;
    
    endmodule	
    	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    测试 testbench

    module VGA_CRTL_tb;
    	
    	reg Clk;
    	reg Reset;
    	reg [23:0] Data;
    	wire VGA_HS;
    	wire_VGA_VS;
    	wire [23:0]VGA_RGB;
    
    	VGA_CTRL VGA_CTRL(
    		Clk,
    		Reset,
    		Data,
    		VGA_HS,
    		VGA_VS,
    		VGA_BLK,
    		VGA_RGB
    		);
    	
    	initial Clk = 1;
    	always #20 Clk = ~Clk;
    
    	// HS 的变化位置
    	// VS 的变化位置
    	// 待显示数据和HS、VS的位置关系
    
    	initial begin 
    		Reset = 0;
    		// Data = 0;
    		#201;
    		Reset = 1;
    		#20000000;
    		$stop
    	end
    
    	always@(posedge Clk or negedge Reset)
    	if(!Reset)
    		Data <= 0;
    	else if(!VGA_BLK)
    		Data <= Data;
    	else 
    		Data <= Data + 1'd1;
    
    endmodule
    	
    	
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    然后调试:需要不断的找bug,修改源代码
    在这里插入图片描述

    多分辨率适配的VGA控制器

    改一下得到一个新的文件,学习条件语法来进行编译

    条件编译和条件控制语句有本质的区别,条件编译:根据不同的条件来选择对应的HDL文件进行编译以得到对应的逻辑电路。

    if a

    cntmax = 256
    elseif b

    cntmax = 618
    else

    endif

    修改如下:
    决定分辨率的是这几个参数:
    在这里插入图片描述
    vga_parameter.v
    在这里插入图片描述在这里插入图片描述

    然后控制器的内容要进行改写:
    ·include “vga_parameter.v”
    在这里插入图片描述
    位宽最好都设计成12位的

    通过条件编译来适配,多分辨率编译器

  • 相关阅读:
    PingCAP Clinic 快速上手指南
    使用 Footprint Analytics, 快速搭建区块链数据应用
    蓝桥杯2022年第十三届决赛真题-背包与魔法
    2022年12月计划(cesium for unreal源码抄写+各个视频教程,1主+多副)
    理解Lua中“元表和元方法“
    【无标题】
    async await
    在Eclipse将Java代码打包为jar用于jmeter BeanShell
    CF825G题解
    SpringBoot+Vue项目大学生体质测试管理系统
  • 原文地址:https://blog.csdn.net/qq_30093417/article/details/125388161