当前位置: 首页 > article >正文

[米联客-XILINX-H3_CZ08_7100] FPGA程序设计基础实验连载-18 SPI接口ADC采集驱动设计

软件版本:VIVADO2021.1

操作系统:WIN10 64bit

硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA

实验平台:米联客-MLK-H3-CZ08-7100开发板

板卡获取平台:https://milianke.tmall.com/

登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!

目录

1概述

2AD7606介绍

2.1芯片功能概述

2.2ADC功能框图

2.3 ADC转换控制时序

2.4 ADC SPI时序

3 硬件电路分析

4AD7606 FPGA程序设计

4.1 AD7606SPI.v

4.2 AD7606SPI程序分析

5 RTL仿真

6硬件接线

7实验结果


1概述

一些低速高精度的ADC/DAC都具有SPI接口,SPI的速率最高可以到几百M,另外由于接口少硬件设计简单,通信时序容易实现,而被广泛应用一些AD/DA数据采集场合,笔者在诸多的项目中都使用到了串行SPI接口的ADC/DAC芯片方案。

本文实现AD7606 SPI通信方式实现8路ADC信号采集,本文也将灵活使用SPI的通信时序,而不是拘泥于前面编写的通用的SPI接口。更多时候我们在FPGA项目应用中会根据实际的外设接口编写最佳的时序方案,来实现最佳的性能。

2AD7606介绍

2.1芯片功能概述

DAQ7606 数据采集卡,AD 转换芯片为AD7606-8,AD760-8 是16 位8 通道同步采样模数数据采集系统(DAS)。AD7606 内置模拟输入箝位保护、二阶抗混叠滤波器、跟踪保持放大器、16 位电荷再分配逐次逼近型ADC、灵活的数字滤波器、2.5V 基准电压源、基准电压缓冲以及高速串行和并行接口。

AD7606 采用5V单电源供电,可以处理±10V 和±5V 真双极性输入信号,同时所有通道均能以高达200 kSPS 的吞吐速率采样。输入箝位保护电路可以耐受最高达±16.5V 的电压。无论以何种采样频率工作,AD7606 的模拟输入阻抗均为1 MΩ。它采用单电源工作方式,具有片内滤波和高输入阻抗,因此无需驱动运算放大器和外部双极性电源。

AD7606 抗混叠滤波器的3 dB 截止频率为22 kHz;当采样速率为200 ksps 时,它具有40 dB 抗混叠抑制特性。灵活的数字滤波器采用引脚驱动,可以改善信噪比(SNR),并降低3 dB 带宽。

2.2ADC功能框图

很多FPGA程序开发者不懂硬件,这是不行的,FPGA程序员不需要去画PCB但是必须可以阅读硬件的芯片datasheet,从datasheet中提取关键的编程信息,并且原理图的外设和FPGA芯片之间的连接关系。

对于AD7606的datasheet大家可以网上查到,从这副图我们可以看到AD7606芯片的关键结构图。

1)、8路18bit ADC输入,支持双极性输入

2)、8路16bit ADC实际通过多路复用的方式实现的,内部真正只有1个16bitADC

3)、支持并口传输和SPI串行传输

4)、具有内部的2.5V基准,通常采用内部电压基准,可以省去一个外部基准。

5)、还有一些比如BUSY、FRSTDATA、信号需要下面继续根据datasheet了解。

2.3 ADC转换控制时序

CONVST时序-转换之后读取

CONVST时序-转换过程读取

AD7606支持2种时序转换,由于我们采用的时串行SPI模式,本身SPI读取数据就会耽误很多时间,所以必须采用第二种工作时序,才能确保200Kbps的采样率。

通过这个转换时序,我们需要把上图的时序中的所有信号作用搞清楚。

1、RESET信号用于对AD7606芯片的复位,复位的高电平时间参数tRESET=50ns,复位和转换信号CONVSTA/ONVSTB的上升沿时间参数t7=25ns

2、CONVSTA/ CONVSTB的低电平时间参数t2=40ns

3、CONVSTA/ CONVSTB如果不是同步,那么他们之间的时间差不能超过t5=0.5ms,我们这里时同时的

4、转换周期tCYCLE=5us

5、BUSY信号为高电平代表数据正在转换,转换时间参数tCONV为最大4.15us

6、CS信号和BUSY信号有一个时间参数t6不能大于25ns

由于设计FPGA接口芯片程序,都是和时序相关联的,所以了解了以上时序参数后,我们FPGA代码设计就要能够满足这些参数指标。

2.4 ADC SPI时序

当数据完成转换后,CS为电平期间,每个时钟的上升沿完成数据的采样,这里有一个FRSTDATA的表中,代表每次转换的第一个数据,这里实际可以不用这个信号,因为每次CS之后的第一个上升沿时钟我们就是开始采样数据,每16次完成一路ADC的采集。

对于AD7606具有8路ADC,DOUTA对于1~4路ADC通道,DOUTB对应5~8路ADC通道。而且ADC的2组4个通道可以一次性完成采集,也就是说16X4共计64个时钟上升沿完成4路ADC采集,DOUTA和DOUTB各4路。

3 硬件电路分析

硬件接口和子卡模块请阅读“附录 1”

配套工程的 FPGA PIN 脚定义路径为 fpga_prj/uisrc/04_pin/ fpga_pin.xdc。

4AD7606 FPGA程序设计

4.1 AD7606SPI.v

/*******************************AD7606 SPI串行采样*********************
--以下是米联客设计的AD7606 SPI串行采样驱动程序
--1.代码简洁,占用极少逻辑资源,代码结构清晰,逻辑设计严谨
--2.AD7606可以工作于并行模式,和串行模式,串行模式可以使用更少的IO
--3.AD7606最高可以工作于200K 8通道同时采样,默认就是工作于200K 采样,SPI_DIV 和T5US_DIV根据不同的系统时钟需要正确设置
*********************************************************************/

`timescale 1ns / 1ns//仿真时间刻度/精度

module uispi7606
(
input          I_ad_clk,         //系统时钟输入   
input           I_ad_rst,         //系统复位输入
input          I_ad_busy,        //ad7606 忙标志位
output [2:0]   O_ad_os,          //ad7606 过采样倍率选择,本驱动不使用
output          O_ad_cs,          //ad7606 CS信号输出,低电平SPI数据线输出AD7606寄存器数据
output reg        O_ad_sclk,        //ad7606 SCLK时钟输出
output         O_ad_rst,         //ad7606 复位输出
output          O_ad_convsta,     //ad7606 A组通道转换
output          O_ad_convstb,     //ad7606 B组通道转换
output          O_ad_range,       //ad7606 模拟输入范围,设置1范围:±10V,设置0范围±5V
input           I_O_ad_out_a,       //串行A组通道采集输入,V1,V2,V3,V4  
input           I_O_ad_out_b,       //串行B组通道采集输入, V5,V6,V7,V8  
output reg [63:0] O_ad_out_a,       //A组通道采集有效数据输出
output reg [63:0] O_ad_out_b,       //B组通道采集有效数据输出
output            O_ad_cap_en                  //采集完成使能
);
localparam  CLK_FREQ =  100000000;
localparam  SET_5US  =  5; //5us周期
localparam  T5US_DIV =  CLK_FREQ*SET_5US/1000000 -1; //计算5us 分频系数
localparam  SPI_DIV  =  CLK_FREQ/16666666 -1 ;//产生SPI时钟,设置最高16.666667MHZ

assign O_ad_range = 1'b1;    //±10V真直流输入范围
assign O_ad_os    = 3'b000;  //无过采样

//ad复位时间高电平,复位时间最少50ns
reg [23: 0] rst_cnt;
assign O_ad_rst   = !rst_cnt[23];
always@(posedge I_ad_clk or posedge I_ad_rst)begin        
    if(I_ad_rst)
        rst_cnt  <= 24'd0;
    else if(!rst_cnt[23])
        rst_cnt  <= rst_cnt + 1'b1;
end       
   
//设置采样频率,AD7606为8通道可以工作于200Kbps采样率,因此采样周期为5us
reg [9:0] tcnt5us;
wire cycle_end = (tcnt5us == T5US_DIV);
always@ (posedge I_ad_clk)begin   
     if(O_ad_rst)
         tcnt5us <= 10'd0;
     else if(tcnt5us < T5US_DIV)
         tcnt5us <= tcnt5us + 1'b1;
     else 
         tcnt5us <= 10'd0;
end

localparam [9:0] SPI_DIV1    = SPI_DIV/2; //半周期分频
reg [9:0] clk_div = 10'd0;//分频计数器   

//SPI 时钟分频,对于200K采样,设置20M时钟
always@(posedge I_ad_clk)begin
    if(clk_div < SPI_DIV)  
        clk_div <= clk_div + 1'b1;
    else 
        clk_div <= 10'd0;
end

//产生SPI时钟
wire clk_en1 = (clk_div == SPI_DIV1);// 半周期使能,控制输出0
wire clk_en2 = (clk_div == SPI_DIV);//  半周期使能,控制输出1

always@(posedge I_ad_clk)begin
     if(clk_en2) O_ad_sclk <= 1'b1; //输出高电平
    else if(clk_en1) O_ad_sclk <= 1'b0; //输出高低平
end

//AD转换状态机
reg [1:0] AD_S;
reg ad_convst; //ADC转换控制信号,A组通道和B组通道采用同一通道
//ADC工作于SPI模式,以及边读边转换模式,本次数据转换的同时,可以读出前一次转换的结果
assign O_ad_cs = ~((AD_S == 2'd3)&&I_ad_busy);//当AD7606工作在串行模式,cs=0代表输出通过SPI数据总线,输出之前的采样数据
assign O_ad_convsta = ad_convst; //ADC转换控制信号,A组通道和B组通道采用同一通道
assign O_ad_convstb = ad_convst; //ADC转换控制信号,A组通道和B组通道采用同一通道

always @(posedge I_ad_clk) 
begin
    if(O_ad_rst||I_ad_rst)begin
        ad_convst <= 1'b1;     
        AD_S <= 2'd0; 
    end
    else begin
        case(AD_S)  
        2'd0:if(clk_en2)begin    //clk_en2,控制SCLK输出1,因此这里相当于SCLK上升沿
             ad_convst <= 1'b0;  //设置ad_convst=0
             AD_S <= 2'd1;//下一状态
        end           
        2'd1:if(clk_en2)begin //延迟50ns,ad_convst低电平至少25ns,对于SCLK时钟是20MHZ,所以这里ad_convst低电平是50ns
             ad_convst <= 1'b1;//ad_convst 低电平50ns后拉高为高电平
             AD_S <= 2'd2;//下一状态
        end 
        2'd2:if(clk_en2&&I_ad_busy)//延迟50ns,并且等待busy高,只要ADC正常工作,busy必然为高,说明ADC处于采样转换下
             AD_S <= 2'd3;            
        2'd3:if(cycle_end)//ADC转换时间最大4.2us,5us周期结束,代表本次8通道完全采集结束
             AD_S <= 2'd0; //回到初始状态,进行下一次采样   
        endcase    
     end             
end

//SPI采样
reg [7 : 0] nbits; // bits计数器,用于计数完成了从AD7606 SPI总线读出的bits数
wire ad_cap_en_r1 = (nbits==8'd64); //数据同步输出使能
reg  ad_cap_en_r2 = 1'b0; //数据同步输出使能寄存一次
assign O_ad_cap_en = ({ad_cap_en_r1,ad_cap_en_r2}==2'b10);//高电平输出系统时钟的一个周期

always@(posedge I_ad_clk) begin //寄存一次ad_cap_en_r1
    ad_cap_en_r2 <= ad_cap_en_r1;
end

//当CS信号为低电平,每个SCL的下降沿输出采样数据,每组通道采样64bits
wire cap_en  = (!O_ad_cs)&&clk_en1&&(nbits<8'd64);

//ADC 串并转换模块
always@(posedge I_ad_clk) begin
    if(O_ad_rst) begin //ADC复位期间重置相关寄存器
        O_ad_out_a <= 64'd0; 
        O_ad_out_b <= 64'd0; 
        nbits    <= 8'd0;
    end 
    else if(O_ad_cs)begin //高电平,重置  nbits   
        nbits   <= 8'd0;                       
    end   
    else if(cap_en)begin//当CS信号为低电平,每个SCL的下降沿采样数据,每组通道采样64bits
        nbits    <= nbits + 1'b1; //
        O_ad_out_a <= {O_ad_out_a[62:0],I_O_ad_out_a};//保存A组通道数据,V1~V4,每个通道16bits
        O_ad_out_b <= {O_ad_out_b[62:0],I_O_ad_out_b};//保存B组通道数据,V5~V8,每个通道16bits
    end                                                                                                                                    
end
                  
endmodule

4.2 AD7606SPI程序分析

本文的SPI接口不是标准的SPI接口,主要区别是传输位宽达到了64bit,而之前我们学习SPI通信的文章是采用的标准的SPI接口去讲解的。标准的接口使用起来会比较方便,但是对于我们这种ADC采集往往编写专用的SPI接口更加实用。

本文的ADC采集程序主要需要注意3点:

1、ADC转换状态机

这个状态机需要设置相关的AD采集转换采集时序

2、SPI采样时序

这个比较简单,和我们之前讲解过标准的SPI接口类似,这里只是把位宽扩展到64bit

3、关键功能设计

1)、时钟单元

时钟单元通过时钟IP产生一个100MHZ的时钟用于AD转换采集时序的状态机以及SPI7606 IP核内部使用,SPI7606 IP核通过计数器,生成采样频率及SPI时钟。

//设置采样频率,AD7606为8通道可以工作于200Kbps采样率,因此采样周期为5us
reg [9:0] tcnt5us;
wire cycle_end = (tcnt5us == T5US_DIV);
always@ (posedge I_ad_clk)begin   
     if(O_ad_rst)
         tcnt5us <= 10'd0;
     else if(tcnt5us < T5US_DIV)
         tcnt5us <= tcnt5us + 1'b1;
     else 
         tcnt5us <= 10'd0;
end

localparam [9:0] SPI_DIV1    = SPI_DIV/2; //半周期分频
reg [9:0] clk_div = 10'd0;//分频计数器   

//SPI 时钟分频,对于200K采样,设置20M时钟
always@(posedge I_ad_clk)begin
    if(clk_div < SPI_DIV)  
        clk_div <= clk_div + 1'b1;
    else 
        clk_div <= 10'd0;
end

//产生SPI时钟
wire clk_en1 = (clk_div == SPI_DIV1);// 半周期使能,控制输出0
wire clk_en2 = (clk_div == SPI_DIV);//  半周期使能,控制输出1

always@(posedge I_ad_clk)begin
     if(clk_en2) O_ad_sclk <= 1'b1; //输出高电平
    else if(clk_en1) O_ad_sclk <= 1'b0; //输出高低平
end

2)、AD7606复位信号

AD7606的复位时间设置为41943040ns远大于芯片要求的50ns,所以满足要求。

//设置采样频率,AD7606为8通道可以工作于200Kbps采样率,因此采样周期为5us
reg [9:0] tcnt5us;
wire cycle_end = (tcnt5us == T5US_DIV);
always@ (posedge I_ad_clk)begin   
     if(O_ad_rst)
         tcnt5us <= 10'd0;
     else if(tcnt5us < T5US_DIV)
         tcnt5us <= tcnt5us + 1'b1;
     else 
         tcnt5us <= 10'd0;
end

localparam [9:0] SPI_DIV1    = SPI_DIV/2; //半周期分频
reg [9:0] clk_div = 10'd0;//分频计数器   

//SPI 时钟分频,对于200K采样,设置20M时钟
always@(posedge I_ad_clk)begin
    if(clk_div < SPI_DIV)  
        clk_div <= clk_div + 1'b1;
    else 
        clk_div <= 10'd0;
end

//产生SPI时钟
wire clk_en1 = (clk_div == SPI_DIV1);// 半周期使能,控制输出0
wire clk_en2 = (clk_div == SPI_DIV);//  半周期使能,控制输出1

always@(posedge I_ad_clk)begin
     if(clk_en2) O_ad_sclk <= 1'b1; //输出高电平
    else if(clk_en1) O_ad_sclk <= 1'b0; //输出高低平
end

3)、采样周期计数器

为了确保200kbps的采样率,我们需要设置一个时间计数器,每间隔5us,定义是T5US_DIV  = 10'd999进行下一次的采样。

//设置采样频率,AD7606为8通道可以工作于200Kbps采样率,因此采样周期为5us
reg [9:0] tcnt5us;
wire cycle_end = (tcnt5us == T5US_DIV);
always@ (posedge I_ad_clk)begin   
     if(O_ad_rst)
         tcnt5us <= 10'd0;
     else if(tcnt5us < T5US_DIV)
         tcnt5us <= tcnt5us + 1'b1;
     else 
         tcnt5us <= 10'd0;
end

4)、AD转换及采样状态机

AD7606芯片的模拟转数字过程由状态机控制,一些控制信号必须满足芯片手册给出的时序要求。我们可以结合程序,以及芯片给出的AD转换时序图分析程序。

上图种的,t1、 t5 、tReset等时间参数都可以在芯片手册里面找到,我们的状态机设计的AD控制及转换时序需要满足上图的要求。

//AD转换状态机
reg [1:0] AD_S;
reg ad_convst; //ADC转换控制信号,A组通道和B组通道采用同一通道
//ADC工作于SPI模式,以及边读边转换模式,本次数据转换的同时,可以读出前一次转换的结果
assign O_ad_cs = ~((AD_S == 2'd3)&&I_ad_busy);//当AD7606工作在串行模式,cs=0代表输出通过SPI数据总线,输出之前的采样数据
assign O_ad_convsta = ad_convst; //ADC转换控制信号,A组通道和B组通道采用同一通道
assign O_ad_convstb = ad_convst; //ADC转换控制信号,A组通道和B组通道采用同一通道

always @(posedge I_ad_clk) 
begin
    if(O_ad_rst||I_ad_rst)begin
        ad_convst <= 1'b1;     
        AD_S <= 2'd0; 
    end
    else begin
        case(AD_S)  
        2'd0:if(clk_en2)begin    //clk_en2,控制SCLK输出1,因此这里相当于SCLK上升沿
             ad_convst <= 1'b0;  //设置ad_convst=0
             AD_S <= 2'd1;//下一状态
        end           
        2'd1:if(clk_en2)begin //延迟50ns,ad_convst低电平至少25ns,对于SCLK时钟是20MHZ,所以这里ad_convst低电平是50ns
             ad_convst <= 1'b1;//ad_convst 低电平50ns后拉高为高电平
             AD_S <= 2'd2;//下一状态
        end 
        2'd2:if(clk_en2&&I_ad_busy)//延迟50ns,并且等待busy高,只要ADC正常工作,busy必然为高,说明ADC处于采样转换下
             AD_S <= 2'd3;            
        2'd3:if(cycle_end)//ADC转换时间最大4.2us,5us周期结束,代表本次8通道完全采集结束
             AD_S <= 2'd0; //回到初始状态,进行下一次采样   
        endcase    
     end             
end

4)、SPI采样单元

完成一次64bit数据传输需要64个时钟,采样的条件需满足三个(!ad_cs_o)&&clk_en1&&(nbits<8'd64),下降沿的时候开始采样,通过nbits计数。这里只要简单实用移位寄存器实现操作就可以。

//SPI采样
reg [7 : 0] nbits; // bits计数器,用于计数完成了从AD7606 SPI总线读出的bits数
wire ad_cap_en_r1 = (nbits==8'd64); //数据同步输出使能
reg  ad_cap_en_r2 = 1'b0; //数据同步输出使能寄存一次
assign O_ad_cap_en = ({ad_cap_en_r1,ad_cap_en_r2}==2'b10);//高电平输出系统时钟的一个周期

always@(posedge I_ad_clk) begin //寄存一次ad_cap_en_r1
    ad_cap_en_r2 <= ad_cap_en_r1;
end

//当CS信号为低电平,每个SCL的下降沿输出采样数据,每组通道采样64bits
wire cap_en  = (!O_ad_cs)&&clk_en1&&(nbits<8'd64);

//ADC 串并转换模块
always@(posedge I_ad_clk) begin
    if(O_ad_rst) begin //ADC复位期间重置相关寄存器
        O_ad_out_a <= 64'd0; 
        O_ad_out_b <= 64'd0; 
        nbits    <= 8'd0;
    end 
    else if(O_ad_cs)begin //高电平,重置  nbits   
        nbits   <= 8'd0;                       
    end   
    else if(cap_en)begin//当CS信号为低电平,每个SCL的下降沿采样数据,每组通道采样64bits
        nbits    <= nbits + 1'b1; //
        O_ad_out_a <= {O_ad_out_a[62:0],I_O_ad_out_a};//保存A组通道数据,V1~V4,每个通道16bits
        O_ad_out_b <= {O_ad_out_b[62:0],I_O_ad_out_b};//保存B组通道数据,V5~V8,每个通道16bits
    end                                                                                                                                    
end

5 RTL仿真

AD7606 SPI串行仿真模型驱动

/*******************************AD7606 SPI串行仿真模型驱动*********************
--以下是米联客设计的AD7606 SPI串行仿真驱动程序
--模拟AD7606的SPI 数据输出时序
*********************************************************************/

`timescale 1ns / 1ns//仿真时间刻度/精度

module ad7606(
output  reg     O_ad_busy,            //系统时钟输入   
input          I_ad_cs,              //ad7606 CS信号输入,低电平SPI数据线输出AD7606寄存器数据
input          I_ad_sclk,            //ad7606 SCLK时钟输入
input          I_ad_reset,           //ad7606 复位输入
input          I_ad_convsta,         //ad7606 A组通道转换开始
input          I_ad_convstb,         //ad7606 B组通道转换开始
input           I_ad_range,           //ad7606 模拟输入范围,设置1范围:±10V,设置0范围±5V
output          O_ad_out_a,           //A组通道采集有效数据输出
output          O_ad_out_b            //B组通道采集有效数据输出
);

//仿真信号,仿真busy忙
always @(posedge I_ad_convsta or posedge I_ad_reset) begin
if(I_ad_reset)begin
   O_ad_busy = 1'b0;
end
else begin
   #10;
   O_ad_busy = 1'b1;
   #4100; //busy 持续4.1us
   O_ad_busy = 1'b0;
end
end

reg       first ;        //通过first设置,第一个时钟,不移位  
reg[15:0] ad_da16 = 16'd0; //ad_da16,ADC的寄存器值
reg[63:0] ad_data;         //4个16bit ADC值,放入此寄存器移位输出

assign O_ad_out_a = ad_data[63]; //a通道,SPI数据总线输出
assign O_ad_out_b = ad_data[63]; //b通道,SPI数据总线输出

always @(posedge I_ad_sclk or posedge I_ad_reset ) begin
if(I_ad_reset)begin
   ad_data = 64'd0;
   first   = 1'b0;
end   
else begin
    if(!I_ad_cs) begin //当ad的CS为低电平,模拟AD寄存器串行数据输出
        if(first == 1'b0) //通过first设置,第一个时钟,不移位
           first = 1'b1;  
         else 
        ad_data[63:0] = {ad_data[62:0],ad_data[63]}; //模拟输出ADC的采集
   end
    else if(I_ad_cs)begin//当ad的CS为高电平
        first   = 1'b0;
        ad_data ={ad_da16,ad_da16,ad_da16,ad_da16};   //初始化需要发送的ADC模拟值
    end    
      
end
end

//每一个CS 上升沿,模拟ADC的值加1
always @(posedge I_ad_cs) begin 
    ad_da16 = ad_da16[12:0] + 1'b1;    
end   
   
   
endmodule
    

tb_AD7606SPI.v仿真文件

/*******************************AD7606 SPI串行仿真模型驱动*********************
--以下是米联客设计的AD7606 SPI串行仿真驱动程序
--模拟AD7606的SPI 数据输出时序
*********************************************************************/

`timescale 1ns / 1ns//仿真时间刻度/精度

module ad7606(
output  reg     O_ad_busy,            //系统时钟输入   
input          I_ad_cs,              //ad7606 CS信号输入,低电平SPI数据线输出AD7606寄存器数据
input          I_ad_sclk,            //ad7606 SCLK时钟输入
input          I_ad_reset,           //ad7606 复位输入
input          I_ad_convsta,         //ad7606 A组通道转换开始
input          I_ad_convstb,         //ad7606 B组通道转换开始
input           I_ad_range,           //ad7606 模拟输入范围,设置1范围:±10V,设置0范围±5V
output          O_ad_out_a,           //A组通道采集有效数据输出
output          O_ad_out_b            //B组通道采集有效数据输出
);

//仿真信号,仿真busy忙
always @(posedge I_ad_convsta or posedge I_ad_reset) begin
if(I_ad_reset)begin
   O_ad_busy = 1'b0;
end
else begin
   #10;
   O_ad_busy = 1'b1;
   #4100; //busy 持续4.1us
   O_ad_busy = 1'b0;
end
end

reg       first ;        //通过first设置,第一个时钟,不移位  
reg[15:0] ad_da16 = 16'd0; //ad_da16,ADC的寄存器值
reg[63:0] ad_data;         //4个16bit ADC值,放入此寄存器移位输出

assign O_ad_out_a = ad_data[63]; //a通道,SPI数据总线输出
assign O_ad_out_b = ad_data[63]; //b通道,SPI数据总线输出

always @(posedge I_ad_sclk or posedge I_ad_reset ) begin
if(I_ad_reset)begin
   ad_data = 64'd0;
   first   = 1'b0;
end   
else begin
    if(!I_ad_cs) begin //当ad的CS为低电平,模拟AD寄存器串行数据输出
        if(first == 1'b0) //通过first设置,第一个时钟,不移位
           first = 1'b1;  
         else 
        ad_data[63:0] = {ad_data[62:0],ad_data[63]}; //模拟输出ADC的采集
   end
    else if(I_ad_cs)begin//当ad的CS为高电平
        first   = 1'b0;
        ad_data ={ad_da16,ad_da16,ad_da16,ad_da16};   //初始化需要发送的ADC模拟值
    end    
      
end
end

//每一个CS 上升沿,模拟ADC的值加1
always @(posedge I_ad_cs) begin 
    ad_da16 = ad_da16[12:0] + 1'b1;    
end   
   
   
endmodule
    

仿真波形图

在5us的采样周期内,我们可以看到convsta/convsta从高到低后,AD转换开始,busy信号变高,之后CS变低,并且可以看到CS的结束在busy信号后,所以可以确保最后读取的数据时已经转换好的数据。

上图通过把数据以模拟信号的方式显示可以看到锯齿波。

6硬件接线

我们使用信号发生器产生两路频率分别为600HZ、300HZ,幅度为5V的正弦波。

(该教程为通用型教程,教程中仅展示一款示例开发板的连接方式,具体连接方式以所购买的开发板型号以及结合配套代码管脚约束为准。)

本实验注意采我们的cep跳线帽跳线1.8V,采用1.8V的FEP-DAQ7606子卡。请确保下载器和开发板已经正确连接,另外需要把核心板上的2P模式开关设置到JTAG模式,即ON ON,并且开发板已经上电。(注意JTAG端子不支持热插拔,而USB接口支持,所以在不通电的情况下接通好JTAG后,再插入USB到电脑,之后再上电,以免造成JTAG IO损坏)

7实验结果

设置Capture mode,设置cap_en信号为高时进行采样

测试输入波形只看通道1和通道2的输入,其他通道读者可以自行测试,结果一样。


http://www.kler.cn/a/282622.html

相关文章:

  • Springboot集成ElasticSearch实现minio文件内容全文检索
  • MySQL【五】
  • linux逻辑卷练习
  • 使用React和Vite构建一个AirBnb Experiences克隆网站
  • 五、函数封装及调用、参数及返回值、作用域、匿名函数、立即执行函数
  • Day 65 || SPFA、判断负权回路、bellman_ford之单源有限最短路
  • 操作系统信号量
  • 【数据结构-二维前缀和】力扣1314. 矩阵区域和
  • Linux学习(15)-网络编程:滑动窗口、拥塞控制、udp
  • HTML 总结
  • 数据挖掘之分类算法
  • Java框架Spring(一)
  • 向量数据库Faiss的搭建与使用|Faiss|向量数据库|高效检索|机器学习|大规模数据
  • 大模型Prompt提示设计简介(2):有效的建议
  • 在C语言中使用POSIX线程库(pthread)实现多线程编程
  • Redis多线程特性
  • CSS中禁用DOM事件
  • OpenCV绘图函数(12)绘制直线函数 line()的使用
  • 数学基础 -- 线性代数之向量基本概念
  • Flask+LayUI开发手记(五):树型表格实现数据展示与编辑
  • 开源 AI 智能名片 O2O 商城小程序在社交私域中的圈层价值
  • 数据库:笔记03SQL
  • geodatatool(地图资源工具)下载高德数据及数据共享
  • 设计模式之工厂模式和策略模式的区别
  • MFC工控项目实例之八选择下拉菜单添加打钩图标
  • 提高 Web 应用程序安全性的标准