0.序言
使用vivado聯(lián)合modelsim實(shí)現(xiàn)SPI協(xié)議基于ADC128S022進(jìn)行模擬信號(hào)連續(xù)采集。
1.SPI協(xié)議簡(jiǎn)介
(1)結(jié)構(gòu)
SPI是串行外設(shè)接口,是一種同步/全雙工/主從式接口。通常由四根信號(hào)線構(gòu)成:
CS_N:片選信號(hào),主從式接口,可以有多個(gè)從機(jī),用片選信號(hào)進(jìn)行從機(jī)選擇;
SCLK:串行時(shí)鐘線,由主機(jī)提供給從機(jī);
MISO:主機(jī)接收(采集)從機(jī)數(shù)據(jù)信號(hào)線;
MOSI:主機(jī)發(fā)送數(shù)據(jù)給從機(jī)信號(hào)線;
(2)工作模式
CKP:時(shí)鐘極性,用來(lái)配置時(shí)鐘線SCLK的電平處于何種狀態(tài)是空閑狀態(tài)或者有效狀態(tài);
CKE:時(shí)鐘相位,配置發(fā)送數(shù)據(jù)和采集數(shù)據(jù)分別是在時(shí)鐘上升沿還是下降沿;
2.ADC128S022芯片簡(jiǎn)介
(1)ADC128S022
ADC128S022模數(shù)轉(zhuǎn)換芯片有8個(gè)通道和12位的分辨率,時(shí)鐘要求時(shí)鐘頻率范圍在1~3.2MHz??梢钥闯鲂酒陌藗€(gè)通道(channel),在SPI協(xié)議中需要選擇采集數(shù)據(jù)的通道。
(2)信號(hào)時(shí)序
ADC128S022的SPI協(xié)議時(shí)序圖如下圖所示(由數(shù)據(jù)手冊(cè)截出):
3.實(shí)例
(1)結(jié)構(gòu)框圖
設(shè)計(jì)完成ADC128S022控制模塊,根據(jù)指定的通道產(chǎn)生控制信號(hào),控制ADC128S022進(jìn)行連續(xù)采集模擬信號(hào),最后采集的信號(hào)通過(guò)Sam_data傳出。
(2)時(shí)序圖
A 控制信號(hào)(截選,因?yàn)橥暾奶L(zhǎng)了只截了一部分)
(a)首先測(cè)試給控制模塊提供復(fù)位(rst_n)和通道選擇(channel),通道可以隨時(shí)變化(8個(gè)通道[0:7]);
(b)cs_n:片選信號(hào),低電平有效。只使用一片,在復(fù)位信號(hào)無(wú)效后,直接將片選拉低,讓芯片處于工作狀態(tài);
?cnt:分頻計(jì)數(shù)器,系統(tǒng)時(shí)鐘使用的是50MHz,ADC芯片時(shí)鐘范圍是0.8~3.2MHz,進(jìn)行20分頻到2.5MHz;20分頻,每10個(gè)時(shí)鐘周期產(chǎn)生一個(gè)標(biāo)志位,時(shí)鐘狀態(tài)反轉(zhuǎn)一次。
(d)sclk_cnt:sclk狀態(tài)計(jì)數(shù)器,共33個(gè)狀態(tài)[0:32],0為初始狀態(tài),其后32個(gè)狀態(tài)為有效循環(huán)狀態(tài);(為什么有效循環(huán)狀態(tài)是32?由上圖2(2)ADC的信號(hào)時(shí)序圖可以看出,數(shù)據(jù)采集周期sclk共16個(gè)周期,因?yàn)閿?shù)據(jù)發(fā)送和采集分別發(fā)送在上升沿和下降沿,所以將每個(gè)周期一分為2,對(duì)應(yīng)32個(gè)狀態(tài))
注意:這只給出了時(shí)序圖截選,完整的太長(zhǎng)了,所以對(duì)剩下部分進(jìn)行了描述:
rst_n:保持不變
channel[2:0]:可以隨時(shí)進(jìn)行變化,表示ADC采集的數(shù)據(jù)的通道,本文只仿真產(chǎn)生了一個(gè)通道的數(shù)據(jù);
cs_n:后續(xù)不變
cnt:一直保持0到9的10狀態(tài)循環(huán)計(jì)數(shù);
cnt_flag:當(dāng)cnt狀態(tài)為0,cnt_flag為1;
sclk_cnt:第一次循環(huán)會(huì)有0到32共33個(gè)狀態(tài),因?yàn)槎嗔艘粋€(gè)初始狀態(tài)0,后面循環(huán)一直為1到32共32個(gè)狀態(tài)的循環(huán);
注意:sclk這里給出只是為了顯示相對(duì)時(shí)序,后續(xù)會(huì)說(shuō)明;
B SPI信號(hào)(對(duì)照2(2)ADC芯片數(shù)據(jù)手冊(cè)給出的時(shí)序圖)
這里給出了一個(gè)周期
cs_n:片選信號(hào)開始已經(jīng)給出;
sclk:最開始有一個(gè)初始狀態(tài)(空閑狀態(tài),及開始的高電平段),其后對(duì)應(yīng)有效循環(huán)中的16個(gè)周期,每個(gè)周期先低后高,數(shù)字表示第幾個(gè)周期,l和h表示高低電平
din:FPGA控制模塊輸出給AD芯片的數(shù)據(jù),前8個(gè)狀態(tài)為控制信號(hào),其中第3到5個(gè)狀態(tài)需要輸出通道選擇信號(hào)(channel[2:])的高到低位;注意:數(shù)據(jù)一定要保證在sclk上升沿處采集,給值是在下降沿給;
DOUT:FPGA輸入的AD芯片采集的數(shù)據(jù);在第5到16個(gè)狀態(tài)得到AD采集的數(shù)據(jù)的高到低位,共12位;注意:ADC模塊采集數(shù)據(jù)是在SCLK下降沿,所以DOUT數(shù)據(jù)在SCLK上升沿是穩(wěn)定的
C SPI連續(xù)采集有效循環(huán)
B中給出了初始狀態(tài)和連續(xù)采集數(shù)據(jù)的有效循環(huán)狀態(tài),這里截出有效循環(huán)狀態(tài),以后一直保持有效循環(huán):
(3)test_bench
test_bench的核心是模擬ADC采集的數(shù)據(jù),并將采集的數(shù)據(jù)按照要求時(shí)序,按位賦給DOUT:
(A) 使用matlab產(chǎn)生模擬的ADC采集的數(shù)據(jù)
說(shuō)明:模擬數(shù)據(jù)為正弦信號(hào),信號(hào)頻率為10000Hz,以16進(jìn)制格式保存為txt文件。
clc
clear
close all
%% 模擬采集的正弦信號(hào)
fs=2.5e6/16; %采樣頻率
f0=10000; %信號(hào)頻率
sam_point=100; %采樣點(diǎn)數(shù)
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_point
if(s(nn)<0)
s_12bit(nn) = uint32(2^12+s(nn));
else
s_12bit(nn) = uint32(s(nn));
end
end
fp = fopen('s_sample.txt','w');
for nn=1:sam_point
fprintf(fp,'%X\n',s_12bit(nn));
end
fclose(fp);
(B) test_ben讀取模擬數(shù)據(jù)給DOUT
a首先:在initial模塊讀出產(chǎn)生的模擬的正弦波信號(hào);
$readmemh("D:/graduate_stuty/FPGA/interface/SPI/s_sample.txt",adc_sam_data);
我們要保證跨過(guò)初始狀態(tài),在每個(gè)有效循環(huán)狀態(tài)中的sclk的4到15個(gè)周期的下降沿把采集的數(shù)據(jù)的11到0位,依次賦給DOUT,保證控制模塊在sclk 5到16個(gè)狀態(tài)采集到采樣數(shù)據(jù)的12位。
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-628972.html
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芯片的輸出信號(hào)
input ADC_dout, //adc芯片給fpga的采樣數(shù)據(jù)
output reg [11:0] Sam_data
);
//片選信號(hào)產(chǎn)生模塊,只有一片,片選信號(hào)直接由復(fù)位信號(hào)產(chǎn)生
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
ADC_cs_n <= 1'b1;
else
ADC_cs_n <= 1'b0;
end
//20分頻器產(chǎn)生,每10個(gè)狀態(tài)產(chǎn)生一個(gè)狀態(tài)反轉(zhuǎn)標(biāo)志信號(hào)
reg [3:0] cnt_10;
reg cnt_flag;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_10 <= 4'd0;
cnt_flag <= 1'b0;
end
else if(ADC_cs_n == 1'b0)begin
if(cnt_10 == 4'd9)begin
cnt_10 <= 4'd0;
cnt_flag <= 1'b1;
end
else begin
cnt_10 <= cnt_10 + 1'b1;
cnt_flag <= 1'b0;
end
end
end
//SCLK狀態(tài)計(jì)數(shù)器產(chǎn)生,33個(gè)狀態(tài)[0:32],初始狀態(tài)為0,有效循環(huán)狀態(tài)為[1:32]
reg [5:0] sclk_cnt;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
sclk_cnt <= 6'd0;
else if(ADC_cs_n == 1'b0)begin
if(cnt_flag == 1'b1)
if(sclk_cnt == 6'd32)
sclk_cnt <= 6'd1;
else
sclk_cnt <= sclk_cnt + 1'b1;
else
sclk_cnt <= sclk_cnt;
end
else
sclk_cnt <=6'd0;
end
//SCLK,DIN賦值及DOUT數(shù)據(jù)采集
reg [11:0] Sam_data_r;//輸出數(shù)據(jù)存儲(chǔ)臨時(shí)變量
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
Sam_data <= 12'd0;
Sam_data_r <= 12'd0;
ADC_sclk <= 1'd1;
ADC_din <= 1'd0;
end
else begin
case(sclk_cnt)
6'd1:begin ADC_sclk <= 1'd0; end
6'd2:begin ADC_sclk <= 1'd1; Sam_data <= Sam_data_r; end
6'd3:begin ADC_sclk <= 1'd0; end
6'd4:begin ADC_sclk <= 1'd1; end
6'd5:begin ADC_sclk <= 1'd0; ADC_din <= channel[2]; end
6'd6:begin ADC_sclk <= 1'd1; end
6'd7:begin ADC_sclk <= 1'd0; ADC_din <= channel[1];end
6'd8:begin ADC_sclk <= 1'd1; end
6'd9:begin ADC_sclk <= 1'd0; ADC_din <= channel[0];end
6'd10:begin ADC_sclk <= 1'd1; Sam_data_r[11] <= ADC_dout; end
6'd11:begin ADC_sclk <= 1'd0; end
6'd12:begin ADC_sclk <= 1'd1; Sam_data_r[10] <= ADC_dout;end
6'd13:begin ADC_sclk <= 1'd0; end
6'd14:begin ADC_sclk <= 1'd1; Sam_data_r[9] <= ADC_dout;end
6'd15:begin ADC_sclk <= 1'd0; end
6'd16:begin ADC_sclk <= 1'd1; Sam_data_r[8] <= ADC_dout;end
6'd17:begin ADC_sclk <= 1'd0; end
6'd18:begin ADC_sclk <= 1'd1; Sam_data_r[7] <= ADC_dout;end
6'd19:begin ADC_sclk <= 1'd0; end
6'd20:begin ADC_sclk <= 1'd1; Sam_data_r[6] <= ADC_dout;end
6'd21:begin ADC_sclk <= 1'd0; end
6'd22:begin ADC_sclk <= 1'd1; Sam_data_r[5] <= ADC_dout;end
6'd23:begin ADC_sclk <= 1'd0; end
6'd24:begin ADC_sclk <= 1'd1; Sam_data_r[4] <= ADC_dout;end
6'd25:begin ADC_sclk <= 1'd0; end
6'd26:begin ADC_sclk <= 1'd1; Sam_data_r[3] <= ADC_dout;end
6'd27:begin ADC_sclk <= 1'd0; end
6'd28:begin ADC_sclk <= 1'd1; Sam_data_r[2] <= ADC_dout;end
6'd29:begin ADC_sclk <= 1'd0; end
6'd30:begin ADC_sclk <= 1'd1; Sam_data_r[1] <= ADC_dout;end
6'd31:begin ADC_sclk <= 1'd0; end
6'd32:begin ADC_sclk <= 1'd1; Sam_data_r[0] <= ADC_dout;end
default:begin Sam_data <= 12'd0; Sam_data_r <= 12'd0; ADC_sclk <= 1'd1; ADC_din <= 1'd0;end
endcase
end
end
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芯片的輸出信號(hào)
reg ADC_dout; //adc芯片給fpga的采樣數(shù)據(jù)
wire [11:0] Sam_data;
parameter T = 20;
//ADC采集的模擬信號(hào)
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
//時(shí)鐘信號(hào)產(chǎn)生模塊
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芯片的輸出信號(hào)
.ADC_dout (ADC_dout), //adc芯片給fpga的采樣數(shù)據(jù)
.Sam_data (Sam_data)
);
//模擬ADC采集的信號(hào)
//復(fù)位信號(hào)上升沿檢測(cè)
reg rst_n_r;
reg rst_flag=0;
always@(posedge clk)begin
rst_n_r <= rst_n;
end
always@(posedge clk)begin
if((rst_n==1'b1)&&(rst_n_r==1'b0))
rst_flag <= 1'b1;
else
rst_flag <= rst_flag;
end
//初始計(jì)數(shù)器
reg [3:0] cnt_12;
always@(posedge clk)begin
if(!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
//有效循環(huán)計(jì)數(shù)器20*16=320
reg [8:0] cnt_320;
reg cnt_320_flag;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_320 <= 9'd0;
cnt_320_flag <= 1'b0;
end
else if(cnt_12 == 4'd11)begin
if(cnt_320 == 9'd319)begin
cnt_320 <= 9'd0;
cnt_320_flag <= 1'b1;
end
else begin
cnt_320 <= cnt_320 + 1'b1;
cnt_320_flag <= 1'b0;
end
end
else begin
cnt_320 <= 9'd0;
cnt_320_flag <= 1'b0;
end
end
//數(shù)據(jù)地址
reg [6:0] addr_99;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
addr_99 <= 7'd0;
else if(cnt_320_flag == 1)begin
if(addr_99 == 7'd99)
addr_99 <= 0;
else
addr_99 <= addr_99 + 1'b1;
end
else
addr_99 <= addr_99;
end
//狀態(tài)賦值
reg [11:0] sam_data_r;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
ADC_dout <= 1'b0;
end
else begin
case(cnt_320)
9'd1:begin sam_data_r <= adc_sam_data[addr_99]; end
9'd81:begin ADC_dout <= sam_data_r[11]; end
9'd101:begin ADC_dout <= sam_data_r[10]; end
9'd121:begin ADC_dout <= sam_data_r[9]; end
9'd141:begin ADC_dout <= sam_data_r[8]; end
9'd161:begin ADC_dout <= sam_data_r[7]; end
9'd181:begin ADC_dout <= sam_data_r[6]; end
9'd201:begin ADC_dout <= sam_data_r[5]; end
9'd221:begin ADC_dout <= sam_data_r[4]; end
9'd241:begin ADC_dout <= sam_data_r[3]; end
9'd261:begin ADC_dout <= sam_data_r[2]; end
9'd281:begin ADC_dout <= sam_data_r[1]; end
9'd301:begin ADC_dout <= sam_data_r[0]; end
default:begin ADC_dout <= ADC_dout; end
endcase
end
end
endmodule
5.仿真結(jié)果
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-628972.html
到了這里,關(guān)于FPGA實(shí)現(xiàn)SPI協(xié)議基于ADC128S022進(jìn)行模擬信號(hào)采集的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!