多精度频率计--转载我之前的blog的内容

这个周末闲来无事,想起本科参加电子设计大赛做的题目就是频率计,连续两年都是这方面的题目,最后在大神的带领下,我也混个二等奖回家,现在回想起来那段暑假留在学校参加比赛,连续熬个几夜的经历真的十分宝贵,令人珍惜,队友的心心相惜着实难忘。记得当时我们的数据结果不是很好,好像最后只做到了20多中号频率,可惜单片机的主频有限。当时檀老师就提出来让我用FPGA做,无赖当时可能对自己不够自信,所以没有实现,当时主要也是纠结FPGA把数据发给上位机这一块,担心数据误码,可能那4天三夜无法解决,于是便选择了保守方案,现在我便想在ZYNQ上实现该功能。

主要涉及以下:A)PL部分逻辑设计

B)自定义AXI4-Lite的IP的建立

C)通过AXI4-Lite总线实现PS与PL间的数据传递

D)PS控制输入输出外设

整体框图:

FCLK_CLK0为工作时钟:100M

FCLK_CLK1为待测时钟:67M(66.66672)

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

用于围绕,实现了闸门信号与被测信号的同步,从而解决了上述问题频脉的等精度测量。从脉冲计数测频法原理可以看出,该方法闸门信号与被测信号不同步,也就是说在时间轴上两路信号随机出现,相对位置具有随机性。因此即使在相同的闸门时间内,被测脉冲计数结果也不一定相同,闸门时间大于N Ttestclk时,越接近(N +1) Ttestclk,误差越大。为了解决这个问题,利用D触发器使闸门信号在被测信号的上升沿产生动作,这样以来测量的实际门控时间刚好是被测信号周期的整数倍,这样就消除了被测信号引起的1个周期的误差。

测频主控模块结构图如下:

不难写出的Verilog代码:

reg cnt_en;
always@(posedge STD_CLK or negedge CLR)
if(!CLR)
	cnt_en<=1'b0;
else if(TPR)
	cnt_en <= 1'b1;
else 
	cnt_en <=1'b0;
	
	//stdCNT
always@(posedge STD_CLK or negedge CLR)
if(!CLR)
	Nstd<='d0;
else if(cnt_en)
	Nstd <= Nstd+1'b1;
else 
	Nstd <=Nstd;


	//TESTCNT
always@(posedge TEST_CLK or negedge CLR)
if(!CLR)
	Ntest<='d0;
else if(cnt_en)
	Ntest <= Ntest+1'b1;
else 
	Ntest <=Ntest;

PS寄存器功能划分:

reg0:控制寄存器0(偏移量:0x00)

分配CLR = slv_reg0 [0];

分配TPR = slv_reg0 [1];

reg1:数据寄存器Nstd(offset:0x04)标准时钟计数值

reg2:数据寄存器Ntest(offset:0x08)待测信号计数值

所以在AXI总线上加入代码:

// Add user logic here
//assign {TPR,CLR}=slv_reg0[1:0];
reg[31:0] Nstd;
reg[31:0] Ntest;
wire	CLR;
wire 	TPR;
assign CLR=slv_reg0[0];
assign TPR=slv_reg0[1];
/* assign Nstd=slv_reg1;	
assign Ntest=slv_reg2; */	

assign slv_reg1=Nstd;	
assign slv_reg2=Ntest;
	
fre	fre_inst(
    .STD_CLK	(S_AXI_ACLK),//把时钟提上去?
    .TPR		(TPR	),
    .TEST_CLK	(TEST_CLK),
    .CLR		(CLR	),
    .Nstd		(Nstd	),
    .Ntest     ( Ntest   )
);

SDK代码:

	 Xil_Out32(FRE_AQC_BASE,0);
	 usleep(10);
	 Xil_Out32(FRE_AQC_BASE,3);
	 usleep(100000);
	 fre_std  =Xil_In32(FRE_AQC_BASE+4);
	 fre_test =Xil_In32(FRE_AQC_BASE+8);
	 //fre_val =(double)fre_test/fre_std*100;//100M
	 fre_val =(double)fre_test/fre_std*244.444458;//250M
	 printf("f=%fMHZ\r\n",fre_val);

PL部分我们需要在闸门型号打开时,我们需要对标准时钟StdClock以及待测时钟TestClock分别进行计数。并通过AXI4-Lite总线读取数据。

误差分析:串口打印数据为66.666779,实际为:66.66672,精度完全满足要求

为了验证更高频率,我开始提高AXI的时钟,设为:

FCLK_CLK0为工作时钟:250M

FCLK_CLK1为待测时钟:203M(209.523819)

实验结果:

完全满足要求!中间发生一个小插曲,我第一个实验是通过在外部引出的PIN,然后用杜邦线连接,当进行第二个实验时,就是提高一下时钟频率而已,发现读出数据为0 ,后来想想,输入频率都200多中号了,杜邦线连接肯定引入干扰,所以我决定在ZYNQ内部链接起来,这样就不会干扰信号。最终结果验证了我的想法!

源代码可以发我邮箱[email protected]索取。

猜你喜欢

转载自blog.csdn.net/Laplace666/article/details/83827039