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程序的狀態圖如下:這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章