首页 > 其他分享 >[米联客-XILINX-H3_CZ08_7100] FPGA_SDK入门篇连载-26PL 自定义 AXI-Lite-频率计

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

时间:2024-09-29 11:22:48浏览次数:12  
标签:wire 自定义 FPGA s00 axi WIDTH input AXI 频率计

软件版本: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概述

2系统框图

3等精度频率计原理

3.1概述

3.2频率测量原理

3.3脉冲计数法

3.4周期测频法

3.5多周期同步测频原理及误差分析

4等精度频率计设计

4.1PS寄存器功能划分

4.2具体实现

4.3频率计PL部分代码设计

5搭建SOC系统工程

5.1SOC系统工程

1:中断设置

2:设置GP Master接口

3:设置复位输出

4:设置PL时钟

5:添加自定义IP

5.2设置AXI外设地址分配

5.3编译并导出平台文件

6搭建Vitis-sdk工程

6.1创建SDK Platform工程

6.2创建APP工程

7方案演示

7.1硬件准备

7.2实验结果


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系统框图

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个周期的误差。

图1. Tpr处理后成为CNT_EN

由于引入了D触发器,CNT_EN不会在Tpr发生变化时立即变化,而是在TestClk上升沿到来时才发生变化,从而保证CNT_EN刚好是TEST_Clk的整数倍。测频法和测周法的原理和误差分析如果不明白,自己画个图试试,可以很好地帮助理解。

解决问题的同时,产生了新的问题:实际闸门时间与预置闸门时间不相等,因此需要获取实际闸门时间。为解决这一问题,引入另一计数器和标准时钟信号。在测量被测信号频率的同时,对标准时钟脉冲进行计数,通过计算即可得到实际闸门时间。这样就得到多周期同步频率计的主要结构,如图2所示。

图2. 测频主控模块结构图

其中,STD_CLK为标准时钟;Tpr为预置门控信号;TEST_CLK为待测信号;CLR为计数清零信号。

在计数允许时间内,同时对标准信号和被测信号进行计数,由于两个计数器计数时间相等,从而得到公式(1)。

Nstd/Fstd=Ntest/Ftest                               公式(1)

其中Nstd为标准时钟计数值;Fstd为标准时钟频率;Ntest为待测信号计数值;Ftest为待测信号频率,由公式(1)可知待测频率为Ftest=Fstd*Ntest/Nstd。

由于未对标准时钟进行同步计数,所以测量结果会产生个标准信号脉冲的误差。

从以上论述可以得出如下结论:

待测信号频率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内部添加用户逻辑如下:

  // Add user logic here
    reg clr;
    reg Tpr;
    reg Tpr_r;
    reg[31:0] Nstd;
    reg[31:0] Ntest;
    
    reg [11:0]rlcd_rgb;
    
    always @( posedge S_AXI_ACLK )
        if ( S_AXI_ARESETN == 1'b0 )
        begin
              clr  <= 1'd0;
              Tpr  <= 1'd0;
        end 
        else 
        begin
              clr <= slv_reg0[0];
              Tpr <= slv_reg0[1];
        end
    
    always @(posedge S_AXI_ACLK)
        if(clr == 1'b0)
        begin
            Nstd <= 32'd0;
        end
        else if(Tpr_r == 1'b1)
        begin
            Nstd <= Nstd + 1'b1;
        end
        else
        begin
            Nstd <= Nstd;
        end
    
    //------------------------------
 
     always @(posedge FRE_i)
        if(clr == 1'b0)
        begin
            Tpr_r <=1'b0;
        end
        else if(Tpr == 1'b1)
        begin
            Tpr_r <= 1'b1;
        end      
    
    always @(posedge FRE_i)
        if(clr == 1'b0)
        begin
            Ntest <= 32'd0;
        end
        else if(Tpr_r == 1'b1)
        begin
            Ntest <= Ntest + 1'b1;
        end    
        else
        begin
            Ntest <= Ntest;
        End

2、这里的测试时钟是FRE_i,后续我们可以观察PS那边计算的结果。

3、自定义IP  FRE_ACQ修改后代码如下:

FRE_AQC_S00_AXI.v

`timescale 1 ns / 1 ps

	module FRE_AQC_S00_AXI #
	(
		// Users to add parameters here

		// User parameters ends
		// Do not modify the parameters beyond this line

		// Width of S_AXI data bus
		parameter integer C_S_AXI_DATA_WIDTH	= 32,
		// Width of S_AXI address bus
		parameter integer C_S_AXI_ADDR_WIDTH	= 4
	)
	(
		// Users to add ports here

		// User ports ends
		// Do not modify the ports beyond this line
		input wire  FRE_i,
		// Global Clock Signal
		input wire  S_AXI_ACLK,
		// Global Reset Signal. This Signal is Active LOW
		input wire  S_AXI_ARESETN,
		// Write address (issued by master, acceped by Slave)
		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
		// Write channel Protection type. This signal indicates the
    		// privilege and security level of the transaction, and whether
    		// the transaction is a data access or an instruction access.
		input wire [2 : 0] S_AXI_AWPROT,
		// Write address valid. This signal indicates that the master signaling
    		// valid write address and control information.
		input wire  S_AXI_AWVALID,
		// Write address ready. This signal indicates that the slave is ready
    		// to accept an address and associated control signals.
		output wire  S_AXI_AWREADY,
		// Write data (issued by master, acceped by Slave) 
		input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,
		// Write strobes. This signal indicates which byte lanes hold
    		// valid data. There is one write strobe bit for each eight
    		// bits of the write data bus.    
		input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,
		// Write valid. This signal indicates that valid write
    		// data and strobes are available.
		input wire  S_AXI_WVALID,
		// Write ready. This signal indicates that the slave
    		// can accept the write data.
		output wire  S_AXI_WREADY,
		// Write response. This signal indicates the status
    		// of the write transaction.
		output wire [1 : 0] S_AXI_BRESP,
		// Write response valid. This signal indicates that the channel
    		// is signaling a valid write response.
		output wire  S_AXI_BVALID,
		// Response ready. This signal indicates that the master
    		// can accept a write response.
		input wire  S_AXI_BREADY,
		// Read address (issued by master, acceped by Slave)
		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
		// Protection type. This signal indicates the privilege
    		// and security level of the transaction, and whether the
    		// transaction is a data access or an instruction access.
		input wire [2 : 0] S_AXI_ARPROT,
		// Read address valid. This signal indicates that the channel
    		// is signaling valid read address and control information.
		input wire  S_AXI_ARVALID,
		// Read address ready. This signal indicates that the slave is
    		// ready to accept an address and associated control signals.
		output wire  S_AXI_ARREADY,
		// Read data (issued by slave)
		output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
		// Read response. This signal indicates the status of the
    		// read transfer.
		output wire [1 : 0] S_AXI_RRESP,
		// Read valid. This signal indicates that the channel is
    		// signaling the required read data.
		output wire  S_AXI_RVALID,
		// Read ready. This signal indicates that the master can
    		// accept the read data and response information.
		input wire  S_AXI_RREADY
	);

	// AXI4LITE signals
	reg [C_S_AXI_ADDR_WIDTH-1 : 0] 	axi_awaddr;
	reg  	axi_awready;
	reg  	axi_wready;
	reg [1 : 0] 	axi_bresp;
	reg  	axi_bvalid;
	reg [C_S_AXI_ADDR_WIDTH-1 : 0] 	axi_araddr;
	reg  	axi_arready;
	reg [C_S_AXI_DATA_WIDTH-1 : 0] 	axi_rdata;
	reg [1 : 0] 	axi_rresp;
	reg  	axi_rvalid;

	// Example-specific design signals
	// local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH
	// ADDR_LSB is used for addressing 32/64 bit registers/memories
	// ADDR_LSB = 2 for 32 bits (n downto 2)
	// ADDR_LSB = 3 for 64 bits (n downto 3)
	localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1;
	localparam integer OPT_MEM_ADDR_BITS = 1;
	//----------------------------------------------
	//-- Signals for user logic register space example
	//------------------------------------------------
	//-- Number of Slave Registers 4
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg0;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg1;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg2;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg3;
	wire	 slv_reg_rden;
	wire	 slv_reg_wren;
	reg [C_S_AXI_DATA_WIDTH-1:0]	 reg_data_out;
	integer	 byte_index;

	// I/O Connections assignments

	assign S_AXI_AWREADY	= axi_awready;
	assign S_AXI_WREADY	= axi_wready;
	assign S_AXI_BRESP	= axi_bresp;
	assign S_AXI_BVALID	= axi_bvalid;
	assign S_AXI_ARREADY	= axi_arready;
	assign S_AXI_RDATA	= axi_rdata;
	assign S_AXI_RRESP	= axi_rresp;
	assign S_AXI_RVALID	= axi_rvalid;
	// Implement axi_awready generation
	// axi_awready is asserted for one S_AXI_ACLK clock cycle when both
	// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is
	// de-asserted when reset is low.

	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_awready <= 1'b0;
	    end 
	  else
	    begin    
	      if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)
	        begin
	          // slave is ready to accept write address when 
	          // there is a valid write address and write data
	          // on the write address and data bus. This design 
	          // expects no outstanding transactions. 
	          axi_awready <= 1'b1;
	        end
	      else           
	        begin
	          axi_awready <= 1'b0;
	        end
	    end 
	end       

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

	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_awaddr <= 0;
	    end 
	  else
	    begin    
	      if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)
	        begin
	          // Write Address latching 
	          axi_awaddr <= S_AXI_AWADDR;
	        end
	    end 
	end       

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

	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_wready <= 1'b0;
	    end 
	  else
	    begin    
	      if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID)
	        begin
	          // slave is ready to accept write data when 
	          // there is a valid write address and write data
	          // on the write address and data bus. This design 
	          // expects no outstanding transactions. 
	          axi_wready <= 1'b1;
	        end
	      else
	        begin
	          axi_wready <= 1'b0;
	        end
	    end 
	end       

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

	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      slv_reg0 <= 0;
	      slv_reg1 <= 0;
	      slv_reg2 <= 0;
	      slv_reg3 <= 0;
	    end 
	  else begin
	    if (slv_reg_wren)
	      begin
	        case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
	          2'h0:
	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
	                // Respective byte enables are asserted as per write strobes 
	                // Slave register 0
	                slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
	              end  
	          2'h1:
	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
	                // Respective byte enables are asserted as per write strobes 
	                // Slave register 1
	                slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
	              end  
	          2'h2:
	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
	                // Respective byte enables are asserted as per write strobes 
	                // Slave register 2
	                slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
	              end  
	          2'h3:
	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
	                // Respective byte enables are asserted as per write strobes 
	                // Slave register 3
	                slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
	              end  
	          default : begin
	                      slv_reg0 <= slv_reg0;
	                      slv_reg1 <= slv_reg1;
	                      slv_reg2 <= slv_reg2;
	                      slv_reg3 <= slv_reg3;
	                    end
	        endcase
	      end
	  end
	end    

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

	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_bvalid  <= 0;
	      axi_bresp   <= 2'b0;
	    end 
	  else
	    begin    
	      if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)
	        begin
	          // indicates a valid write response is available
	          axi_bvalid <= 1'b1;
	          axi_bresp  <= 2'b0; // 'OKAY' response 
	        end                   // work error responses in future
	      else
	        begin
	          if (S_AXI_BREADY && axi_bvalid) 
	            //check if bready is asserted while bvalid is high) 
	            //(there is a possibility that bready is always asserted high)   
	            begin
	              axi_bvalid <= 1'b0; 
	            end  
	        end
	    end
	end   

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

	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_arready <= 1'b0;
	      axi_araddr  <= 32'b0;
	    end 
	  else
	    begin    
	      if (~axi_arready && S_AXI_ARVALID)
	        begin
	          // indicates that the slave has acceped the valid read address
	          axi_arready <= 1'b1;
	          // Read address latching
	          axi_araddr  <= S_AXI_ARADDR;
	        end
	      else
	        begin
	          axi_arready <= 1'b0;
	        end
	    end 
	end       

	// Implement axi_arvalid generation
	// axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both 
	// S_AXI_ARVALID and axi_arready are asserted. The slave registers 
	// data are available on the axi_rdata bus at this instance. The 
	// assertion of axi_rvalid marks the validity of read data on the 
	// bus and axi_rresp indicates the status of read transaction.axi_rvalid 
	// is deasserted on reset (active low). axi_rresp and axi_rdata are 
	// cleared to zero on reset (active low).  
	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_rvalid <= 0;
	      axi_rresp  <= 0;
	    end 
	  else
	    begin    
	      if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)
	        begin
	          // Valid read data is available at the read data bus
	          axi_rvalid <= 1'b1;
	          axi_rresp  <= 2'b0; // 'OKAY' response
	        end   
	      else if (axi_rvalid && S_AXI_RREADY)
	        begin
	          // Read data is accepted by the master
	          axi_rvalid <= 1'b0;
	        end                
	    end
	end    

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

    // Output register or memory read data
    always @( posedge S_AXI_ACLK )
    begin
      if ( S_AXI_ARESETN == 1'b0 )
        begin
          axi_rdata  <= 0;
        end 
      else
        begin    
          // When there is a valid read address (S_AXI_ARVALID) with 
          // acceptance of read address by the slave (axi_arready), 
          // output the read dada 
          if (slv_reg_rden)
            begin
              axi_rdata <= reg_data_out;     // register read data
            end   
        end
    end    

    // Add user logic here
    reg clr;
    reg Tpr;
    reg[31:0] Nstd;
    reg[31:0] Ntest;
    
    reg [11:0]rlcd_rgb;
        always @( posedge S_AXI_ACLK )
                begin
                  if ( S_AXI_ARESETN == 1'b0 )
                    begin
                        clr  <= 1'd0;
                        Tpr  <= 1'd0;
                    end 
                  else
                    begin
                        clr <= slv_reg0[0];
                        Tpr <= slv_reg0[1];
                    end
                end  
    
    always @(posedge S_AXI_ACLK)
        if(clr == 1'b0)
        begin
            Nstd <= 32'd0;
        end
        else if(Tpr == 1'b1)
        begin
            Nstd <= Nstd + 1'b1;
        end
        else
        begin
            Nstd <= Nstd;
        end
    
    //------------------------------
    
    always @(posedge FRE_i)
        if(clr == 1'b0)
        begin
            Ntest <= 32'd0;
        end
        else if(Tpr == 1'b1)
        begin
            Ntest <= Ntest + 1'b1;
        end    
        else
        begin
            Ntest <= Ntest;
        end
     
    // User logic ends

    endmodule

FRE_AQC.v

`timescale 1 ns / 1 ps

	module FRE_AQC#
	(
		// Users to add parameters here

		// User parameters ends
		// Do not modify the parameters beyond this line


		// Parameters of Axi Slave Bus Interface S00_AXI
		parameter integer C_S00_AXI_DATA_WIDTH	= 32,
		parameter integer C_S00_AXI_ADDR_WIDTH	= 4
	)
	(
		// Users to add ports here
		input wire  FRE_i,
		// User ports ends
		// Do not modify the ports beyond this line


		// Ports of Axi Slave Bus Interface S00_AXI
		input wire  s00_axi_aclk,
		input wire  s00_axi_aresetn,
		input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_awaddr,
		input wire [2 : 0] s00_axi_awprot,
		input wire  s00_axi_awvalid,
		output wire  s00_axi_awready,
		input wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_wdata,
		input wire [(C_S00_AXI_DATA_WIDTH/8)-1 : 0] s00_axi_wstrb,
		input wire  s00_axi_wvalid,
		output wire  s00_axi_wready,
		output wire [1 : 0] s00_axi_bresp,
		output wire  s00_axi_bvalid,
		input wire  s00_axi_bready,
		input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_araddr,
		input wire [2 : 0] s00_axi_arprot,
		input wire  s00_axi_arvalid,
		output wire  s00_axi_arready,
		output wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_rdata,
		output wire [1 : 0] s00_axi_rresp,
		output wire  s00_axi_rvalid,
		input wire  s00_axi_rready
	);
// Instantiation of Axi Bus Interface S00_AXI
	FRE_AQC_S00_AXI # ( 
		.C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH),
		.C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH)
	) FRE_AQC_S00_AXI_inst (
		.FRE_i(FRE_i),
		.S_AXI_ACLK(s00_axi_aclk),
		.S_AXI_ARESETN(s00_axi_aresetn),
		.S_AXI_AWADDR(s00_axi_awaddr),
		.S_AXI_AWPROT(s00_axi_awprot),
		.S_AXI_AWVALID(s00_axi_awvalid),
		.S_AXI_AWREADY(s00_axi_awready),
		.S_AXI_WDATA(s00_axi_wdata),
		.S_AXI_WSTRB(s00_axi_wstrb),
		.S_AXI_WVALID(s00_axi_wvalid),
		.S_AXI_WREADY(s00_axi_wready),
		.S_AXI_BRESP(s00_axi_bresp),
		.S_AXI_BVALID(s00_axi_bvalid),
		.S_AXI_BREADY(s00_axi_bready),
		.S_AXI_ARADDR(s00_axi_araddr),
		.S_AXI_ARPROT(s00_axi_arprot),
		.S_AXI_ARVALID(s00_axi_arvalid),
		.S_AXI_ARREADY(s00_axi_arready),
		.S_AXI_RDATA(s00_axi_rdata),
		.S_AXI_RRESP(s00_axi_rresp),
		.S_AXI_RVALID(s00_axi_rvalid),
		.S_AXI_RREADY(s00_axi_rready)
		
		//.FRE_i(FRE_i)
	);
	// Add user logic here
	// User logic ends
	endmodule

5搭建SOC系统工程

详细的搭建过程这里不再重复,对于初学读者如果还不清楚如何创建SOC工程的,请学习“01Vitis Soc开发入门”这篇文章。

5.1SOC系统工程

1:中断设置

本实验可以不设置中断

2:设置GP Master接口

3:设置复位输出

4:设置PL时钟

5:添加自定义IP

设置自定义IP路径,并且添加IP

5.2设置AXI外设地址分配

只要添加的AXI总线外设都要正确分配地址,这一步不能遗漏

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平台。

6搭建Vitis-sdk工程

创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。 

6.1创建SDK Platform工程

右击soc_base编译,编译的时间可能会有点长

6.2创建APP工程

7方案演示

7.1硬件准备

本实验需要用到 JTAG 下载器、USB 转串口外设,另外需要把核心板上的 2P 模式开关设置到 JTAG 模式,即 ON ON(注意新版本的 MLK_H3_CZ08-7100-MZ7100FC),支持 JTAG 模式,对于老版本的核心板,JTAG 调试的时候 一定要拔掉 TF 卡,并且设置模式开关为 OFF OFF)

7.2实验结果

本实验中通过50M参考时钟对100M被采样时钟进行采样,程序中采样的次数越多(时间),精度越高。

标签:wire,自定义,FPGA,s00,axi,WIDTH,input,AXI,频率计
From: https://blog.csdn.net/u011570052/article/details/142449943

相关文章

  • [米联客-XILINX-H3_CZ08_7100] FPGA_SDK入门篇连载-23PL 自定义 AXI-Lite 协议 IP
    软件版本:VIVADO2021.1操作系统:WIN1064bit硬件平台:适用XILINXA7/K7/Z7/ZU/KU系列FPGA实验平台:米联客-MLK-H3-CZ08-7100开发板板卡获取平台:https://milianke.tmall.com/登录“米联客”FPGA社区http://www.uisrc.com视频课程、答疑解惑!目录1概述2系统框图3AXI总线......
  • pbootcms留言板取消验证码提交自定义表单时取消验证码
    在PBootCMS中取消留言板的验证码功能,可以通过后台的全局配置来进行设置。以下是具体的步骤:步骤详解登录后台:使用管理员账号登录PBootCMS后台。进入全局配置:在后台菜单中找到并点击 全局配置。进入配置参数:在全局配置页面中找到并点击 配置参数。进入安全......
  • 基于FPGA 多通道多带宽多速率 DDC设计
    摘要:数字阵列雷达的核心内容之一是单元级回波信号中频或射频数字化后,在数字域进行幅/相加权实现接收数字波束形成,并具有灵活的波束调度和更好的抗有源干扰的性能,基于多通道数字化接收机的数字阵列模块是数字阵列雷达的关键模块。论述了数字阵列模块内部基于FPGA的多通......
  • Javax Validation 自定义注解校验(身份证号校验)
    一、场景分析我们使用SpringMVC在Controller层,对身份证号进行数据校验的话,经常采用以下方式:@RestController@RequiredArgsConstructor@RequestMapping("member")publicclassMemberController{//身份证号码正则表达式Stringregex="^(^[1-9]\\d{5}(18|......
  • C语言自定义类型:联合体
    目录前言一、联合体1.1联合体类型的声明1.2联合体的特点1.3相同成员的结构体和联合体对比1.4联合体大小的计算1.5联合体的⼀个练习总结前言前面我讲到C语言中的自定义结构——结构体,其实C语言中的自定义结构不只有结构体,还有枚举和联合体,我们今天就来学习一下......
  • 深入剖析 MyBatis-Plus:操作总结、对比与实践案例(CRUD 操作、分页、条件构造器、自动填
    MyBatis-Plus是MyBatis的增强工具,它极大简化了MyBatis的配置和操作,提高了开发效率。本文从基本操作到高阶用法,详细介绍了MyBatis-Plus的常见功能及与MyBatis的区别,并通过实际案例展示其强大的扩展能力。MyBatis-Plus基于MyBatis,但旨在减少开发者的代码量,增强可......
  • 自定义数据源实现读写分离
    说明:读写分离,指把数据库的操作分为读操作、写操作(更新、新增、删除),在多数据库实例(如主从结构)下,把读操作和写操作访问的数据库分开,以此缓解单数据库的压力。读写分离实现的前提,需要数据库之间能同步数据,数据不一致,读写分离没有意义。数据同步可参考下面文章:MySQL主从结构......
  • Ant-design-vue Table 自定义列斑马纹效果
    在AntDesignVue的`Table`组件中,要实现自定义列的斑马纹效果,可以通过设置`rowClassName`属性来实现。以下是一个示例:```html<template> <a-table:data-source="data":rowClassName="rowClassName">  <a-table-columnv-for="columnincolumns":k......
  • 鸿蒙(HarmonyOS)实战开发篇——基于ArkUI现有能力实现自定义弹窗封装方案
    推荐看点鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总【OpenHarmony】鸿蒙南向开发保姆级知识点汇总~持续更新中……场景描述自定义弹窗是应用开发需要实现的基础功能,包括但不限于HarmonyOS开发者文档中定义的模态、半模态、Toast等形式,封装一个好用且和UI组件解耦的弹窗组......
  • Ant-design-vue Table 自定义列斑马纹效果
    业务需求在使用ant-design-vue的Table组件的时候,在某个业务模块的内因其承载的功能比较多,各个条件间界定不明显导致感官上十分的模糊,所以需要增加类似斑马纹的填充区分。table组件自带只支持行的斑马纹而我们需要的是列的斑马纹。table组件本身是不支持的所以只能通过其他方......