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

📄 freedev_aic23_20070123.v

📁 在开发FPGA上比较有用
💻 V
字号:
//---------------------------------------------------------
//杭州自由电子科技TLV320AIC23音频模块
//电话:0571-85084089
//网址:www.freefpga.com
//邮件:
//开发日期:20070122
//简要说明:
//          1、向上连接Avalone总线,设置为Slave设备,支持旁路
//             模式mode_reg=00、DMA传输模式mode_reg=01、FIFO
//             环路模式mode_reg=10
//          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_data;   // test fifo data;
	
	// 模块软件复位
	wire s_rst = command_reg[0];

	// 总线读信号
	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 {28'h0,infifo_rdempty,outfifo_wrfull,wirq,rirq};
	    3'b100: out_data <= #1 {24'h0,infifo_rdusedw[7:0]};
		3'b101: out_data <= #1 {24'h0,outfifo_wrusedw[7:0]};
		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,并且输入队列数据>200
		rirq<= #1 ((irq_mask[0]==1'b0) && (infifo_rdusedw > 8'd200)) ? 1'b1 : 1'b0;
		
		// 写中断生成条件:写中断屏蔽位0,并且输出队列数据<56
		wirq<= #1 ((irq_mask[1]==1'b0) && (outfifo_wrusedw < 8'd56)) ? 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 fifo_mode = mode_reg[1:0]==2'b10 ?1:0;					// Fifo 环路模式
	wire dma_mode = fifo_mode ? 1:(mode_reg[1:0]==2'b01 ? 1:0);	// DMA传输模式
		
	//========================================== FIFO ============================================
	//Fifo 环路模式
	//IN OUT FIFO AVALONE接口端环路条件
	wire in_out_req = (~infifo_rdempty)?1:0;
	
	//输入FIFO相关定义
	wire [31:0]infifo_rdata;
	reg  [31:0]infifo_wdata;
	
	wire [7:0]infifo_rdusedw;
	wire [7:0]infifo_wrusedw;
	wire infifo_rdempty;
	wire infifo_wrfull;
	
	// infifo_rd读信号 
	// 		FIFO环路模式时 只要非空就生成读请求信号
	//		其他情况 读3'b111时读请求信号有效
	wire infifo_rd= fifo_mode? in_out_req : ((addr==3'b111) ? ~(rd_n | cs_n):0);
	reg  infifo_wr;
	
	// infilo 半满信号
	wire infifo_rdhalf_full=infifo_rdusedw[7];
	wire infifo_wrhalf_full=infifo_wrusedw[7];
	
	//输出FIFO相关定义
	wire  [31:0]outfifo_rdata;
	// outfifo_wdata数据 
	//		fifo环路模式时是infifo_rdata
	// 		非fifo环路模式outfifo_wdata就是avalon总线输入数据。
	wire  [31:0]outfifo_wdata = fifo_mode?infifo_rdata:wdata;
	
	wire [7:0]outfifo_rdusedw;
	wire [7:0]outfifo_wrusedw;
	wire outfifo_rdempty;
	wire outfifo_wrfull;
	
	reg  outfifo_rd;
	wire outfifo_wr= fifo_mode? in_out_req :((addr==3'b111) ? ~(wr_n | cs_n):0);
	wire outfifo_rdhalf_full=outfifo_rdusedw[7];
	wire outfifo_wrhalf_full=outfifo_wrusedw[7];	
	
	//输入FIFO
	fd_fifo in_fifo(
	.aclr(s_rst),				//输入FIFO 异步清除
	
	.rdclk(clk),				//输入FIFO 读时钟
	.rdreq(infifo_rd),			//输入FIFO 读请求
	.q(infifo_rdata),			//输入FIFO 读数据
	.rdempty(infifo_rdempty),	//输入FIFO 空标志
	.rdusedw(infifo_rdusedw),	//输入FIFO 使用计数
	
	.wrclk(bclk),				//输入FIFO 写时钟
	.wrreq(infifo_wr),			//输入FIFO 写请求
	.data(infifo_wdata),		//输入FIFO 写数据
	.wrfull(infifo_wrfull),		//输入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 读出数据
	.rdempty(outfifo_rdempty),	//输出FIFO 空标志
	.rdusedw(outfifo_rdusedw),  //输出FIFO 使用计数
	
	.wrclk(clk),				//输出FIFO 写时钟
	.wrreq(outfifo_wr),			//输出FIFO 写请求
	.data(outfifo_wdata),		//输出FIFO 写数据
	.wrfull(outfifo_wrfull),	//输出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;
	
	reg [31:0]test_count;

	// 数字音频接口 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;
		infifo_wr <= #1 1'b0;
		test_count <= #1 32'h0;
	end else
	begin
		if(lrcout)		//LRCOUT 高电平时清相关寄存器 20070122修改为LRCOUT
			begin
				recved <= #1 recv;
				recv <= #1 32'h0;
				recv_count <= #1 5'h0;
				recv_state <= #1 RECEIVE;      
			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
						if(dma_mode)
						begin
							infifo_wdata <= #1 {recv[30:0],dout};
							infifo_wr <=#1 1'b1;
							recv_state <= #1 WRITE_FIFO;
						end
						else
						begin
							// 20070122增加非dma模式同样需要接收最后一位
							recv <= #1 {recv[30:0],dout};
							
							recv_state <= #1 IDLE;
						end
					end    
				end
			WRITE_FIFO:
				begin
					recv_state <=#1 STOP;
				end
			STOP:
				begin
					infifo_wr <= #1 1'b0;
					recv_state <= #1 IDLE;
				end
			
		endcase
	end 
   
	//数字音频接口DSP模式旁路处理块
	reg    [31:0]send;       // send data to dac
	reg    [31:0]sended;     // sended data
	reg    [4:0]send_count;  // send counter
	reg    [1:0]send_state;  // send state 
	reg    bypass_out;
	
	//因为out_flag是lrcin推后一拍,所以使用bclk的下降沿能捕获到out_flag==1。
	//同时在bclk的下降沿把输出移位数据准备好。
	// recved 数据是读入状态机接收的前一帧数据,
	always @(negedge bclk) 
	if(~rst_n)
	begin
		send_state <= IDLE;
	end else 
	begin  
		if(out_flag)  //检测到lrcin的上升沿
		begin
			bypass_out <= #1 recved[31]; 
			send <= #1 {recved[30:0],1'b0};
			send_count <= #1 5'h1;  
			send_state <= #1 SEND; 
		end
		else 
		case (send_state)
			SEND:
				begin
					bypass_out <= #1 send[31];
					send <= #1 {send[30:0],1'b0};
					send_count <= send_count + 5'h1;
					if( send_count == 5'b11111)
					begin
						send_state <= #1 IDLE;
					end    
				end
		endcase
	end
	
	//数字音频接口 (DSP模式 DMA模式处理方式一致)
	//因为out_flag是lrcin推后一拍,所以使用bclk的下降沿能捕获到out_flag==1。
	//同时在bclk的下降沿把输出移位数据准备好。
	// recved 数据是读入状态机接收的前一帧数据
	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(out_flag & dma_mode &(~outfifo_rdempty)) 
		begin
			test_data <=#1 outfifo_rdata;		// test_data 测试时通过AVALONE 地址5读取
			dma_out <= #1 outfifo_rdata[31]; 
			dmasend <= #1 {outfifo_rdata[30:0],1'b0 };
			dmasend_count <= #1 5'h1;  
			dmasend_state <= #1 SEND; 
			outfifo_rd <= #1 1'b0;
		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_mode?dma_out:(bypass_mode ? bypass_out:0);
     
endmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -