[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA基础篇连载-31基于FPGA简易示波器显示驱

文档创建者:FPGA课程
浏览次数:233
最后更新:2024-09-06
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-FPGA部分 » 2_FPGA实验篇(仅旗舰) » 1-FPGA基础入门实验
本帖最后由 FPGA课程 于 2024-9-6 14:14 编辑

​ 软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!



1概述
FPGA在数据采集,数据处理,图像视频领域都有广泛的应用。很多FPGA工程师苦恼,如何让FPGA采集的数据可以直观显示。如果上一个LINUX再弄一个QT写示波器软件,工作又太复杂了。基于此,设计一款基于FPGA的示波器对实时采集的波形数据在显示器上直观显示,具有非常好实的用价值。
基于此目的,米联客在本方案中,完成了基于FPGA的一款简易示波器显示驱动设计,由于时间和精力问题,这款基于FPGA的示波器驱动目前还只能以描点的方式进行显示。并且没有复杂的功能,只能简单的展示采集的数据。但是这个不妨碍我们后期对该示波器IP进一步升级完善。万事开头难,让我们开始把。
系统框图
ebefc577668d4103b524ccb18c606893.jpg
首先,从顶层框架上进行设计,对于波形显示部分,我们只要给出wave_clk,wave_de,wave_data三个信号,既可以完成波形显示。
其次,简易示波器的驱动部分需要完成包括背景绘制、栅格绘制、曲线绘制(绘制坐标点方式)
此外,我们需要考虑尽量少的FPGA资源实现这个示波器。比如用BRAM保存有效的数据点,然后通过数据比对的方式,只对有效数据点输出到显示器上。
最后,我们还要设计一个简单的乒乓存储,可以一边存储数据,一边绘制波形
2波形绘制
关于HDMI输出IP的部分这里不再介绍,VTC时序设计部分这里也不详细介绍。如果读者这些基础知识不清楚的,请阅读前面的实验。
2.1波形绘制显示原理
通过前面关于VTC IP视频时序驱动的学习,以及TPG IP测试图形显示的学习,我们知道,对于显示器上的图像,是从液晶屏的左上角,一个像素点一个像素点绘制,当一行所有绘制完成,进行下一行的绘制。利用肉眼的视觉暂留原理,一般1秒显示25帧以上,我们就能看到视频是动态的。
本方案中,我们绘制的波形曲线只需要显示波形的数据点,比如对于1920*1080的显示区域,我们时间上只要绘制1920点波形点即可。
为了方便我们理解,我们定义HS方向是X坐标,VS方向是Y坐标。
比如我们这里设计的是显示1024个波形数据点,在绘制每一行的图像的时候,比对每一个数据和VS的Y坐标是否相等,如果相等就绘制这个波形点。这样我们就能完成1024个波形点在整个屏幕的显示。
83acb913e3734be59e541b253a405763.jpg
2.2画中画的vtc视频时序模块设计
3d864a6b6bdb4566aea18ac799c93311.jpg
我们这里显示的波形数据点是1024,高度是256,因此我们需要实现一个画中画的功能。栅格绘制,以及波形数据点会以画中画的有效区域进行显示。
支持画中画的uivtc.v源码
  1. /*************uivtc(video timing controller)视频时序控制器*************
  2. --版本号1.1
  3. --以下是米联客设计的uivtc(video timing controller)视频时序控制器
  4. --1.代码简洁,占用极少逻辑资源,代码结构清晰,逻辑设计严谨
  5. --2.使用方便,只需要输入6个参数既可以实现对不同视频分辨率时序的控制
  6. --3.该视频时序控制,一个时钟对应一个像素
  7. --4.通常我们说的像素,比如1080P代表了1920*1080是指视频的有效显示区域,实际的视频还包含不能显示的区域,比如行同步,场同步时间
  8. --5.通常我们说的行视频信号,也称之为视频的水平像素信号;场视频信号,也称之为视频的垂直像素信号;
  9. --6.针对波形绘制,增加画中画绘制区域功能
  10. *********************************************************************/

  11. `timescale 1ns / 1ns //仿真时间刻度/精度

  12. module uivtc#
  13. (
  14. parameter H_ActiveSize   =   1980,               //视频时间参数,行视频信号,一行有效(需要显示的部分)像素所占的时钟数,一个时钟对应一个有效像素
  15. parameter H_FrameSize    =   1920+88+44+148,     //视频时间参数,行视频信号,一行视频信号总计占用的时钟数
  16. parameter H_SyncStart    =   1920+88,            //视频时间参数,行同步开始,即多少时钟数后开始产生行同步信号
  17. parameter H_SyncEnd      =   1920+88+44,         //视频时间参数,行同步结束,即多少时钟数后停止产生行同步信号,之后就是行有效数据部分

  18. parameter V_ActiveSize   =   1080,               //视频时间参数,场视频信号,一帧图像所占用的有效(需要显示的部分)行数量,通常说的视频分辨率即H_ActiveSize*V_ActiveSize
  19. parameter V_FrameSize    =   1080+4+5+36,        //视频时间参数,场视频信号,一帧视频信号总计占用的行数量
  20. parameter V_SyncStart    =   1080+4,             //视频时间参数,场同步开始,即多少行数后开始产生场同步信号
  21. parameter V_SyncEnd      =   1080+4+5,           //视频时间参数,场同步结束,即多少场数后停止产生场同步信号,之后就是场有效数据部分

  22. parameter H2_ActiveSize  =   640,
  23. parameter V2_ActiveSize  =   480
  24. )
  25. (
  26. input           I_vtc_rstn,//系统复位
  27. input           I_vtc_clk, //系统时钟
  28. output  reg     O_vtc_vs,  //场同步输出
  29. output  reg     O_vtc_hs,  //行同步输出
  30. output  reg     O_vtc_de,  //视频数据有效  
  31. input  [11:0]   I_vtc2_offset_x,//相对屏幕原点(左上角)X方向偏移
  32. input  [11:0]   I_vtc2_offset_y,//相对屏幕原点(左上角)Y方向偏移
  33. output  reg     O_vtc2_de     //绘制有效的显示区域
  34. );

  35. reg [11:0] hcnt = 12'd0;    //行像素计数器,寄存器
  36. reg [11:0] vcnt = 12'd0;    //场像素计数器,寄存器   
  37. reg [2 :0] rst_cnt = 3'd0;  //复位计数器,寄存器
  38. wire rst_sync = rst_cnt[2]; //同步复位

  39. always @(posedge I_vtc_clk or negedge I_vtc_rstn)begin //通过计数器产生同步复位
  40.     if(I_vtc_rstn == 1'b0)
  41.         rst_cnt <= 3'd0;
  42.     else if(rst_cnt[2] == 1'b0)
  43.         rst_cnt <= rst_cnt + 1'b1;
  44. end   

  45. //行像素计数器
  46. always @(posedge I_vtc_clk)begin
  47.     if(rst_sync == 1'b0) //复位
  48.         hcnt <= 12'd0;
  49.     else if(hcnt != (H_FrameSize - 1'b1))//计数范围从0 ~ H_FrameSize-1
  50.         hcnt <= hcnt + 1'b1;
  51.     else
  52.         hcnt <= 12'd0;
  53. end         

  54. //场计数器,用于计数已经完成的行视频信号
  55. always @(posedge I_vtc_clk)begin
  56.     if(rst_sync == 1'b0)
  57.         vcnt <= 12'd0;
  58.     else if(hcnt == (H_ActiveSize  - 1'b1)) begin//是否一行像素结束
  59.            vcnt <= (vcnt == (V_FrameSize - 1'b1)) ? 12'd0 : vcnt + 1'b1;//每一行计数,场计数器加1,计数范围0~V_FrameSize - 1
  60.     end
  61. end

  62. wire hs_valid  =  hcnt < H_ActiveSize; //行信号有效像素部分
  63. wire vs_valid  =  vcnt < V_ActiveSize; //场信号有效像素部分
  64. wire vtc_hs   =  (hcnt >= H_SyncStart && hcnt < H_SyncEnd);//产生hs,行同步信号
  65. wire vtc_vs    = (vcnt > V_SyncStart && vcnt <= V_SyncEnd);//产生vs,场同步信号      
  66. wire vtc_de   =  hs_valid && vs_valid;//只有当行像素有效和场像素同时有效,视频数据部分才是有效

  67. //画中画,波形绘制区域
  68. wire hs2_valid  =  (hcnt>=I_vtc2_offset_x)&& (hcnt<(I_vtc2_offset_x+H2_ActiveSize)); //画中画,波形绘制区域HS有效信号
  69. wire vs2_valid  =  (vcnt>=I_vtc2_offset_y)&& (vcnt<(I_vtc2_offset_y+V2_ActiveSize)); //画中画,波形绘制区域VS有效信号
  70. wire vtc2_de    =  hs2_valid && vs2_valid; //画中画,数据有效绘制信号

  71. //完一次寄存打拍输出,有利于改善时序,尤其对于高分辨率,高速的信号,打拍可以改善内部时序,以运行于更高速度
  72. always @(posedge I_vtc_clk)begin
  73.     if(rst_sync == 1'b0)begin
  74.         O_vtc_vs <= 1'b0;
  75.         O_vtc_hs <= 1'b0;
  76.         O_vtc_de <= 1'b0;
  77.         O_vtc2_de <= 1'b0;
  78.     end
  79.     else begin
  80.         O_vtc_vs <= vtc_vs; //场同步信号打拍输出
  81.         O_vtc_hs <= vtc_hs; //行同步信号打拍输出
  82.         O_vtc_de <= vtc_de; //视频有效信号打拍输出
  83.         O_vtc2_de <= vtc2_de; //画中画,数据有效绘制信号
  84.     end
  85. end

  86. endmodule
复制代码

2.3 uiwave.v源码
uiwave.v
  1. /*************uivtc(video timing controller)视频时序控制器*************
  2. --版本号1.1
  3. --以下是米联客设计的uivtc(video timing controller)视频时序控制器
  4. --1.代码简洁,占用极少逻辑资源,代码结构清晰,逻辑设计严谨
  5. --2.使用方便,只需要输入6个参数既可以实现对不同视频分辨率时序的控制
  6. --3.该视频时序控制,一个时钟对应一个像素
  7. --4.通常我们说的像素,比如1080P代表了1920*1080是指视频的有效显示区域,实际的视频还包含不能显示的区域,比如行同步,场同步时间
  8. --5.通常我们说的行视频信号,也称之为视频的水平像素信号;场视频信号,也称之为视频的垂直像素信号;
  9. --6.针对波形绘制,增加画中画绘制区域功能
  10. *********************************************************************/

  11. `timescale 1ns / 1ns //仿真时间刻度/精度

  12. module uivtc#
  13. (
  14. parameter H_ActiveSize   =   1980,               //视频时间参数,行视频信号,一行有效(需要显示的部分)像素所占的时钟数,一个时钟对应一个有效像素
  15. parameter H_FrameSize    =   1920+88+44+148,     //视频时间参数,行视频信号,一行视频信号总计占用的时钟数
  16. parameter H_SyncStart    =   1920+88,            //视频时间参数,行同步开始,即多少时钟数后开始产生行同步信号
  17. parameter H_SyncEnd      =   1920+88+44,         //视频时间参数,行同步结束,即多少时钟数后停止产生行同步信号,之后就是行有效数据部分

  18. parameter V_ActiveSize   =   1080,               //视频时间参数,场视频信号,一帧图像所占用的有效(需要显示的部分)行数量,通常说的视频分辨率即H_ActiveSize*V_ActiveSize
  19. parameter V_FrameSize    =   1080+4+5+36,        //视频时间参数,场视频信号,一帧视频信号总计占用的行数量
  20. parameter V_SyncStart    =   1080+4,             //视频时间参数,场同步开始,即多少行数后开始产生场同步信号
  21. parameter V_SyncEnd      =   1080+4+5,           //视频时间参数,场同步结束,即多少场数后停止产生场同步信号,之后就是场有效数据部分

  22. parameter H2_ActiveSize  =   640,
  23. parameter V2_ActiveSize  =   480
  24. )
  25. (
  26. input           I_vtc_rstn,//系统复位
  27. input           I_vtc_clk, //系统时钟
  28. output  reg     O_vtc_vs,  //场同步输出
  29. output  reg     O_vtc_hs,  //行同步输出
  30. output  reg     O_vtc_de,  //视频数据有效  
  31. input  [11:0]   I_vtc2_offset_x,//相对屏幕原点(左上角)X方向偏移
  32. input  [11:0]   I_vtc2_offset_y,//相对屏幕原点(左上角)Y方向偏移
  33. output  reg     O_vtc2_de     //绘制有效的显示区域
  34. );

  35. reg [11:0] hcnt = 12'd0;    //行像素计数器,寄存器
  36. reg [11:0] vcnt = 12'd0;    //场像素计数器,寄存器   
  37. reg [2 :0] rst_cnt = 3'd0;  //复位计数器,寄存器
  38. wire rst_sync = rst_cnt[2]; //同步复位

  39. always @(posedge I_vtc_clk or negedge I_vtc_rstn)begin //通过计数器产生同步复位
  40.     if(I_vtc_rstn == 1'b0)
  41.         rst_cnt <= 3'd0;
  42.     else if(rst_cnt[2] == 1'b0)
  43.         rst_cnt <= rst_cnt + 1'b1;
  44. end   

  45. //行像素计数器
  46. always @(posedge I_vtc_clk)begin
  47.     if(rst_sync == 1'b0) //复位
  48.         hcnt <= 12'd0;
  49.     else if(hcnt != (H_FrameSize - 1'b1))//计数范围从0 ~ H_FrameSize-1
  50.         hcnt <= hcnt + 1'b1;
  51.     else
  52.         hcnt <= 12'd0;
  53. end         

  54. //场计数器,用于计数已经完成的行视频信号
  55. always @(posedge I_vtc_clk)begin
  56.     if(rst_sync == 1'b0)
  57.         vcnt <= 12'd0;
  58.     else if(hcnt == (H_ActiveSize  - 1'b1)) begin//是否一行像素结束
  59.            vcnt <= (vcnt == (V_FrameSize - 1'b1)) ? 12'd0 : vcnt + 1'b1;//每一行计数,场计数器加1,计数范围0~V_FrameSize - 1
  60.     end
  61. end

  62. wire hs_valid  =  hcnt < H_ActiveSize; //行信号有效像素部分
  63. wire vs_valid  =  vcnt < V_ActiveSize; //场信号有效像素部分
  64. wire vtc_hs   =  (hcnt >= H_SyncStart && hcnt < H_SyncEnd);//产生hs,行同步信号
  65. wire vtc_vs    = (vcnt > V_SyncStart && vcnt <= V_SyncEnd);//产生vs,场同步信号      
  66. wire vtc_de   =  hs_valid && vs_valid;//只有当行像素有效和场像素同时有效,视频数据部分才是有效

  67. //画中画,波形绘制区域
  68. wire hs2_valid  =  (hcnt>=I_vtc2_offset_x)&& (hcnt<(I_vtc2_offset_x+H2_ActiveSize)); //画中画,波形绘制区域HS有效信号
  69. wire vs2_valid  =  (vcnt>=I_vtc2_offset_y)&& (vcnt<(I_vtc2_offset_y+V2_ActiveSize)); //画中画,波形绘制区域VS有效信号
  70. wire vtc2_de    =  hs2_valid && vs2_valid; //画中画,数据有效绘制信号

  71. //完一次寄存打拍输出,有利于改善时序,尤其对于高分辨率,高速的信号,打拍可以改善内部时序,以运行于更高速度
  72. always @(posedge I_vtc_clk)begin
  73.     if(rst_sync == 1'b0)begin
  74.         O_vtc_vs <= 1'b0;
  75.         O_vtc_hs <= 1'b0;
  76.         O_vtc_de <= 1'b0;
  77.         O_vtc2_de <= 1'b0;
  78.     end
  79.     else begin
  80.         O_vtc_vs <= vtc_vs; //场同步信号打拍输出
  81.         O_vtc_hs <= vtc_hs; //行同步信号打拍输出
  82.         O_vtc_de <= vtc_de; //视频有效信号打拍输出
  83.         O_vtc2_de <= vtc2_de; //画中画,数据有效绘制信号
  84.     end
  85. end

  86. endmodule
复制代码

uiwave_buf.v源码中有以下代码
  1. assign   O_pixel_en  = I_vtc_de_r&(I_vtc_vcnt[7:0] == wave_data[7:0]);
复制代码

O_pixel_en信号就是wave1_pixel_en和wave2_pixel_en信号,在上级对wave1_pixel_en跟wave2_pixel_en
有效的像素赋值,输出波形点颜色,grid_de有效的区域显示栅格点,其他区域显示黑色背景。
Uiwave.v绘制背景、栅格、波形点的代码如下:
  1. //1--绘制波形曲线1,绿色点
  2. //2--绘制波形曲线2,黄色点
  3. //3--绘制栅格虚线,白色点
  4. //4--绘制背景色,黑色
  5. always @(posedge I_vtc_clk)begin
  6.     casex({grid_de,wave2_pixel_en,wave1_pixel_en})
  7.             3'bxx1:
  8.                O_vtc_rgb <= {8'h00,8'hff,8'h00};   //wave1信号显示像素颜色
  9.             3'bx10:
  10.                O_vtc_rgb <= {8'hff,8'hff,8'h00};   //wave2信号显示像素颜色
  11.             3'b100:
  12.                O_vtc_rgb <= {8'h96,8'h96,8'h96};   //网格显示像素为白色点
  13.         default:
  14.                O_vtc_rgb <= {8'h00,8'h00,8'h00};   //黑色背景
  15.     endcase
  16. end
复制代码

2.4 uiwave_buf.v通过BRAM缓存ADC数据
通过控制buf_flag信号,每次读写的地址进行切换,确保不会对同一个地址同时进行读写,造成数据冲突。
  1. /*************uiwave_buf简易波形绘制驱动******************************
  2. --版本号1.0
  3. --1.代码简洁,占用极少逻辑资源,代码结构清晰,逻辑设计严谨
  4. --2.使用方便,只需要输入ADC的值,就能完成波形绘制
  5. --3.占用资源少,波形输入8bits ADC值,存储到BLOCK RAM 只需要1048*8bit 大小的BRAM,即可完成1通道的波形存储
  6. --4.乒乓绘制,当绘制一个波形的时候,另外一个波形存储到另外一段地址空间
  7. --5.绘制过程中,每一行数据都读出和Y坐标匹配,如果匹配成功,使能O_pixel_en绘制这个数据点
  8. *********************************************************************/

  9. `timescale 1ns / 1ns //仿真时间刻度/精度

  10. module uiwave_buf
  11. (
  12. input         I_wave_clk,    //写数据输入时钟,和ADC采集时钟同步
  13. input  [7 :0] I_wave_data,   //写数据
  14. input         I_wave_data_de,//写数据有效

  15. input         I_vtc_clk,     //VTC时序发生器时钟输入
  16. input         I_vtc_rstn,    //VTC时序发生器复位
  17. input         I_vtc_vs,      //VTC时序发生器的VS同步信号输入
  18. input         I_vtc_de_r,    //VTC时序发生器的de有效区域输入
  19. input  [7 :0] I_vtc_vcnt,    //VTC的数据偏移,主要对有符号数据进行调整
  20. output        O_pixel_en     //输出输出使能
  21. );

  22. //BRAM 简单双口BRAM
  23. reg  [9 :0] addra = 0;  //BRAM 通道A地址     
  24. //reg         ena   = 0;  //BRAM 通道A使能
  25. reg         wea   = 0;  //BRAM 通道A写使能
  26. reg  [9 :0] addrb = 0;  //BRAM 通道B地址
  27. reg         enb   = 0;  //BRAM 通道B读使能
  28. reg  [0 :0] WR_S,RD_S;  //写状态机,读状态机
  29. reg         buf_flag;//buf_flag用于乒乓地址缓存切换
  30. reg         addr0_en;//用于设置写第一个数据相对地址0

  31. wire [7 :0] wave_data;//写波形数据到BRAM
  32. reg  [3 :0] async_vtc_vs =0; //同步信号

  33. always @(posedge I_wave_clk)begin //对异步I_vtc_vs采样
  34.     async_vtc_vs <= {async_vtc_vs[2:0],I_vtc_vs};
  35. end


  36. //绘制波形数据点使能,绘制原理:
  37. //当匹配到存储的ADC数据和正在扫描的Y坐标值一致就输出,每个X坐标方向绘制1个波形点
  38. assign   O_pixel_en  = I_vtc_de_r&(I_vtc_vcnt[7:0] == wave_data[7:0]);

  39. //写BRAM 状态机
  40. always @(posedge I_wave_clk or negedge I_vtc_rstn)begin
  41.     if(I_vtc_rstn == 1'b0)begin //复位重置所有寄存器
  42.        addra      <= 10'd0;
  43.        addr0_en   <= 1'b1;
  44.        wea        <= 1'b0;
  45.        buf_flag   <= 1'b0;
  46.        WR_S       <= 1'd0;
  47.     end
  48.     else begin
  49.         case(WR_S) //写状态机
  50.         0:begin
  51.               if(I_wave_data_de)begin //有效波形数据点
  52.                if(addra == 1023)begin //1024个数据写完
  53.                  wea      <= 1'b0; //停止写
  54.                  addra    <= 0;    //相对地址设置0
  55.                  addr0_en <= 1'b1;
  56.                  WR_S     <= 1'd1;//进入状态机1
  57.                end
  58.                else begin //写入1024个数据
  59.                  wea      <= 1'b1; //写使能
  60.                  addr0_en <= 1'b0;
  61.                  addra    <= (addr0_en == 1'b0) ? (addra + 1'b1) : 0;//相对地址递增
  62.                end
  63.             end
  64.             else begin
  65.               wea <= 1'b0;
  66.             end
  67.         end
  68.         1:begin //等待VTC时序同步
  69.             if(async_vtc_vs[3:2] == 2'b10)begin//当数据同步后,准备下一次写
  70.                WR_S     <= 1'd0; //回到状态0
  71.                buf_flag <= ~buf_flag;//乒乓地址切换
  72.             end
  73.         end
  74.         default:WR_S   <= 2'd0;
  75.         endcase
  76.      end
  77. end


  78. //读BRAM 状态机
  79. always @(posedge I_vtc_clk or negedge I_vtc_rstn)begin
  80.     if(I_vtc_rstn == 1'b0)begin//复位重置所有寄存器
  81.        addrb   <= 10'd0;
  82.        RD_S    <= 1'd0;
  83.     end
  84.     else begin
  85.         case(RD_S)
  86.         0:begin
  87.             if(I_vtc_de_r)begin //I_vtc_de_r代表了有效绘制区域
  88.                if(addrb == 1023)begin //1024个数据读完
  89.                  addrb <= 0;    //相对地址设置0
  90.                  RD_S  <= 1'd1; //进入状态1
  91.                end
  92.                else //没一样都会扫描所有的ADC数据
  93.                  addrb   <= addrb + 1'b1;//相对地址递增
  94.             end
  95.         end
  96.         1:begin
  97.             if(I_vtc_de_r == 0) //等待de变为0
  98.                 RD_S <= 0; //回到状态0重新扫描
  99.               
  100.   
  101.         end
  102.         default:RD_S   <= 1'd0;
  103.         endcase
  104.      end
  105. end   


  106. wave_ram buf_inst(
  107. .dina(I_wave_data), //写入波形数据
  108. .addra({buf_flag,addra}), //写地址,其中addra是相对地址,buf_flag是地址高位,用于读写的乒乓切换
  109. .wea(wea), //写使能
  110. .clka(I_wave_clk),//写时钟


  111. .doutb(wave_data), //读出的波形数据
  112. .addrb({~buf_flag,addrb}), //写地址,其中addrb是相对地址,buf_flag是地址高位,用于读写的乒乓切换
  113. .clkb(I_vtc_clk)//读时钟
  114. );


  115. endmodule
复制代码

2.5 BRAM IP设置
关于更多BRAM的IP介绍请阅读前面关于BRAM的实验
f7272ef67687433b86e73f979fe11849.jpg
数据输入8bits,深度2048,这样设计可以使用最少的BRAM完成2段曲线的存储。所以如果是ADC数据,输入高8bit即可。
1c76c08321104748b55816ed94f8bff6.jpg
b9b4652c9f9146b6a8ea84ff8fbf822f.jpg
3测试数据产生
为了验证波形显示驱动,我们编写了一个简单的三角波程序
  1. /**********************wave_test波形测试显示*************************
  2. *********************************************************************/
  3. `timescale 1ns / 1ns//仿真时间刻度/精度

  4. module wave_test
  5. (
  6. input           I_sysclk_p,
  7. input           I_sysclk_n,         //系统时钟输入   
  8. output          O_hdmi_clk_p,       //HDMI时钟输出 P端
  9. output          O_hdmi_clk_n,       //HDMI时钟输出 N端
  10. output [2:0]    O_hdmi_tx_p,        //HDMI数据输出 P端
  11. output [2:0]    O_hdmi_tx_n         //HDMI数据输出 N端
  12. );

  13. localparam SYSCLKHZ     =  100_000_000; //定义系统时钟50MHZ
  14. localparam T500MS_CNT   = (SYSCLKHZ/2-1); //定义每500ms访问一次EEPROM

  15. wire I_clk;
  16. IBUFGDS CLK_U(
  17. .I(I_sysclk_p),
  18. .IB(I_sysclk_n),
  19. .O(I_clk)
  20. );

  21. //上电延迟复位
  22. reg [7:0]    rst_cnt=0; //复位计数器
  23. wire  rstn = rst_cnt[7];//用高位复位
  24. wire pclkx1,pclkx5,clk100M,locked; //MMCM/PLL时钟信号   

  25. wire vtc_rstn,vtc_clk,vtc_vs,vtc_hs,vtc_de,vtc2_grid_de_o,vtc2_de_o;
  26. wire [23:0] rgb_o; //RGB颜色寄存器

  27. assign vtc_clk  = pclkx1;//像素时钟
  28. assign vtc_rstn = locked;//clk100M

  29. //例化MMCM/PLL IP
  30. clk_wiz_1 clk_hdmi_pll_inst
  31. (
  32. .clk_in1(I_clk),
  33. .reset(!rst_cnt[7]),
  34. .locked(locked),
  35. .clk_out1(pclkx1),//像素时钟
  36. .clk_out2(pclkx5),//HDMI输出5倍像素时钟
  37. .clk_out3(clk100M)//100M时钟,给ADC采集用
  38. );

  39. always @(posedge I_clk)begin
  40.     if (rst_cnt[7])
  41.         rst_cnt <=  rst_cnt;
  42.     else
  43.         rst_cnt <= rst_cnt+1'b1;
  44. end

  45. //例化HDMI 输出IP
  46. uihdmitx #
  47. (
  48. .FAMILY("7FAMILY")  //选择芯片所支持的系列"7FAMILY" "UFAMILY"            
  49. )
  50. uihdmitx_inst
  51. (
  52. .I_rstn(locked),//复位
  53. .I_hs(vtc_hs),//hs信号
  54. .I_vs(vtc_vs),//vs信号
  55. .I_de(vtc_de),//de信号
  56. .I_rgb({rgb_o}),//RGB数据
  57. .I_pclkx1(pclkx1),//像素时钟
  58. .I_pclkx2_5(1'b0),//2.5倍像素时钟,只有UFAMILY需要
  59. .I_pclkx5(pclkx5),//5倍像素时钟
  60. .O_hdmi_tx_clk_p(O_hdmi_clk_p),//HDMI时钟输出P端
  61. .O_hdmi_tx_clk_n(O_hdmi_clk_n),//HDMI时钟输出N端
  62. .O_hdmi_tx_p(O_hdmi_tx_p),//HDMI输出数据P端
  63. .O_hdmi_tx_n(O_hdmi_tx_n)//HDMI输出数据N端
  64. );

  65. //此VTC IP 用于产生绘制波形的有效区域,波形绘制区域大小未1024*600
  66. uivtc#
  67. (
  68. .H_ActiveSize(1280),          //视频时间参数,行视频信号,一行有效(需要显示的部分)像素所占的时钟数,一个时钟对应一个有效像素
  69. .H_FrameSize(1280+88+44+239), //视频时间参数,行视频信号,一行视频信号总计占用的时钟数
  70. .H_SyncStart(1280+88),        //视频时间参数,行同步开始,即多少时钟数后开始产生行同步信号
  71. .H_SyncEnd(1280+88+44),   //视频时间参数,行同步结束,即多少时钟数后停止产生行同步信号,之后就是行有效数据部分
  72. .V_ActiveSize(720),           //视频时间参数,场视频信号,一帧图像所占用的有效(需要显示的部分)行数量,通常说的视频分辨率即H_ActiveSize*V_ActiveSize
  73. .V_FrameSize(720+4+5+28),     //视频时间参数,场视频信号,一帧视频信号总计占用的行数量
  74. .V_SyncStart(720+4),          //视频时间参数,场同步开始,即多少行数后开始产生场同步信号
  75. .V_SyncEnd (720+4+5),      //视频时间参数,场同步结束,即多少场数后停止产生场同步信号,之后就是场有效数据部分
  76. .H2_ActiveSize(1024),         //波形绘制区域行像素大小        
  77. .V2_ActiveSize(256)           //波形绘制区域场像素大小
  78. )
  79. uivtc_inst
  80. (
  81. .I_vtc_clk(vtc_clk),         //系统时钟
  82. .I_vtc_rstn(vtc_rstn),       //系统复位
  83. .I_vtc2_offset_x(128),         //X坐标相对屏幕的原始坐标的偏移
  84. .I_vtc2_offset_y(200),         //Y坐标相对屏幕的原始坐标的偏移
  85. .O_vtc_vs(vtc_vs),//场同步输出
  86. .O_vtc_hs(vtc_hs),//行同步输出
  87. .O_vtc_de(vtc_de),//视频数据有效
  88. .O_vtc2_de(vtc2_de_o)//绘制波形显示区域的有效区域
  89. );

  90. //测试数据产生,通过test_data产生测试数据,可以用于测试波形显示器的基本功能测试

  91. reg [25:0]  t500ms_cnt   = 26'd0;//500ms计数器

  92. wire t500ms_en = (t500ms_cnt==T500MS_CNT);//500ms 使能信号

  93. //每间隔500ms状态机运行一次
  94. always@(posedge clk100M) begin
  95.     if(locked == 0)
  96.         t500ms_cnt <= 0;
  97.     else if(t500ms_cnt == T500MS_CNT)
  98.         t500ms_cnt <= 0;
  99.     else
  100.         t500ms_cnt <= t500ms_cnt + 1'b1;
  101. end

  102. reg [1:0]WAVE_S;       //写数据状态机
  103. reg [9:0]test_data =0; //测试数据

  104. wire data_en = (WAVE_S == 0|| WAVE_S == 1); //写数据使能

  105. always @(posedge clk100M)begin
  106.     if(locked == 1'b0)begin
  107.         WAVE_S    <= 2'd2;
  108.         test_data <=10'd0;
  109.     end
  110.     else begin
  111.        case(WAVE_S)
  112.             0:begin
  113.               if(test_data == 255)
  114.                 WAVE_S <= 2'd1;
  115.               else
  116.                 test_data <= test_data + 1'b1; //数据递增
  117.             end
  118.             1:begin
  119.               if(test_data == 0)
  120.                 WAVE_S <= 2'd2;
  121.               else
  122.                 test_data <= test_data - 1'b1; //数据递减
  123.             end
  124.             2:
  125.             if(t500ms_en)
  126.                 WAVE_S <= 2'd0;
  127.             else
  128.                 WAVE_S <= WAVE_S;
  129.             default:begin
  130.                 WAVE_S <= 2'd0;
  131.             end
  132.        endcase  
  133.     end
  134. end

  135. //例化波形显示器 IP,默认支持2个通道数据,可以扩展支持更多通道
  136. uiwave uiwave_inst
  137. (
  138. //波形1
  139. .I_wave1_clk(clk100M),//系统时钟输入
  140. .I_wave1_data(test_data[7:0]),//波形测试数据
  141. .I_wave1_data_de(data_en),//数据有效信号

  142. //波形2
  143. .I_wave2_clk(clk100M),//系统时钟输入
  144. .I_wave2_data(~test_data[7:0]),//演示2通道显示,对另外一个波形通道取反
  145. .I_wave2_data_de(data_en),//数据有效信号

  146. .I_vtc_rstn(vtc_rstn),//时序发生复位
  147. .I_vtc_clk (vtc_clk), //像素时钟
  148. .I_vtc_vs  (vtc_vs),  //场同步输出
  149. .I_vtc_de  (vtc2_de_o),//同步,绘制波形显示区域的有效区域
  150. .O_vtc_rgb(rgb_o)//同步RGB数据 绘制数据输出   
  151.    
  152. );

  153. endmodule
复制代码

4测试结果
4.1硬件接线
(该教程为通用型教程,教程中仅展示一款示例开发板的连接方式,具体连接方式以所购买的开发板型号以及结合配套代码管脚约束为准。)
请确保下载器和开发板已经正确连接,另外需要把核心板上的2P模式开关设置到JTAG模式,即ON ON,并且开发板已经上电。(注意JTAG端子不支持热插拔,而USB接口支持,所以在不通电的情况下接通好JTAG后,再插入USB到电脑,之后再上电,以免造成JTAG IO损坏)

53ea74827c4e4361910a8083619913a3.jpg
4.2运行结果
44617dac7f9e49ff995185784cab1898.jpg





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

本版积分规则