这个周末闲来无事,想起本科参加电子设计大赛做的题目就是频率计,连续两年都是这方面的题目,最后在大神的带领下,我也混个二等奖回家,现在回想起来那段暑假留在学校参加比赛,连续熬个几夜的经历真的十分宝贵,令人珍惜,队友的心心相惜着实难忘。记得当时我们的数据结果不是很好,好像最后只做到了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]索取。