【Verilog硬件语言学习笔记2】ADC122S625驱动程序

发布于:2025-07-04 ⋅ 阅读:(16) ⋅ 点赞:(0)

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


网站公告

今日签到

点亮在社区的每一天
去签到