基于FPGA的AD7606并行接口驱动程序仿真及上板

作者:数字站

前文通过FPGA实现了AD7606的并行接口驱动代码,本文仿真该接口程序及上板测试。手里只有Altera的板子,因此使用Quartus + Modelsim实现,但是最后会提供Quartus和Vivado两个工程,文末获取。

Altera板子及模块如下所示所示:
图1 开发环境.png

图1 开发环境

Matlab生成二进制波形文件

Matlab对应程序如下所示,200KHz采样率生成2KHz的正弦波,最后将生成的数据以二进制的形式写入waveform_bit.txt文件中。

f1=2000; %频率为2KHz
Fs=200000;%采样频率为200KHz
N=16;   %量化位数
%% 产生并量化信号
t=0:1/Fs:1;
s=sin(2*pi*f1*t);%产生2KHz正弦波
s=s/max(abs(s));%归一化处理
Q_s=round(s*(2^(N-1)-1));%16比特量化

%% 绘制时域波形
t=0:1/Fs:100/Fs;t=t*1000; %设置显示数据范围
t_in_s=Q_s(1:length(t));
figure(1);
subplot(111)
plot(t,t_in_s);%显示滤波之前的波形数据
xlabel('时间(ms)');ylabel('幅度(V)');title('2kHz信号时域波形');

%% 将波形数据以二进制形式输出到文件中,便于后续TestBentch读取;
fid=fopen('D:\dome\ad7606\ad7606\matlab\waveform_bit.txt','w');
for i=1:length(Q_s)
    B_s=dec2bin(Q_s(i)+(Q_s(i)<0)*2^N,N);
    for j=1:N
        if B_s(j)=='1'
            tb=1;
        else
            tb=0;
        end
        fprintf(fid,'%d',tb);  
    end
    fprintf(fid,'\r\n');
end
fprintf(fid,';'); 
fclose(fid);

生成波形如下所示,横坐标的单位忽略,不重要。

图2 matlab生成波形.png

图2 matlab生成波形

这份程序拿到后要自己修改19行的waveform_bit.txt文件路径,生成的二进制波形文件如下所示。图片
图3 生成的二进制文件.png

图3 生成的二进制文件

工程仿真

Altera开发使用Quartus和Modelsim联合仿真,对应的TestBentch如下所示,使用readmemb函数读取waveform_bit.txt文件中前DATA_NUM个16位二进制数据,然后在busy下降沿后输出,给AD7606八个通道输入相同数据。

`timescale 1 ns/1 ns
//--###############################################################################################
//--#
//--# File Name    : test
//--# Designer    : 数字站
//--# Tool      : Quartus 2018.1
//--# Design Date  : 2024.11.3
//--# Description  : 
//--# Version    : 0.0
//--# Coding scheme  : UTF-8(If the Chinese comment of the file is garbled, please do not save it and check whether the file is opened in GBK encoding mode)
//--#
//--###############################################################################################
module test();
    localparam          CYCLE    =   20    ;//系统时钟周期,单位ns,默认10ns;
    localparam          RST_TIME  =   10    ;//系统复位持续时间,默认10个系统时钟周期;
    
    reg                 clk         =   'd1     ;//系统时钟,100MHz;
    reg                 rst_n       =   'd1     ;//系统复位,高电平有效;
    reg                 busy        =   'd0     ;//转换完成指示信号,下降沿有效;
    reg                 frstdata    =   'd0     ;//指示采集到的第一个数据;
    reg     [15 : 0]    adc_din     =   'd0     ;//AD7606所采集到的十六位数据信号;

    wire                cs                      ;//AD7606片选信号,读数据时拉低;
    wire                rd                      ;//AD7606读使能信号,读数据时拉低,下降沿时AD7606将数据发送到数据线上,上升沿时可以读出数据;
    wire                reset                   ;//AD7606复位信号,高电平有效,每次复位至少拉高50ns;
    wire    [2 : 0]     os                      ;//AD7606过采样模式信号,默认不使用过采样;
    wire                convst                  ;//AD7606采样启动信号,无效时高电平,采样计数器完成时拉低两个时钟;

    //待测试的模块例化
    top u_top (
        .clk        ( clk       ),//系统时钟,50MHz;
        .rst_n      ( rst_n     ),//系统复位,低电平有效;
        .busy       ( busy      ),//转换完成指示信号,下降沿有效;
        .frstdata   ( frstdata  ),//指示采集到的第一个数据;
        .adc_din    ( adc_din   ),//AD7606所采集到的十六位数据信号;
        .cs         ( cs        ),//AD7606片选信号,读数据时拉低;
        .rd         ( rd        ),//AD7606读使能信号,读数据时拉低,下降沿时AD7606将数据发送到数据线上,上升沿时可以读出数据;
        .reset      ( reset     ),//AD7606复位信号,高电平有效,每次复位至少拉高50ns;
        .os         ( os        ),//AD7606过采样模式信号,默认不使用过采样;
        .convst     ( convst    ) //AD7606采样启动信号,无效时高电平,采样计数器完成时拉低两个时钟;
    );
    
    initial begin
        forever #(CYCLE/2) clk = ~clk;//生成本地时钟50M 
    end

    //产生复位信号
    localparam DATA_NUM = 400;
    reg [15:0] stimulus[1:DATA_NUM];
    integer Pattern;
    initial begin
        $readmemb("waveform_bit.txt",stimulus);//从外部TX文件(waveform_bit.txt)读入数据作为测试激励;
        Pattern = 1;
        #1;
        rst_n = 1'b0;
        #(CYCLE*RST_TIME);
        rst_n = 1'b1;
        repeat(20)@(posedge clk);
        repeat(DATA_NUM)begin
            @(posedge convst);
            busy <= 1'b1;
            repeat(30)@(posedge clk);
            busy <= 1'b0;
            @(negedge rd);
            adc_din <= stimulus[Pattern];
            Pattern <= Pattern + 1;
            @(posedge clk);
        end
        repeat(20)@(posedge clk);//延迟20个时钟周期;
        $stop;
    end

endmodule

为了让readmemb函数正确读取文件,请将waveform_bit.txt文件放到ad7606\quartus\prj\simulation\modelsim这个路径下,如下所示。虽然readmemb函数可以指定路径,但是Modelsim联合仿真会失败,所以直接将文件放在Modelsim指定路径下最保险。

图4 waveform_bit.txt文件存放路径.png

图4 waveform_bit.txt文件存放路径

当Quartus和Modelsim联合设置完成后,打开工程后如下操作,使用Modelsim联合仿真。

图5 联合仿真.png

图5 联合仿真

首先将modelsim自动加载的信号删除,如下所示。

图6 删除信号.png

图6 删除信号

如下所示,依次点击File,Load,Macro File…加载之前保存的波形文件。

图片图7 加载波形数据.png

图7 加载波形数据

如下所示,选择wave.do波形文件。

图8 打开wave.do文件.png

图8 打开wave.do文件

然后重新运行仿真文件,如下所示。

图9 重新运行仿真.png

图9 重新运行仿真

运行结果如下所示,紫色信号为采集的波形数据,由于8个通道输入相同数据,因此每轮采集数据相同。

10.png

图10 整体时序

上电后delay_cnt计数结束后,首先拉高reset八个时钟周期复位ad7606,然后状态机回到空闲状态,且将rst_flag拉高表示已经复位过ad7606了。

图11 复位时序.png

图11 复位时序

如下所示,当delay_cnt计数结束且rst_flag为高电平时,之后把convst拉低三个时钟,等待busy下降沿后,产生片选cs和读使能rd信号,在rd上升沿依次读取八个通道的输入数据。

图12 采集数据时序.png

图12 采集数据时序

如下所示,片选cs和读使能rd在rdata_cnt等于2时拉低,在rdata_cnt等于6时拉高,同时采集adc_din的数据。

图13 采集数据.png

图13 采集数据

仿真到此结束,有兴趣可以使用matlab生成多组数据,然后在不同通道输入不同波形数据,则可以看到各个通道采集的数据。

注意Vivado版本Test文件的readmemb函数路径必须使用”/”,否则读取数据会失败,如下所示。

图14 波形文件路径.png

图14 波形文件路径

上板测试

工程综合完毕后,如下所示,依次点击tools,Signal Tap Logic Analyzer打开Signal Tap II抓取接口时序。

图15 打开Signal Tap II.png

图15 打开Signal Tap II

开发板接上下载器并且上电后,如下所示,点击Setup,然后加载sof文件并下载。

图16 下载程序.png

图16 下载程序

设置convst上升沿作为触发条件,然后点击单次触发,如下所示。

图17 单次触发.png

图17 单次触发

采集时序如下所示:

图18 采集数据.png

图18 采集数据

如下所示,第一个comvst第一个上升沿在第0个采样点的位置,第二个上升沿在第500个采样点的位置,而采样时钟频率为100MHz,计算可得convst频率为200KHz,也就是采样率200KHz。

图19 采样时序.png

图19 采样时序

如下所示,当检测到busy后,开始产生片选和读使能,在读使能的上升沿采集通道转换后的数据。由于开发板的AD7606引脚处于悬空状态,电压大约为1.7V,转换成数字信号的数据为(1.7/5)*2^15 = 11141 = 16’h2B85,与下面采集的数据也大致差不多。

图20 采集数据时序.png

图20 采集数据时序

其余几个通道采集的数据如下,都基本相等,为16’h2EC0左右。

图21 八个通道数据时序.png

图21 八个通道数据时序

如下所示,使用黄色跳线帽将通道0与GND短接,其余七个通道依旧悬空。

图22 短接通道零引脚.png

图22 短接通道零引脚

然后Signal Tap II单次采集数据,结果如下所示,通道0采集的数据为0,其余通道采集的数据依旧大致保持不变。

图23 采集数据.png

图23 采集数据

接口时序验证结束,可以在公众号后台回复“AD7606并行接口驱动程序“(不包括引号)即可获取工程,包含Quartus和Vivado工程。

文章来源:数字站

最新文章

最新文章