1. 程式人生 > >多精度頻率計--轉載我之前的blog的內容

多精度頻率計--轉載我之前的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;
[email protected](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
[email protected](posedge STD_CLK or negedge CLR)
if(!CLR)
	Nstd<='d0;
else if(cnt_en)
	Nstd <= Nstd+1'b1;
else 
	Nstd <=Nstd;


	//TESTCNT
[email protected]
(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]索取。