ADS1256芯片手册阅读笔记
特性:
24bit;高达30kSPS的数据输出速率;支持4通道差分输入或者8通道单端模拟输入;SPI串行接口;超低噪声。
内部结构:
电气特性:
引脚功能介绍:
串行接口时序:
输入复用
- AN0~AN7八个模拟输入;
- 八个输入可以是4组差分输入或者8个单端输入;
- 每个通道可以通过multiplexer register 配置成差分正输入(或者差分负输入);
ADS1256原理图:
使用模式:
单次转换模式:
spi发送写寄存器wreg命令发送对应寄存器的值发送同步命令发送WAKEUP命令发送数据转换命令等待drdy为低电平时读取24bit数据。
单一通道的单次转换设计流程图:
// SPI驱动
`// ============================================================
// File Name : spi_driver.v
// Function : spi driver
// Author : snjshping
// Date : 20191213
// ============================================================
module spi_driver
(
input Clock,
input Rst_n,
input iSpi_start_sig,
input [23:0] iSpi_wr_data,
input iSpi_miso,
output reg [23:0] oSpi_rd_data,
output oSpi_rd_end,
output oSpi_wr_end,
output reg oSpi_mosi,
output oSpi_sclk
);
reg [23:0] rWr_data_buff;
reg [23:0] rRd_data_buff;
reg [4:0] rClk_cnt;
reg rClk_valid;
assign oSpi_wr_end = (rClk_cnt[4:0] == 5’d30) ? 1’b1 : 1’b0;
assign oSpi_rd_end = (rClk_cnt[4:0] == 5’d30) ? 1’b1 : 1’b0;
always @(posedge Clock or negedge Rst_n)
begin
if(Rst_n == 1’b0)
begin
rClk_cnt[4:0] <= 5’d0;
end
else if(iSpi_start_sig == 1’b1)
begin
rClk_cnt[4:0] <= rClk_cnt[4:0] + 5’d1;
end
else
begin
rClk_cnt[4:0] <= 5’d0;
end
end
always @(posedge Clock or negedge Rst_n)
begin
if(Rst_n == 1’b0)
begin
oSpi_mosi <= 1’b0;
rWr_data_buff[23:0] <= 24’d0;
end
else
begin
case(rClk_cnt[4:0])
5’d0 : begin
oSpi_mosi <= 1’b0;
rWr_data_buff[23:0] <= iSpi_wr_data[23:0];
end
5’d1 : oSpi_mosi <= rWr_data_buff[23];
5’d2 : oSpi_mosi <= rWr_data_buff[22];
5’d3 : oSpi_mosi <= rWr_data_buff[21];
5’d4 : oSpi_mosi <= rWr_data_buff[20];
5’d5 : oSpi_mosi <= rWr_data_buff[19];
5’d6 : oSpi_mosi <= rWr_data_buff[18];
5’d7 : oSpi_mosi <= rWr_data_buff[17];
5’d8 : oSpi_mosi <= rWr_data_buff[16];
5’d9 : oSpi_mosi <= rWr_data_buff[15];
5’d10 : oSpi_mosi <= rWr_data_buff[14];
5’d11 : oSpi_mosi <= rWr_data_buff[13];
5’d12 : oSpi_mosi <= rWr_data_buff[12];
5’d13 : oSpi_mosi <= rWr_data_buff[11];
5’d14 : oSpi_mosi <= rWr_data_buff[10];
5’d15 : oSpi_mosi <= rWr_data_buff[9];
5’d16 : oSpi_mosi <= rWr_data_buff[8];
5’d17 : oSpi_mosi <= rWr_data_buff[7];
5’d18 : oSpi_mosi <= rWr_data_buff[6];
5’d19 : oSpi_mosi <= rWr_data_buff[5];
5’d20 : oSpi_mosi <= rWr_data_buff[4];
5’d21 : oSpi_mosi <= rWr_data_buff[3];
5’d22 : oSpi_mosi <= rWr_data_buff[2];
5’d23 : oSpi_mosi <= rWr_data_buff[1];
5’d24 : oSpi_mosi <= rWr_data_buff[0];
default : oSpi_mosi <= 1’b0;
endcase
end
end
always @(negedge Clock or negedge Rst_n)
begin
if(Rst_n == 1’b0)
begin
rClk_valid <= 1’b0;
rRd_data_buff[23:0] <= 24’d0;
oSpi_rd_data[23:0] <= 24’d0;
end
else
begin
case(rClk_cnt[4:0])
5’d0 : rClk_valid <= 1’b0;
5’d1 : rClk_valid <= 1’b1;
5’d2 : rRd_data_buff[23] <= iSpi_miso;
5’d3 : rRd_data_buff[22] <= iSpi_miso;
5’d4 : rRd_data_buff[21] <= iSpi_miso;
5’d5 : rRd_data_buff[20] <= iSpi_miso;
5’d6 : rRd_data_buff[19] <= iSpi_miso;
5’d7 : rRd_data_buff[18] <= iSpi_miso;
5’d8 : rRd_data_buff[17] <= iSpi_miso;
5’d9 : rRd_data_buff[16] <= iSpi_miso;
5’d10 : rRd_data_buff[15] <= iSpi_miso;
5’d11 : rRd_data_buff[14] <= iSpi_miso;
5’d12 : rRd_data_buff[13] <= iSpi_miso;
5’d13 : rRd_data_buff[12] <= iSpi_miso;
5’d14 : rRd_data_buff[11] <= iSpi_miso;
5’d15 : rRd_data_buff[10] <= iSpi_miso;
5’d16 : rRd_data_buff[9] <= iSpi_miso;
5’d17 : rRd_data_buff[8] <= iSpi_miso;
5’d18 : rRd_data_buff[7] <= iSpi_miso;
5’d19 : rRd_data_buff[6] <= iSpi_miso;
5’d20 : rRd_data_buff[5] <= iSpi_miso;
5’d21 : rRd_data_buff[4] <= iSpi_miso;
5’d22 : rRd_data_buff[3] <= iSpi_miso;
5’d23 : rRd_data_buff[2] <= iSpi_miso;
5’d24 : rRd_data_buff[1] <= iSpi_miso;
5’d25 : begin
rClk_valid <= 1’b0;
rRd_data_buff[0] <= iSpi_miso;
end
5’d26 : oSpi_rd_data[23:0] <= rRd_data_buff[23:0];
default : rClk_valid <= 1’b0;
endcase
end
end
assign oSpi_sclk = rClk_valid & Clock;
endmodule
/**************************************************************
spi_driver u0_spi_driver
(
.oSpi_sclk (),
.Rst_n (),
.iSpi_start_en (),
.iSpi_wr_data (),
.iSpi_iSpi_miso (),
.oSpi_oSpi_mosi (),
.oSpi_oSpi_sclk (),
.oSpi_rd_data (),
.oSpi_rd_done (),
.oSpi_wr_done ()
);
**************************************************************/
// 时钟分频
//=============================================================
// Module : freq_devide_test.v
// Function : 分频测试
// Date : 20191207
=============================================================
module freq_divide #
(
parameter FREQ_DIVIDE_FACTOR = 5’d24
)
(
input Clock ,
input Rst_n ,
output reg oDivide_clk
);
reg [4:0] rDivide_cnt;
always @ ( posedge Clock or negedge Rst_n )
begin
if(Rst_n == 1’b0)
begin
rDivide_cnt[4:0] <= 5’d0;
end
else
begin
rDivide_cnt[4:0] <= (rDivide_cnt[4:0] == FREQ_DIVIDE_FACTOR) ? 5’d0 : (rDivide_cnt[4:0] + 5’d1);
end
end
always @ ( posedge Clock or negedge Rst_n )
begin
if(Rst_n == 1’b0)
begin
oDivide_clk <= 1’b1;
end
else
begin
oDivide_clk <= (rDivide_cnt[4:0] == FREQ_DIVIDE_FACTOR) ? (~oDivide_clk) : oDivide_clk;
end
end
endmodule`
// 顶层模块:```
// ============================================================
// File Name : ads1256_sample.v
// Function : realize A/D convert of ads1256 with 24bit
// Author : snjshping
// Date : 20191226
// Version : 2.0
// ============================================================
module ads1256_sample #
(
// register value
parameter STATUS_REG = 8’h01, // 状态寄存器
parameter MUX_REG = 8’h1f, // 通道寄存器
parameter ADCON_REG = 8’h20, // 控制寄存器
parameter DRATE_REG = 8’hf0, // 数据速率寄存器
parameter IO_REG = 8’he0 // IO寄存器
)
(
input Clock ,
input Rst_n ,
input iStart_conv_en ,
input iAd_dout ,
input iAd_drdy ,
output oAd_sclk ,
output oAd_din ,
output reg oAd_cs_n ,
output oAd_reset_n ,
output [3:0] oAd_dio ,
output reg [23:0] oAd_value ,
output reg oAd_conv_done
);
// ============================================================
// parameter define
// ============================================================
// register address
localparam STATUS_REG_ADDR = 4’h0;
localparam MUX_REG_ADDR = 4’h1;
localparam ADCON_REG_ADDR = 4’h2;
localparam DRATE_REG_ADDR = 4’h3;
localparam IO_REG_ADDR = 4’h4;
// command define
localparam WAKEUP = 8’h00;
localparam RDATA = 8’h01;
localparam RDATAC = 8’h03;
localparam SDATAC = 8’h0f;
localparam SELFCAL = 8’hf0;
localparam SELFOCAL = 8’hf1;
localparam SELFGCAL = 8’hf2;
localparam SYSOCAL = 8’hf3;
localparam SYSGCAL = 8’hf4;
localparam SYNC = 8’hfc;
localparam STANDBY = 8’hfd;
localparam RESET = 8’hfe;
// state define
localparam ST_IDLE = 10’b00_0000_0001;
localparam ST_TX_STATUS = 10’b00_0000_0010;
localparam ST_TX_ADCON = 10’b00_0000_0100;
localparam ST_TX_DRATE = 10’b00_0000_1000;
localparam ST_TX_IO = 10’b00_0001_0000;
localparam ST_TX_MUX = 10’b00_0010_0000;
localparam ST_TX_RDATA = 10’b00_0100_0000;
localparam ST_WAITING = 10’b00_1000_0000;
localparam ST_READ_DATA = 10’b01_0000_0000;
localparam ST_CONV_END = 10’b10_0000_0000;
//=============================================================
// wire define
//=============================================================
wire wSpi_rd_end ;
wire wSpi_wr_end ;
wire [23:0] wSpi_rd_data;
wire Clock_driv ;
//=============================================================
// reg define
//=============================================================
reg [9:0] rState ; // stete of state machine
reg [4:0] rDelay_cnt ; // delay counter
reg [23:0] rSpi_wr_data ;
reg rSpi_start_sig;
//-------------------------------------------------------------
//
//-------------------------------------------------------------
assign oAd_reset_n = 1’b1; // don’t reset ads1256
assign oAd_dio[3:0] = 4’b0000; //
//-------------------------------------------------------------
// one segment state machine
//-------------------------------------------------------------
always @ ( posedge Clock_driv or negedge Rst_n )
begin
if(Rst_n == 1’b0)
begin
oAd_cs_n <= 1’b1;
oAd_conv_done <= 1’b0;
rSpi_start_sig <= 1’b0;
rDelay_cnt[4:0] <= 5’d0;
rSpi_wr_data[23:0] <= 24’d0;
oAd_value[23:0] <= 24’d0;
rState[9:0] <= ST_IDLE;
end
else
begin
case(rState[9:0])
ST_IDLE : begin
oAd_cs_n <= 1’b1;
oAd_conv_done <= 1’b0;
rSpi_start_sig <= 1’b0;
rDelay_cnt[4:0] <= 5’d0;
rSpi_wr_data[23:0] <= 24’d0;
rState[9:0] <= (iStart_conv_en == 1’b1) ? ST_TX_STATUS : ST_IDLE;
end
ST_TX_STATUS : begin
oAd_cs_n <= 1’b0;
rSpi_start_sig <= 1’b1;
rSpi_wr_data[23:0] <= {4’h5,STATUS_REG_ADDR,8’h00,STATUS_REG}; // 写状态寄存器
rState[9:0] <= (wSpi_wr_end == 1’b1) ? ST_TX_ADCON : ST_TX_STATUS;
end
ST_TX_ADCON : begin
oAd_cs_n <= 1’b0;
rSpi_start_sig <= 1’b1;
rSpi_wr_data[23:0] <= {4’h5,ADCON_REG_ADDR,8’h00,ADCON_REG}; // 写A/D控制寄存器
rState[9:0] <= (wSpi_wr_end == 1’b1) ? ST_TX_DRATE : ST_TX_ADCON;
end
ST_TX_DRATE : begin
oAd_cs_n <= 1’b0;
rSpi_start_sig <= 1’b1;
rSpi_wr_data[23:0] <= {4’h5,DRATE_REG_ADDR,8’h00,DRATE_REG}; // 写数据速率寄存器
rState[9:0] <= (wSpi_wr_end == 1’b1) ? ST_TX_IO : ST_TX_DRATE;
end
ST_TX_IO : begin
oAd_cs_n <= 1’b0;
rSpi_start_sig <= 1’b1;
rSpi_wr_data[23:0] <= {4’h5,IO_REG_ADDR,8’h00,IO_REG}; // 写IO寄存器
rState[9:0] <= (wSpi_wr_end == 1’b1) ? ST_TX_MUX : ST_TX_IO;
end
ST_TX_MUX : begin
oAd_cs_n <= 1’b0;
rSpi_start_sig <= 1’b1;
rSpi_wr_data[23:0] <= {4’h5,MUX_REG_ADDR,8’h00,MUX_REG}; // 写输入通道寄存器
rState[9:0] <= (wSpi_wr_end == 1’b1) ? ST_TX_RDATA : ST_TX_MUX;
end
ST_TX_RDATA : begin
oAd_cs_n <= 1’b0;
rSpi_start_sig <= (wSpi_wr_end != 1’b1) ? 1’b1 : 1’b0;
if(iAd_drdy == 1’b0)
begin
rSpi_wr_data[23:0] <= {SYNC,WAKEUP,RDATA}; // 发送同步、唤醒、读数据命令
end
else ;
rState[9:0] <= (wSpi_wr_end == 1’b1) ? ST_WAITING : ST_TX_RDATA;
end
ST_WAITING : begin // 等待
oAd_cs_n <= 1’b0;
rSpi_start_sig <= 1’b0;
rSpi_wr_data[23:0] <= 24’d0;
rDelay_cnt[4:0] <= (rDelay_cnt[4:0] == 5’d6) ? 5’d0 : (rDelay_cnt[4:0] + 5’d1);
rState[9:0] <= (rDelay_cnt[4:0] == 5’d6) ? ST_READ_DATA : ST_WAITING;
end
ST_READ_DATA : begin // 读数据
oAd_cs_n <= 1’b0;
rSpi_start_sig <= (wSpi_rd_end != 1’b1) ? 1’b1 : 1’b0;
oAd_value[23:0] <= (wSpi_rd_end == 1’b1) ? wSpi_rd_data[23:0] : oAd_value[23:0];
rState[9:0] <= (wSpi_rd_end == 1’b1) ? ST_CONV_END : ST_READ_DATA;
end
ST_CONV_END : begin
oAd_cs_n <= 1’b0;
oAd_conv_done <= 1’b1;
rSpi_start_sig <= 1’b0;
rSpi_wr_data[23:0] <= 24’d0;
rState[9:0] <= ST_IDLE;
end
default : ;
endcase
end
end
spi_driver u0_spi_driver
(
.Clock ( Clock_driv ),
.Rst_n ( Rst_n ),
.iSpi_start_sig ( rSpi_start_sig),
.iSpi_wr_data ( rSpi_wr_data ),
.iSpi_miso ( iAd_dout ),
.oSpi_mosi ( oAd_din ),
.oSpi_sclk ( oAd_sclk ),
.oSpi_rd_data ( wSpi_rd_data ),
.oSpi_rd_end ( wSpi_rd_end ),
.oSpi_wr_end ( wSpi_wr_end )
);
//-------------------------------------------------------------
// generate division clock signal
//-------------------------------------------------------------
freq_divide #
(
.FREQ_DIVIDE_FACTOR ( 5’d24 )
)
u0_freq_divide
(
.Clock ( Clock ),
.Rst_n ( Rst_n ),
.oDivide_clk ( Clock_driv )
);
endmodule
/**************************************************************
module ads1256_sample #
(
// register value
parameter STATUS_REG = 8’h01,
parameter MUX_REG = 8’h1f, //
parameter ADCON_REG = 8’h20,
parameter DRATE_REG = 8’hf0,
parameter IO_REG = 8’he0
)
(
.Clock (),
.Rst_n (),
.iStart_conv_en (),
.iAd_dout (),
.iAd_drdy (),
.oAd_sclk (),
.oAd_din (),
.oAd_cs_n (),
.oAd_reset_n (),
.oAd_dio (),
.oAd_value (),
.oAd_conv_done ()
);
**************************************************************/