ADC芯片ADC122S625的驱动代码
该芯片的时序图如下图所示:
上面是间断工作模式,表示在一定时间内,nCS会周期性的开启关闭,使得整个ADC处在一个间断工作的状态。此时在一个工作周期内,ADC会先后输出Chan_A与Chan_B两个通道的数字信号,这里注意,ADC输出的数字信号是由高到低输出的,且输出的是补码!因为ADC所检测的压降可能是负的。
上面的这个与连续工作模式的,此时ADC持续工作,会不断输出Chan_A与Chan_B两个通道的数字信号。此时nCS就一直拉低,但是这对于你的时序控制的要求就很高,一但一个数据出错,后面所有的ADC数据读取都会出错。
因此,我还是推荐大家使用上面的间断工作模式,此时ADC的稳定性以及代码的容错能力会好很多。
对应的间断工作模式的示例代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2025/03/17 10:02:18
// Design Name:
// Module Name: ADC122S625_Driver
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module ADC122S625_Driver(
input clk ,// 主时钟(例如50MHz)
input rst_n ,// 异步复位(低有效)
input dout ,// 串行数据输入
input Read_en ,// 开启DAC信号(高有效)
output reg cs_n ,// 片选信号(低有效)
output reg sclk ,// SPI时钟
output reg [ 11:0] chA_data ,// 通道A转换结果
output reg [ 11:0] chB_data ,// 通道B转换结果
output reg data_valid // 数据有效标志
);
// 对于整个ADC芯片,与FPGA通信的有cs_n, dout, sclk
// 首先是sclk的时钟生成,这里clk的周期20ns,50MHz;sclk频率1.6MHz~6.4MHz
// 此时我们选择sclk频率为3.7MHz
parameter sclk_FREQ = 2_000_000 ;
parameter clk_FREQ = 50_000_000 ;
localparam count_period = clk_FREQ/sclk_FREQ;
reg [0:5] cnt ;
reg [0:5] sclk_cnt ;
reg last_sclk ;
always @(negedge rst_n or posedge clk) begin
// 当rst_n为低时,或者Read_en为低时,停止工作
if (((!rst_n)||(!Read_en))) begin
cnt<=0;
end
else if (cnt<count_period-1) begin
cnt<=cnt+1;
end
else begin
cnt<=0;
end
end
// 生成采样时钟sclk
always @(negedge rst_n or posedge clk) begin
if (((!rst_n)||(!Read_en))) begin
sclk<=1;
last_sclk<=0;
end
else if (cnt==count_period/2) begin
sclk<=1;
end
else if (cnt==0) begin
sclk<=0;
end
last_sclk<=sclk;
end
// 生成时钟序列信号sclk_cnt
always @(negedge rst_n or posedge clk) begin
if ((((!rst_n)||(!Read_en)))) begin
sclk_cnt<=0;
end
else if ((last_sclk==1)&&(sclk==0)) begin
sclk_cnt<=sclk_cnt+1;
end
else if (sclk_cnt==35) begin
sclk_cnt<=0;
end
end
// CS控制
always @(negedge rst_n or posedge clk) begin
if (((!rst_n)||(!Read_en))) begin
cs_n<=1;
end
else if ((last_sclk==1)&&(sclk==0)) begin
if (sclk_cnt==0) begin
cs_n<=0;
end
else if (sclk_cnt==34) begin
cs_n<=1;
end
end
end
// 输出有效数据
always @(posedge clk) begin
// always @(negedge rst_n or posedge clk) begin
if (((!rst_n)||(!Read_en))) begin
chA_data<=0;
chB_data<=0;
data_valid<=0;
end
// 数据已经准备好
if ((last_sclk==0)&&(sclk==1)) begin
// 读取数据A
if (sclk_cnt<17&&sclk_cnt>4) begin
data_valid<=0;
chA_data[16-sclk_cnt]<=dout;
end
// 读取数据B
else if (sclk_cnt<33&&sclk_cnt>20) begin
chB_data[32-sclk_cnt]<=dout;
end
else if (sclk_cnt==33) begin
data_valid=1;
end
else if (sclk_cnt==34) begin
data_valid=0;
end
end
end
endmodule