⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 freedev_aic23.v

📁 在开发FPGA上比较有用
💻 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 + -