状态机设计实践

目录

VGA时序控制器的设计

 设计过程:

1.按区域显示

2.按像素显示

   设计过程:


VGA时序控制器的设计

   VGA(Video Graphics Array)是IBM公司于1987年推出基于模拟信号的视频显示标准,目前仍是计算机、投影仪和液晶显示器等电子产品基本的视频接口标准。

   VGA应用DB15物理接口。    VGA接口信号的定义如右图所示,主要有5条基本信号线:红、绿、蓝三基色模拟信号线,以及行同步(HSYNC)和场同步(VSYNC)两条数字信号线。

   VGA三基色模拟量采用RS343电平标准,其中红色和蓝色信号的电压范围为0~0.714V,如图6-39所示,而绿色信号的电压范围为0~1.0V。

VGA行、场同步信号分别为行扫描和场扫描提供同步信号,采用TTL电平标准。

  行同步信号和场同步信号分为前沿(front porch) 、同步头(sync)、后沿(back porch)和显示(display interval)四个阶段。行同步信号以像素(pixel)为单位,而场同步信号则以行(line)为单位。行、场同步头(a段)为低电平有效,而b、c和d段时则为高电平。c段为显示时间窗口,其余时段处于消隐(blank)状态。

VGA将显示图像按行划分为若干个像素,按列划分为若干行,采用动态扫描方式刷新图像   基于FPGA实现的VGA应用系统的典型结构如图所示,由锁相环、VGA时序控制器和像素生成电路三部分组成。

   VGA时序控制器的设计与开发板VGA接口电路有密切的关系。   DE2-115开发板的VGA接口电路如图所示。

 设计过程:

基于上述VGA接口电路,设计VGA时序控制器的结构框图如图所示,由两个过程语句和DAC控制信号生成逻辑语句三部分组成。

   根据上述结构框图,描述分辨率为640480@60Hz模式行、场同步信号以及像素坐标X、Y的VGA时序控制器的Verilog HDL代码参考如下:

 module VGA_controller (
    input  wire       iVGA_clk,         // VGA输入时钟
    output wire       oVGA_clk,        // VGA输出时钟
    output reg        VGA_HS,         // VGA行同步信号
    output reg        VGA_VS,         // VGA场同步信号
    output reg [9:0] X,                 // 像素行坐标X
    output reg [9:0] Y,                 // 像素列坐标Y
    output wire       DAC_clk,         // ADV7123时钟
    output wire       DAC_sync_n,     // ADV7123同步信号
    output wire       DAC_blank_n     // ADV7123消隐信号
    );
    // 640×480@60Hz行参数定义
    localparam H_FRONT = 16;    // 前沿
    localparam H_SYNC  = 96;     // 同步头
    localparam H_BACK  = 48;     // 后沿
    localparam H_ACT   = 640;    // 显示段
    localparam H_BLANK = H_FRONT+H_SYNC+H_BACK;           // 消隐期
    localparam H_TOTAL = H_FRONT+H_SYNC+H_BACK+H_ACT; // 总像素
    // 640×480@60Hz场参数定义
    localparam V_FRONT = 10;    // 前沿
    localparam V_SYNC  = 2;      // 同步头
    localparam V_BACK  = 33;     // 后沿
    localparam V_ACT   = 480;                                             // 显示段
    localparam V_BLANK = V_FRONT+V_SYNC+V_BACK;               // 消隐期
    localparam V_TOTAL = V_FRONT+V_SYNC+V_BACK+V_ACT;     // 总行数
    // 内部变量定义
    reg [9:0] H_cnt;      // 行计数器
    reg [9:0] V_cnt;      // 场计数器
    // VGA输出时钟逻辑
    assign oVGA_clk = iVGA_clk;
    // ADV7123时钟信号逻辑 
    assign DAC_clk = ~iVGA_clk;
    // ADV7123同步信号逻辑
    assign DAC_sync_n = 1'b0;			
    // ADV7123消隐信号逻辑
    assign DAC_blank_n = ~((H_cnt<H_BLANK)||(V_cnt<V_BLANK));
    // 行同步信号VGA_HS和行像素坐标X生成过程
    always @( posedge iVGA_clk ) begin
        // 行计数
        if( H_cnt < H_TOTAL )
            H_cnt <= H_cnt+1'b1;
        else
            H_cnt <= 0;
        // 行同步头生成
       if( H_cnt == H_FRONT-1 )		// 检测行前沿结束点
           VGA_HS <= 1'b0;
       if( H_cnt == H_FRONT+H_SYNC-1 )          // 检测行同步头结束点
          VGA_HS <= 1'b1;	  
	   // 行像素坐标生成
	   if ( H_cnt >= H_BLANK)
	         X  <= H_cnt - H_BLANK;
	    else
	         X <=  0;
	end
    //  场同步信号VGA_VS和列坐标Y生成过程
    always @( posedge VGA_HS ) begin
        // 场计数
       if ( V_cnt < V_TOTAL )
           V_cnt <= V_cnt+1'b1;
       else
	V_cnt <= 0;
       // 场同步头生成
       if( V_cnt == V_FRONT-1 )		// 检测场前沿结束点
           VGA_VS <= 1'b0;
       if ( V_cnt == V_FRONT+V_SYNC-1 )	// 检测场同步头结束点
           VGA_VS <= 1'b1;
       // 列像素坐标生成
       if ( V_cnt >= V_BLANK )
           Y <= V_cnt - V_BLANK;
       else
          Y <= 0;
     end
endmodule

   为了测试VGA时序控制器的功能,还需要编写像素生成模块,产生RGB数字量给VGA接口电路,在VGA时序控制器的作用下,驱动接口电路依次在像素坐标点(X、Y)上显示VGA色彩信息。

  为方便理解像素的生成原理,可以将VGA显示方案分为按区域显示、按像素显示和按目标显示三种类型。

1.按区域显示

   按区域显示是指将VGA显示屏划分为若干个规则的区域,每个区域分配一种色彩。例如,将显示屏按行划分为8个区、按列划分为8个区,则整个屏幕共划分为(8×8=)64个区域。每个区域分配不同的色彩时,则会形成彩色方格图像(color pattern),如图所示。

描述8×8彩色方格图像的Verilog HDL代码参考如下:

module VGA_pattern (VGA_clk,X,Y,VGA_red,VGA_gre,VGA_blue);
    input        VGA_clk;      // 来自iVGA_clk/oVGA_clk
    input [9:0] X,Y;            // 像素点坐标
    output reg [7:0] VGA_red,VGA_gre,VGA_blue; 
    always @( posedge VGA_clk ) begin    // 方格色彩定义 
       VGA_red  <=  ( Y < 120 )	?	64   : 
	            ( Y >= 120 && Y < 240 ) ?	128  :
	            ( Y >= 240 && Y < 360 ) ?	192  : 255 ;
       VGA_gre  <=  ( X < 80 )	?	            32    :
	            ( X >= 80 && X < 160 )   ?	64   :
	            ( X >= 160 && X < 240 )  ?	92   :
	            ( X >= 240 && X < 320 )  ?	128  :
	            ( X >= 320 && X < 400 )  ?	160  :
	            ( X >= 400 && X < 480 )  ?	192  :
	            ( X >= 480 && X < 560)   ?	224  : 255 ; 
       VGA_blue <=  ( Y < 60 )	 ?	            255  :   
	            ( Y >= 60 && Y < 120 ) ?	224  :
		( Y >= 120 && Y < 180 ) ?	192  :
	            ( Y >= 180 && Y < 240 )  ?	160  :
	            ( Y >= 240 && Y < 300 ) ?	128  :
		( Y >= 300 && Y < 360 ) ?	96   :
            	( Y >= 360 && Y < 420 ) ?	64   : 32 ;
    end
 endmodule

   定制锁相环IP(ALTPLL)产生25.2MHz(从c0输出)和2.52MHz(从c1输出)方波信号,分别作为VGA时钟(iVGA_clk)和嵌入式逻辑分析仪的时钟,然后将锁相环、VGA时序控制器(VGA_controller)和像素生成模块(VGA_pattern)连接成图所示的顶层测试电路(VGA_pattern_tst.bdf)。

2.按像素显示

【REVIEW】基于FPGA实现的VGA应用系统的典型结构如图所示,由锁相环、VGA时序控制器和像素生成电路三部分组成。

【REVIEW】为方便理解像素的生成原理,可以将VGA显示方案分为: 1.按区域显示; 2. 按像素显示;  3.按目标显示 三种类型。

   按像素显示是指将VGA像素信息存储在ROM/RAM中,每个像素点对应一组存储单元,然后在VGA时序控制器的作用下从ROM/RAM中读取数据显示图像。

   对于简单的静态图像显示,可以应用FPGA片上ROM保存每个像素的色彩数据。计算机图像文件格式: BMP,TIFF,JPEG,GIF,PNG...

   计算机系统中广泛使用RGB模式表示图像的色彩,有RGB888、RGB565和RGB332等多种模式。     RGB888将红、绿、蓝三基色色彩数据各用一个字节表示,有2563(= 16777216)种色彩组合,相应的图像称为真彩(true color)图像。   RGB565将红、绿、蓝三基色色彩数据用两个字节表示,有65536种色彩组合。   RGB332将红、绿、蓝三基色色彩数据用一个字节表示,有256种色彩组合。

在640×480显示模式下:

存储RGB888需要(640×480×24=)7200kbits;                            

存储RGB565需要(640×480×16=)4800kbits;                            

存储RGB332需要(640×480×8=)2400kbits。

   设计过程:

从位图文件中提取RGB数据可以通过文件操作语句实现,既可以通过编写C程序实现,也可以应用Matlab中的m语言实现。

   从位图文件中提取RGB分量,合成为RGB332色彩数据,并生成存储器初始化文件的C程序参考如下:

 #include <stdio.h>
 #include <malloc.h>
 #define BM 	19778         // 位图文件标志:0x424d,对应十进制19778
 #define PATH  "c:\\tiger.bmp"   // 位图文件路径,设位图文件存储在C盘根目录下 
 /* 子程序1:判断是否为位图文件,位图标志在0~1字节。*/
 int IsBitMap(FILE *fp)
  {
   unsigned short bfType;
   fread(&bfType,1,2,fp);
   if(bfType==BM) return 1;
     else	return 0;
   }  
 /* 子程序2:获取位图宽度,参数在18~21字节。 */ 
 long getBitMapWidth(FILE *fp)
   {
   long biWidth;
   fseek(fp,18,SEEK_SET);   // 设置文件指针,指向从文件头开始、偏移量为18的位置
   fread(&biWidth,1,4,fp);    // 读取4个字节 
   return biWidth;	        // 返回参数
   }
   /* 子程序3:获取位图高度,参数在22~25字节。 */ 
 long getBitMapHeight(FILE *fp)
  {
   long biHeight;
   fseek(fp,22,SEEK_SET);    // 设置文件指针,指向从文件头开始、偏移量为22的位置
   fread(&biHeight,1,4,fp);    // 读取4个字节
   return biHeight;	           // 返回参数
   }  
 /* 子程序4:获取每个像素的位数,参数在28~29字节。 */ 
 unsigned short getBitsPerPixel(FILE *fp)
   {
   unsigned short biBitCount;
   fseek(fp,28,SEEK_SET);       // 设置文件指针,指向从文件头开始、偏移量为28的位置
   fread(&biBitCount,1,2,fp);     // 读取2个字节
   return biBitCount;               // 返回参数
   } 
  /* 子程序5:获取图像数据区的起始位置,参数在10~13字节。 */
  long getMapAreaOffBits(FILE *fp)
   {
   long bfOffBits;
   fseek(fp,10,SEEK_SET);     // 设置文件指针,指向从文件头开始、偏移量为10的位置
   fread(&bfOffBits,1,4,fp);   // 读取4个字节
   return bfOffBits;             // 返回参数
   } 
 /* 子程序6:获取RGB分量值,合成RGB332色彩数据,并建立存储器初始化文件。 */
 void getRGBdata(FILE* fp,unsigned char *r,unsigned char *g,unsigned char *b)
  {
   FILE* fp_rgb;   // 定义存储器初始化文件指针
   // 变量定义
   int i, j=0;                           // 循环变量
   int BytesPerLine;                   // 行字节数变量
   unsigned char* pixel=NULL;       // 像素指针,初始化为空指针
   long biHeight,biWidth;             // 像素高度和宽度变量
   unsigned short BitsPerPixel;       // 每个像素的位数
   long bfOffBits;
   long ROM_init_address;            // 初始化地址
   unsigned char ROM_init_data;     // 初始化数据
   // 获取位图参数
   biHeight=getBitMapHeight(fp);     // 获取图像高度
   biWidth=getBitMapWidth(fp);      // 获取图像宽度
   BitsPerPixel=getBitsPerPixel(fp);   // 获取每个像素的位数
   bfOffBits=getMapAreaOffBits(fp);   // 获取图像数据区的起始地址
   // 打开存储器初始化文件 
   fp_rgb=fopen("c:\\tiger_rgb332.mif",  "w+");
   // 添加参数信息标注
   fprintf(fp_rgb,"WIDTH=8;\n");                           // 位宽为8
   fprintf(fp_rgb,"DEPTH=%ld;\n",biWidth*biHeight);     // 单元数=宽度*高度
   fprintf(fp_rgb,"ADDRESS_RADIX=UNS;\n");            // 地址以十进制表示
   fprintf(fp_rgb,"DATA_RADIX=UNS;\n");                 // 数据以十进制表示
   fprintf(fp_rgb,"CONTENT BEGIN\n");                    // 存储开始标志
  // 计算每行占用的字节数,补0对齐
  BytesPerLine=((BitsPerPixel*biWidth+31)>>5)<<2;
  // 分配行字节缓冲区
  pixel=(unsigned char *)malloc(BytesPerLine); 
  // 像素三基色分解 
  for(j=biHeight-1;j>=0;j--)    // 按行倒序处理
    {
    // 设置文件指针,指向对应行像素的起始地址
    fseek(fp,bfOffBits+j*BytesPerLine,SEEK_SET);
    // 读取全行字节数据
    fread(pixel,1,BytesPerLine,fp);
    // 行像素BGR分解
    for(i = 0; i < biWidth; i++)     
      {
       *(b+i)=pixel[i*3];      // 提取B分量,存入蓝色缓冲区   b: b7b6b5b4b3b2b1b0         
       *(g+i)=pixel[i*3+1];    // 提取G分量,存入绿色缓冲区  g: g7gg6g5g4g3g2g1g0
       *(r+i)=pixel[i*3+2];    // 提取R分量,存入红色缓冲区  r: r7r6r5r4r3r2r1r0 
      }
    // 合成RGB332格式数据,写入存储器初始化数据文件      rgb: r7r6r5g4g3g2b1b0
    for(i = 0; i < biWidth; i++)
      { 
      ROM_init_address=(biHeight-1-j)*biWidth+i;
      ROM_init_data=((*(r+i)>>5)<<5)+((*(g+i)>>5)<<2)+(*(b+i)>>6);
      fprintf(fp_rgb,"%6d : %2d;\n",ROM_init_address,ROM_init_data);  
      }
   }  
  fprintf(fp_rgb,"END;\n");  // 存储数据结束标志
	 fclose(fp_rgb);    // 关闭存储文件
  } 
  int main()    // 主程序
  {
   FILE *fp=fopen(PATH,"r");         // 打开位图文件
   unsigned char *r,*g,*b;             // 定义行缓冲区指针
   // 开辟行像素缓冲区,按每行2000个字节设置
  r=(unsigned char *)malloc(2000);  // 红色缓冲区
  b=(unsigned char *)malloc(2000);  // 绿色缓冲区
  g=(unsigned char *)malloc(2000);  // 蓝色缓冲区
  // 判断是否为位图文件
  if(IsBitMap(fp)) printf("该文件是位图!\n");
    else {  printf("该文件不是位图!\n");
           // 不进行处理,关闭文件返回
           fclose(fp); return 0; 
           } 
           // 读取并显示位图信息		
   printf("位图宽度=%ld,位图高度=%ld\n",
   getBitMapWidth(fp),getBitMapHeight(fp));
   printf("该图像是%d位图\n",getBitsPerPixel(fp));
   printf("图像数据区偏移地址=%d\n",getMapAreaOffBits(fp));
  // 读取色彩数据,生成RGB232存储器初始化文件
  getRGBdata(fp,r,g,b);
  return 1;   // 返回操作系统
 }

编译并运行C程序,将生成存储器初始化数据文件tiger_rgb332.mif,然后定制ROM,并将tiger_rgb332.mif加载到ROM中。

定制ROM_tiger_rgb332,输出HDL的语言类型为Verilog HDL。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三十度角阳光的问候

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值