FPGA音频编解码驱动及I2C写入代码
使用音频编解码芯片为WM8731,其通过I2C对WM8731进行寄存器写入,将需要写入的数据放入例化的ROM块中,通过状态机控制数据的写入;通过对50M和24M的时钟分频提供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;
rom rom_inst ( //ROM的例化程序
.address (I2Caddress ),
.clock ( clk ),
.q ( data)
);
memorypll memorypll_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
else count2 <= count2 + 1'b1;
end
//
//
//
reg [5:0] count3;
always @(posedge bclk or negedge rst_n ) //对DA进行赋值
begin
if(!rst_n)
begin
dadat <= 1'b0;
count3 <= 6'd32;
dalrc <= 1'b0;
end
else if(count3 > 0)
begin
dadat <= dadataddress[count3];
count3 <= count3 - 1'b1;
end
else if(count3 < 1)
begin
count3 <= 6'd32;
dalrc <= ~dalrc;
end
end
//
//
//
reg[5:0] count4;
always @(posedge bclk or negedge rst_n ) //对AD的数据读取
begin
if(!rst_n)
begin
addataddress <= 32'd0;
count4 <= 6'd32;
adlrc <= 1'b0;
end
else if(count4 > 1'b0)
begin
addataddress[count4] <= addat;
count4 <= count4 - 1'b1;
end
else if(count4 < 1'b1)
begin
count4 <= 6'd32;
//addataddress <= 32'd0;
adlrc <= ~adlrc;
end
end
//
//
always @( adlrc) //在一组数据完成后,AD的数据给DA
begin
dadataddress <= addataddress;
end
endmodule