回答

收藏

米尔MYD-C7Z020开发板试用10---自定义IP实现频率测量

#其他 #其他 1431 人阅读 | 0 人回复 | 2019-12-15

本帖最后由 武器哈12 于 2019-12-15 16:55 编辑

    传统的数字频率测量方法有脉冲计数法和周期测频法,但这两种方法分别适合测量高频和低频信号,具有较大的局限性。多周期同步测频法以脉冲计数法为基础,并对之进行改进,实现了全频段的等精度测量,且测量精度大大提高,因此多周期同步测频法在目前测频系统中得到越来越广泛的应用。    一。频率测量原理
    所谓频率,就是周期性信号在单位时间内变化的次数。频率测量的方法有很多种,在模拟电路中有比较测频法,响应测频法,游标法等;在数字电路中,有基于脉冲计数测频原理的直接测频法、周期测频法、在直接测频法的基础上发展起来的多周期同步测频法和全同步数字测频法。本小节简单介绍计数测频法和周期测频法,重点分析多周期同步测频法的工作原理。
    (1)脉冲计数法
    脉冲计数法原理:在预置的闸门时间 Tpr 内对被测脉冲信号进行计数,得到脉冲数Nx,通过公式 Fx=Nx/Tpr 可计算出单位时间内脉冲个数,即被测信号的频率。该方法测量误差来源于闸门时间 Tpr 和计数值 Nx,且被测信号频率 Fx 与闸门开启时间 Tpr 越大,测频精度越高。因此,该方法适合于高频率信号的测量。

    (2)周期测频法
    预置测频闸门开启时间 Tpr 等于被测信号的周期 Tx,通过计数器在闸门时间 Tpr内基准时钟信号进行计数,若得到的基准时钟信号脉冲个数为 Nx,且基准时钟周期为T,则可按公式 Tx=T*Nx 计算出待测信号的周期 Tx,然后换算得到被测信号频率。该方法的测量误差来源于基准时钟信号和计数误差,且测量相对误差与被测频率 Fx 成正比,与基准时钟频率 F 成反比。所以,当被测信号频率越低,基准时钟频率越高时,周期测频法的测量精度越高。

     二、等精度频率测量设计
     使用AXI-lite总线,定义如下几个寄存器:


    本文方案实现亦分为两部分,一是计数值的获取,该部分由测频控制模块(PL 实现)完成;二是结果的计算及显示,该部分工作由 PS 完成。采用板载的50MHz时钟信号作为标准信号,可使测量的最大相对误差比较小。
    (3)频率测量PL部分代码
  • module myipfrequency_v1_0_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

  • // 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
  •     //-----------自己制造一个CLKTEST-------------------
  •      reg rCLKTEST;
  •      reg [3:0]i;
  •      always @(posedge S_AXI_ACLK)
  •            if(S_AXI_ARESETN == 1'b0)
  •            begin
  •                i <= 4'd0;
  •                rCLKTEST <= 1'd0;
  •            end
  •            else
  •                case(i)
  •                 0,1,2,3:
  •                 begin
  •                     rCLKTEST <= 1'b0;
  •                     i <= i + 1'b1;
  •                 end
  •                 4,5,6:
  •                 begin
  •                     rCLKTEST <= 1'b1;
  •                     i <= i + 1'b1;
  •                 end
  •                 7:
  •                 begin
  •                     rCLKTEST <= 1'b0;
  •                     i <= 4'd0;
  •                 end
  •                endcase

  •     wire CLKTEST = rCLKTEST;
  •     //------------------------------
  •     always @(posedge CLKTEST)
  •         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
  •     endmodule
    (4)PS部分代码设计
  • #include <stdio.h>
  • #include "sleep.h"
  • #include "xil_io.h"

  • #define myipBaseAddr   0x43C00000
  • #define reg0  (myipBaseAddr + 0)   //1:Tpr闸门信号,0:clr复位清零信号(offset:0x00)
  • #define reg1  (myipBaseAddr + 4)   //数据寄存器Nstd(offset:0x04)
  • #define reg2  (myipBaseAddr + 8)   //数据寄存器Ntest(offset:0x08)

  • int main()
  • {
  • long  Nstd,Ntest;
  • float temp;

  • while(1){

  • Xil_Out32(reg0,0x00);
  • Nstd = Xil_In32(reg1);
  • Ntest = Xil_In32(reg2);
  • printf("first Nstd = %lu\n",Nstd);
  • printf("first Ntest = %lu\n",Ntest);

  • //砸门打开一秒
  • Xil_Out32(reg0,0x03);
  • sleep(1);
  • Xil_Out32(reg0,0x01);

  • //--1s之后再次读取并打印
  • Nstd = Xil_In32(0x43C00000 + 4);
  • Ntest = Xil_In32(0x43C00000 + 8);
  • printf("second Nstd = %d\n",Nstd);
  • printf("second Ntest = %d\n",Ntest);
  • temp = Nstd;
  • printf("Ftest = %.5fM\n",50*Ntest/temp);

  • }
  • return 0;
  • }    
下载程序后,实验结果如下:

附上我的工程:
MYiRfre_detect.zip (18.92 MB, 下载次数: 1)








分享到:
回复

使用道具 举报

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

本版积分规则

关闭

站长推荐上一条 /3 下一条