【接口协议】FPGA实现SPI协议基于ADC128S022进行模拟信号采集

编程入门 行业动态 更新时间:2024-10-27 00:32:42

【接口<a href=https://www.elefans.com/category/jswz/34/1771197.html style=协议】FPGA实现SPI协议基于ADC128S022进行模拟信号采集"/>

【接口协议】FPGA实现SPI协议基于ADC128S022进行模拟信号采集

0.序言

使用vivado联合modelsim实现SPI协议基于ADC128S022进行模拟信号连续采集。

1.SPI协议简介

(1)结构

SPI是串行外设接口,是一种同步/全双工/主从式接口。通常由四根信号线构成:
CS_N:片选信号,主从式接口,可以有多个从机,用片选信号进行从机选择;
SCLK:串行时钟线,由主机提供给从机;
MISO:主机接收(采集)从机数据信号线;
MOSI:主机发送数据给从机信号线;

(2)工作模式

CKP:时钟极性,用来配置时钟线SCLK的电平处于何种状态是空闲状态或者有效状态;
CKE:时钟相位,配置发送数据和采集数据分别是在时钟上升沿还是下降沿;

2.ADC128S022芯片简介

(1)ADC128S022

ADC128S022模数转换芯片有8个通道和12位的分辨率,时钟要求时钟频率范围在1~3.2MHz。可以看出芯片的八个通道(channel),在SPI协议中需要选择采集数据的通道。

(2)信号时序

ADC128S022的SPI协议时序图如下图所示(由数据手册截出):

3.实例

(1)结构框图

设计完成ADC128S022控制模块,根据指定的通道产生控制信号,控制ADC128S022进行连续采集模拟信号,最后采集的信号通过Sam_data传出。

(2)时序图

A 控制信号(截选,因为完整的太长了只截了一部分)

(a)首先测试给控制模块提供复位(rst_n)和通道选择(channel),通道可以随时变化(8个通道[0:7]);
(b)cs_n:片选信号,低电平有效。只使用一片,在复位信号无效后,直接将片选拉低,让芯片处于工作状态;
©cnt:分频计数器,系统时钟使用的是50MHz,ADC芯片时钟范围是0.8~3.2MHz,进行20分频到2.5MHz;20分频,每10个时钟周期产生一个标志位,时钟状态反转一次。
(d)sclk_cnt:sclk状态计数器,共33个状态[0:32],0为初始状态,其后32个状态为有效循环状态;(为什么有效循环状态是32?由上图2(2)ADC的信号时序图可以看出,数据采集周期sclk共16个周期,因为数据发送和采集分别发送在上升沿和下降沿,所以将每个周期一分为2,对应32个状态)
注意:这只给出了时序图截选,完整的太长了,所以对剩下部分进行了描述:
rst_n:保持不变
channel[2:0]:可以随时进行变化,表示ADC采集的数据的通道,本文只仿真产生了一个通道的数据;
cs_n:后续不变
cnt:一直保持0到9的10状态循环计数;
cnt_flag:当cnt状态为0,cnt_flag为1;
sclk_cnt:第一次循环会有0到32共33个状态,因为多了一个初始状态0,后面循环一直为1到32共32个状态的循环;
注意:sclk这里给出只是为了显示相对时序,后续会说明;
B SPI信号(对照2(2)ADC芯片数据手册给出的时序图)
这里给出了一个周期

cs_n:片选信号开始已经给出;
sclk:最开始有一个初始状态(空闲状态,及开始的高电平段),其后对应有效循环中的16个周期,每个周期先低后高,数字表示第几个周期,l和h表示高低电平
din:FPGA控制模块输出给AD芯片的数据,前8个状态为控制信号,其中第3到5个状态需要输出通道选择信号(channel[2:])的高到低位;注意:数据一定要保证在sclk上升沿处采集,给值是在下降沿给;
DOUT:FPGA输入的AD芯片采集的数据;在第5到16个状态得到AD采集的数据的高到低位,共12位;注意:ADC模块采集数据是在SCLK下降沿,所以DOUT数据在SCLK上升沿是稳定的
C SPI连续采集有效循环
B中给出了初始状态和连续采集数据的有效循环状态,这里截出有效循环状态,以后一直保持有效循环:

(3)test_bench

test_bench的核心是模拟ADC采集的数据,并将采集的数据按照要求时序,按位赋给DOUT:
(A) 使用matlab产生模拟的ADC采集的数据
说明:模拟数据为正弦信号,信号频率为10000Hz,以16进制格式保存为txt文件。

clc
clear
close all
%% 模拟采集的正弦信号
fs=2.5e6/16;        %采样频率
f0=10000;           %信号频率
sam_point=100;      %采样点数
t=0:1/fs:1-1/fs;
s=sin(2*pi*f0*t);
s=s.*(2^11);
plot(t(1:100),s(1:100))
s_12bit=zeros(1,sam_point);
for nn=1:sam_pointif(s(nn)<0) s_12bit(nn) = uint32(2^12+s(nn)); elses_12bit(nn) = uint32(s(nn)); end
end
fp = fopen('s_sample.txt','w');
for nn=1:sam_pointfprintf(fp,'%X\n',s_12bit(nn));
end
fclose(fp);

(B) test_ben读取模拟数据给DOUT
a首先:在initial模块读出产生的模拟的正弦波信号;

        $readmemh("D:/graduate_stuty/FPGA/interface/SPI/s_sample.txt",adc_sam_data);

我们要保证跨过初始状态,在每个有效循环状态中的sclk的4到15个周期的下降沿把采集的数据的11到0位,依次赋给DOUT,保证控制模块在sclk 5到16个状态采集到采样数据的12位。

4.完整代码

(1)ADC128S022控制模块

module SPI_interface(input                   clk     ,input                   rst_n   ,input       [2:0]       channel ,output reg              ADC_cs_n,output reg              ADC_sclk,output reg              ADC_din ,   //fpga给adc芯片的输出信号input                   ADC_dout,    //adc芯片给fpga的采样数据    output reg  [11:0]      Sam_data);//片选信号产生模块,只有一片,片选信号直接由复位信号产生always@(posedge clk or negedge rst_n)beginif(!rst_n)ADC_cs_n <= 1'b1;else    ADC_cs_n <= 1'b0;end //20分频器产生,每10个状态产生一个状态反转标志信号reg [3:0]   cnt_10;reg         cnt_flag;always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_10 <= 4'd0;cnt_flag <= 1'b0; endelse if(ADC_cs_n == 1'b0)beginif(cnt_10 == 4'd9)begincnt_10 <= 4'd0;cnt_flag <= 1'b1;endelse begincnt_10 <= cnt_10 + 1'b1;cnt_flag <= 1'b0;end           endend//SCLK状态计数器产生,33个状态[0:32],初始状态为0,有效循环状态为[1:32]reg [5:0] sclk_cnt;always@(posedge clk or negedge rst_n)beginif(!rst_n)sclk_cnt <= 6'd0;else if(ADC_cs_n == 1'b0)beginif(cnt_flag == 1'b1)if(sclk_cnt == 6'd32)sclk_cnt <= 6'd1;else sclk_cnt <= sclk_cnt +  1'b1;elsesclk_cnt <= sclk_cnt;endelse sclk_cnt <=6'd0;end//SCLK,DIN赋值及DOUT数据采集reg [11:0]  Sam_data_r;//输出数据存储临时变量always@(posedge clk or negedge rst_n)beginif(!rst_n)beginSam_data <= 12'd0;Sam_data_r <= 12'd0;ADC_sclk <= 1'd1;ADC_din <= 1'd0;endelse begincase(sclk_cnt)6'd1:begin  ADC_sclk <= 1'd0; end6'd2:begin  ADC_sclk <= 1'd1; Sam_data <= Sam_data_r; end6'd3:begin  ADC_sclk <= 1'd0; end6'd4:begin  ADC_sclk <= 1'd1; end6'd5:begin  ADC_sclk <= 1'd0; ADC_din <= channel[2]; end6'd6:begin  ADC_sclk <= 1'd1; end6'd7:begin  ADC_sclk <= 1'd0; ADC_din <= channel[1];end6'd8:begin  ADC_sclk <= 1'd1; end6'd9:begin  ADC_sclk <= 1'd0; ADC_din <= channel[0];end6'd10:begin ADC_sclk <= 1'd1; Sam_data_r[11] <= ADC_dout; end6'd11:begin ADC_sclk <= 1'd0; end6'd12:begin ADC_sclk <= 1'd1; Sam_data_r[10] <= ADC_dout;end6'd13:begin ADC_sclk <= 1'd0; end6'd14:begin ADC_sclk <= 1'd1; Sam_data_r[9] <= ADC_dout;end6'd15:begin ADC_sclk <= 1'd0; end6'd16:begin ADC_sclk <= 1'd1; Sam_data_r[8] <= ADC_dout;end6'd17:begin ADC_sclk <= 1'd0; end6'd18:begin ADC_sclk <= 1'd1; Sam_data_r[7] <= ADC_dout;end6'd19:begin ADC_sclk <= 1'd0; end6'd20:begin ADC_sclk <= 1'd1; Sam_data_r[6] <= ADC_dout;end6'd21:begin ADC_sclk <= 1'd0; end6'd22:begin ADC_sclk <= 1'd1; Sam_data_r[5] <= ADC_dout;end6'd23:begin ADC_sclk <= 1'd0; end6'd24:begin ADC_sclk <= 1'd1; Sam_data_r[4] <= ADC_dout;end6'd25:begin ADC_sclk <= 1'd0; end6'd26:begin ADC_sclk <= 1'd1; Sam_data_r[3] <= ADC_dout;end6'd27:begin ADC_sclk <= 1'd0; end6'd28:begin ADC_sclk <= 1'd1; Sam_data_r[2] <= ADC_dout;end6'd29:begin ADC_sclk <= 1'd0; end6'd30:begin ADC_sclk <= 1'd1; Sam_data_r[1] <= ADC_dout;end6'd31:begin ADC_sclk <= 1'd0; end6'd32:begin ADC_sclk <= 1'd1; Sam_data_r[0] <= ADC_dout;enddefault:begin  Sam_data <= 12'd0; Sam_data_r <= 12'd0; ADC_sclk <= 1'd1; ADC_din <= 1'd0;endendcaseendend
endmodule

(2)test_bench

`timescale 1ns / 1ps
module SPI_interface_tb;reg                 clk     ;reg                 rst_n   ;reg       [2:0]     channel ;wire                ADC_cs_n;wire                ADC_sclk;wire                ADC_din ;   //fpga给adc芯片的输出信号reg                 ADC_dout;    //adc芯片给fpga的采样数据    wire  [11:0]        Sam_data;parameter T = 20;//ADC采集的模拟信号reg [11:0] adc_sam_data [0:99];//初始化模块initial begin$readmemh("D:/graduate_stuty/FPGA/interface/SPI/s_sample.txt",adc_sam_data);clk = 1'b0;     rst_n = 1'b0;  channel = 3'd0;#(T*4);rst_n = 1'b1;  channel = 3'd3;end//时钟信号产生模块always#(T/2) clk = ~clk;//模块例化SPI_interface u_SPI_interface(.clk            (clk     ),.rst_n          (rst_n   ),.channel        (channel ),.ADC_cs_n       (ADC_cs_n),.ADC_sclk       (ADC_sclk),.ADC_din        (ADC_din ),   //fpga给adc芯片的输出信号.ADC_dout       (ADC_dout),    //adc芯片给fpga的采样数据    .Sam_data       (Sam_data));//模拟ADC采集的信号//复位信号上升沿检测reg rst_n_r;reg rst_flag=0;always@(posedge clk)beginrst_n_r <= rst_n;endalways@(posedge clk)beginif((rst_n==1'b1)&&(rst_n_r==1'b0))rst_flag <= 1'b1;elserst_flag <= rst_flag;end//初始计数器reg [3:0] cnt_12;always@(posedge clk)beginif(!rst_n)cnt_12 <= 0;else if((rst_flag==1)&&(cnt_12<4'd11))cnt_12 <= cnt_12 +1'b1;else       cnt_12 <= cnt_12;end//有效循环计数器20*16=320reg [8:0] cnt_320;reg       cnt_320_flag;always@(posedge clk or negedge rst_n)beginif(!rst_n)begin cnt_320 <= 9'd0;cnt_320_flag <= 1'b0;endelse if(cnt_12 == 4'd11)beginif(cnt_320 == 9'd319)begincnt_320 <= 9'd0;cnt_320_flag <= 1'b1;endelse begin    cnt_320 <= cnt_320 + 1'b1;cnt_320_flag <= 1'b0;endendelse begincnt_320 <= 9'd0;cnt_320_flag <= 1'b0;endend//数据地址reg [6:0] addr_99;always@(posedge clk or negedge rst_n)beginif(!rst_n)addr_99 <= 7'd0;else if(cnt_320_flag == 1)beginif(addr_99 == 7'd99)addr_99 <= 0;elseaddr_99 <= addr_99 + 1'b1;endelseaddr_99 <= addr_99;end//状态赋值reg [11:0] sam_data_r;always@(posedge clk or negedge rst_n)beginif(!rst_n)beginADC_dout <= 1'b0;endelse begincase(cnt_320) 9'd1:begin sam_data_r <= adc_sam_data[addr_99]; end9'd81:begin  ADC_dout <= sam_data_r[11]; end9'd101:begin ADC_dout <= sam_data_r[10]; end9'd121:begin ADC_dout <= sam_data_r[9]; end9'd141:begin ADC_dout <= sam_data_r[8]; end9'd161:begin ADC_dout <= sam_data_r[7]; end9'd181:begin ADC_dout <= sam_data_r[6]; end9'd201:begin ADC_dout <= sam_data_r[5]; end9'd221:begin ADC_dout <= sam_data_r[4]; end9'd241:begin ADC_dout <= sam_data_r[3]; end9'd261:begin ADC_dout <= sam_data_r[2]; end9'd281:begin ADC_dout <= sam_data_r[1]; end9'd301:begin ADC_dout <= sam_data_r[0]; enddefault:begin ADC_dout <= ADC_dout; endendcaseend end 
endmodule

5.仿真结果

更多推荐

【接口协议】FPGA实现SPI协议基于ADC128S022进行模拟信号采集

本文发布于:2024-02-08 21:35:18,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1675307.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:协议   信号   接口   FPGA   SPI

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!