?? 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 + -