1. 程式人生 > >FPGA音訊編解碼驅動及I2C寫入程式碼

FPGA音訊編解碼驅動及I2C寫入程式碼

FPGA音訊編解碼驅動及I2C寫入程式碼

使用音訊編解碼晶片為WM8731,其通過I2CWM8731進行暫存器寫入,將需要寫入的資料放入例化的ROM塊中,通過狀態機控制資料的寫入;通過對50M24M的時鐘分頻提供WM8731的主時鐘和位寫入時鐘,資料沒有進行處理,僅僅是資料的採集,後期資料可以進行FFT等數字訊號處理操作。程式碼最後邊有一個波形的模擬圖,程式碼裡有一點需要修改,在模擬圖裡可以看出來。共勉

程式碼如下:

module memory(                                      //I2C資料通訊協議

            clk,               //系統輸入

50M時鐘

clk24,             //系統輸入24M時鐘

rst_n,             //系統復位

            sclk,              //I2C時鐘線

            sdin,             //I2C資料線

mclk,              //wm8731的主時鐘

bclk,              //傳送資料的bit時鐘

dadat,             //DA接受的資料

addat,             //AD傳送的資料

dalrc,             //DA的聲道選擇

adlrc,              //AD的聲道選擇

data,

I2Caddress

           ); 

input clk,rst_n,clk24;

output sclk,sdin;

output mclk,bclk,dalrc,adlrc,dadat;           //使用WM8731作為slave模式

input addat;

output [8:0] data;

output [6:0] I2Caddress;

reg sclk,sdin;

reg bclk,dalrc,adlrc,dadat;

wire mclk;

romrom_inst (                     //ROM的例化程式

.address (I2Caddress ),

.clock ( clk ),

.q ( data)

);

memorypllmemorypll_inst (                           //例化的Pll

.areset ( rst_n ),

.inclk0 ( clk ),

.c0 ( mclk ),

.locked ( locked_sig )

);

//assign data = q;

//assign I2Caddress = address;

reg flag;                //應答訊號

reg [6:0] I2Caddre;            //I2C的訪問地址

reg [6:0] I2Caddress;       //      //記憶體的地址

wire [8:0] data;                //記憶體的資料

reg [5:0] state;               //狀態描述

reg [31:0] dadataddress;        //DA存放資料記憶體

reg [31:0] addataddress;        //AD存放資料記憶體

parameter IDLE  = 6'd0;        //復位初始化狀態

parameter START = 6'd1;        //開始狀態

parameter I2CADDR0 = 6'd2;     //I2C的地址資料

parameter I2CADDR1 = 6'd3;

parameter I2CADDR2 = 6'd4;

parameter I2CADDR3 = 6'd5;

parameter I2CADDR4 = 6'd6;

parameter I2CADDR5 = 6'd7;

parameter I2CADDR6 = 6'd8;

parameter REWE  = 6'd9;        //對於從機的讀寫選擇

parameter I2Caddress0 = 6'd10;    //記憶體的地址

parameter I2Caddress1 = 6'd11;

parameter I2Caddress2 = 6'd12;

parameter I2Caddress3 = 6'd13;

parameter I2Caddress4 = 6'd14;

parameter I2Caddress5 = 6'd15;

parameter I2Caddress6 = 6'd16;

parameter DATA0 = 6'd17;       //記憶體的資料       

parameter DATA1 = 6'd18;

parameter DATA2 = 6'd19;

parameter DATA3 = 6'd20;

parameter DATA4 = 6'd21;

parameter DATA5 = 6'd22;

parameter DATA6 = 6'd23;

parameter DATA7 = 6'd24;

parameter DATA8 = 6'd25;

parameter STOP  = 6'd26;       //關閉狀態

parameter ACK0 = 6'd27;        //應答狀態

parameter ACK1 = 6'd28;

parameter ACK2 = 6'd29;

parameter READY = 6'd30;

parameter PRESTOP = 6'd31;

parameter N = 625;

reg [9:0] count;              //計數

always @(posedge clk or negedge rst_n)     //I2C時鐘的調配,輸入時鐘50M,輸出時鐘40k,對其1250分頻

begin

     if(!rst_n)

    begin

   count <= 10'd0;

sclk  <= 1'b0;

 end

  else if( count==N )

    begin

   sclk  <= ~sclk;

count <= 10'd0;

 end

  else count <= count + 1'b1;

end

//

//

//

always @(sclk )     //對於狀態機的描述

begin

      if(!rst_n)

  begin

   state <= IDLE;

flag  <= 0;

I2Caddress <= 7'd0;

  end

else

  begin

        case(state)                        //對於29種狀態的描述

IDLE : if(sclk == 1)                 //起始狀態

               begin 

  sdin <= 1;

  flag  <= 0;

  state <= READY;

end

 else state <= IDLE;

READY : if(sclk == 1)                //準備狀態

          begin

         sdin <= 0;

flag  <= 0;

         state <= START;

       end

     else state <= READY;

START : if(sclk == 0)                //起始狀態

           begin

    sdin <= 0;

 flag  <= 0;

 state <= I2CADDR0;

  end

else state <= START;

I2CADDR0 : if(sclk == 0)              //I2C地址

             begin

   sdin <= 0;

flag  <= 0;

state <= I2CADDR1;

 end

  else state <= I2CADDR0;

I2CADDR1 : if(sclk == 0)           

             begin

   sdin <= 1;

flag  <= 0;

state <= I2CADDR2;

 end

  else state <= I2CADDR1;

I2CADDR2 : if(sclk == 0)             

             begin

   sdin <= 1;

flag  <= 0;

state <= I2CADDR3;

 end

  else state <= I2CADDR2;

I2CADDR3 : if(sclk == 0)             

             begin

   sdin <= 0;

flag  <= 0;

state <= I2CADDR4;

 end

  else state <= I2CADDR3;

I2CADDR4 : if(sclk == 0)              

             begin

   sdin <= 1;

flag  <= 0;

state <= I2CADDR5;

 end

  else state <= I2CADDR4;

I2CADDR5 : if(sclk == 0)             

             begin

   sdin <= 0;

flag  <= 0;

state <= I2CADDR6;

 end

  else state <= I2CADDR5;

I2CADDR6 : if(sclk == 0)              

             begin

   sdin <= 0;

flag  <= 0;

state <= REWE;

 end

  else state <= I2CADDR6;

REWE : if(sclk == 0)                 //讀寫狀態

          begin

   sdin <= 0;

flag  <= 0;

state <= ACK0;

 end

  else state <= REWE;

ACK0 : if(sclk == 0)                  //應答狀態

         begin

  flag  <= 0;

  sdin <= I2Caddress[6];

  state <= I2Caddress0;

end

 else state <= ACK0;

I2Caddress0 : if(sclk == 0)              //資料地址狀態

             begin

   flag  <= 0;

   sdin <= I2Caddress[5];

   state <= I2Caddress1;

 end

  else state <= I2Caddress0;

I2Caddress1 : if(sclk == 0)              

             begin

   flag  <= 0;

   sdin <= I2Caddress[4];

   state <= I2Caddress2;

 end

  else state <= I2Caddress1;

I2Caddress2 : if(sclk == 0)              

             begin

   flag  <= 0;

   sdin <= I2Caddress[3];

   state <= I2Caddress3;

 end

  else state <= I2Caddress2;

I2Caddress3 : if(sclk == 0)              

             begin

   flag  <= 0;

   sdin <= I2Caddress[2];

   state <= I2Caddress4;

 end

  else state <= I2Caddress3;

I2Caddress4 : if(sclk == 0)              

             begin

   flag  <= 0;

   sdin <= I2Caddress[1];

   state <= I2Caddress5;

 end

  else state <= I2Caddress4;

I2Caddress5 : if(sclk == 0)              

             begin

   flag  <= 0;

   sdin <= I2Caddress[0];

   state <= I2Caddress6;

 end

  else state <= I2Caddress5;

I2Caddress6 : if(sclk == 0)              

             begin

   flag  <= 0;

   sdin <= data[8];

   state <= ACK1;

 end

  else state <= I2Caddress6;

     DATA0 : if(sclk == 0)                     //應答狀態

           begin

    flag  <= 0;

    sdin <= 0;

 state <= ACK1;

  end

            else state <= DATA0;

  ACK1 : if(sclk == 0)                    //資料狀態

            begin

  flag  <= 0;

  sdin <= data[7];

  state <= DATA1;

end

 else state <= ACK1;

  DATA1 : if(sclk == 0)                   

            begin

  flag  <= 0;

  sdin <= data[6];

  state <= DATA2;

end

 else state <= DATA1;

  DATA2 : if(sclk == 0)                 

            begin

  flag  <= 0;

  sdin <= data[5];

  state <= DATA3;

end

 else state <= DATA2;

  DATA3 : if(sclk == 0)                   

            begin

  flag  <= 0;

  sdin <= data[4];

  state <= DATA4;

end

 else state <= DATA3;

  DATA4 : if(sclk == 0)                  

            begin

  flag  <= 0;

  sdin <= data[3];

  state <= DATA5;

end

 else state <= DATA4;

  DATA5 : if(sclk == 0)                    

            begin

  flag  <= 0;

  sdin <= data[2];

  state <= DATA6;

end

 else state <= DATA5;

  DATA6 : if(sclk == 0)                    

            begin

  flag  <= 0;

  sdin <= data[1];

  state <= DATA7;

end

 else state <= DATA6;

  DATA7 : if(sclk == 0)                   

            begin

  flag  <= 0;

  sdin <= data[0];

  state <= DATA8;

end

 else state <= DATA7;

  DATA8 : if(sclk == 0)                    

            begin

  flag  <= 0;

  sdin <= 0;

  state <= ACK2;

end

 else state <= DATA8;

  ACK2 : if(sclk == 1)                 //應答狀態

           begin

    flag  <= 0;

    sdin <= 0;

 state <= PRESTOP;

  end

else state <= ACK2;

  PRESTOP : if(sclk == 1)              //結束前狀態

              begin

    flag  <= 1;

    sdin <= 1;

 state <= STOP;

  end

else state <= PRESTOP;

  STOP : if(sclk == 0)

           begin

    flag  <= 0;

    sdin <= 0;

 state <= IDLE;

 I2Caddress <= I2Caddress + 1;

  end

else state <= STOP;

  default :  begin 

               state <= IDLE;

               flag  <= 0;

 end

       endcase

       end

end  

//

//

// 

reg [9:0] count2;

always @(posedge clk24 or negedge rst_n)              //24Mhz的時鐘分為48Khz

begin

     if(!rst_n)

    begin

   count2 <= 10'd0;

bclk  <= 1'b0;

 end

  else if( count2==500 )

    begin

   bclk  <= ~bclk;

count2 <= 10'd0;

 end