![片上系统设计思想与源代码分析](https://wfqqreader-1252317822.image.myqcloud.com/cover/301/688301/b_688301.jpg)
6.5 IIS接口控制器设计与源代码分析
6.5.1 IIS控制器框图
模块框图如图6-10所示。
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0129_0001.jpg?sign=1739281382-asFXSTeCzyg9oGavDlYt9XjYoVsZDoVQ-0-e2ad4c8a0d07f614e4a943ff5365b445)
图6-10 IIS接口模块框图
6.5.2 功能描述
支持的总线标准为WISHBONE rev B3。
PSRA为SCK分频率器,其值为时钟频率/音频采样频率/32-1,再取整数。目前IIS接口只支持最常见8比特音频,采样速率可自由选择,只受Audio Codec的限制。若改为16比特,只需将FIFO的宽度增加到32位即可。
PSRA为CDCLK分频率器,其值为8×(PSRA+1)-1。目前IIS接口只支持256fs CDCLK。一般Audio Codec都支持。对其他分频率的支持尚未验证。
TxFIFO和RxFIFO都是深度32,宽16。高8比特为左声道,低8比特为右声道。
L3mode针对uda1341a设计,不是IIS协议本身的内容。
IIS接口支持DMA和非DMA两种模式。DMA所设计模式为支持DemoSoC的DMA控制器而设计。
目前只支持标准IIS格式,如图6-11所示。不支持MSB-justfied模式。
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0129_0002.jpg?sign=1739281382-SNM4a0up2vO5e8B3DMBjtDUDSP8ZigHZ-0-0f59953d7852042c4254c59017c04c0a)
图6-11 标准IIS格式时序
6.5.3 接口信号
IIS接口控制器接口信号如表6-1所示。
表6-1 IIS接口信号
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0130_0001.jpg?sign=1739281382-NXIYP5mXejaPXkLtHKhoylqOHTeVGFSE-0-1c64fe969e9e1f9821396e6dd7efda1f)
6.5.4 典型速率
音频编解码器的工作时钟CODECCLK或CDCLK必须以256或384倍音频采样频率fs方式工作。表6-2列出了fs和CODECCLK的典型值。
表6-2 音频CODEC时钟(CODECLK = 256 or 384fs)
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0130_0002.jpg?sign=1739281382-qWicRVCKJencsztLp20ftNEhENLJ48Xg-0-41daeedfc3572769a507fe5db9bb5c1c)
当左右声道采样比特均为8比特时,串行时钟频率fIISCLK=16fs;当左右声道采样比特均为16比特时,串行时钟频率fIISCLK=32fs;当左右声道采样比特均为24比特时,串行时钟频率fIISCLK=48fs,串行时钟IISCLK的典型值如表6-3所示。
表6-3 可用串行时钟频率(IISCLK = 16 or 32 or 48fs)
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0130_0003.jpg?sign=1739281382-2VI486kMZgJue4tZvYclXSZbSzz7813S-0-380776261010694fec81209dbcc12da1)
6.5.5 IIS总线接口寄存器
IIS总线接口寄存器定义及说明如表6-4~表6-9所示。
表6-4 IIS控制寄存器(IISCON)
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0130_0004.jpg?sign=1739281382-bSc7GzL2mU8kyIcKeaQURIeDcJQxeUnh-0-ad9f059b82c245487575032afca51010)
表6-9 IIS L3 REGISTER
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0133_0003.jpg?sign=1739281382-zbi4HL0ivO0S8qGGUS0kkxUM1pmQ0Hst-0-b48b555fc7be441e0941298a8b083433)
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0130_0005.jpg?sign=1739281382-KWVAB9f94CbE3Snmd3dN2CyC4Nj7FzF3-0-0e8b3e6eb8d12938132132fb56ed53af)
表6-5 IIS MODE REGISTER(IISMOD)REGISTER
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0131_0002.jpg?sign=1739281382-yZY4wYc4Ii2SHejT0XlkWAdNRA2aP3ed-0-8a3eecf7effa84ff95a2fef95976878e)
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0131_0003.jpg?sign=1739281382-90J87ZdzPqTaZEIrUziDmNg3q8GPhh8e-0-32c88a26fae5eadfa906a1d6cd6700e3)
表6-6 PRESCALER(IISPSR)REGISTER
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0132_0002.jpg?sign=1739281382-nq3h5He72oLoCeRAwg30CIUuceIqxB54-0-8e574bf94247ce9a63546b010ca386ef)
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0132_0003.jpg?sign=1739281382-UvI8JW2ewakzry7vV3DCM2YvjVmom2GN-0-7d0aae1d71ba98b512814dbbeeb304f7)
表6-7 IIS FIFO CONTROL(IISFCON)REGISTER
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0132_0004.jpg?sign=1739281382-ChZF8oPuYTSjJiKXSTwcLt3Bm8BZPcLf-0-21cda9d340eeb8b8689a60a2e5e583db)
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0132_0005.jpg?sign=1739281382-A0nZfoOF5uXjv0xAg1On4JpTexlyWNvh-0-c19829481bca872fd90a85ac49491b1d)
表6-8 IIS FIFO(IISFIFO)REGISTER
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0133_0001.jpg?sign=1739281382-3vGotjX6aaDhxxKFXSRhkkGEnDbTLnYe-0-98e8b15db1e3933b17aff434e74b3fff)
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0133_0002.jpg?sign=1739281382-PKYzt4nIDamjlXuy3Y2tzAlP6K9rEPYT-0-aa0c8b79fe033b875fbbb9ab11031382)
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0133_0004.jpg?sign=1739281382-wrEQMYlR6EKoEhFGrkl8nETocKdXoDwe-0-afd40802668d4554cedf5d7a3d8c204b)
6.5.6 设计文件列表
IIS控制器设计文件列表如表6-10所示。
表6-10 IIS控制器设计文件
![](https://epubservercos.yuewen.com/54D051/3590509604582801/epubprivate/OEBPS/Images/figure_0133_0005.jpg?sign=1739281382-j0e1smG5yHn4VvueZ3oZ8R9NuoMiTtmq-0-c574fa533d5051577dc461b6acc30d53)
6.5.7 源代码分析
`include "timescale.v" module iis_top(clk,rstn,wb_data_i,wb_data_o,wb_addr_i,wb_sel_i, wb_we_i,wb_cyc_i ,wb_stb_i, wb_ack_o,wb_err_o,wb_rty_o, ws,sck,datai,datao,cdclk, //IIS接口 l3mode,l3clock,l3data,// //uda1341ts L3控制接口 dma_req,dma_ack//DMA请求接口 ); //寄存器地址和数据宽度定义,IIS接口寄存器的定义见前文 parameter WB_WIDTH=32; parameter IISCON_ADDR = 6'd0; parameter IISMOD_ADDR = 6'd4; parameter IISPSR_ADDR = 6'd8; parameter IISFCON_ADDR = 6'd12; parameter IISFIFO_ADDR = 6'd16; parameter IISL3_ADDR = 6'd20; ……//此处忽略输入输出信号 output reg [1:0] dma_req; //两个DMA通道,一个音频输入,一个音频输出 input [1:0] dma_ack; //寄存器操作逻辑1.IISCON wire wb_cyc_stb=wb_cyc_i & wb_stb_i; wire tx_fifo_full,tx_fifo_empty; wire rx_fifo_full,rx_fifo_empty; reg [31:0] rx_fifo_data; reg [5:0] iiscon; wire tx_fifo_rdy=~tx_fifo_empty; wire rx_fifo_rdy =~tx_fifo_full; wire iiscon_rd={tx_fifo_rdy,rx_fifo_rdy,iiscon}; wire tx_dma_req_ena = iiscon[5]; wire rx_dma_req_ena = iiscon[4]; wire tx_chl_idle_cmd = iiscon[3]; wire rx_chl_idle_cmd = iiscon[2]; wire prescaler_ena = iiscon[1]; wire iis_ena = iiscon[0]; wire sel_iiscon = (wb_addr_i==IISCON_ADDR) & (|wb_sel_i) & (wb_cyc_stb); always @( posedge clk or negedge rstn) begin if(~rstn) iiscon<=0; else if(sel_iiscon & wb_we_i & wb_ack_o) begin iiscon[5:0] <=wb_data_i[5:0]; end end //1.IIS模式寄存器 reg [7:0] iismod; wire [1:0] transfer_mode = iismod [7:6]; wire active_level_left = iismod[5]; wire serial_if_format = iismod[4]; wire serial_bit_per_chl= iismod[3]; wire master_clk_fre =iismod[2]; wire [1:0] sck_fre_sel = iismod[1:0]; wire sel_iismod = (wb_addr_i==IISMOD_ADDR) & (|wb_sel_i) & (wb_cyc_stb); always @( posedge clk or negedge rstn) begin if(~rstn) iismod<=8'hc0;//default to receive & transmit else if(sel_iismod & wb_we_i & wb_ack_o) begin iismod[7:0] <=wb_data_i[7:0]; end end //2.IISPSR reg [31:0] iispsr; wire [15:0] psra=iispsr[31:16]; //用于从系统时钟分频生成CODECLK wire [15:0] psrb=iispsr[15:0]; //用于从系统时钟分频生成sck wire sel_iispsr = (wb_addr_i==IISPSR_ADDR) & (|wb_sel_i) & (wb_cyc_stb); always @( posedge clk or negedge rstn) begin if(~rstn) iispsr<={16'd31,16'd3}; else if(sel_iispsr & wb_we_i & wb_ack_o) begin iispsr <=wb_data_i; end end //3. IISCON reg [3:0] iisfcon; wire txfifo_mode= iisfcon[3]; wire rxfifo_mode= iisfcon[2]; wire rxfifo_enable= iisfcon[1]; wire txfifo_enable= iisfcon[0]; wire [4:0] tx_fifo_cnt; wire [4:0] rx_fifo_cnt; wire [15:0] iisfcon_rd= {iisfcon,tx_fifo_cnt,rx_fifo_cnt} ; wire sel_iisfcon = (wb_addr_i==IISFCON_ADDR) & (|wb_sel_i) & (wb_cyc_stb); always @( posedge clk or negedge rstn) begin if(~rstn) iisfcon<=4'h3; else if(sel_iisfcon & wb_we_i & wb_ack_o) begin iisfcon <=wb_data_i[15:12]; end end //4. iis_rx_fifo和iis_tx_fifo; //wishbone read & write reg tx_rdreq,tx_wrreq; reg [31:0] tx_fifo_data; wire sel_iisfifo = (wb_addr_i==IISFIFO_ADDR) & (|wb_sel_i) & (wb_cyc_stb); //tx fifo write. always @( posedge clk or negedge rstn) begin if(~rstn) begin tx_wrreq<=1'b0; end else if(sel_iisfifo & wb_we_i & wb_ack_o) begin tx_wrreq<=1'b1; tx_fifo_data<= wb_data_i; end else begin tx_wrreq<=1'b0; end end //IISL3_ADDR reg [15:0] l3_reg_out; reg [5:0] l3_reg_in; reg l3_trig; reg l3_reg_in_rdy; wire sel_iisl3 = (wb_addr_i==IISL3_ADDR) & (|wb_sel_i) & (wb_cyc_stb); //write loigc of L3 register always @(posedge clk or negedge rstn) begin if(~rstn) begin l3_trig<=1'b0; l3_reg_out<=0; end else if(sel_iisl3 & wb_we_i & wb_ack_o) begin l3_trig<=1'b1; l3_reg_out<=wb_data_i[15:0]; end else l3_trig<=1'b0; end //WISHBONE总线读逻辑 wire selected=sel_iisl3|sel_iiscon|sel_iismod|sel_iisfcon|sel_iisfifo|sel_iispsr; wire wr_ack = wb_we_i & (sel_iisl3|sel_iiscon|sel_iismod|sel_iisfcon |sel_iispsr| (sel_iisfifo& (!tx_fifo_full))); reg rd_fifo_ack; wire rd_ack = (~wb_we_i) &( (sel_iiscon|sel_iismod|sel_iisfcon|sel_iispsr|sel_iisl3)| rd_fifo_ack); assign wb_ack_o= wr_ack | rd_ack; assign wb_rty_o=1'b0; assign wb_data_o =sel_iiscon? {32'b0,iiscon_rd}:sel_iismod?{32'b0,iismod}: sel_iispsr?{32'b0,iispsr}:sel_iisfcon?{32'b0,iisfcon_rd}: sel_iisl3?{32'b0,l3_reg_in_rdy,l3_reg_in}: {16'b0,rx_fifo_data}; wire rx_fifo_rdreq = sel_iisfifo & !wb_we_i & (|wb_sel_i); always @(posedge clk or negedge rstn) begin if(~rstn) begin rd_fifo_ack<=1'b0; end else begin rd_fifo_ack<=rx_fifo_rdreq?1'b1:1'b0; end end assign wb_err_o= 0 //发生FIFO逻辑 wire fifo_aclr=~rstn; reg rx_wrreq; wire tx_fifo_sclr=~txfifo_enable; wire rx_fifo_sclr=~rxfifo_enable; wire [31:0] tx_fifo_q; wire [31:0] rx_fifo_q; fifo32x32 tx_fifo(.data(tx_fifo_data),.wrreq(tx_wrreq),.rdreq(tx_rdreq),.clock(clk) , .aclr(fifo_aclr), .sclr(tx_fifo_sclr),.q(tx_fifo_q),.full(tx_fifo_full),.empty(tx_fifo_empty),.usedw(t x_fifo_cnt)); fifo32x32 rx_fifo(.data(rx_fifo_data),.wrreq(rx_wrreq),.rdreq(rx_fifo_rdreq), .clock(clk), .aclr(fifo_aclr),.sclr(rx_fifo_sclr),.q(rx_fifo_q),.full(rx_fifo_full),.empty(rx_fif o_empty),.usedw(rx_fifo_cnt) ); always @(posedge clk or negedge rstn) begin if(~rstn) begin dma_req<=2'b0; end else begin if(dma_ack[1]) dma_req[1]<=1'b0; else if(rx_fifo_cnt>24) dma_req[1]<=1'b1; if(dma_ack[0]) dma_req[0]<=1'b0; else if(tx_fifo_cnt<8) dma_req[0]<=1'b1; end end //IIS接口逻辑,生成sck,ws,datai,cdclk。 //first is the cdclk and sck reg [10:0] psra_cnt; reg [6:0] psrb_cnt; wire [10:0] psra_cnt_mark=(psra)>>1; wire [6:0] psrb_cnt_mark=(psrb)>>1; //reg sck,cdclk; assign sck = psra_cnt<=psra_cnt_mark; assign cdclk = psrb_cnt<=psrb_cnt_mark; always @(posedge clk or negedge rstn) begin if(~rstn) begin psra_cnt<=0; psrb_cnt<=0; end else if(tx_chl_idle_cmd&tx_chl_idle_cmd) begin psra_cnt<=0; psrb_cnt<=0; end else if(iis_ena) begin if(psra_cnt<(psra)) begin psra_cnt<=psra_cnt+1; end else begin psra_cnt<=0; end if(psrb_cnt<(psrb)) begin psrb_cnt<=psrb_cnt+1; end else begin psrb_cnt<=0; end end end //生成ws reg sck_q; always @ (posedge clk) begin sck_q<=sck;end wire posedge_sck=sck &(!sck_q); wire negedge_sck=(!sck) &(sck_q); reg datao; reg [4:0] ws_cnt; reg [31:0] serial_out; reg [31:0] serial_in; assign ws= active_level_left?(ws_cnt>4'd15):(!(ws_cnt>4'd15)); always @(posedge clk or negedge rstn) begin if(~rstn) begin ws_cnt<=5'h1F;tx_rdreq<=1'b0;serial_out<=0;datao<=0; rx_wrreq<=1'b0; serial_in<=0; end else begin if(iis_ena) begin if(negedge_sck) begin ws_cnt<=ws_cnt-1; end if(posedge_sck && ws_cnt==5'h1F && !tx_chl_idle_cmd && !tx_fifo_empty) begin tx_rdreq<=1'b1; end else tx_rdreq<=1'b0; if(tx_rdreq) serial_out<=tx_fifo_q;//data ready if(negedge_sck) datao<=serial_out[ws_cnt]; //rx logic. if(negedge_sck && ws_cnt==5'h1E && !rx_chl_idle_cmd && !rx_fifo_full) begin rx_wrreq<=1'b1; rx_fifo_data<=serial_in; end else rx_wrreq<=1'b0; if(posedge_sck) begin if(ws_cnt<5'h1F) serial_in[ws_cnt+1]<=datai; else serial_in[0]<=datai; end end end //L3接口,不是IIS的一部分,uda1341ts需要L3接口进行初始化 reg l3data_ena; wire l3datai=l3data; reg l3datao; assign l3data=l3data_ena?l3datao : 1'bz; parameter L3_READ=1'b0; parameter L3_WRITE=1'b1; reg l3_wr_or_rd; end reg [4:0] l3_state; parameter L3_IDLE=5'd1, L3_ADDR=5'd2, L3_SHIFT_OUT=5'd4, L3_SHIFT_IN=5'd8, L3_ADDR_END=5'd16; reg [11:0] l3_cnt_low; reg [3:0] l3_cnt_high; reg l3mode,l3clock; wire [2:0] l3_shiftin_index=l3_cnt_high[3:1]-1; wire [7:0] l3_data_out_high_byte=l3_reg_out[15:8]; always @(posedge clk or negedge rstn) begin if(~rstn) begin l3_reg_in<=0; l3_wr_or_rd<=L3_WRITE; l3_state<=L3_IDLE; l3mode<=1'b1; l3clock<=1'b1; l3data_ena<=1'b0; l3_cnt_low<=0; l3_cnt_high<=0; l3_reg_in_rdy<=1'b0; l3datao<=1'b0; end else begin case (l3_state) L3_IDLE:begin if(l3_trig) begin l3_state<=L3_ADDR; l3mode<=1'b0; l3_cnt_low<=0; l3clock<=1'b1; l3data_ena<=1'b0; l3_cnt_high<=0; l3_cnt_low<=1; end else begin l3_cnt_low<=l3_cnt_low+1; if(l3_cnt_low==psra[11:0]) begin l3data_ena<=1'b0; end end end L3_ADDR: begin l3_reg_in_rdy<=1'b0; if(l3_cnt_low<psra[11:0]) begin l3_cnt_low<=l3_cnt_low+1; end else begin l3_cnt_low<=0; end if(l3_cnt_low==0) begin l3clock<=~l3clock; if(l3_cnt_high==4'hf) begin l3_cnt_high<=0; l3_state<=L3_ADDR_END; end else begin l3_cnt_high<=l3_cnt_high+1; l3data_ena<=1'b1; l3datao<=l3_reg_out[l3_cnt_high[3:1]]; end end end L3_ADDR_END:begin if(l3_cnt_low<(psra[11:0])) begin l3_cnt_low<=l3_cnt_low+1; end else begin l3_cnt_low<=1; l3mode<=1'b1; if(l3_reg_out[0]==1'b1) begin l3_state<=L3_SHIFT_IN; l3data_ena<=1'b0; end else begin l3_state<=L3_SHIFT_OUT; end end end L3_SHIFT_IN:begin if(l3_cnt_low<psra[11:0]) begin l3_cnt_low<=l3_cnt_low+1; end else begin l3_cnt_low<=0; end if(l3_cnt_low==0) begin if(l3_cnt_high==4'hf) begin l3_cnt_low<=1; l3_cnt_high<=0; l3_state<=L3_IDLE; l3_reg_in_rdy<=1'b1; end else begin l3_cnt_high<=l3_cnt_high+1; l3clock<=~l3clock;l3_reg_in[l3_shiftin_index]<=l3datai; end end end L3_SHIFT_OUT: begin//shift data out if(l3_cnt_low<psra[11:0]) begin l3_cnt_low<=l3_cnt_low+1; end else begin l3_cnt_low<=0; end if(l3_cnt_low==0) begin l3clock<=~l3clock; if(l3_cnt_high==4'hf) begin l3_cnt_high<=0; l3_state<=L3_IDLE;end else begin l3_cnt_high<=l3_cnt_high+1; l3data_ena<=1'b1; l3datao<=l3_data_out_high_byte[l3_cnt_high[3:1]]; end end end default:begin l3_state<=L3_IDLE; end endcase end end endmodule