[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA_SDK入门篇连载-26PL 自定义 AXI-Lite-频率计

文档创建者:FPGA课程
浏览次数:142
最后更新:2024-09-28
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-SOC » 1_SDK应用方案(仅旗舰型号) » 1-SDK基础入门方案
本帖最后由 FPGA课程 于 2024-9-28 13:43 编辑

​ 软件版本: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概述
本课节设计一个带AXI4-Lite总线的IP,来完成频率计的实验。频率计虽然小,五脏俱全,涉及到ZYNQ多方面应用,比如:
1:PL部分逻辑设计
2:自定义AXI4-Lite的IP的建立
3:通过AXI4-Lite总线实现PS与PL间的数据传递
4:PS控制输入输出外设
实验目的:
1:掌握等精度频率计工作原理
2:通过AXI-LITE-SLAVE寄存器访问,读取频率值
3:通过VITIS-SDK读取AXI-LITE-SLAVE寄存器获取频率值
2系统框图
f690caf210ab40dfb92f53b02a495168.jpg
3等精度频率计原理
3.1概述
传统的数字频率测量方法有脉冲计数法和周期测频法,但这两种方法分别适合测量高频和低频信号,具有较大的局限性。多周期同步测频法以脉冲计数法为基础,并对之进行改进,实现了全频段的等精度测量,且测量精度大大提高,因此多周期同步测频法在目前测频系统中得到越来越广泛的应用。很多文献对多周期同步测频法的等精度测量原理有所介绍,但多数文献都是从测频控制模块的结构和测频波形出发,对测频原理进行论述。就我的亲身感触而言,这种阐述方式并不能帮助读者很快很好地理解频率计的原理(也有可能是本人比较笨>_<),因此,本文以脉冲计数法为基础,对之进行逐步改进得到多周期同步测频法,即等精度测频法,个人觉得这种逐步深入的方法可以更好地理解等精度频率计的原理。
3.2频率测量原理
所谓频率,就是周期性信号在单位时间内变化的次数。频率测量的方法有很多种,在模拟电路中有比较测频法,响应测频法,游标法等;在数字电路中,有基于脉冲计数测频原理的直接测频法、周期测频法、在直接测频法的基础上发展起来的多周期同步测频法和全同步数字测频法。本小节简单介绍计数测频法和周期测频法,重点分析多周期同步测频法的工作原理。
3.3脉冲计数法
脉冲计数法原理:在预置的闸门时间Tpr内对被测脉冲信号进行计数,得到脉冲数Nx,通过公式Fx=Nx/Tpr可计算出单位时间内脉冲个数,即被测信号的频率。
该方法测量误差来源于闸门时间Tpr和计数值Nx,且被测信号频率Fx与闸门开启时间Tpr越大,测频精度越高。因此,该方法适合于高频率信号的测量。
3.4周期测频法
预置测频闸门开启时间Tpr等于被测信号的周期Tx,通过计数器在闸门时间Tpr内基准时钟信号进行计数,若得到的基准时钟信号脉冲个数为Nx,且基准时钟周期为T,则可按公式Tx=T*Nx计算出待测信号的周期Tx,然后换算得到被测信号频率。
该方法的测量误差来源于基准时钟信号和计数误差,且测量相对误差与被测频率Fx成正比,与基准时钟频率F成反比。所以,当被测信号频率越低,基准时钟频率越高时,周期测频法的测量精度越高。
3.5多周期同步测频原理及误差分析
多周期同步频率测量法以脉冲计数测频法为基础,实现了闸门信号与被测信号的同步,从而解决了上述问题,实现了测量全频段的等精度测量。
从脉冲计数测频法原理可以看出,该方法闸门信号与被测信号不同步,也就是说在时间轴上两路信号随机出现,相对位置具有随机性。因此即使在相同的闸门时间内,被测脉冲计数结果也不一定相同,闸门时间大于N*Ttestclk时,越接近(N+1)*Ttestclk,误差越大。为了解决这个问题,利用D触发器使闸门信号在被测信号的上升沿产生动作,这样以来测量的实际门控时间刚好是被测信号周期的整数倍,这样就消除了被测信号引起的1个周期的误差。
这里还是给个时序图,解释一下引入D触发器为何能消除被测信号引起的1个周期的误差。
7d4a26212487434b881eda026151019f.jpg
图1. Tpr处理后成为CNT_EN
由于引入了D触发器,CNT_EN不会在Tpr发生变化时立即变化,而是在TestClk上升沿到来时才发生变化,从而保证CNT_EN刚好是TEST_Clk的整数倍。测频法和测周法的原理和误差分析如果不明白,自己画个图试试,可以很好地帮助理解。
解决问题的同时,产生了新的问题:实际闸门时间与预置闸门时间不相等,因此需要获取实际闸门时间。为解决这一问题,引入另一计数器和标准时钟信号。在测量被测信号频率的同时,对标准时钟脉冲进行计数,通过计算即可得到实际闸门时间。这样就得到多周期同步频率计的主要结构,如图2所示。
image.jpg ​​
图2. 测频主控模块结构图
其中,STD_CLK为标准时钟;Tpr为预置门控信号;TEST_CLK为待测信号;CLR为计数清零信号。
在计数允许时间内,同时对标准信号和被测信号进行计数,由于两个计数器计数时间相等,从而得到公式(1)。
Nstd/Fstd=Ntest/Ftest                               公式(1)
其中Nstd为标准时钟计数值;Fstd为标准时钟频率;Ntest为待测信号计数值;Ftest为待测信号频率,由公式(1)可知待测频率为Ftest=Fstd*Ntest/Nstd。
由于未对标准时钟进行同步计数,所以测量结果会产生​±1个标准信号脉冲的误差。
从以上论述可以得出如下结论:
待测信号频率Ftest的相对测量误差与待测信号频率无关。
增大Tpr或提高Fstd,可以增大Nstd,减少测量误差,提高测量精度。
标准频率误差为△Fstd/Fstd。测试电路可采用高频率稳定度和高精度的恒温可微调的晶体振荡器作标准频率发生电路从而进一步降低测频误差。
4等精度频率计设计
4.1PS寄存器功能划分
reg0:控制寄存器0(offset:0x00)
                        
Bit
                        
                        
功能
                        
                        
Bit31~bit2
                        
                        
保留
                        
                        
Bit1
                        
                        
闸门信号Tpr(高时打开闸门)
                        
                        
Bit0
                        
                        
复位/清零信号clr(低有效)
                        
reg1:数据寄存器Nstd(offset:0x04)
                        
Bit
                        
                        
功能
                        
                        
Bit31~bit0
                        
                        
标准时钟计数值
                        
reg2:数据寄存器Ntest(offset:0x08)
                        
Bit
                        
                        
功能
                        
                        
Bit31~bit0
                        
                        
待测信号计数值
                        
4.2具体实现
本文方案实现亦分为两部分,一是计数值的获取,该部分由测频控制模块(PL实现)完成;二是结果的计算及显示,该部分工作由PS完成。开发板板载的100MHz时钟信号作为标准信号,可使测量的最大相对误差小于或等于10-8。
4.3频率计PL部分代码设计
测频主要控制部分结构图在原理篇已经给出,该结构并不复杂,且所用元件较为常见。因此可以自行编码实现,也可以调用元件库实现。
这部分涉及到创建基于AXI4-Lite总线的IP核,方法参见前面章节内容
根据之前的分析,PL部分我们需要在闸门型号打开时,我们需要对标准时钟StdClock以及待测时钟TestClock分别进行计数。闸门信号关闭时停在计算,并把计数值存放到寄存器中等待PS通过AXI4-Lite总线读取数据。
1、在自定义AXI4-Lite IP内部添加用户逻辑如下:
  1.   // Add user logic here
  2.     reg clr;
  3.     reg Tpr;
  4.     reg Tpr_r;
  5.     reg[31:0] Nstd;
  6.     reg[31:0] Ntest;
  7.    
  8.     reg [11:0]rlcd_rgb;
  9.    
  10.     always @( posedge S_AXI_ACLK )
  11.         if ( S_AXI_ARESETN == 1'b0 )
  12.         begin
  13.               clr  <= 1'd0;
  14.               Tpr  <= 1'd0;
  15.         end
  16.         else
  17.         begin
  18.               clr <= slv_reg0[0];
  19.               Tpr <= slv_reg0[1];
  20.         end
  21.    
  22.     always @(posedge S_AXI_ACLK)
  23.         if(clr == 1'b0)
  24.         begin
  25.             Nstd <= 32'd0;
  26.         end
  27.         else if(Tpr_r == 1'b1)
  28.         begin
  29.             Nstd <= Nstd + 1'b1;
  30.         end
  31.         else
  32.         begin
  33.             Nstd <= Nstd;
  34.         end
  35.    
  36.     //------------------------------

  37.      always @(posedge FRE_i)
  38.         if(clr == 1'b0)
  39.         begin
  40.             Tpr_r <=1'b0;
  41.         end
  42.         else if(Tpr == 1'b1)
  43.         begin
  44.             Tpr_r <= 1'b1;
  45.         end      
  46.    
  47.     always @(posedge FRE_i)
  48.         if(clr == 1'b0)
  49.         begin
  50.             Ntest <= 32'd0;
  51.         end
  52.         else if(Tpr_r == 1'b1)
  53.         begin
  54.             Ntest <= Ntest + 1'b1;
  55.         end   
  56.         else
  57.         begin
  58.             Ntest <= Ntest;
  59.         End
复制代码

2、这里的测试时钟是FRE_i,后续我们可以观察PS那边计算的结果。
3、自定义IP  FRE_ACQ修改后代码如下:
FRE_AQC_S00_AXI.v

  1. `timescale 1 ns / 1 ps

  2.         module FRE_AQC_S00_AXI #
  3.         (
  4.                 // Users to add parameters here

  5.                 // User parameters ends
  6.                 // Do not modify the parameters beyond this line

  7.                 // Width of S_AXI data bus
  8.                 parameter integer C_S_AXI_DATA_WIDTH        = 32,
  9.                 // Width of S_AXI address bus
  10.                 parameter integer C_S_AXI_ADDR_WIDTH        = 4
  11.         )
  12.         (
  13.                 // Users to add ports here

  14.                 // User ports ends
  15.                 // Do not modify the ports beyond this line
  16.                 input wire  FRE_i,
  17.                 // Global Clock Signal
  18.                 input wire  S_AXI_ACLK,
  19.                 // Global Reset Signal. This Signal is Active LOW
  20.                 input wire  S_AXI_ARESETN,
  21.                 // Write address (issued by master, acceped by Slave)
  22.                 input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
  23.                 // Write channel Protection type. This signal indicates the
  24.                     // privilege and security level of the transaction, and whether
  25.                     // the transaction is a data access or an instruction access.
  26.                 input wire [2 : 0] S_AXI_AWPROT,
  27.                 // Write address valid. This signal indicates that the master signaling
  28.                     // valid write address and control information.
  29.                 input wire  S_AXI_AWVALID,
  30.                 // Write address ready. This signal indicates that the slave is ready
  31.                     // to accept an address and associated control signals.
  32.                 output wire  S_AXI_AWREADY,
  33.                 // Write data (issued by master, acceped by Slave)
  34.                 input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,
  35.                 // Write strobes. This signal indicates which byte lanes hold
  36.                     // valid data. There is one write strobe bit for each eight
  37.                     // bits of the write data bus.   
  38.                 input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,
  39.                 // Write valid. This signal indicates that valid write
  40.                     // data and strobes are available.
  41.                 input wire  S_AXI_WVALID,
  42.                 // Write ready. This signal indicates that the slave
  43.                     // can accept the write data.
  44.                 output wire  S_AXI_WREADY,
  45.                 // Write response. This signal indicates the status
  46.                     // of the write transaction.
  47.                 output wire [1 : 0] S_AXI_BRESP,
  48.                 // Write response valid. This signal indicates that the channel
  49.                     // is signaling a valid write response.
  50.                 output wire  S_AXI_BVALID,
  51.                 // Response ready. This signal indicates that the master
  52.                     // can accept a write response.
  53.                 input wire  S_AXI_BREADY,
  54.                 // Read address (issued by master, acceped by Slave)
  55.                 input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
  56.                 // Protection type. This signal indicates the privilege
  57.                     // and security level of the transaction, and whether the
  58.                     // transaction is a data access or an instruction access.
  59.                 input wire [2 : 0] S_AXI_ARPROT,
  60.                 // Read address valid. This signal indicates that the channel
  61.                     // is signaling valid read address and control information.
  62.                 input wire  S_AXI_ARVALID,
  63.                 // Read address ready. This signal indicates that the slave is
  64.                     // ready to accept an address and associated control signals.
  65.                 output wire  S_AXI_ARREADY,
  66.                 // Read data (issued by slave)
  67.                 output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
  68.                 // Read response. This signal indicates the status of the
  69.                     // read transfer.
  70.                 output wire [1 : 0] S_AXI_RRESP,
  71.                 // Read valid. This signal indicates that the channel is
  72.                     // signaling the required read data.
  73.                 output wire  S_AXI_RVALID,
  74.                 // Read ready. This signal indicates that the master can
  75.                     // accept the read data and response information.
  76.                 input wire  S_AXI_RREADY
  77.         );

  78.         // AXI4LITE signals
  79.         reg [C_S_AXI_ADDR_WIDTH-1 : 0]         axi_awaddr;
  80.         reg          axi_awready;
  81.         reg          axi_wready;
  82.         reg [1 : 0]         axi_bresp;
  83.         reg          axi_bvalid;
  84.         reg [C_S_AXI_ADDR_WIDTH-1 : 0]         axi_araddr;
  85.         reg          axi_arready;
  86.         reg [C_S_AXI_DATA_WIDTH-1 : 0]         axi_rdata;
  87.         reg [1 : 0]         axi_rresp;
  88.         reg          axi_rvalid;

  89.         // Example-specific design signals
  90.         // local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH
  91.         // ADDR_LSB is used for addressing 32/64 bit registers/memories
  92.         // ADDR_LSB = 2 for 32 bits (n downto 2)
  93.         // ADDR_LSB = 3 for 64 bits (n downto 3)
  94.         localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1;
  95.         localparam integer OPT_MEM_ADDR_BITS = 1;
  96.         //----------------------------------------------
  97.         //-- Signals for user logic register space example
  98.         //------------------------------------------------
  99.         //-- Number of Slave Registers 4
  100.         reg [C_S_AXI_DATA_WIDTH-1:0]        slv_reg0;
  101.         reg [C_S_AXI_DATA_WIDTH-1:0]        slv_reg1;
  102.         reg [C_S_AXI_DATA_WIDTH-1:0]        slv_reg2;
  103.         reg [C_S_AXI_DATA_WIDTH-1:0]        slv_reg3;
  104.         wire         slv_reg_rden;
  105.         wire         slv_reg_wren;
  106.         reg [C_S_AXI_DATA_WIDTH-1:0]         reg_data_out;
  107.         integer         byte_index;

  108.         // I/O Connections assignments

  109.         assign S_AXI_AWREADY        = axi_awready;
  110.         assign S_AXI_WREADY        = axi_wready;
  111.         assign S_AXI_BRESP        = axi_bresp;
  112.         assign S_AXI_BVALID        = axi_bvalid;
  113.         assign S_AXI_ARREADY        = axi_arready;
  114.         assign S_AXI_RDATA        = axi_rdata;
  115.         assign S_AXI_RRESP        = axi_rresp;
  116.         assign S_AXI_RVALID        = axi_rvalid;
  117.         // Implement axi_awready generation
  118.         // axi_awready is asserted for one S_AXI_ACLK clock cycle when both
  119.         // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is
  120.         // de-asserted when reset is low.

  121.         always @( posedge S_AXI_ACLK )
  122.         begin
  123.           if ( S_AXI_ARESETN == 1'b0 )
  124.             begin
  125.               axi_awready <= 1'b0;
  126.             end
  127.           else
  128.             begin   
  129.               if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)
  130.                 begin
  131.                   // slave is ready to accept write address when
  132.                   // there is a valid write address and write data
  133.                   // on the write address and data bus. This design
  134.                   // expects no outstanding transactions.
  135.                   axi_awready <= 1'b1;
  136.                 end
  137.               else           
  138.                 begin
  139.                   axi_awready <= 1'b0;
  140.                 end
  141.             end
  142.         end      

  143.         // Implement axi_awaddr latching
  144.         // This process is used to latch the address when both
  145.         // S_AXI_AWVALID and S_AXI_WVALID are valid.

  146.         always @( posedge S_AXI_ACLK )
  147.         begin
  148.           if ( S_AXI_ARESETN == 1'b0 )
  149.             begin
  150.               axi_awaddr <= 0;
  151.             end
  152.           else
  153.             begin   
  154.               if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)
  155.                 begin
  156.                   // Write Address latching
  157.                   axi_awaddr <= S_AXI_AWADDR;
  158.                 end
  159.             end
  160.         end      

  161.         // Implement axi_wready generation
  162.         // axi_wready is asserted for one S_AXI_ACLK clock cycle when both
  163.         // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is
  164.         // de-asserted when reset is low.

  165.         always @( posedge S_AXI_ACLK )
  166.         begin
  167.           if ( S_AXI_ARESETN == 1'b0 )
  168.             begin
  169.               axi_wready <= 1'b0;
  170.             end
  171.           else
  172.             begin   
  173.               if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID)
  174.                 begin
  175.                   // slave is ready to accept write data when
  176.                   // there is a valid write address and write data
  177.                   // on the write address and data bus. This design
  178.                   // expects no outstanding transactions.
  179.                   axi_wready <= 1'b1;
  180.                 end
  181.               else
  182.                 begin
  183.                   axi_wready <= 1'b0;
  184.                 end
  185.             end
  186.         end      

  187.         // Implement memory mapped register select and write logic generation
  188.         // The write data is accepted and written to memory mapped registers when
  189.         // axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to
  190.         // select byte enables of slave registers while writing.
  191.         // These registers are cleared when reset (active low) is applied.
  192.         // Slave register write enable is asserted when valid address and data are available
  193.         // and the slave is ready to accept the write address and write data.
  194.         assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;

  195.         always @( posedge S_AXI_ACLK )
  196.         begin
  197.           if ( S_AXI_ARESETN == 1'b0 )
  198.             begin
  199.               slv_reg0 <= 0;
  200.               slv_reg1 <= 0;
  201.               slv_reg2 <= 0;
  202.               slv_reg3 <= 0;
  203.             end
  204.           else begin
  205.             if (slv_reg_wren)
  206.               begin
  207.                 case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
  208.                   2'h0:
  209.                     for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
  210.                       if ( S_AXI_WSTRB[byte_index] == 1 ) begin
  211.                         // Respective byte enables are asserted as per write strobes
  212.                         // Slave register 0
  213.                         slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
  214.                       end  
  215.                   2'h1:
  216.                     for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
  217.                       if ( S_AXI_WSTRB[byte_index] == 1 ) begin
  218.                         // Respective byte enables are asserted as per write strobes
  219.                         // Slave register 1
  220.                         slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
  221.                       end  
  222.                   2'h2:
  223.                     for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
  224.                       if ( S_AXI_WSTRB[byte_index] == 1 ) begin
  225.                         // Respective byte enables are asserted as per write strobes
  226.                         // Slave register 2
  227.                         slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
  228.                       end  
  229.                   2'h3:
  230.                     for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
  231.                       if ( S_AXI_WSTRB[byte_index] == 1 ) begin
  232.                         // Respective byte enables are asserted as per write strobes
  233.                         // Slave register 3
  234.                         slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
  235.                       end  
  236.                   default : begin
  237.                               slv_reg0 <= slv_reg0;
  238.                               slv_reg1 <= slv_reg1;
  239.                               slv_reg2 <= slv_reg2;
  240.                               slv_reg3 <= slv_reg3;
  241.                             end
  242.                 endcase
  243.               end
  244.           end
  245.         end   

  246.         // Implement write response logic generation
  247.         // The write response and response valid signals are asserted by the slave
  248.         // when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted.  
  249.         // This marks the acceptance of address and indicates the status of
  250.         // write transaction.

  251.         always @( posedge S_AXI_ACLK )
  252.         begin
  253.           if ( S_AXI_ARESETN == 1'b0 )
  254.             begin
  255.               axi_bvalid  <= 0;
  256.               axi_bresp   <= 2'b0;
  257.             end
  258.           else
  259.             begin   
  260.               if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)
  261.                 begin
  262.                   // indicates a valid write response is available
  263.                   axi_bvalid <= 1'b1;
  264.                   axi_bresp  <= 2'b0; // 'OKAY' response
  265.                 end                   // work error responses in future
  266.               else
  267.                 begin
  268.                   if (S_AXI_BREADY && axi_bvalid)
  269.                     //check if bready is asserted while bvalid is high)
  270.                     //(there is a possibility that bready is always asserted high)   
  271.                     begin
  272.                       axi_bvalid <= 1'b0;
  273.                     end  
  274.                 end
  275.             end
  276.         end   

  277.         // Implement axi_arready generation
  278.         // axi_arready is asserted for one S_AXI_ACLK clock cycle when
  279.         // S_AXI_ARVALID is asserted. axi_awready is
  280.         // de-asserted when reset (active low) is asserted.
  281.         // The read address is also latched when S_AXI_ARVALID is
  282.         // asserted. axi_araddr is reset to zero on reset assertion.

  283.         always @( posedge S_AXI_ACLK )
  284.         begin
  285.           if ( S_AXI_ARESETN == 1'b0 )
  286.             begin
  287.               axi_arready <= 1'b0;
  288.               axi_araddr  <= 32'b0;
  289.             end
  290.           else
  291.             begin   
  292.               if (~axi_arready && S_AXI_ARVALID)
  293.                 begin
  294.                   // indicates that the slave has acceped the valid read address
  295.                   axi_arready <= 1'b1;
  296.                   // Read address latching
  297.                   axi_araddr  <= S_AXI_ARADDR;
  298.                 end
  299.               else
  300.                 begin
  301.                   axi_arready <= 1'b0;
  302.                 end
  303.             end
  304.         end      

  305.         // Implement axi_arvalid generation
  306.         // axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both
  307.         // S_AXI_ARVALID and axi_arready are asserted. The slave registers
  308.         // data are available on the axi_rdata bus at this instance. The
  309.         // assertion of axi_rvalid marks the validity of read data on the
  310.         // bus and axi_rresp indicates the status of read transaction.axi_rvalid
  311.         // is deasserted on reset (active low). axi_rresp and axi_rdata are
  312.         // cleared to zero on reset (active low).  
  313.         always @( posedge S_AXI_ACLK )
  314.         begin
  315.           if ( S_AXI_ARESETN == 1'b0 )
  316.             begin
  317.               axi_rvalid <= 0;
  318.               axi_rresp  <= 0;
  319.             end
  320.           else
  321.             begin   
  322.               if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)
  323.                 begin
  324.                   // Valid read data is available at the read data bus
  325.                   axi_rvalid <= 1'b1;
  326.                   axi_rresp  <= 2'b0; // 'OKAY' response
  327.                 end   
  328.               else if (axi_rvalid && S_AXI_RREADY)
  329.                 begin
  330.                   // Read data is accepted by the master
  331.                   axi_rvalid <= 1'b0;
  332.                 end               
  333.             end
  334.         end   

  335.         // Implement memory mapped register select and read logic generation
  336.     // Slave register read enable is asserted when valid address is available
  337.     // and the slave is ready to accept the read address.
  338.     assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;
  339.     always @(*)
  340.     begin
  341.           // Address decoding for reading registers
  342.           case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
  343.             2'h0   : reg_data_out <= 32'd11;
  344.             2'h1   : reg_data_out <= Nstd;
  345.             2'h2   : reg_data_out <= Ntest;
  346.             2'h3   : reg_data_out <= 32'd14;
  347.             default : reg_data_out <= 0;
  348.           endcase
  349.     end

  350.     // Output register or memory read data
  351.     always @( posedge S_AXI_ACLK )
  352.     begin
  353.       if ( S_AXI_ARESETN == 1'b0 )
  354.         begin
  355.           axi_rdata  <= 0;
  356.         end
  357.       else
  358.         begin   
  359.           // When there is a valid read address (S_AXI_ARVALID) with
  360.           // acceptance of read address by the slave (axi_arready),
  361.           // output the read dada
  362.           if (slv_reg_rden)
  363.             begin
  364.               axi_rdata <= reg_data_out;     // register read data
  365.             end   
  366.         end
  367.     end   

  368.     // Add user logic here
  369.     reg clr;
  370.     reg Tpr;
  371.     reg[31:0] Nstd;
  372.     reg[31:0] Ntest;
  373.    
  374.     reg [11:0]rlcd_rgb;
  375.         always @( posedge S_AXI_ACLK )
  376.                 begin
  377.                   if ( S_AXI_ARESETN == 1'b0 )
  378.                     begin
  379.                         clr  <= 1'd0;
  380.                         Tpr  <= 1'd0;
  381.                     end
  382.                   else
  383.                     begin
  384.                         clr <= slv_reg0[0];
  385.                         Tpr <= slv_reg0[1];
  386.                     end
  387.                 end  
  388.    
  389.     always @(posedge S_AXI_ACLK)
  390.         if(clr == 1'b0)
  391.         begin
  392.             Nstd <= 32'd0;
  393.         end
  394.         else if(Tpr == 1'b1)
  395.         begin
  396.             Nstd <= Nstd + 1'b1;
  397.         end
  398.         else
  399.         begin
  400.             Nstd <= Nstd;
  401.         end
  402.    
  403.     //------------------------------
  404.    
  405.     always @(posedge FRE_i)
  406.         if(clr == 1'b0)
  407.         begin
  408.             Ntest <= 32'd0;
  409.         end
  410.         else if(Tpr == 1'b1)
  411.         begin
  412.             Ntest <= Ntest + 1'b1;
  413.         end   
  414.         else
  415.         begin
  416.             Ntest <= Ntest;
  417.         end
  418.      
  419.     // User logic ends

  420.     endmodule
复制代码

FRE_AQC.v
  1. `timescale 1 ns / 1 ps

  2.         module FRE_AQC#
  3.         (
  4.                 // Users to add parameters here

  5.                 // User parameters ends
  6.                 // Do not modify the parameters beyond this line


  7.                 // Parameters of Axi Slave Bus Interface S00_AXI
  8.                 parameter integer C_S00_AXI_DATA_WIDTH        = 32,
  9.                 parameter integer C_S00_AXI_ADDR_WIDTH        = 4
  10.         )
  11.         (
  12.                 // Users to add ports here
  13.                 input wire  FRE_i,
  14.                 // User ports ends
  15.                 // Do not modify the ports beyond this line


  16.                 // Ports of Axi Slave Bus Interface S00_AXI
  17.                 input wire  s00_axi_aclk,
  18.                 input wire  s00_axi_aresetn,
  19.                 input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_awaddr,
  20.                 input wire [2 : 0] s00_axi_awprot,
  21.                 input wire  s00_axi_awvalid,
  22.                 output wire  s00_axi_awready,
  23.                 input wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_wdata,
  24.                 input wire [(C_S00_AXI_DATA_WIDTH/8)-1 : 0] s00_axi_wstrb,
  25.                 input wire  s00_axi_wvalid,
  26.                 output wire  s00_axi_wready,
  27.                 output wire [1 : 0] s00_axi_bresp,
  28.                 output wire  s00_axi_bvalid,
  29.                 input wire  s00_axi_bready,
  30.                 input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_araddr,
  31.                 input wire [2 : 0] s00_axi_arprot,
  32.                 input wire  s00_axi_arvalid,
  33.                 output wire  s00_axi_arready,
  34.                 output wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_rdata,
  35.                 output wire [1 : 0] s00_axi_rresp,
  36.                 output wire  s00_axi_rvalid,
  37.                 input wire  s00_axi_rready
  38.         );
  39. // Instantiation of Axi Bus Interface S00_AXI
  40.         FRE_AQC_S00_AXI # (
  41.                 .C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH),
  42.                 .C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH)
  43.         ) FRE_AQC_S00_AXI_inst (
  44.                 .FRE_i(FRE_i),
  45.                 .S_AXI_ACLK(s00_axi_aclk),
  46.                 .S_AXI_ARESETN(s00_axi_aresetn),
  47.                 .S_AXI_AWADDR(s00_axi_awaddr),
  48.                 .S_AXI_AWPROT(s00_axi_awprot),
  49.                 .S_AXI_AWVALID(s00_axi_awvalid),
  50.                 .S_AXI_AWREADY(s00_axi_awready),
  51.                 .S_AXI_WDATA(s00_axi_wdata),
  52.                 .S_AXI_WSTRB(s00_axi_wstrb),
  53.                 .S_AXI_WVALID(s00_axi_wvalid),
  54.                 .S_AXI_WREADY(s00_axi_wready),
  55.                 .S_AXI_BRESP(s00_axi_bresp),
  56.                 .S_AXI_BVALID(s00_axi_bvalid),
  57.                 .S_AXI_BREADY(s00_axi_bready),
  58.                 .S_AXI_ARADDR(s00_axi_araddr),
  59.                 .S_AXI_ARPROT(s00_axi_arprot),
  60.                 .S_AXI_ARVALID(s00_axi_arvalid),
  61.                 .S_AXI_ARREADY(s00_axi_arready),
  62.                 .S_AXI_RDATA(s00_axi_rdata),
  63.                 .S_AXI_RRESP(s00_axi_rresp),
  64.                 .S_AXI_RVALID(s00_axi_rvalid),
  65.                 .S_AXI_RREADY(s00_axi_rready)
  66.                
  67.                 //.FRE_i(FRE_i)
  68.         );
  69.         // Add user logic here
  70.         // User logic ends
  71.         endmodule
复制代码

5搭建SOC系统工程
详细的搭建过程这里不再重复,对于初学读者如果还不清楚如何创建SOC工程的,请学习“01Vitis Soc开发入门”这篇文章。
5.1SOC系统工程
51fde71afb8c4e2b84b67afb0facf105.jpg
1:中断设置
本实验可以不设置中断
336ed8be8ee542949d7e4470d03c6739.jpg
2:设置GP Master接口
bb28ea15c84541b2b8c51fa477f76db9.jpg
3:设置复位输出
4300080c18004eb8979f5e2a99209871.jpg
4:设置PL时钟
27b32d6b3c294984bc768c543061b4c2.jpg
5:添加自定义IP
设置自定义IP路径,并且添加IP
c4c896cc49b5477fa3d2dcf87ee92bf6.jpg
5.2设置AXI外设地址分配
只要添加的AXI总线外设都要正确分配地址,这一步不能遗漏
be4f4ee39c30488c85443f61131e24fc.jpg
5.3编译并导出平台文件
以下步骤简写,有不清楚的看第一篇文章。
1:单击Block文件à右键àGenerate the Output ProductsàGlobalàGenerate。
2:单击Block文件à右键à Create a HDL wrapper(生成HDL顶层文件)àLet vivado manager wrapper and auto-update(自动更新)。
3:添加配套工程路径下uisrc/04_pin/fpga_pin.xdc约束文件
4:生成Bit文件。
5:导出到硬件: FileàExport HardwareàInclude bitstream
6:导出完成后,对应工程路径的soc_hw路径下有硬件平台文件:system_wrapper.xsa的文件。根据硬件平台文件system_wrapper.xsa来创建需要Platform平台。
545883f4648d4c78bda4c861b61e6385.jpg
6搭建Vitis-sdk工程
创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。
6.1创建SDK Platform工程
64aa81ee8eae4da88df1ceb019af1217.jpg
右击soc_base编译,编译的时间可能会有点长
6.2创建APP工程
fd5bd0bdb87441248c06301d38547a27.jpg
7方案演示
7.1硬件准备
本实验需要用到 JTAG 下载器、USB 转串口外设,另外需要把核心板上的 2P 模式开关设置到 JTAG 模式,即 ON ON(注意新版本的 MLK_H3_CZ08-7100-MZ7100FC),支持 JTAG 模式,对于老版本的核心板,JTAG 调试的时候 一定要拔掉 TF 卡,并且设置模式开关为 OFF OFF)

980279a7a8b1411eb0fedb5e3473b242.jpg
7.2实验结果
本实验中通过50M参考时钟对100M被采样时钟进行采样,程序中采样的次数越多(时间),精度越高。
df10464bbc6a4bea94ccef85ec1b20a5.jpg
92e7e43feb464e58ac175c8101242711.jpg
1ed42b072e06423e9583bc2a040dcc34.jpg
1ed42b072e06423e9583bc2a040dcc34.jpg
92e7e43feb464e58ac175c8101242711.jpg
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则