文章目录
@[toc]
芯片主要功能
2路16bit的ADC模拟电压采集
主要管脚介绍
控制时序
读操作
换算关系
特别注意
相关Verilog代码
读驱动
仿真TB
本文主要记录笔者AD7903的调试记录,同时也适用于AD7903相关系列。
芯片主要功能
2路16bit的ADC模拟电压采集
各路电压范围可设;
各路电压数据16bit输出;
主要管脚介绍
管脚总览如下:

相当于两个ADC模拟电压采集器,从管脚上看有两路ADC采集信号;
数字控制端,通过COVx、SCKx、SDIx、SDOx来控制,根据接法,有不同的控制时序;
控制时序
采用CS Mode, 4-Wire Interface Without Busy Indicator 的硬件连接方式

读操作
官方给出的时序如下:

同时拉高COV1、COV2,开始转换;
同时拉高COV1、COV2后,转化时间为500~700ns;
转化完成后通过两路SDI1、SDI2来选择采集的通道,应该在SCK的下降沿采集数据;
采集完最后,需至少等待一段时间,该时间内芯片内部在准备下一次转换操作;
总结以上,读操作时序图如下,一次读操作的总时间至少为2.5us(一般大于该值);

换算关系
采集的16bit总线上的数据为补码形式,在Verilog中通过singed可直接使用进行加减乘除运算。
特别注意
在COVx拉高后,手册上说转化时间为500~700ns,因此在4线模式下,我们应该至少等待700ns在进行读写操作;
实际调试时,手册上写SCK理论可支持高低电平时间5ns,实际我测的话不支持这么高的速率,使用50MHz进行采集时,出现采样的值时不时出现0x8000的现象,经过排查,是时序太紧张了。因此我把速率放慢至25MHz(高电平20ns,低电平20ns)。
相关Verilog代码
读驱动
`timescale 1ns / 1ps
// ********************************************************************************** //
// Company: JingCe
// Engineer: Chen Xiong Zhi
//
// File name: ad7903_wrapper.v
// Create Date: 2025/05/29 08:31:59
// Version: V1.0
// PATH: AD7903_wrapperad7903_wrapper.v
// Descriptions:
//
// ********************************************************************************** //
`default_nettype none
module ad7903_wrapper (
input wire sys_clk_i ,//100MHZ£¬10ns
input wire rst_n_i ,
//
input wire adc_acq_en_i ,
output wire adc_acq_valid ,
output reg [ 15: 0] adc_acq_ch1 ,
output reg [ 15: 0] adc_acq_ch2 ,
//gpio
output reg SCLK_o ,
output reg CONVERT_o ,
output reg SDI1_o ,
output reg SDI2_o ,
input wire SDO1_i ,
input wire SDO2_i
);
// ********************************************************************************** //
//---------------------------------------------------------------------
// declarations
//---------------------------------------------------------------------
localparam T_CONV = (800 / 10) + 1;
localparam T_CS = 73 ;
localparam T_DONE = 22 ;
localparam S_IDLE = 0 ;
localparam S_CONVERT = 1 ;
localparam S_CS1 = 2 ;
localparam S_CS2 = 3 ;
localparam S_DONE = 4 ;
reg [ 2: 0] state ;
reg [ 9: 0] clk_cnt ;
reg SCLK_r1 ;
// ********************************************************************************** //
//---------------------------------------------------------------------
// main code
//---------------------------------------------------------------------
always@(posedge sys_clk_i)begin
SCLK_r1 <= SCLK_o;
end
always@(posedge sys_clk_i)begin
if(!rst_n_i)
state <= S_IDLE;
else case(state)
S_IDLE:
if (adc_acq_en_i)
state <= S_CONVERT;
S_CONVERT:
if (clk_cnt == T_CONV - 1)
state <= S_CS1;
S_CS1:
if (clk_cnt == T_CS - 1)
state <= S_CS2;
S_CS2:
if (clk_cnt == T_CS - 1)
state <= S_DONE;
S_DONE:
if (clk_cnt == T_DONE - 1)
state <= S_IDLE;
default: state <= S_IDLE;
endcase
end
always@(posedge sys_clk_i)begin
case (state)
S_IDLE: clk_cnt <= 'd0;
S_CONVERT:
if (clk_cnt == T_CONV - 1)
clk_cnt <= 'd0;
else
clk_cnt <= clk_cnt + 'd1;
S_CS1,S_CS2:
if (clk_cnt == T_CS - 1)
clk_cnt <= 'd0;
else
clk_cnt <= clk_cnt + 'd1;
S_DONE:
if (clk_cnt == T_DONE - 1)
clk_cnt <= 'd0;
else
clk_cnt <= clk_cnt + 'd1;
default:clk_cnt <= 'd0;
endcase
end
always@(posedge sys_clk_i)begin
case (state)
S_CONVERT,S_CS1,S_CS2: CONVERT_o <= 'd1;
default: CONVERT_o <= 'd0;
endcase
end
always@(posedge sys_clk_i)begin
case (state)
S_CS1:
if (clk_cnt > T_CS - 4)
SDI1_o <= 'd1;
else
SDI1_o <= 'd0;
default: SDI1_o <= 'd1;
endcase
end
always@(posedge sys_clk_i)begin
case (state)
S_CS2:
if (clk_cnt > T_CS - 4)
SDI2_o <= 'd1;
else
SDI2_o <= 'd0;
default: SDI2_o <= 'd1;
endcase
end
always@(posedge sys_clk_i)begin
case (state)
S_CS1,S_CS2:
if (clk_cnt > T_CS - 7)
SCLK_o <= 'd0;
else if ( | clk_cnt[6:2])
SCLK_o <= ~clk_cnt[1];
else
SCLK_o <= 'd0;
default: SCLK_o <= 'd0;
endcase
end
always@(posedge sys_clk_i)begin
if (!rst_n_i) begin
adc_acq_ch1 <= 'd0;
end
else case (state)
S_CS1:
if (SCLK_o && SCLK_r1)
adc_acq_ch1[15 - (clk_cnt[6:2] - 1)] <= SDO1_i;
default: adc_acq_ch1 <= adc_acq_ch1;
endcase
end
always@(posedge sys_clk_i)begin
if (!rst_n_i) begin
adc_acq_ch2 <= 'd0;
end
else case (state)
S_CS2:
if (SCLK_o && SCLK_r1)
adc_acq_ch2[15 - (clk_cnt[6:2] - 1)] <= SDO2_i;
default: adc_acq_ch2 <= adc_acq_ch2;
endcase
end
assign adc_acq_valid = (state == S_DONE) && (clk_cnt == 0);
endmodule
`default_nettype wire
仿真TB
//****************************************Copyright (c)***********************************//
// Copyright(C) Xiaoxin2ciyuan
// All rights reserved
// File name: ad7903_wrapper_tb.v
// Last modified Date: 2025/05/29 10:13:50
// Last Version: V1.0
// Descriptions:
//----------------------------------------------------------------------------------------
// Created by: Chen Ambition
// Created date: 2025/05/29 10:13:50
// Version: V1.0
// Descriptions:
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//
module ad7903_wrapper_tb();
reg sys_clk_i ;
reg rst_n_i ;
reg adc_acq_en_i ;
wire SCLK_o ;
wire CONVERT_o ;
wire SDI1_o ;
wire SDI2_o ;
reg SDO1_i ;
reg SDO2_i ;
initial
begin
#2
rst_n_i = 0 ;
sys_clk_i = 0 ;
adc_acq_en_i = 0 ;
#10
rst_n_i = 1 ;
#100
adc_acq_en_i = 1 ;
end
parameter CLK_FREQ = 100;//Mhz
always # ( 1000/CLK_FREQ/2 ) sys_clk_i = ~sys_clk_i ;
ad7903_wrapper u_ad7903_wrapper(
.sys_clk_i (sys_clk_i ), // 100MHZ£¬20ns
.rst_n_i (rst_n_i ),
//
.adc_acq_en_i (adc_acq_en_i ),
//gpio
.SCLK_o (SCLK_o ),
.CONVERT_o (CONVERT_o ),
.SDI1_o (SDI1_o ),
.SDI2_o (SDI2_o ),
.SDO1_i (SDO1_i ),
.SDO2_i (SDO2_i )
);
endmodule


















暂无评论内容