AD7656是一款16位同步采样双极ADC转换器,本文中用状态机方式实现了AD7656芯片的Verilog驱动,并且将驱动直接挂在了altera芯片的Avalon总线上,使其altera芯片能够通过总线直接控制ADC芯片,其代码如下:
module AD7656_drive(clk,rst_n,slave_rd_n,slave_cs_n,slave_address,slave_rddata,ad_cs_n,sclking,sclk,CONVST,DOUTA,DOUTB); 
 //-------------------------------------------- 
     input clk;
     input rst_n;
      input sclking; 
      wire  sclk;    
 //-----------------------------------------
 //Avalon--MM interface
     input  slave_rd_n;
     input  slave_cs_n;  
     output[31:0] slave_rddata;
     input [1:0]slave_address;
     
     reg  [31:0] slave_rddata;
 //------------------------------------------
 //AD7656 interface
     reg[31:0]data_in_A/* synthesis noprune */;
     reg[31:0]data_in_B/* synthesis noprune */;
     
     output reg   CONVST;///
     output       sclk; ///
     output reg   ad_cs_n;
     input        DOUTA;//
     input        DOUTB;
 //------------------------------------------------    
     
      reg [5:0] bitnum; ///
      
      reg [3:0]  delay_200ns; //
      reg [8:0]  delay_4_us;
     reg [2:0] cstate;//
      reg [2:0] nstate;//
      parameter empty=0,start=1,delay_4us=2,data_transfer=3,stop=4,transfer_interval=5;
 //----------------------------------------------------------------------------------------------------
 assign  sclk=sclking;    ///the deg is 0 compared with the primitive input clk
 //-----------------------------------------------------------------------------------------------------
 //reset  module-----we apply the asynchronous reset and release the reset  signal synchronously
 reg rst_nr1,rst_nr2;
 always @(posedge clk or negedge rst_n)begin
     if(!rst_n)   rst_nr1<=0;
     else              rst_nr1<=1;
 end
always @(posedge clk  or negedge rst_n)begin
     if(!rst_n)       rst_nr2<=0;
     else                  rst_nr2<=rst_nr1;
 end
 //-------------------------------------------------------------------------------------------------------
 //pulse-generation technique---refer to Recommend Design Practices (9-7) in Quartus II Help for details 
 reg pulse1,pulse2;
 wire sclk_neg;  //check the  negedge edge of sclk
 always @(posedge clk or  negedge  rst_nr2)begin
     if(!rst_nr2)begin
         pulse1<=1;
         pulse2<=1;    
     end
     else  begin
         pulse1<=sclk;
         pulse2<=pulse1;                
     end
 end
assign  sclk_neg=(~pulse1)&&pulse2;
 //------------------------------------------------------------------------------------------------------------
 reg pulse3,pulse4;
 wire sclk_pos;  //check the  posedge edge of sclk
 always @(posedge clk or  negedge  rst_nr2)begin
     if(!rst_nr2)begin
         pulse3<=0;
         pulse4<=0;    
     end
     else  begin
         pulse3<=sclk;
         pulse4<=pulse3;                
     end
 end
 assign  sclk_pos=pulse3&&(~pulse4);
 //---------------------------------------------------------------------------------------------------------
 //assign ad_cs_n=~(nstate==data_transfer|nstate==start);
 //----------------------------------------------------------------------------------------------------
 always @(posedge clk or negedge rst_nr2)
 begin
     if(!rst_nr2)                 bitnum<=6'd0; 
     else if(nstate==start)    bitnum<=6'd31;
     else if((nstate==data_transfer)&& sclk_neg)   bitnum<=bitnum-1;
     else if(nstate==stop)    bitnum<=0;
 end
 //-----------------------------------------------------------------------------------------------------
 //delay  module-----------delay  4us to save conversion's time
 always@(posedge clk or negedge rst_nr2)//develop  latch??
     if(!rst_nr2)                                      delay_4_us<=0;
     else if((nstate==delay_4us)&&sclk_pos)  delay_4_us<= delay_4_us+1'd1;//why nstate??
     else if(nstate==empty)                        delay_4_us<=0;    
    wire flag_4us=(delay_4_us==4);//the mark of counter's arrival 
 //---------------------------------------------------------------------------------------------------
 //delay  module-----------delay  200ns to indicate transfer interval
 always@(posedge clk or negedge rst_nr2)//develop  latch
     if(!rst_nr2)                                      delay_200ns<=0;
     else if((nstate==transfer_interval)&&sclk_neg)    delay_200ns<= delay_200ns+1'd1;
     else if(nstate==empty)                        delay_200ns<=0;    
    wire flag_200ns=(delay_200ns==1); //the mark of counter's arrival     
 //----------------------------------------------------------------------------------------------------
 always @(posedge clk or negedge rst_nr2)    
 begin
      if(!rst_nr2) cstate<=empty;
      else begin
             cstate <= nstate;
          end
 end
 //----------------------------------------------------------------------------------------------------
 always @(cstate or sclk_neg or bitnum or flag_4us or flag_200ns)  //this is a combinational logic
         begin
                 case (cstate)
                 empty:  nstate <= delay_4us;                                 
                 delay_4us: begin   ///
                     if (flag_4us&&sclk_neg)
                         nstate = start;                                                 
                     else
                         nstate = delay_4us;
                 end
                 start: begin
                     if (sclk_neg)
                     begin
                         nstate = data_transfer;
                     end
                     else
                         nstate = start;
                 end
                 data_transfer: begin
                     if (sclk_neg&&(bitnum==6'd0))
                         nstate = stop;
                     else
                         nstate = data_transfer;
                 end
                 stop: begin   //question 
                     if (sclk_neg)
                         nstate = transfer_interval;
                     else
                         nstate = stop;
                 end
                 transfer_interval: begin //cun zai wen  ti 
                     if (flag_200ns&&sclk_neg)
                         nstate = empty;
                     else
                         nstate = transfer_interval;
                 end
                default:  begin 
                           nstate  = 'hx; 
                      end        
             endcase
             end
 //---------------------------------------------------------------------------------------------------
 //3rd always block,the sequential FSM output
 always @(posedge clk or negedge rst_nr2)    
      if(!rst_nr2) begin
              CONVST<=0;
                 ad_cs_n<=1; 
                 end
      else begin
                 begin
                 CONVST<=0;
                 ad_cs_n<=1; 
                 end
             case(cstate)
             empty:          begin 
                         CONVST<=0;
                         ad_cs_n<=1; 
                             end
             delay_4us:  begin 
                         CONVST<=1;
                             ad_cs_n<=1; 
                             end
             start:          begin 
                             CONVST<=1; 
                             ad_cs_n<=0; 
                             end
             data_transfer:begin 
                             if(bitnum==16&&(sclk ==1))
                               begin
                                 CONVST<=1;
                                 ad_cs_n<=1; 
                               end
                             else
                               begin
                                CONVST<=1;
                                 ad_cs_n<=0; 
                               end
                             end
             stop:            begin 
                             CONVST<=1;
                             ad_cs_n<=1; 
                             end
             transfer_interval:begin
                         CONVST<=0;
                             ad_cs_n<=1; 
                             end
          endcase
          end
 //-------------------------------------------------------------------------------------------------------
 //Avalon--MM interface
 wire slave_rdcs_n=slave_rd_n|slave_cs_n;
always@(posedge clk or negedge rst_nr2)
 begin 
         if(!rst_nr2)     slave_rddata[31:0]<=0;
         else if(slave_rdcs_n && slave_address==2'h0)  
         slave_rddata[31:0]<=data_in_A;
         else if(slave_rdcs_n && slave_address==2'h1)  
         slave_rddata[31:0]<=data_in_B;
         else
         slave_rddata[31:0]<=slave_rddata[31:0];        
 end
 //----------------------------------------------------------------------------------------------------
 always @(posedge clk or negedge rst_nr2)
     if(!rst_nr2)begin            
         data_in_A[31:0]<=0;
         data_in_B[31:0]<=0;
         end
     else if((nstate==data_transfer)&&sclk_neg)begin   
        data_in_A[bitnum]<=DOUTA; 
         data_in_B[bitnum]<=DOUTB;
         end
         
 //------------------------------------------------------------------------------------------------------
 endmodule