基于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");
}
从上面的音频模块框图可以知道:
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");
}
相关文章推荐
- C#进阶系列——AOP?AOP!
- Oracle常用系统表汇总整理
- apache日志提示[warn] (OS 64)指定的网络名不再可用。 : winnt_accept
- Android开发书籍pdf汇总
- 图像处理函数详解——padarray(matlab)
- SOAPUI测试REST项目(一)---REST Service Mocking
- MD5文字加密方法
- 友善之臂の用自己的qt4.7程序替换掉友善之臂的start qt4.7.0
- 【cl】测试用例【文本框-电子邮箱】
- xml特殊字符转义技术
- iOS项目开发实战——获取本机IP地址
- String.Split()函数
- jconsole检查性能及死锁
- [leetcode-278]Dungeon Game(java)
- 白话machine learning之Loss Function
- JDFZ 1112 高三楼 数的划分
- 白话machine learning之Loss Function
- Centos 6.4 python 2.6.6 升级到 2.7.3
- SOAPUI测试WSDL项目(十)---MockService脚本概述
- mfc创建线程