上一節(jié)我們體驗(yàn)了一把PS和PL是怎樣聯(lián)合開發(fā)的,這種ARM和FPGA聯(lián)合設(shè)計(jì)是ZYNQ的精華所在。這一節(jié)我們實(shí)現(xiàn)一個(gè)稍微復(fù)雜一點(diǎn)的功能——測(cè)量未知信號(hào)的頻率,PS和PL通過AXI總線交互數(shù)據(jù),實(shí)現(xiàn)我們希望的功能。
如何測(cè)量數(shù)字信號(hào)的頻率
最簡(jiǎn)單的辦法——在一段時(shí)間內(nèi)計(jì)數(shù)
在我們?cè)O(shè)定的時(shí)間(Tpr) 內(nèi)對(duì)被測(cè)信號(hào)的脈沖進(jìn)行計(jì)數(shù), 得Nx, Fx=Nx/Tpr。
Tpr 越大,測(cè)頻精度越高。這種方法適合于高頻信號(hào),因?yàn)檫@里可能會(huì)有一個(gè)被測(cè)信號(hào)周期的誤差,測(cè)量高頻信號(hào)時(shí)誤差小。
另一個(gè)變種——在一個(gè)周期內(nèi)計(jì)數(shù)
在 被測(cè)信號(hào)一個(gè)周期內(nèi)對(duì)基準(zhǔn)時(shí)鐘信號(hào)計(jì)數(shù),得Nx, 基準(zhǔn)時(shí)鐘周期為T, 則Tx=T*Nx, Fx=1/Tx。
被測(cè)信號(hào)頻率越低, 基準(zhǔn)時(shí)鐘頻率越高,測(cè)量精度越高。因此這種方法適用于低頻信號(hào)。
二者結(jié)合——多個(gè)周期同步計(jì)數(shù)
這種方法的精髓在于同步二字。
在計(jì)數(shù)時(shí)引入D觸發(fā)器,在被測(cè)信號(hào)的上升沿計(jì)數(shù)(Ntest),實(shí)際測(cè)量時(shí)間是被測(cè)信號(hào)周期的整數(shù)倍,消除了可能的1 個(gè)周期的誤差。
引入一個(gè)標(biāo)準(zhǔn)時(shí)鐘信號(hào)(Fstd已知),在測(cè)量被測(cè)信號(hào)頻率的同時(shí),對(duì)標(biāo)準(zhǔn)時(shí)鐘脈沖進(jìn)行計(jì)數(shù)(Nstd)。
它倆的計(jì)數(shù)時(shí)間相同:Nstd/Fstd = Ntest / Ftest,所以Ftest=Fstd*Ntest/Nstd
增大Tpr或提高Fstd,可以提高測(cè)量精度。這種方法高低頻通吃。
今天我們要采用的是第三種方法,系統(tǒng)框圖如下:
可見看見后面兩個(gè)計(jì)數(shù)模塊的使能信號(hào)都是來自D觸發(fā)器的輸出,D觸發(fā)器的輸入是待測(cè)信號(hào),也就是測(cè)量時(shí)間會(huì)是待測(cè)信號(hào)的整數(shù)倍,然后兩個(gè)模塊分別對(duì)待測(cè)信號(hào)和一個(gè)已知頻率的時(shí)鐘信號(hào)進(jìn)行脈沖計(jì)數(shù)。
設(shè)計(jì)思路是:
得到計(jì)數(shù)值——PL完成
計(jì)算頻率——PS完成
新建一個(gè)工程叫Freq_Meter,
創(chuàng)建基于AXI總線的頻率計(jì)數(shù)模塊
命名為Freq_EA,默認(rèn)4個(gè)寄存器,添加端口:
添加用戶邏輯,復(fù)位信號(hào)連接到系統(tǒng)的,寄存器0的第0位用于計(jì)數(shù)清零,第1位用于控制計(jì)數(shù)時(shí)間:
reg clr;
reg Tpr;
reg[31:0] Nstd;
reg[31:0] Ntest;
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]; //復(fù)位
Tpr 《= slv_reg0[1]; //預(yù)置時(shí)間
end
end
//-----------------------------
always @(posedge S_AXI_ACLK) begin //標(biāo)準(zhǔn)時(shí)鐘
if(!clr)
Nstd 《= 32’d0;
else if(Tpr == 1‘b1)
Nstd 《= Nstd + 1’b1;
else
Nstd 《= Nstd;
end
//------------------------------
always @(posedge Ftest) begin //待測(cè)信號(hào)
if(!clr)
Ntest 《= 32‘d0;
else if(Tpr == 1’b1)
Ntest 《= Ntest + 1‘b1;
else
Ntest 《= Ntest;
end
// User logic ends
endmodule
計(jì)數(shù)值存到寄存器1,2中,寄存器0留著給控制信號(hào)(Tpr,rst):
頂層文件里,添加端口號(hào):
端口調(diào)用里的信號(hào)補(bǔ)齊:
打包好IP。然后回到之前的工程,添加這個(gè)IP到庫里。
新建一個(gè)Block Design,添加zynq核,因?yàn)槲覀冃枰獌蓚€(gè)信號(hào),一個(gè)標(biāo)準(zhǔn)時(shí)鐘(已知的,這里用的是100M),一個(gè)待測(cè)信號(hào),我們都用PS產(chǎn)生,最后我們可以看下這種方法測(cè)的到底準(zhǔn)不準(zhǔn):
添加Freq_EA,CLK1連接到Ftest上,連接好后的框圖如下:
一系列順序操作,生成比特流后導(dǎo)入到SDK。
SDk部分設(shè)計(jì)
新建一個(gè)應(yīng)用工程,首先還是找到xparameters.h文件,找到我們的IP的基地址:
列一下,前面的硬件設(shè)計(jì)是這樣的:
寄存器0是給控制i信號(hào)的,第0位用于計(jì)數(shù)復(fù)位,第1為用于控制計(jì)數(shù)時(shí)間,拉高時(shí)開始計(jì)數(shù),然后拉低時(shí)停止計(jì)數(shù),
寄存器1存的是標(biāo)準(zhǔn)時(shí)鐘計(jì)數(shù)值,
寄存器2是待測(cè)信號(hào)計(jì)數(shù)值。
一些相關(guān)注釋在代碼后邊
#include
#include “xil_io.h”
#include “sleep.h”
#include “xparameters.h”
#include “xil_types.h”
int main(){
u32 N_std,N_test;
double Freq_test;
while(1){
Xil_Out32(XPAR_FREQ_EA_V1_0_0_BASEADDR,0); //0000_0000 低電平復(fù)位
usleep(10);
Xil_Out32(XPAR_FREQ_EA_V1_0_0_BASEADDR,3); //0000_0011 10us后開始計(jì)數(shù)
usleep(100000); //計(jì)數(shù)0.1s,最高計(jì)數(shù)32位,不能溢出了
N_std =Xil_In32(XPAR_FREQ_EA_V1_0_0_BASEADDR+4);
N_test =Xil_In32(XPAR_FREQ_EA_V1_0_0_BASEADDR+8);
xil_printf(“N_std=%d\r\n”,N_std);
xil_printf(“N_test=%d\r\n”,N_test);
Freq_test =(double)100.0*N_test/N_std; //標(biāo)準(zhǔn)時(shí)鐘是100MHz
printf(“The Frequency is %f MHz\r\n”,F(xiàn)req_test);
sleep(2);
}
return 0;
}
上電,program FPGA,運(yùn)行軟件部分:
可以看見:
對(duì)比一下,可以精確到小數(shù)點(diǎn)后4位,還是很準(zhǔn)的:
小插曲:
打印函數(shù)不能用xil_printf(),因?yàn)閄ilinx提供的打印函數(shù)不能打印浮點(diǎn)數(shù)。上面是我一開始用的xil_printf,結(jié)果數(shù)字出不來,要么計(jì)數(shù)一些奇怪符號(hào),下面是換成C自帶的庫函數(shù)就可以了
總結(jié):
基于AXI總線的開發(fā)是很強(qiáng)大的,PS可以和Pl交互,不管是控制信號(hào)還是數(shù)據(jù),甚至PL可以控制PS,這里權(quán)當(dāng)拋磚引玉。
評(píng)論
查看更多