您的位置:首页 > 其它

基于mini2440 IIS 模块总结

2015-09-08 09:36 369 查看
一.音频模块框图:



从上面的音频模块框图可以知道:

s3c2440 cpu中含有一个IIS控制器,然后板上面也含有一个编解码芯片(UDA1341)。

录音过程:外部模拟信号通过麦克风1和麦克风2传入UDA1341编解码芯片,然后在编解码芯片内模拟信号转换为数字信号(A/D转换),再通过I2SDI输入到IIS控制器,最后由DMA将IIS控制器中的录音数据搬运到内存中。

即:模拟信号----UDA1341中A/D转换----通过I2SDI进入IIS控制器---通过DMA搬运到内存中。

播音过程:首先DMA将内存中的音乐数据搬运到IIS控制器中,然后通过I2SDO数据线传送到编解码芯片(UDA1341)中,在编解码芯片中数字信号转换为模拟信号(D/A转换),最后模拟信号通过耳机传送出去,这样整个的播音过程就完成了。

即:数字信号---通过DMA从内存中搬运到IIS控制器中----通过i2SDO到UDA1341中D/A转换----模拟信号

总结:由上可知,音频模块涉及的方面比较多,有DMA  中断 IIS控制模块 UDA1341编解码芯片 L3协议(CPU通过L3协议对UDA1341编解码芯片进行初始化,因为L3协议没有专门的控制模块,所以对UDA1341编解码芯片的初始化,我们只有通过I/O口模拟的方法来对它进行配置了).

其中:IIS有四根线,包含 serial data input(IISDI), serial data output(IISDO),left/right channel select(IISLRCK),and serial bit clock(IISCLK);the device generating IISLRCK and IISCLK is the master.

二.IIS各个涉及模块的总结:

1.首先我们先来看一下S3C2440的原理图:



由上面的原理图可知,音频模块主要涉及的信号线有CDCLK(system clock),I2SCLK(serial bit clock),I2SLRCK(left/right channel select),I2SDI(serial data input),I2SDO(serial data output).L3MODE(因为IIS控制器通过l3协议初始化编解码芯片时,要传编解码地址信息和数据信息,然而传编解码地址信息和数据信息的时序又不同,所以通过这根线来区分)。L3CLOCK(L3协议传送数据的时钟线) 
L3DATA(L3协议传送的数据线).


所以首先我们应该配置这些引脚,将CDCLK I2SCLK I2SLRCK I2SDI I2SDO 五根线的I/O口配置为相应的功能模式,L3MODE  L3data  L3clock 的I/O应该配置为输出功能.

2.DMA模块的总结:

DMA(直接内存寻址,不需要CPU的干预)是一个搬运工,在s3c2440中我们可以看到,s3c2440中,在系统总线和外部总线之间可以支持4个通道控制。每个通道可以处理以下4种情况:

《1》源地址和目的地址都在系统总线上。

《2》源地址在系统总线上,目的地址在外部总线上。

《3》源地址在外部总线上,目的地址在系统总线上。

《4》源地址和目的地址都在外部总线上。

  



由上图可知:DMA的四个通道支持的源如上。在音频模块中,我们需要的是播音和录音,为了同时播音和录音,我们最好不要让播音和录音同时使用同一个通道,所以我们可以选择通道1作为录音源,通道0可以作为播音源,通道2既可以播音也可以用来录音。在本文中,我们选择通道1作为录音源,通道2作为播放源的通道。

DMA有整服务和单服务的两种不同的模式:

相同点:都是搬运完后才产生中断。

不同点:整服务模式是搬运完才清除ACK,单服务模式是每完成一次原子操作就就清除ACK.

我们选择单服务模式。

查询模式:一旦查到DREQ是低电平则马上响应ACK,并进行下一次的搬运动作。

握手模式:搬运完后通知DREQ信号。

下面是查询和握手模式的时序图:





由图和相关的理论可知,握手模式是比较可靠的。所以我们一般选择握手模式。

通过上述,我们可以知道,我们使用DMA时,选择的是单服务握手模式而且选择的是(a unit transfer).

关于DATA SIZE = half word = 两个字节= 16bit 是在制作的时候 作演示版级别的CD样带16-bit/44.1 kHz   

对于搬运的次数=总字节数/每次传输的字节  在本文中 我们选择的是 每次传输的是16bit,而且转码的工具是以char类型 来存放的。所以次数=总数组大小/2。

还需要注意 源地址、目的地址,是固定是增长、在外部总线上还是内部总线上。

在音频这个模块中,内存地址是增长的  IIS 的FIFO是一个固定的地址,而且内存控制是在内部总线上,而IIS控制器是在外部总线上面。

NOTE:初始化DMA要打开相应的DMA通道的中断,再初始化相应的寄存器就可以使DMA模块工作。

3.IIS控制模块.





由上面的IIS模块图可以知道:使用的PCLK产生的时钟,所以IIS是处于外部总线上面。

PCLK(50MHZ)通过分频器产生SCLK LRCK 提供IIS所需要的时钟需要,以及模块外部需要的时钟(编解码芯片的需要),为了使编解码芯片和IIS控制器能够正常的同步工作,所以我们在配置相应的寄存器的时候要使IPSR_A和IPSR_B这两个值要相等。

 2)  normal transfer:  transmit  准备好发送数据----not empty  flag=1;empty flag=0

                       receive  准备好接收数据not full  flag =1;full flag=0

       DMA transfer:   flag =1    (由规格书可以得出)

       作演示版级别的CD样带16-bit/44.1 kHz 

 

   3)  数据传输模式:IIS-bus format  MSB-justified  这是两种不同的数据传输模式,在这里我们选择IIS-bus format 这种格式比较好,是因为这种格式是延时了一点时间之后再发送高位,这样保证了不会丢失高位。





 





值得注意的是,在选时序和数据传输的格式时,我们需要参照UDA1341这款芯片的数据手册来看,因为我们要保证IIS控制器和UDA1341编解码芯片正常的工作的话,就需要使双方的传输频率和格式要一样。

载波频率 、采样率 

采样频率:是指录音设备在一秒钟内对声音信号的采样次数,采样频率越高声音的还原就越真实越自然。在当今的主流声卡上,采样频率一般共分为22.05KHz、44.1KHz、48KHz三个等级,22.05只能达到FM广播的声音品质,44.1KHz则是理论上的CD音质界限,48KHz则更加精确一些。对于高于48KHz的采样频率人耳已无法辨别出来了,所以在电脑上没有多少使用价值。   

44.1khz*256=编解码时钟的频率

左右声道时钟:实际上等于采样率

采样时钟又叫系统时钟:  得到一个声道(含左右声道16bit+16bit)的数据即采样一次所用的时钟周期数。(16+16)bit  256个系统时钟得到32bit-à

             256个系统时钟要传送32bit----》8个系统时钟传1bit,内部有缓冲(常采用32FS)----串行时钟周期 

 

编解码时钟:系统时钟(采样一次使用的系统周期数)*采样率

串行时钟:传输一位音频数据所用的时钟周期数。

采样位数:采样位数可以理解为声卡处理声音的解析度。这个数值越大,解析度就越高,录制和回放的声音就越真实。电脑中的声音文件是用数字0和1来表示的。所以在电脑上录音的本质就是把模拟声音信号转换成数字信号。反之,在播放时则是把数字信号还原成模拟声音信号输出。 

声卡的位:是指声卡在采集和播放声音文件时所使用数字声音信号的二进制位数。声卡的位客观地反映了数字声音信号对输入声音信号描述的准确程度。8位代表2的8次方——256,16位则代表2的16次方——64K。比较一下,一段相同的音乐信息,16位声卡能把它分为64K个精度单位进行处理,而8位声卡只能处理256个精度单位,造成了较大的信号损失,最终的采样效果自然是无法相提并论的。

4.UDA1341编解码芯片以及L3协议(IO口模拟)

查看UDA1341编解码芯片的规格书,我们可以得到以下信息:

音频编解码芯片的的属性有:系统时钟  增益放大 音量 各种特效-低重音  三倍音等,麦的敏感度  输入通道的选择等等。这些属性都是通过L3协议来控制的。(L3MODE  L3CLK  L3DATA)因为L3没有专门的控制模块,所以要用IO口模拟的方法通过L3来配置UDA1341编解码芯片,使编解码芯片工作。

IO口模拟的方式----低端CPU 

 (1)把相应的管脚配置为输出

 (2)把输出引脚的电平拉高、拉低定义好相应的宏。

(3)把时序描出来,如果时序比较复杂,则分段封装函数再调用

在编解码芯片的手册中,我们可以看到编解码芯片的地址是:

Bit【7:2】000101

BIt【1:0】indicate the type of the subsequent data transfer as shown as follow:





由上图可知:编解码芯片一共有三个寄存器:DATA0 DATA1 STATUS

其中STATUS是用于设置复位,系统时钟频率 数据输入模式 以及 DC滤波等内容。

DATA0 包含直接寻址模式和扩展寻址模式 直接寻址模式是直接进行模式的控制,包含音量,静音等等,而扩展寻址模式是在直接寻址模式下先设置的3位扩展地址,而在直接寻址模式下设置5位扩展数据。在DATA1下,可以读取到被检测的峰值。

注:在这里我们需要配置的寄存器有STATUS  DATA0(录音时) DATA1(只读寄存器)



 

 



以上两图是l3协议发送地址和发送数据时的时序图。我们通过IO模拟的方法将发送的时序描出来(即手动拉高拉低电平)。

下面是该模块的代码实现:

/************************************************

  NAME    : IIS.C

  DESC   :

  Revision: 2015.9.6 ver 0.0

 ************************************************/

#include "iis.h"

#include "pwm.h"

 

static volatile unsigned int Playflag;

static volatile unsigned int recordflag;

/***********************************************

Function  name  :   DMA2_handle

Description     :   interrupt service function of DMA2

Input parameter :   none

Return          :   none   

Others      :   none                                      

*************************************************/

static void __irq DMA2_handle()

{

 //clear the interrupt

 rSRCPND |=(1<<19);  //INT_DMA2

 rINTPND |=(1<<19);  //INT_DMA2

 Playflag = 1;

}

/***********************************************

Function  name  :   DMA2_for_play

Description     :   Dma2 for play music

Input parameter :   voicebuf  bytes

Return          :   none   

Others      :   none                                      

*************************************************/

void DMA2_for_play(unsigned char *voicebuf,unsigned int bytes)

{

 //init the interrupt

 rSRCPND |=(1<<19);  //INT_DMA2

 rINTPND |=(1<<19);  //INT_DMA2

 rINTMSK &=~(1<<19); //enable the interrupt

 rINTMOD &=~(1<<19);  //select the irq mode

 

 //config the register

 rDISRC2 = (int)voicebuf;

 rDISRCC2 = (0<<1)|(0<<0); //the SDRAM address is increment and the SDRAM is on the AHB

 rDIDST2 = (int)IISFIFO;  //the address of the destination

 rDIDSTC2 = (0<<2)|(1<<1)|(1<<0);//whole service mode  and the address of the IIS won't changed after transmited

 rDCON2 = (1<<31)|(0<<30)|(1<<29)|(0<<28)|(0<<27)|(0<<24)|(1<<23)|(1<<22)|(1<<20)|(bytes/2);

 rDMASKTRIG2 = (0<<2)|(1<<1)|(0);

 

 pISR_DMA2 =(unsigned int)DMA2_handle;

}

/***********************************************

Function  name  :   DMA1_handle

Description     :   interrupt service function of DMA1

Input parameter :   none

Return          :   none   

Others      :   none                                      

*************************************************/

static void __irq DMA1_handle()

{

 //clear the interrupt

 rSRCPND |=(1<<18);  //INT_DMA1

 rINTPND |=(1<<18);  //INT_DMA1

 recordflag = 1;

 

}

/***********************************************

Function  name  :   DMA1_for_record

Description     :   Dma1 for record

Input parameter :   voicebuf bytes

Return          :   none   

Others      :   none                                      

*************************************************/

void DMA1_for_record(unsigned char *voicebuf,unsigned int bytes)

{

 //init the interrupt

 rSRCPND |=(1<<18);  //INT_DMA1

 rINTPND |=(1<<18);  //INT_DMA1

 rINTMSK &=~(1<<18); //enable the interrupt

 rINTMOD &=~(1<<18);  //select the irq mode

 

 pISR_DMA1 = (unsigned int)DMA1_handle;

 //config the register

 rDISRC1 = (int)IISFIFO;  //the source address

 rDISRCC1 = (1<<1)|(1<<0); //the source is in the APB and the address is fixed

 rDIDST1 = (int)voicebuf;  //the destination address

 rDIDSTC1 = (0<<2)|(0<<1)|(0); //enable the interrupt,des is in the AHB,address is increment

 rDCON1 = (1<<31)|(0<<30)|(1<<29)|(0<<27)|(0<<28)|(2<<24)|(1<<23)|(1<<22)|(1<<20)|(bytes/2);

 rDMASKTRIG1 = (0<<2)|(1<<1)|(0);

}

/***********************************************

Function  name  :   stop_IIS_DMA2

Description     :   stop the service of the DMA2

Input parameter :   none

Return          :   none   

Others      :   none                                      

*************************************************/

void stop_IIS_DMA2()

{

 rDMASKTRIG2 &=~(1<<1); //DMA channel off

 rINTMSK |=(1<<19); //_DMA2

 

}

/***********************************************

Function  name  :   stop_IIS_DMA1

Description     :   stop the service of the DMA1

Input parameter :   none

Return          :   none   

Others      :   none                                      

*************************************************/

void stop_IIS_DMA1()

{

 rDMASKTRIG1 &=~(1<<1); //DMA channel off

 rINTMSK |=(1<<18); //Init_DMA1

}


/***********************************************

Function  name  :   IIS_pin_init

Description     :   引脚初始化

Input parameter :   none

Return          :   none   

Others      :   none                                      

*************************************************/

void IIS_pin_init()

{

 unsigned int temp;

 temp = rGPECON;

 temp &=~(0xff3);

 temp |=(0xa<<6)|(0xa<<2)|(2);//I2SDO  I2SDI CDCLK I2SSCLK I2SLRCK

 rGPECON = temp;

 

 rGPEUP |=(0xf<<1)|(1);

 

 temp = rGPBCON;

 temp &=~(0xf3<<4);

 temp |=(0x15<<4); //L3mode   L3DATA  L3clock config to output mode

 rGPBCON = temp; 

}

/***********************************************

Function  name  :   set_IIS_for_record

Description     :   录音功能函数

Input parameter :   none

Return          :   none   

Others      :   none                                      

*************************************************/

void set_IIS_for_record(void)

{

 rIISCON = (0x1<<4)|(0x1<<3)|(0x1<<1);

 //16bit 384fs
bd70
32fs  

 rIISMOD = (0x0<<9)+(0x0<<8)+(0x1<<6)+(0x0<<5)+(0x0<<4)+(0x1<<3)+(0x1<<2)+(0x1<<0);

 //  IISLRCK = 44.1KHZ  CODECLK = 384fs  16.93

 rIISPSR = (0x2<<5)|(0x2); //research the handbook  Prescaler A = PCLK/16.93 = 2 + 1

 rIISFCON = (0x1<<14)|(0x1<<12); 

}

/***********************************************

Function  name  :   set_IIS_for_play

Description     :   播放功能函数

Input parameter :   none

Return          :   none   

Others      :   none                                      

*************************************************/

void set_IIS_for_play(void)

{

 rIISCON = (0x1<<5)|(0x1<<2)|(0x1<<1);

 //16bit  384fs  32fs

 rIISMOD = (0x0<<9)+(0x0<<8)+(0x2<<6)+(0x0<<5)+(0x0<<4)+(0x1<<3)+(0x1<<2)+(0x1<<0);

 //IISLRCK = 44.1KHZ  CODECLK = 384fs  16.93

 rIISPSR = (0x2<<5)|(0x2);  //research the handbook Prescaler A = PCLK/16.93 = 2 + 1

 rIISFCON = (0x1<<15)|(0x1<<13);

}

/***********************************************

Function  name  :   start_IIS

Description     :   启动IIS

Input parameter :   none

Return          :   none   

Others      :   none                                      

*************************************************/

void start_IIS(void)

{

 rIISCON |= (0x1<<0); //enable IIS interface

}

/***********************************************

Function  name  :   stop_IIS

Description     :   关闭IIS

Input parameter :   none

Return          :   none   

Others      :   none                                      

*************************************************/

void stop_IIS(void)

{

 rIISCON &= ~(0x1<<0); //disable IIS interface

 rIISFCON = 0x0; //disable fifo

}


/***********************************************

Function  name  :   set_L3_data

Description     :   利用L3协议发送数据

Input parameter :   addr *pdata size

Return          :   none   

Others      :   none                                      

*************************************************/

static void set_L3_data(unsigned char addr,unsigned char *pdata,unsigned char size)

{

 int i,j;

 //address

 L3M_H;

 L3C_H;

 for(j=0;j<100;j++);

 

 L3M_L;

 for(j=0;j<100;j++);

 

 for(i=0;i<8;i++)

 {

  if(addr&0x01)

  {

   L3D_H;

   L3C_L;

   for(j=0;j<100;j++);

   L3C_H;

   for(j=0;j<100;j++);

  }

  else

  {

   L3D_L;

   L3C_L;

   for(j=0;j<100;j++);

   L3C_H;

   for(j=0;j<100;j++);

  }

  addr>>=1;

 }

 

 //finish setup time

 for(j=0;j<100;j++);

 L3M_H;

 for(j=0;j<100;j++);

 

 

 

 

 while(size)

 {

  //data

     L3M_L;

     for(j=0;j<100;j++);

 

     L3M_H;

     for(j=0;j<100;j++);

     

  for(i=0;i<8;i++)

  {

   if(*pdata&0x01)

   {

    L3D_H;

    L3C_L;

    for(j=0;j<100;j++);

    L3C_H;

    for(j=0;j<100;j++);

   }

   else

   {

    L3D_L;

    L3C_L;

    for(j=0;j<100;j++);

    L3C_H;

    for(j=0;j<100;j++);

   }

   (*pdata) >>=1;

  }

  

  //finish setup time

  for(j=0;j<100;j++);

  L3M_L;

  

  for(j=0;j<100;j++);

  L3M_H;

  for(j=0;j<100;j++);

  

  pdata++;

  size--;

 }

}

/***********************************************

Function  name  :   set_UDA1341_work

Description     :   使音频解码芯片工作

Input parameter :   mode

Return          :   none   

Others      :   none                                      

*************************************************/

static void set_UDA1341_work(unsigned int mode)

{

 unsigned char regdata[10],i;

 

 //configure the STATUS register.

 i=0;

 //0x50 = 0,1,01, 0000  reset,  384fs,  IIS-bus, no DC-filtering

 regdata[i++] = 0x50;

 

 if(mode == IISPLAYBACK)

 {

  //1,0,0,0, 0,0,01  gain of DAC 0db, gain of ADC 0db  PAD:non-inverting  PDA:non-inverting DS:single speed playback  DAC:on  ADC:off

  regdata[i++] = 0x81;

 }

 else if(mode==IISRECORD)

 {

  //1,0,1,0,  0,0,01  gain of DAC 0db,gain of ADC 6db  PAD:non-inverting PDA:non-inverting DS:single speed playback DAC:off  ADC:on

  regdata[i++] = 0xa2;

 }

 

 set_L3_data(UDA1341STATUS, regdata, i);

 //configure the DATA0

 

 i=0;

 if(mode == IISRECORD) //MIC Amplifier Gain 9db

 {

   /********下面可省略********/

   regdata[i++] = 0 << 6 ;//volume 0db

   regdata[i++] = 1 << 6 | 14 << 2 | 0 << 0;  //bass boost 18~24db

   regdata[i++] = 2 << 6 | 0 << 5 | 2 << 3 | 0 << 2 | 0 << 0;  //de-emphasis 44.1Khz 

   set_L3_data(UDA1341DATA0,regdata,i);

   /**********************/

   i=0;

   regdata[i++]  = UDA1341DATA0EXTEND0 | 2; //mic sensitivity  input channel select

   regdata[i++] = 7 << 5 | 6 << 2 | 2 << 0;//注意:bit[7][6][5]是全1此数据才能写进去

  

   /********下面可省略********/

   regdata[i++] = UDA1341DATA0EXTEND0 | 4;   //Input channel 2 amplifier gain

   regdata[i++] = 7 << 5 | 1 << 4 | 1 << 1;

   regdata[i++] = UDA1341DATA0EXTEND0 | 5;   //Input channel 2 amplifier gain

   regdata[i++] = 7 << 5 | 3 << 1;

   /**********************/

 

   set_L3_data(UDA1341DATA0, regdata,i);

  

 }

 

}

/***********************************************

Function  name  :   IIS_record_voice

Description     :   IIS 为录音功能

Input parameter :   *voicebuf 录音数据的缓存  bytes--所录的字节数

Return          :   none   

Others      :   none                                      

*************************************************/

void IIS_record_voice(unsigned char *voicebuf,unsigned int bytes)

{

 recordflag = 0;

 IIS_pin_init();

 set_UDA1341_work(IISRECORD);

 set_IIS_for_record();

 DMA1_for_record(voicebuf,bytes);

 start_IIS();

 

 while(!recordflag)

 {

  uart_printf("aa.");

  delayns1(1); //delay for 1s

 }

 

 delayns(1); //delay for 200ms

 stop_IIS();

 stop_IIS_DMA1();

 uart_printf("record end \n");

}

/***********************************************

Function  name  :   IIS_play_voice

Description     :   IIS 为播音

Input parameter :   *voicebuf 播音数据所存放的缓存  bytes--所录的字节数

Return          :   none   

Others      :   none                                      

*************************************************/

extern void Delay_MS( unsigned int time);

void IIS_play_voice(unsigned char *voicebuf,unsigned int bytes)

{

 Playflag = 0;

 IIS_pin_init();

 set_UDA1341_work(IISPLAYBACK); //enable 编解码芯片

 set_IIS_for_play();

 DMA2_for_play(voicebuf,bytes);

 start_IIS();

 while(!Playflag)

 {

  uart_printf("~");

  Delay_MS(5000);

 }

 delayns(1); //delay for 200ms

 stop_IIS();

 stop_IIS_DMA2();

 uart_printf("play end \n");

}


 

 

 

 


 

 

 

 

 

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: