上一节咱们体会了一把PS和PL是怎样联合开发的,这种ARM和FPGA联合规划是ZYNQ的精华地点。这一节咱们完结一个略微杂乱一点的功用——丈量不知道信号的频率,PS和PL经过AXI总线交互数据,完结咱们期望的功用。
怎么丈量数字信号的频率
最简略的办法——在一段时刻内计数
在咱们设定的时刻(Tpr) 内对被测信号的脉冲进行计数, 得Nx, Fx=Nx/Tpr。
Tpr 越大,测频精度越高。这种办法适合于高频信号,由于这儿或许会有一个被测信号周期的差错,丈量高频信号时差错小。
另一个变种——在一个周期内计数
在 被测信号一个周期内对基准时钟信号计数,得Nx, 基准时钟周期为T, 则Tx=T*Nx, Fx=1/Tx。
被测信号频率越低, 基准时钟频率越高,丈量精度越高。因而这种办法适用于低频信号。
二者结合——多个周期同步计数
这种办法的精华在于同步二字。
在计数时引进D触发器,在被测信号的上升沿计数(Ntest),实践丈量时刻是被测信号周期的整数倍,消除了或许的1 个周期的差错。
引进一个规范时钟信号(Fstd已知),在丈量被测信号频率的一起,对规范时钟脉冲进行计数(Nstd)。
它俩的计数时刻相同:Nstd/Fstd = Ntest / Ftest,所以Ftest=Fstd*Ntest/Nstd
增大Tpr或进步Fstd,能够进步丈量精度。这种办法高低频通吃。
今日咱们要选用的是第三种办法,体系框图如下:
可见看见后边两个计数模块的使能信号都是来自D触发器的输出,D触发器的输入是待测信号,也便是丈量时刻会是待测信号的整数倍,然后两个模块别离对待测信号和一个已知频率的时钟信号进行脉冲计数。
规划思路是:
得到计数值——PL完结
核算频率——PS完结
新建一个工程叫Freq_Meter,
创立根据AXI总线的频率计数模块
命名为Freq_EA,默许4个寄存器,增加端口:
增加用户逻辑,复位信号连接到体系的,寄存器0的第0位用于计数清零,第1位用于操控计数时刻:
// Add user logic here
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]; //复位
Tpr 《= slv_reg0[1]; //预置时刻
end
end
//—————————–
always @(posedge S_AXI_ACLK) begin //规范时钟
if(!clr)
Nstd 《= 32’d0;
else if(Tpr == 1‘b1)
Nstd 《= Nstd + 1’b1;
else
Nstd 《= Nstd;
end
//——————————
always @(posedge Ftest) begin //待测信号
if(!clr)
Ntest 《= 32‘d0;
else if(Tpr == 1’b1)
Ntest 《= Ntest + 1‘b1;
else
Ntest 《= Ntest;
end
// User logic ends
endmodule
计数值存到寄存器1,2中,寄存器0藏着给操控信号(Tpr,rst):
顶层文件里,增加端口号:
端口调用里的信号补齐:
打包好IP。然后回到之前的工程,增加这个IP到库里。
新建一个Block Design,增加zynq核,由于咱们需求两个信号,一个规范时钟(已知的,这儿用的是100M),一个待测信号,咱们都用PS发生,最终咱们能够看下这种办法测的究竟准禁绝:
增加Freq_EA,CLK1连接到Ftest上,连接好后的框图如下:
一系列次序操作,生成比特流后导入到SDK。
SDk部分规划
新建一个使用工程,首要仍是找到xparameters.h文件,找到咱们的IP的基地址:
列一下,前面的硬件规划是这样的:
寄存器0是给操控i信号的,第0位用于计数复位,第1为用于操控计数时刻,拉高时开端计数,然后拉低时中止计数,
寄存器1存的是规范时钟计数值,
寄存器2是待测信号计数值。
一些相关注释在代码后边
#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 低电平复位
usleep(10);
Xil_Out32(XPAR_FREQ_EA_V1_0_0_BASEADDR,3); //0000_0011 10us后开端计数
usleep(100000); //计数0.1s,最高计数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; //规范时钟是100MHz
printf(“The Frequency is %f MHz\r\n”,Freq_test);
sleep(2);
}
return 0;
}
上电,program FPGA,运转软件部分:
能够看见:
比照一下,能够准确到小数点后4位,仍是很准的:
小插曲:
打印函数不能用xil_printf(),由于Xilinx供给的打印函数不能打印浮点数。上面是我一开端用的xil_printf,成果数字出不来,要么计数一些古怪符号,下面是换成C自带的库函数就能够了
总结:
根据AXI总线的开发是很强壮的,PS能够和Pl交互,不管是操控信号仍是数据,乃至PL能够操控PS,这儿权当抛砖引玉。