FPGA|CPLD|ASIC论坛
直播中

王鸿

8年用户 740经验值
擅长:电源/新能源 嵌入式技术 光电显示
私信 关注
[经验]

【锆石A4 FPGA试用体验】VGA的输出应用

本帖最后由 超级开发板 于 2017-10-8 09:39 编辑


今天,我们来进行锆石A4 FPGA开发板的VGA输出应用
20170927_234520.jpg
FPGA能通过硬件描述语言的编程编程您想要的芯片,当然,也能把它变成带有简单显卡功能的芯片,通过编程,至少能进行显示信号的输出,当然,如果您有更高能力的编程,还能将它变成更功能强大的芯片。

有人说德语是个工具,其实Verilog也能算是工具,就像一把锤子,其本身并不包含您的设计思想,您需要在大脑或草稿中构思好您的电路框架,再用硬件描述语言把这一设计理念实现化,让FPGA读懂您想要的需求,让它变成您需要的样子。

如此一来,我们需要先了解VGA信号的构成,以及VGA显示成像的原理。

经过查阅资料,我们可以了解到:VGA信号]驱动显示器一般用的是扫描的方式,而且一般是逐行扫描。

逐行扫描这个词可能过于术语,顾名思义是一行一行扫下来的,而具体上,它其实是从屏幕左上的第一个像素点向右改变像素的色彩,每行结束会同步一下。

硬件引脚方面:

随便找根不用了的VGA线剥开,发现里面一堆线,其中五根比较重要:

三根粗的RGB:
红色信号 r
绿色信号 g
蓝色信号 b

俩像素信号起始同步:
行同步信号 hs
场同步信号 vs

然后还有根地线也比较重要,屏蔽线初期弄的话可以随便搞搞,等弄的差不多了要追求显示质量了,再去研究它们,这儿先满足最基本的显示需求。

20160504235209041.jpg

. 20160504235439076.png

然后是代码方面:

实现最基本功能的参考范例:
  1. module Main(
  2.     CLK,
  3.     VGA_HS,
  4.     VGA_VS,
  5.     VGA_R,
  6.     VGA_G,
  7.     VGA_B
  8.     );

  9.     input CLK;
  10.     output VGA_HS,VGA_VS, VGA_R, VGA_G, VGA_B;

  11.     reg[10:0] x_counter;
  12.     reg[10:0] y_counter;

  13.     reg [3:1] GRBX;

  14.     initial begin
  15.         x_counter = 0;
  16.         y_counter = 0;
  17.     end

  18. // Always block to drive drawing, {front|back}-doors, and syncs.
  19.     always @(posedge CLK) begin
  20.         if(x_counter == 1055)
  21.         begin
  22.             x_counter = 0;

  23.             if(y_counter == 627)
  24.                 y_counter = 0;
  25.             else
  26.                 y_counter = y_counter + 1;
  27.         end
  28.         else
  29.             x_counter = x_counter + 1;

  30.     end

  31.     always @(x_counter or y_counter)
  32.     begin
  33.         if (x_counter<100)  GRBX<=3'b111;
  34.             else if (x_counter<200)   GRBX<=3'b110;
  35.             else if (x_counter<300)   GRBX<=3'b101;
  36.             else if (x_counter<400)  GRBX<=3'b100;
  37.             else if (x_counter<500)   GRBX<=3'b011;
  38.             else if (x_counter<600)   GRBX<=3'b010;
  39.             else if (x_counter<700)   GRBX<=3'b001;
  40.             else  GRBX<=3'b000 ;
  41.         end

  42.     assign  VGA_R=GRBX[2];
  43.     assign  VGA_G=GRBX[3];
  44.     assign  VGA_B=GRBX[1];

  45.     assign VGA_HS = x_counter > 839 && x_counter < 968;
  46.     assign VGA_VS = y_counter > 600 && y_counter < 605;

  47. endmodule





带注释的参考代码:
  1. //640*480@60HZ,时钟像素:25MHZ
  2. module a1( nclk,rst_n, hsync,vsync,  vga_r,r0,r1,r2,vga_g,g0,g1,g2,vga_b,b0,b1,b2);
  3. input nclk;      
  4.    //内部100M时钟输入
  5. input rst_n;   
  6.    //复位键
  7. output reg  hsync,vsync;  
  8.   //场同步,行同步信号
  9. output vga_r,vga_g,vga_b,r0,r1,r2,g0,g1,g2,b0,b1,b2;  
  10.   //颜色信号输出
  11.    reg[10:0] x_cnt;   
  12.    //行坐标计数,为后面行的0或者1及具体像素点的位置做准备
  13. reg[9:0] y_cnt;   
  14.     //列坐标计数,为后面列的0或者1及具体像素点的位置做准备
  15. reg clk;            
  16.   //实现4分频后的像素点频率 //100M到25M分频器设计
  17. reg[2:0]clk_cnt;initial      
  18.   //寄存器变量赋初值
  19. begin clk=1'b0;
  20. clk_cnt=3'd0;
  21. end
  22.   //红绿蓝的其他三个端口
  23. assign r0=1'b0;
  24. assign r1=1'b0;
  25. assign r2=1'b0;
  26. assign g0=1'b0;
  27. assign g1=1'b0;
  28. assign g2=1'b0;
  29. assign b0=1'b0;
  30. assign b1=1'b0;
  31. assign b2=1'b0;
  32.   always @(negedge nclk) begin  clk_cnt = clk_cnt + 1;
  33. if(clk_cnt==3'd2) clk =1'b1; else if(clk_cnt==3'd4) begin   clk = 1'b0;
  34. clk_cnt=3'd0;
  35.   end
  36.   end  
  37.    //VGA显示的设计   
  38. //像素点的计数
  39.   always@(posedge clk or negedge rst_n) begin  if(!rst_n) x_cnt=11'd0;
  40. else if(x_cnt==11'd800) x_cnt=11'd0; else x_cnt = x_cnt + 1'b1;  
  41.        end   
  42.   //行的计数
  43. always@(posedge clk or negedge rst_n) if(!rst_n) y_cnt = 10'd0;  else if(y_cnt==10'd525) y_cnt=11'd0;
  44. else if(x_cnt==11'd800)y_cnt = y_cnt + 1'b1;
  45. //定义屏幕显示区域
  46.   wire valid = (x_cnt>=11'd144)&&(x_cnt<=11'd784)&&(y_cnt>=10'd35)&&(y_cnt<=10'd515);
  47. wire [9:0] xpos = x_cnt-11'd144; wire [9:0] ypos = y_cnt-10'd35;
  48. //行时序的确定  
  49. always@(posedge clk or negedge rst_n) if(!rst_n) hsync =1'b0;
  50. //复位从0开始
  51. else if(x_cnt==11'd0) hsync=1'b0; else if(x_cnt==11'd96) hsync=1'b1;
  52. //帧时序的确定
  53.   always@(posedge clk or negedge rst_n) if(!rst_n) vsync =1'b0;
  54. //复位从0开始
  55. else if(y_cnt==10'd0) vsync=1'b0; else if(y_cnt==10'd2) vsync=1'b1;
  56. //划分不同显示界面
  57. wire a_dis=((xpos>=200)&&(xpos<=220))&&((ypos>=140)&&(ypos<=460));
  58. wire b_dis=((xpos>=580)&&(xpos<=600))&&((ypos>=140)&&(ypos<=460));
  59. wire c_dis=((xpos>=220)&&(xpos<=580))&&((ypos>=140)&&(ypos<=160));
  60.   wire d_dis=((xpos>=220)&&(xpos<=580))&&((ypos>=440)&&(ypos<=460));
  61. wire e_rdy=((xpos>=385)&&(xpos<=415))&&((ypos>=285)&&(ypos<=315));  
  62. //RGB像素点的赋值
  63. assign vga_r= valid?e_rdy:1'b0;
  64. assign vga_g= valid?  (a_dis|b_dis|c_dis|d_dis):1'b0;
  65. assign vga_b= valid?  ~(a_dis|b_dis|c_dis|d_dis):1'b0;
  66. endmodule


然后,我们将代码编译,并烧写到锆石A4 FPGA开发板上,

找一根合适的VGA线材接入到锆石A4 FPGA开发板的VGA接口中,

重新上电锆石A4 FPGA开发板,以开始运行VGA刷写显示代码,

20170928_210354.jpg

我们可以看到上电后先是完全的黑屏,然后从左上角顶部开始向下刷写白色,
由于锆石A4 FPGA开发板的运算速度极快,
即使反应很快的人类也只能看到白色从上到下被载入,
试着放慢过速率,还是快到转瞬刷白,
每行的从左到右如果想观察的话,可以借助高速相机,
或者按照开发者什么都自己做的行事风格,
再买块锆石A4 FPGA开发板,写个高速相机的软件,
用FPGA的速度捕捉FPGA的速度,

大概上电后零点几秒就全白了,效果如下
20171008_091158.jpg

然后按右侧实体按键的第二个键,全红
20171008_091224.jpg

然后第三个键,左上角有小字,字库已经用了双点像素,普通屏幕轻松看到,如果是视网膜屏贴近了即可看清
20171008_091325.jpg


然后是第四个键,从白刷黑的感觉很舒服,感觉整个屏幕的像素都被抚平
20171008_091600.jpg

下一篇:实时互动检测电路的实现




回帖(2)

卢志豪

2017-9-30 11:12:15
资料很不错,值得收藏
举报

王鸿

2017-10-11 10:05:38
引用: d***sy199205 发表于 2017-9-30 11:12
资料很不错,值得收藏

感谢您的支持                                             
举报

更多回帖

发帖
×
20
完善资料,
赚取积分