前言:
本设计中使用AD的是ADI的AD7989-1,AD7989-1是18-bit,逐次逼近型模数转换器。支持CS模式、链模式。本设计中采用3线CS模式,此模式常用于连接到SPI接口的数字主机,关于AD7989的详细信息请参考芯片手册:AD7989-1_7989-5.pdf
一. AD接口
1)3线CS模式的时序图如下:
2)时序规格如下:
注:
(1) 查看数据手册,知道3线CS模式,SPI接口数据传输时,MSB是在CNV信号下降压后0.5~1个clk(50MHz)有效,之后的数据位都是在SCLK的下降沿有效。
(2) 因为SCLK下降沿数据变化(其它位数据有效),我们在上升沿读数据。因此在AD接口模块ad7989_dev_if.v中,sclk上升沿将sdo上的数据移入到serial_buffer中。
3)时序设计: 参考之前写的一篇博客:http://blog.csdn.net/yang2011079080010/article/details/51541083
二. AD接口的实现
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2016/05/16 16:33:43
// Design Name:
// Module Name: ad7989_dev_if
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 注:ADC采样率100KSPS
//
module ad7989_dev_if (
input ad_clk,rst_n,ad_start,//ad_start: ad_start是由PS部分发送过来的ad采样控制信号
input ad_sdo, //ad转换串型数据
output ad_cnv,
output ad_sclk,
output [17:0] ad_data,
output ad_data_rdy // data is available
);
parameter FPGA_CLOCK_FREQ = 50; //50MHz
parameter TCYC = 10;
parameter ADC_CYC_CNT = FPGA_CLOCK_FREQ * TCYC - 1;
localparam IDLE = 3'b001;
localparam READ = 3'b010;
localparam DONE = 3'b100;
reg [9:0] adc_tcyc_cnt;
reg [2:0] main_state,next_state;
reg [4:0] sclk_cnt;
reg [17:0] serial_buffer;
reg serial_read_done;
reg [17:0] ad_data_reg;
wire tmsb_almost_valid;
wire buffer_reset_s;
// wire [17:0] ad_data;
assign ad_cnv = (adc_tcyc_cnt > 25 && ad_start == 1) ? 1'b1 : 1'b0; //adc_tcyc_cnt = 25时,cnv变为低电平
assign tmsb_almost_valid = (adc_tcyc_cnt == 26 ) ? 1'b1 : 1'b0;
assign ad_sclk = (adc_tcyc_cnt > 6 && adc_tcyc_cnt < 25) ? ad_clk : 1'b0; //adc_tcyc_cnt = 24时读MSB
assign buffer_reset_s = (adc_tcyc_cnt == 26) ? 1'b1: 1'b0;
assign ad_data_rdy = (serial_read_done == 1'b1 && adc_tcyc_cnt == 5) ? 1'b1:1'b0;
assign ad_data = (ad_data_rdy == 1'b1) ? serial_buffer : ad_data_reg; //ad_data修改成ad_data_reg
//ad_data_reg缓存输出数据
always @(posedge ad_clk) begin
if(!rst_n) ad_data_reg <= 18'd0;
else ad_data_reg <= ad_data;
end
//adc_tcyc_cnt控制AD采样率
always @(posedge ad_clk,negedge rst_n) begin
if(~rst_n) adc_tcyc_cnt <= ADC_CYC_CNT;
else if(adc_tcyc_cnt != 0 && ad_start == 1) adc_tcyc_cnt <= adc_tcyc_cnt - 1'b1;
else adc_tcyc_cnt <= ADC_CYC_CNT;
end
always @(posedge ad_clk,negedge rst_n) begin
if(~rst_n) main_state <= IDLE;
else main_state <= next_state;
end
always @(*)
begin
case(main_state)
IDLE: begin
if(tmsb_almost_valid) next_state = READ;
else next_state <= IDLE;
end
READ: begin
if(sclk_cnt == 0) next_state = DONE;
else next_state = READ;
end
DONE: next_state = READ;
default: next_state = IDLE;
endcase
end
always @(posedge ad_clk) begin
case(main_state)
IDLE: serial_read_done <= 1'b1;
READ: serial_read_done <= 1'b0;
DONE: serial_read_done <= 1'b1;
default: serial_read_done <= 1'b0;
endcase
end
always @(posedge ad_clk) begin
if(buffer_reset_s == 1'b1) begin
serial_buffer <= 18'd0;
sclk_cnt <= 5'd18;
end
else if(sclk_cnt > 5'd0) begin
sclk_cnt <= sclk_cnt - 5'd1;
serial_buffer <= {serial_buffer[16:0],ad_sdo};
end
end
endmodule
版权声明:本文为yang2011079080010原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。