📄 freedev_aic23.v
字号:
//---------------------------------------------------------
//杭州自由电子科技TLV320AIC23音频模块
//电话:0571-85084089
//网址:www.freefpga.com
//邮件:
//开发日期:20070122
//简要说明:
// 1、向上连接Avalone总线,设置为Slave设备
// 2、向下连接TLV320AIC23数字音频接口DSP模式数据
// 格式。
// 3、两个时钟域之间用FIFO隔离。
//---------------------------------------------------------
module freedev_aic23(clk,rst_n,irq,cs_n,rd_n,wr_n,addr,rdata,wdata,
lrcin,din,lrcout,dout,bclk);
input clk; // master clk
input rst_n; // reset
output irq; // interrupt request
input cs_n; // chip select
input rd_n; // read signal
input wr_n; // write signal
input [2:0]addr;// address
output [31:0]rdata; // out data
input [31:0]wdata; // in data
input lrcin; // aic master mode,from AIC23 to fpga
output din; // to DAC
input lrcout; // aic master mode,from AIC23 TO fpga
input dout; // from ADC
input bclk; // bclk from AIC23
//================================= clk时钟域:avalone slave 接口部分 ==============================
// 寄存器定义
reg [31:0] mode_reg; // 模式寄存器 address 000
reg [31:0] command_reg; // 命令寄存器 address 001
reg [31:0] irq_mask; // 中断屏蔽寄存器 address 010
// FIFO状态寄存器 address 011
// inFIFO计数寄存器 address 100
// outFIFO计数寄存器 address 101
// 未使用 address 110
// FIFO数据 address 111
reg rirq,wirq;
reg [31:0] out_data; // out data
reg [31:0] test_count; // test counter
// 模块软件复位
wire s_rst = command_reg[0];
wire start = command_reg[1];
// 总线读信号
wire wacc = ~cs_n & ~wr_n;
// 总线写信号
wire racc = ~cs_n & ~rd_n;
// 写寄存器
always @(posedge clk or negedge rst_n)
if (!rst_n )
begin
mode_reg <= #1 32'h0;
command_reg <= #1 32'h0;
irq_mask <= #1 32'h3; //默认屏蔽中断
end
else
if ( wacc )
begin
case ( addr )
3'b000 : mode_reg <= #1 wdata; //写模式寄存器
3'b001 : command_reg <= #1 wdata; //写命令寄存器
3'b010 : irq_mask <= #1 wdata; //写中断屏蔽寄存器
default: ;
endcase
end
always @(posedge clk)
begin
if( racc )
case (addr)
3'b000: out_data <= #1 mode_reg;
3'b001: out_data <= #1 command_reg;
3'b010: out_data <= #1 irq_mask;
3'b011: out_data <= #1 {26'h0,,wirq,rirq,infifo_rdempty,infifo_rdfull,outfifo_wrempty,outfifo_wrfull};
3'b100: out_data <= #1 {23'h0,infifo_rdusedw[8:0]};
3'b101: out_data <= #1 {23'h0,outfifo_wrusedw[8:0]};
3'b110: out_data <= #1 test_count;
default: ;
endcase
end
// 中断信号生成(有读或写中断)
assign irq = rirq | wirq;
always @(posedge clk)
if (!rst_n )
begin
rirq <= #1 1'b0;
wirq <= #1 1'b0;
end else
begin
// 读中断生成条件:读中断屏蔽位0,并且输入队列数据>400或输入队列满
rirq<= #1 ((irq_mask[0]==1'b0) && (infifo_rdfull ||(infifo_rdusedw >400))) ? 1'b1 : 1'b0;
// 写中断生成条件:写中断屏蔽位0,并且输出队列数据<112或输出队列空
wirq<= #1 ((irq_mask[1]==1'b0) && (outfifo_wrempty ||(outfifo_wrusedw <112))) ? 1'b1 : 1'b0;
end
// 读寄存器或读FIFO数据
assign rdata = (addr==3'b111)?infifo_rdata:out_data;
//跨时钟域异步控制信号
wire bypass_mode = mode_reg[1:0]==2'b00 ? 1:0; // 复位默认是数字旁路
wire dma_mode = mode_reg[1:0]==2'b01 ? 1:0; // DMA传输模式
wire fifo_mode = mode_reg[1:0]==2'b10 ? 1:0; // Fifo 环路模式
//========================================== FIFO ============================================
//Fifo 环路模式 FIFO读请求生成
wire fifo_loop_req = (~infifo_rdempty)?1:0;
//输入FIFO相关定义
wire [31:0]infifo_rdata;
reg [31:0]infifo_wdata;
wire [8:0]infifo_rdusedw;
wire [8:0]infifo_wrusedw;
wire infifo_rdfull;
wire infifo_rdempty;
wire infifo_wrfull;
wire infifo_wrempty;
// infifo_rd读信号
// 读3'b111时FIFO读请求信号有效
wire read_addr7 = (addr==3'b111) && (rd_n==1'b0) && (cs_n==1'b0);
wire infifo_rd= read_addr7 ? 1:0;
reg infifo_wr;
//输出FIFO相关定义
wire [31:0]outfifo_rdata;
// outfifo_wdata数据就是avalon总线输入数据。
wire [31:0]outfifo_wdata = wdata;
wire [8:0]outfifo_rdusedw;
wire [8:0]outfifo_wrusedw;
wire outfifo_rdfull;
wire outfifo_rdempty;
wire outfifo_wrfull;
wire outfifo_wrempty;
//reg outfifo_rd;
wire write_addr7 = (addr==3'b111) && (wr_n==1'b0) && (cs_n==1'b0);
wire outfifo_wr= write_addr7 ? 1:0;
//输入FIFO
fd_fifo in_fifo(
.aclr(s_rst), //输入FIFO 异步清除
.rdclk(clk), //输入FIFO 读时钟
.rdreq(infifo_rd), //输入FIFO 读请求
.q(infifo_rdata), //输入FIFO 读数据
.rdfull(infifo_rdfull), //输入FIFO 读满标志
.rdempty(infifo_rdempty), //输入FIFO 空标志
.rdusedw(infifo_rdusedw), //输入FIFO 使用计数
.wrclk(bclk), //输入FIFO 写时钟
.wrreq(infifo_wr), //输入FIFO 写请求
.data(infifo_wdata), //输入FIFO 写数据
.wrfull(infifo_wrfull), //输入FIFO 写满标志
.wrempty(infifo_wrempty), //输入FIFO 写空标志
.wrusedw(infifo_wrusedw) //输入FIFO 使用计数
);
//输出FIFO
fd_fifo out_fifo(
.aclr(s_rst), //输出FIFO 异步清除
.rdclk(bclk), //输出FIFO 读时钟 读时钟每个数据帧读一次在lrcin为1时的bclk上升沿读出
.rdreq(lrcin), //输出FIFO 读请求 以lrcin作为读使能信号
.q(outfifo_rdata), //输出FIFO 读出数据
.rdfull(outfifo_rdfull), //输出FIFO 读满标志
.rdempty(outfifo_rdempty), //输出FIFO 读空标志
.rdusedw(outfifo_rdusedw), //输出FIFO 使用计数
.wrclk(clk), //输出FIFO 写时钟
.wrreq(outfifo_wr), //输出FIFO 写请求
.data(outfifo_wdata), //输出FIFO 写数据
.wrfull(outfifo_wrfull), //输出FIFO 写满标志
.wrempty(outfifo_wrempty), //输出FIFO 写空标志
.wrusedw(outfifo_wrusedw) //输出FIFO 使用计数
);
//=============================== bclk时钟域: TLV320AIC23数字音频接口 =====================
reg s_lrcin,d_lrcin; //lrcin同步和延时
reg s_lrcout,d_lrcout; //lrcout同步和延时
always @(posedge bclk)
begin
d_lrcin <= s_lrcin;
s_lrcin <= lrcin;
d_lrcout <= s_lrcout;
s_lrcout <= lrcout;
end
wire in_flag,out_flag; //AIC23 DSP MODE
assign in_flag = ~d_lrcout & s_lrcout; // lrcout的上升沿
assign out_flag= ~d_lrcin & s_lrcin; // lrcin的上升沿
reg [31:0]recv; // recv data from aic23 adc
reg [31:0]recved; // recved data
reg [4:0]recv_count; // recv counter
reg [1:0]recv_state; // recv state
// state machine
parameter RECEIVE = 2'b00;
parameter SEND = 2'b00;
parameter WRITE_FIFO = 2'b01;
parameter READ_FIFO = 2'b01;
parameter STOP = 2'b10;
parameter IDLE = 2'b11;
// 数字音频接口 DSP方式 数据读入状态机
// 数据读入状态机说明:
// 复位时初始化为IDLE状态。
// 当lrcout为1时(TLV320AIC23 DSP Mode数据前有1个bclk周期为1)清计数器进入RECEIVE状态。
// 在RECEIVE状态 移位接收数据,保存到recv,recv_count为移位计数值,当recv_count==31,
// 数据入infifo_wdata,同时infifo_wr请求信号有效,状态机进入WRITE_FIFO状态
// 在WRITE_FIFO状态,状态机进入STOP状态,在这个bclk的上升沿数据写入infifo
// STOP状态,状态机进入IDLE,完成一次数据的接收。
always @(posedge bclk)
if (!rst_n )
begin
recv_state <= #1 IDLE;
test_count <= #1 32'h0;
end else
begin
if(lrcin & start & ~infifo_wrfull)
begin
recved <= #1 recv;
recv <= #1 32'h0;
recv_count <= #1 5'h0;
infifo_wr <= #1 1'b0;
recv_state <= #1 RECEIVE;
test_count <= test_count + 32'h1;
end
else
case (recv_state)
RECEIVE:
begin
recv <= #1 {recv[30:0],dout};
recv_count <= recv_count + 5'h1;
if( recv_count == 5'b11111)
begin
infifo_wdata <= #1 {recv[30:0],dout};
infifo_wr <=#1 1'b1;
recv_state <= #1 WRITE_FIFO;
end
end
WRITE_FIFO:
begin
recv_state <=#1 STOP;
end
STOP:
begin
infifo_wr <= #1 1'b0;
recv_state <= #1 IDLE;
end
IDLE:
begin
recv_state <= #1 IDLE;
end
endcase
end
//数字音频接口 (DSP模式 DMA模式处理方式一致)
//因为out_flag是lrcin推后一拍,所以使用bclk的下降沿能捕获到out_flag==1。
//同时在bclk的下降沿把输出移位数据准备好。
reg [31:0]dmasend; // send data to dac
reg [31:0]dmasended; // sended data
reg [4:0]dmasend_count; // send counter
reg [1:0]dmasend_state; // send state
reg dma_out;
always @(negedge bclk)
if(~rst_n )
begin
dmasend_state <= IDLE;
end else
begin
if( lrcin & ~outfifo_rdempty) //检测到lrcin=1
begin
dma_out <= #1 outfifo_rdata[31];
dmasend <= #1 {outfifo_rdata[30:0],1'b0 };
dmasend_count <= #1 5'h1;
dmasend_state <= #1 SEND;
end
else
case (dmasend_state)
SEND:
begin
dma_out <= #1 dmasend[31];
dmasend <= #1 {dmasend[30:0],1'b0};
dmasend_count <= dmasend_count + 5'h1;
if( dmasend_count == 5'b11111)
dmasend_state <= #1 IDLE;
end
endcase
end
assign din = dma_out;
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -