AD7903 CS Mode 4-Wire模式Verilog驱动编写解析

文章目录

@[toc]

芯片主要功能

2路16bit的ADC模拟电压采集

主要管脚介绍
控制时序

读操作

换算关系
特别注意
相关Verilog代码

读驱动
仿真TB

本文主要记录笔者AD7903的调试记录,同时也适用于AD7903相关系列。


芯片主要功能

2路16bit的ADC模拟电压采集

各路电压范围可设;

各路电压数据16bit输出;


主要管脚介绍

管脚总览如下:

相当于两个ADC模拟电压采集器,从管脚上看有两路ADC采集信号;

数字控制端,通过COVxSCKxSDIxSDOx来控制,根据接法,有不同的控制时序;


控制时序

采用CS Mode, 4-Wire Interface Without Busy Indicator 的硬件连接方式

读操作

官方给出的时序如下:

同时拉高COV1COV2,开始转换;

同时拉高COV1COV2后,转化时间为500~700ns;

转化完成后通过两路SDI1SDI2来选择采集的通道,应该在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                                                  
© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容