ad7606的八通道modelsim仿真

ad7606的八通道modelsim仿真

解决的疑问主要有一下几点:
(1)之前一直困惑于如何确定AD的采样频率,后来在朋友的提示下,在程序中加入了定时器,每50us读取一次数据,实现采样频率变为20K。
(2)对ad_reset信号,之前一直以为计数器记满之后,会自动复位,似的该信号会马上变为高电平,仿真后才发现并未如此,满量程的计数器将会一直保持在ff的状态,使得ad-reset信号保持为低,也就进入了循环采样的状态。cnt计数器只是对ad复位进行操作,这正决定采样频率的是cnt50us计数器。
(3)使用$random函数模拟采样信号,使得仿真结果更真实可观。

ad的采样程序如下:

`timescale 1ns / 1ns
//////////////////////////////////////////////////////////////////////////////////
// Module Name:    ad7606 
//////////////////////////////////////////////////////////////////////////////////
module ad7606(
   input                clk,                  //50mhz
    input               rst_n,

    input [15:0]        ad_data,            //ad7606 采样数据
    input               ad_busy,            //ad7606 忙标志位
   input                first_data,         //ad7606 第一个数据标志位  

    output [2:0]        ad_os,              //ad7606 过采样倍率选择
    output reg          ad_cs,              //ad7606 AD cs
    output reg          ad_rd,              //ad7606 AD data read
    output reg          ad_reset,           //ad7606 AD reset
    output reg          ad_convstab,         //ad7606 AD convert start

    output reg [15:0] ad_ch1,              //AD第1通道的数据
    output reg [15:0] ad_ch2,              //AD第2通道的数据
    output reg [15:0] ad_ch3,              //AD第3通道的数据
    output reg [15:0] ad_ch4,              //AD第4通道的数据
    output reg [15:0] ad_ch5,              //AD第5通道的数据
    output reg [15:0] ad_ch6,              //AD第6通道的数据
    output reg [15:0] ad_ch7,              //AD第7通道的数据
    output reg [15:0] ad_ch8,              //AD第8通道的数据  
   output reg [3:0]  state
    //output reg [3:0] cnt

    );



reg [7:0] cnt = 0 ;
reg [15:0] cnt50us = 0;
reg [5:0] i;
//reg [3:0] state;

parameter IDLE=4'd0;
parameter AD_CONV=4'd1;
parameter Wait_1=4'd2;
parameter Wait_busy=4'd3;
parameter READ_CH1=4'd4;
parameter READ_CH2=4'd5;
parameter READ_CH3=4'd6;
parameter READ_CH4=4'd7;
parameter READ_CH5=4'd8;
parameter READ_CH6=4'd9;
parameter READ_CH7=4'd10;
parameter READ_CH8=4'd11;
parameter READ_DONE=4'd12;
//parameter display=4'd13;

assign ad_os=3'b000;  //无过采样

//ad复位
always@(posedge clk)
 begin
    if(cnt<8'hff) begin
        cnt<=cnt+1;
        ad_reset<=1'b1;
      end
      else
        ad_reset<=1'b0;  //计数器达到ff后停止,ad_reset恒为零     
   end

//使用定时器来设置采样频率
always @(posedge clk or negedge rst_n) //每50us读取一次数据,ad的采样率为20K
    begin
        if(rst_n == 0)
            cnt50us <= 0;
        else begin 
            if(cnt50us < 16'd2499)
                begin
                    cnt50us <= cnt50us + 1;
                end
            else
                cnt50us <= 0;
            end
    end

always @(posedge clk) 
 begin
     if (ad_reset==1'b1) begin   //初始化ad
             state<=IDLE; 
             ad_ch1<=0;
             ad_ch2<=0;
             ad_ch3<=0;
             ad_ch4<=0;
             ad_ch5<=0;
             ad_ch6<=0;
             ad_ch7<=0;
             ad_ch8<=0;
             ad_cs<=1'b1;
             ad_rd<=1'b1; 
             ad_convstab<=1'b1;   //8通道同步采样
             i<=0;
     end         
     else begin
          case(state)     //need time:(20+2+5+1+3*8+1)*20ns=1060ns, fmax=1/1060ns=1MHZ
          IDLE: begin
                 ad_cs<=1'b1;
                 ad_rd<=1'b1; 
                 ad_convstab<=1'b1; 
                 if(i==20) begin        //延时20个时钟后开始转换
                     i<=0;           
                     state<=AD_CONV;
                 end
                 else 
                     i<=i+1'b1;
          end
          AD_CONV: begin       
                 if(i==2) begin                        //等待2个lock,convstab的下降沿最少为25ns,故至少需要两个时钟
                     i<=0;           
                     state<=Wait_1;
                     ad_convstab<=1'b1;                      
                 end
                 else begin
                     i<=i+1'b1;
                     ad_convstab<=1'b0;                     //启动AD转换
                 end
          end
          Wait_1: begin            
                 if(i==5) begin                           //等待5个clock, 等待busy信号为高(tconv)
                     i<=0;
                     state<=Wait_busy;
                 end
                 else 
                     i<=i+1'b1;
          end        
          Wait_busy: begin            
                 if(ad_busy==1'b0) begin                    //等待busy为低电平  即转换之后读取模式
                     i<=0;           
                     state<=READ_CH1;
                 end
          end
          READ_CH1: begin 
                 ad_cs<=1'b0;                              //cs信号有效  直到读取8通道结束
                 if(i==3) begin                            // 低电平持续3个时钟,完成通道1的读入
                     ad_rd<=1'b1;
                     i<=0;
                     ad_ch1<=ad_data;                        //读CH1
                     state<=READ_CH2;                
                 end
                 else begin
                     ad_rd<=1'b0;   
                     i<=i+1'b1;
                 end
          end
          READ_CH2: begin 
                 if(i==3) begin
                     ad_rd<=1'b1;
                     i<=0;
                     ad_ch2<=ad_data;                        //读CH2
                     state<=READ_CH3;                
                 end
                 else begin
                     ad_rd<=1'b0;   
                     i<=i+1'b1;
                 end
          end
          READ_CH3: begin 
                 if(i==3) begin
                     ad_rd<=1'b1;
                     i<=0;
                     ad_ch3<=ad_data;                        //读CH3
                     state<=READ_CH4;                
                 end
                 else begin
                     ad_rd<=1'b0;   
                     i<=i+1'b1;
                 end
          end
          READ_CH4: begin 
                 if(i==3) begin
                     ad_rd<=1'b1;
                     i<=0;
                     ad_ch4<=ad_data;                        //读CH4
                     state<=READ_CH5;                
                 end
                 else begin
                     ad_rd<=1'b0;   
                     i<=i+1'b1;
                 end
          end
          READ_CH5: begin 
                 if(i==3) begin
                     ad_rd<=1'b1;
                     i<=0;
                     ad_ch5<=ad_data;                        //读CH5
                     state<=READ_CH6;                
                 end
                 else begin
                     ad_rd<=1'b0;   
                     i<=i+1'b1;
                 end
          end
          READ_CH6: begin 
                 if(i==3) begin
                     ad_rd<=1'b1;
                     i<=0;
                     ad_ch6<=ad_data;                        //读CH6
                     state<=READ_CH7;                
                 end
                 else begin
                     ad_rd<=1'b0;   
                     i<=i+1'b1;
                 end
          end
          READ_CH7: begin 
                 if(i==3) begin
                     ad_rd<=1'b1;
                     i<=0;
                     ad_ch7<=ad_data;                        //读CH7
                     state<=READ_CH8;                
                 end
                 else begin
                     ad_rd<=1'b0;   
                     i<=i+1'b1;
                 end
          end
          READ_CH8: begin 
                 if(i==3) begin
                     ad_rd<=1'b1;
                     i<=0;
                     ad_ch8<=ad_data;                        //读CH8
                     state<=READ_DONE;               
                 end
                 else begin
                     ad_rd<=1'b0;   
                     i<=i+1'b1;
                 end
          end
          READ_DONE:begin                                 //完成读,回到idle状态
                     ad_rd<=1'b1;    
                     ad_cs<=1'b1;
                     if(cnt50us == 16'd2499)                      //不加此条件,则ad完成一次读取需1280ns,采样频率781.25K,但需注意ad每通道的追高采样只能为200K
                        state<=IDLE;
                    else
                        state<=READ_DONE;
          end       
          default:  state<=IDLE;
          endcase   
    end   

 end

endmodule

仿真测试程序如下:

`timescale 1 ns/ 1 ns
module ad7606_vlg_tst();
// constants                                           
// general purpose registers

// test vector input registers
reg ad_busy;
reg [15:0] ad_data;
reg clk;
reg first_data;
reg rst_n;
// wires                                               
wire [15:0]  ad_ch1;
wire [15:0]  ad_ch2;
wire [15:0]  ad_ch3;
wire [15:0]  ad_ch4;
wire [15:0]  ad_ch5;
wire [15:0]  ad_ch6;
wire [15:0]  ad_ch7;
wire [15:0]  ad_ch8;
wire ad_convstab;
wire ad_cs;
wire [2:0]  ad_os;
wire ad_rd;
wire ad_reset;
wire [3:0] state;

// assign statements (if any)                          
ad7606 i1 (
// port map - connection between master ports and signals/registers   
    .ad_busy(ad_busy),
    .ad_ch1(ad_ch1),
    .ad_ch2(ad_ch2),
    .ad_ch3(ad_ch3),
    .ad_ch4(ad_ch4),
    .ad_ch5(ad_ch5),
    .ad_ch6(ad_ch6),
    .ad_ch7(ad_ch7),
    .ad_ch8(ad_ch8),
    .ad_convstab(ad_convstab),
    .ad_cs(ad_cs),
    .ad_data(ad_data),
    .ad_os(ad_os),
    .ad_rd(ad_rd),
    .ad_reset(ad_reset),
    .clk(clk),
    .first_data(first_data),
    .rst_n(rst_n),
    .state(state)
    //.cnt(cnt)
);
initial                                                
    begin                                                  
        ad_busy = 0;
        first_data = 0;
        clk = 0;
        forever             //50MHz
        #10
        clk = ~clk;                                                                                                                                            
        $display("Running testbench");                       
   end  
initial
    begin
      rst_n = 1;
      #10;
      rst_n = 0;
      #20;
      rst_n = 1; 
    end

always@(posedge clk)                        
    begin                                                  

      ad_data <= $random;      //使用随机数模拟采样信号        

    end  

endmodule

仿真结果如下:
仿真结果,每5000ns读取一次数据

ad程序的状态图如下:ad7606的八通道modelsim仿真_第1张图片

你可能感兴趣的:(verilog,modelsim)