[Actel FPGA] 基于FPGA的LCD&VGA控制器设计

[复制链接]
 楼主| usber 发表于 2009-5-14 14:14 | 显示全部楼层 |阅读模式
&nbsp;&nbsp;介绍了基于FPGA的图形式LCD&VGA控制器的设计,详细讨论了用VHDL设计行场扫描时序的方法,这种设计方法稍作改动便可产生任意行场扫描时序,具有很好的可重用性。该控制器已成功地在某型飞机座舱图形显示系统中使用。&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;飞机座舱图形显示系统已发展到第六代,即采用有源矩阵彩色液晶显示器AMLCD(Active&nbsp;Matrix&nbsp;Liquid&nbsp;Crystal&nbsp;Display)。当前高分辨率的军用AMLCD显示模块还只能依靠进口,且控制电路板须安装在该显示模块提供的机箱内。这种安装方式对AMLCD控制电路板的尺寸要求高,要求尽可能减少所设计电路板的尺寸。在笔者设计的新一代飞机座舱图形显示系统中使用了大规模现场可编程门阵列FPGA(Field&nbsp;Programmable&nbsp;Gata&nbsp;Array),这种设计方式可以将以前需要多块集成芯片的电路设计到一块大模块可编程逻辑器件中,大大减少了电路板的尺寸,增强了系统的可靠性和设计的灵活性。本文详细介绍了已在实际项目中应用的基于FPGA的图形式AMLCD控制器设计,这种设计方法稍作修改即可应用于常见VGA视频接口电路的设计。&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;图形显示系统简介&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;图1是飞机座舱图形显示系统结构框图。图中处理器采用AD公司的ADSP21061芯片,AMLCD采用Korry公司的KDM710全彩色液晶显示模块,该模块为5×5英寸、600×600分辨率彩色液晶显示模块,24位数字RGB输入。两个帧存A和B采用IDT公司的71V424高速异步静态RAM,系统采用两个帧存轮流操作的方法:当DSP向其中一个帧存写象素时,由FPGA构成的帧存控制器将另一个帧存中的象素顺序读出送给AMLCD,反之亦然。图形显示系统通过IDT公司的71V04双口RAM接收主机的显示信息。图1中的帧存控制器和视频控制器由Xilinx公司的SpartanII芯片XS2S50实现。&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;KMD710显示模块&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;如图1所示,美国Korry公司提供的KDM710全彩色液晶显示模块接口信号主要如下几组:3个8位RGB数字信号、行同步信号HSYNC、场同步信号VSYNC、数据使能信号DATA_EN和点时钟输入DCLK。根据AMLCD数据手册所需求的时序,确定扫描时序和相应的时序参数如图2所示。一般,图形终端显示器扫描制式与广播电视的标准有点不同,须根据显示模块所提供的时间要求来确定扫描时序,其中的行场同步的前后肩,可以根据需要进行微调,一般为了防止每行的第一个象素丢失,要求行同步后肩C与行同步脉冲宽B尽量相等。图2中的点时钟为20MHz,行周期为650个时钟周期,场周期为615个行周期(场频为50Hz)。&nbsp;<br /><br /><br /><br /><br /><br /><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;LCD&VGA控制器设计&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;设计行场扫描时序,一般有两种方式:查找表方式和编程逻辑方式。查找表方式主要由存储芯片构成,如SRAM、EPROM、PORM等。使用时,先根据所要产生的时序在存储单元写入相应的数值,查表时再从表内读出时应存储单元的数值,以形成扫描时序。扫描时序查找表分为行扫描时序查找表和场扫描时序查找表。场扫描时序查找表的输入时钟由行同步脉冲提供。用查找表形成时序的方法存在体积大、计算烦琐的缺点。随着大规模逻辑芯片的出现,利用编程逻辑方法产生行场扫描时序是一个发展方向。这种方法具有电路简单、功能强、修改方便、可靠性高等优点。图3为LCD控制器的框图。&nbsp;<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;在本设计中,点时钟DCLK由处理器DSP的系统时钟40MHz经数字锁相环二分频得到。点时钟驱动行时序生成器,产生图2所示的行同步信号HS和行消隐信号HB。为避免毛刺,控制器设计采用同步设计方法,如图3所示,行同步信号HS通过一个微分电路,产生一个点时钟周期宽的场时序生成器使能信号。在使能信号有效时,场时序生成器开始计数,并产生场同步信号VS和场消隐信号VB。行消隐信号HB和场消隐信号VB相与后即为数据使能信号DATA_EN。该数据使能信号作为产生帧存地址计数器的计数使能,以保证DATA_EN信号为高时,将象素送给AMLCD显示。在DCLK的上升沿,帧存地址计数器加一,帧存SRAM经过一段延时后,象素数据出现在总线上。在DCLK的下降沿AMLCD将数据读入。该LCD控制器的设计方法很容易用于VGA视频接口。在VGA接口电路的设计中,不需点时钟电路,只须将行同步信号与场同步信号输出,将数据使能信号作为复合消隐信号输入即可。产生行场扫描时序的VHDL描述如下:&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;entity&nbsp;seq_gen&nbsp;is&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;port(clk_seq&nbsp;:&nbsp;in&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;rst_seq&nbsp;:&nbsp;in&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;lcd_hs_out&nbsp;:&nbsp;out&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;lcd_dataen&nbsp;:&nbsp;out&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;lcd_vs_out&nbsp;:&nbsp;out&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;pix_clk&nbsp;:&nbsp;out&nbsp;std_logic&nbsp;);&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;seq_gen;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;architecture&nbsp;rtl_seq_gen&nbsp;of&nbsp;seq_gen&nbsp;is&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;signal&nbsp;lcd_hb&nbsp;:&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;signal&nbsp;lcd_hs&nbsp;:&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;signal&nbsp;lcd_vb&nbsp;:&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;signal&nbsp;lcd_vs&nbsp;:&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;signal&nbsp;clken_vcount&nbsp;:&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;begin&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;hcount:&nbsp;block&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;signal&nbsp;hcountreg&nbsp;:std_logic_vector(9&nbsp;downto&nbsp;0);&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;signal&nbsp;hz_temp&nbsp;:&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;signal&nbsp;lcd_hz&nbsp;:&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;begin&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;process&nbsp;(clk_seq,lcd_hz)&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;begin&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(lcd_hz&nbsp;=&nbsp;'1')&nbsp;then&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;hcountreg&nbsp;&lt=&nbsp;(others&nbsp;=&gt'0');&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;elsif&nbsp;clk_seq'event&nbsp;and&nbsp;clk_seq&nbsp;=&nbsp;'1'&nbsp;then&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;hcountreg&nbsp;&lt=&nbsp;hcountreg&nbsp;+1;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;if;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;process;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;lcd_hb&nbsp;&lt=&nbsp;'0'&nbsp;when&nbsp;hcountreg&nbsp;&gt=600&nbsp;and&nbsp;hcountreg&nbsp;&lt&nbsp;650&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;'1';&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;lcd_hs&nbsp;&lt='0'&nbsp;when&nbsp;hcountreg&nbsp;&gt=610&nbsp;and&nbsp;hcountreg&nbsp;&lt&nbsp;630&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;'1';&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;hz_temp&nbsp;&lt=&nbsp;'1'&nbsp;when&nbsp;hcountreg&nbsp;=&nbsp;650&nbsp;else&nbsp;'0';&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;lcd_hz&nbsp;&lt=hz_temp&nbsp;or&nbsp;rst_seq;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;block&nbsp;hcount;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;diff&nbsp;:&nbsp;block&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;signal&nbsp;inputrega&nbsp;:&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;signal&nbsp;inputregb&nbsp;:&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;begin&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;process(clk_seq)&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;begin&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;clk_seq'event&nbsp;and&nbsp;clk_seq='1'&nbsp;then&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;inputregb&nbsp;&lt=&nbsp;inputrega;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;inputrega&nbsp;&lt=&nbsp;not&nbsp;lcd_hs;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;if;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;process;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;clken_vcount&nbsp;&lt=&nbsp;not&nbsp;inputregb&nbsp;and&nbsp;inputrega;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;block&nbsp;diff;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;vcount&nbsp;:&nbsp;block&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;signal&nbsp;vcountreg&nbsp;:&nbsp;std_logic_vector(9&nbsp;downto&nbsp;0);&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;signal&nbsp;vz_temp&nbsp;:&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;signal&nbsp;lcd_vz&nbsp;:&nbsp;std_logic;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;begin&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;process&nbsp;(clk_seq,lcd_vz)&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;begin&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;if(lcd_vz='1')then&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;vcountreg&nbsp;&lt=&nbsp;(others&nbsp;=&gt&nbsp;'0');&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;elsif&nbsp;clk_seq'event&nbsp;and&nbsp;clk_seq&nbsp;=&nbsp;'1'&nbsp;then&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;clken_vcount&nbsp;=&nbsp;'1'&nbsp;then&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;vcountreg&nbsp;&lt=&nbsp;vcountreg&nbsp;+1;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;if;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;if;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;process;&nbsp;<br /><br /><br /><br />lcd_vb&nbsp;&lt=&nbsp;'0'&nbsp;when&nbsp;vcountreg&nbsp;&gt=600&nbsp;and&nbsp;vcountreg&nbsp;&lt&nbsp;615&nbsp;<br /><br /><br /><br />else&nbsp;'1';&nbsp;<br /><br /><br /><br />lcd_vs&nbsp;&lt='0'&nbsp;when&nbsp;vcountreg&nbsp;&gt=607&nbsp;and&nbsp;vcounreg&nbsp;&lt&nbsp;610&nbsp;<br /><br /><br /><br />else&nbsp;'1';&nbsp;<br /><br /><br /><br />vz_temp&nbsp;&lt=&nbsp;'1'&nbsp;when&nbsp;vcountreg&nbsp;=&nbsp;615&nbsp;else&nbsp;'0';&nbsp;<br /><br /><br /><br />lcd_vz&nbsp;&lt=&nbsp;vz_temp&nbsp;or&nbsp;rst_seq;&nbsp;<br /><br /><br /><br />end&nbsp;block&nbsp;vcount;&nbsp;<br /><br /><br /><br />pix_clk&nbsp;&lt=clk_seq;&nbsp;<br /><br /><br /><br />lcd_dataen&nbsp;&lt=lcd_hb&nbsp;and&nbsp;lcd_vb;&nbsp;<br /><br /><br /><br />lcd_hs_out&nbsp;&lt=lcd_hs;&nbsp;<br /><br /><br /><br />lcd_vs_out&nbsp;&lt=lcd_vs;&nbsp;<br /><br /><br /><br />end&nbsp;rtl_seq_gen;&nbsp;<br /><br /><br /><br />这种用VHDL产生扫描时序的方法简单、易读,并且易于修改。在代码中只须修改一些时序参数就能产生任意时序的波形,具有很好的可重用性。用FPGA&nbsp;Express&nbsp;3.5半VHDL代码综合后,通过Foundation&nbsp;3.1i进行布局和布线,用Foundation提供的门级仿真工具产生的行扫描时序仿真图如图4所示。&nbsp;<br /><br /><br /><br />采用FPGA技术设计的AMLCD控制器,大大减少了电路板的尺寸,同时增加了系统可靠性和设计灵活性。这种用VHDL语言实现现行场扫描时序生成器的方法,具有简便。易读和可重用性强的特点。该AMLCD控制器已用Xilinx公司的SpartanII系列器件XC2S50实现,并在飞机座舱图形显示系统中实现应用。&nbsp;<br />
jumpoo 发表于 2009-5-15 09:39 | 显示全部楼层

re

  
您需要登录后才可以回帖 登录 | 注册

本版积分规则

15

主题

86

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部