s3c2440的IIS应用——放音与录音Lyping.gan

IIS(Inter-IC Sound)由飞利浦公司开发,是一种常用的音频设备接口,主要用于CD、MD、MP3等设备。

s3c2440一共有5个引脚用于IIS:IISDO、IISDI、IISSCLK、IISLRCK和CDCLK。前两个引脚用于数字音频信号的输出和输入,另外三个引脚都与音频信号的频率有关,可见要用好IIS,就要把信号频率设置正确。IISSCLK为串行时钟,每一个时钟信号传送一位音频信号,因此IISSCLK的频率=声道数×采样频率×采样位数,如采样频率fs为44.1kHz,采样的位数为16位,声道数2个(左、右两个声道),则IISSCLK的频率=32fs=1411.2kHz。IISLRCK为帧时钟,用于切换左、右声道,如IISLRCK为高电平表示正在传输的是左声道数据,为低电平表示正在传输的是右声道数据,因此IISLRCK的频率应该正好等于采样频率。由于IIS只负责数字音频信号的传输,而要真正实现音频信号的放、录,还需要额外的处理芯片(在这里,我们使用的是UDA1341),CDCLK为该芯片提供系统同步时钟,即编解码时钟,主要用于音频的A/D、D/A采样时的采样时钟,一般CDCLK为256fs或384fs。

通过以上分析可以发现,采样频率fs对频率的设置至关重要。而fs不是任意设置的,一般基于不同的应用场合和听觉效果,而设置不同的几个固定的值,如8kHz、16kHz、22.05kHz、44.1kHz、48kHz、96kHz等。为了使系统得到以fs为基数的各类时钟信号,就要重新调整系统时钟。s3c2440用于IIS的时钟源有PCLK和MPLLin,我们这里选择PCLK作为IIS的时钟源。PCLK经过两个预分频器处理后分别得到IISSCLK、IISLRCK和CDCLK(预分频器A得到IISSCLK、IISLRCK,预分频器B得到CDCLK)。寄存器IISPSR是IIS预分频器寄存器,5~9位是预分频器A,0~4位是预分频器B,一般来说,这两个预分频器的值N相等,即只要知道一个,另一个也就知道,而这里我们是通过CDCLK来计算预分频器B的值N的,即CDCLK=PCLK / (N+1)。PCLK与FCLK有一定的比例关系,而FCLK又是由输入频率Fin得到。在这里,我们为了简化计算,不改变PCLK与FCLK的比例关系(即维持在启动代码中定义的1:8的关系),那么由Fin而得到CDCLK一共涉及到四个参数:MDIV、PDIV、SDIV和前面公式中的N,涉及到的寄存器有MPLLCON和IISPSR。因此要得到这四个参数值,就需要一点耐心地计算,原则是误差最小,其中需要注意的是,计算的结果(包括中间过程的结果)不要溢出,即不要超过32位。例如Fin为12MHz,我们设置采样频率fs=44.1kHz,而CDCLK=384fs=16.9344MHz,那么经过计算,最终得到N=3,MDIV=150,PDIV=5,SDIV=0,即IISPSR = (3< <5)="" |="" 3;,mpllcon=""><<12) |=""><<4) |="">

s3c2440有关IIS的寄存器除了IISPSR外,还包括IIS控制寄存器IISCON,主要用于控制数据传输的方式、预分频器和IIS接口是否开启;IIS模式寄存器IISMOD,主要用于设置IIS的时钟源、主从方式、接收发送方式、串行接口方式、每个声道串行数据位数和各种频率值;IIS的FIFO接口寄存器IISFCON用于设置和判断数据传输的FIFO状态;而寄存器IISFIFO则用于音频数据的传输。

由于s3c2440要实现IIS的录、放音,还需要UDA1341芯片,因此我们再简要介绍一下这个芯片的使用。s3c2440与UDA1341之间除了我们前面介绍过的IIS接口相连接外,还有一个称之为L3总线的连接,用于s3c2440配置UDA1341内部的寄存器。由于s3c2440不具备L3总线接口,因此我们是用三个通用IO口来模拟L3,从而实现L3总线的传输。UDA1341有两种模式:地址模式和数据传输模式。地址模式表示传输的是地址信息,它的高6位永远是000101,低两位表示的是传输的模式,是状态模式、数据0模式还是数据1模式,其中状态模式主要用于配置UDA1341的各类初始状态,数据模式主要用于改善音频输入、输出的效果。

下面我们就给出具体的程序,在这里我们使用的是正常模式来实现数据的输入和输出的,即不使用DMA模式。首先是实现s3c2440对某一音频信号数据的输出,即放音。我们事先已知道该音频信号的各类特性,如采样频率、声道数、采样信号的位数等。

…… ……

//L3接口

#define L3C (1<<4) gpb4="">

#define L3D (1<<3) gpb3="">

#define L3M (1<<2) gpb2="">

//纯音频信号数据数组

unsigned char music[ ] = {

0xB8, 0xFF, 0xBA, 0xFF, 0xBF, 0xFF, 0xC0, 0xFF, 0xD4, 0xFF, 0xD3, 0xFF, 0xF2, 0xFF, 0xED, 0xFF,

0x0E, 0x00, 0x05, 0x00, 0x1C, 0x00, 0x0F, 0x00, 0x15, 0x00, 0x06, 0x00, 0xFC, 0xFF, 0xEC, 0xFF,

…… ……

}

//L3总线接口的写函数

//输入参数data为要写入的数据

//输入参数address,为1表示地址模式,为0表示数据传输模式

static void WriteL3(U8 data,U8 address)

{

int i,j;

if(address == 1)

rGPBDAT = rGPBDAT & ~(L3D | L3M | L3C) | L3C; //L3D=L, L3M=L(地址模式), L3C=H

else

rGPBDAT = rGPBDAT & ~(L3D | L3M | L3C) | (L3C | L3M); //L3M=H(数据传输模式)

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

; //等待一段时间

//并行数据转串行数据输出,以低位在前、高位在后的顺序

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

{

if(data & 0x1) // H

{

rGPBDAT &= ~L3C; //L3C=L

rGPBDAT |= L3D; //L3D=H

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

; //等待一段时间

rGPBDAT |= L3C; //L3C=H

rGPBDAT |= L3D; //L3D=H

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

; //等待一段时间

}

else // L

{

rGPBDAT &= ~L3C; //L3C=L

rGPBDAT &= ~L3D; //L3D=L

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

; //等待一段时间

rGPBDAT |= L3C; //L3C=H

rGPBDAT &= ~L3D; //L3D=L

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

; //等待一段时间

}

data >>= 1;

}

rGPBDAT = rGPBDAT & ~(L3D | L3M | L3C) | (L3C | L3M); //L3M=H,L3C=H

}

//放音

void playsound(unsigned char *buffer, int length)

{

int count,i;

char flag;

rGPBDAT = rGPBDAT & ~(L3M|L3C|L3D) |(L3M|L3C); //L3开始传输:L3M=H, L3C=H

//配置UDA1341

WriteL3(0×14 + 2,1); //状态模式(000101xx+10)

WriteL3(0×60,0); //0,1,10, 000,0 : 状态0,复位

WriteL3(0×14 + 2,1); //状态模式 (000101xx+10)

WriteL3(0×10,0); //0,0,01, 000,0 : 状态0, 384fs,IIS,no DC-filtering

WriteL3(0×14 + 2,1); //状态模式 (000101xx+10)

WriteL3(0xc1,0); //1,0,0,0, 0,0,01:状态1,

//Gain of DAC 6 dB,Gain of ADC 0dB,ADC non-inverting,

//DAC non-inverting,Single speed playback,ADC-Off DAC-On

//配置s3c2440的IIS寄存器

//预分频器为3,所以CDCLK=PCLK/(3+1)=16.928kHz

rIISPSR = 3<>

//无效DMA,输入空闲,预分频器有效

rIISCON = (0<><><><><<1);>

//PCLK为时钟源,输出模式,IIS模式,每个声道16位,CODECLK=384fs,SCLK=32fs

rIISMOD = (0<><><><><><><><<0);>

rIISFCON = (0<><<13);>

flag=1;

count=0;

//开启IIS

rIISCON |= 0x1;

while(flag)

{

if((rIISCON & (1<<7))==0)>

{

//FIFO中的数据为16位,深度为32

//当输出FIFO为空时,一次性向FIFO写入32个16位数据

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

{

rIISFIFO=(buffer[2*i+count])+(buffer[2*i+1+count]<>

}

count+=64;

if(count>length)

flag=0; //音频数据传输完,则退出

}

}

rIISCON = 0×0; //关闭IIS

}

void Main(void)

{

//配置MPLL

//fs=44.1kHz,CODECLK=384fs=16.9344MHz

//不改变CLKDIVN,所以PCLK=FCLK/8

//MPLLCON:MDIV=150,PDIV=5,SDIV=0,所以FCLK=541.7143MHz,PCLK=67.714MHz

rMPLLCON = (150< <12)="" |=""><<4) |="">

//配置L3接口总线,GPB2:L3MODE, GPB3:L3DATA, GPB4:L3CLOCK

rGPBCON = 0x015550; //输出

rGPBUP = 0x7ff; //上拉无效

rGPBDAT = 0x1e4;

//配置IIS接口

rGPEUP = rGPEUP & ~(0x1f) | 0x1f; //上拉无效,GPE[4:0] 1 1111

rGPECON = rGPECON & ~(0x3ff) | 0x2aa;

playsound(music,sizeof(music));

while(1)

{

;

}

}

上面的程序可以实现简单的播放内存中固有音频数据的功能,下面的程序实现了录制一段音频数据,然后再播出的功能。我们用UART来控制录、放音:当s3c2440接收到0x51时录音,接收到0x55时停止录音,接收到0x66时放音。

…… ……

#define L3C (1<<4) gpb4="">

#define L3D (1<<3) gpb3="">

#define L3M (1<<2) gpb2="">

unsigned char record_buffer[1000000]; //用于存放录制的音频数据

char stop,cmd;

//UART中断

void __irq uartISR(void)

{

char ch;

rSUBSRCPND |= 0x1;

rSRCPND |= 0x1<>

rINTPND |= 0x1<>

ch=rURXH0;

switch(ch)

{

case 0x51: //开始录音

cmd=0x01;

break;

case 0x55: //停止录音

stop=1; //置退出录音标志

break;

case 0x66: //放音

cmd=0x03;

break;

}

rUTXH0=ch;

}

…… ……

//录音

//输入参数为数组,输出参数为所录制数据的字节长度

int record(unsigned char * buffer)

{

int count,i;

unsigned short temp;

rGPBDAT = rGPBDAT & ~(L3M|L3C|L3D) |(L3M|L3C); //L3开始传输: L3M=H, L3C=H

//配置UDA1341

WriteL3(0x14 + 2,1); //状态模式(000101xx+10)

WriteL3(0x60,0); //0,1,10, 000,0 : 状态0,复位

WriteL3(0x14 + 2,1); //状态模式 (000101xx+10)

WriteL3(0x10,0); //0,0,01, 000,0 : 状态0, 384fs,IIS,no DC-filtering

WriteL3(0x14 + 2,1); //状态模式 (000101xx+10)

WriteL3(0xa2,0); //1,0,1,0, 0,0,10 状态1

//Gain of DAC 0 dB,Gain of ADC 6dB,ADC non-inverting,

//DAC non-inverting,Single speed playback,ADC-On DAC-Off

WriteL3(0x14 + 0,1); //DATA0 (000101xx+00)

WriteL3(0x7b,0); //01,11 10,11 : Data0, Bass Boost 18~24dB, Treble 6dB

WriteL3(0xc4,0); //1100 0,100 : Extended addr(3bits), 100

WriteL3(0xf0,0); //111,1 00,00 : DATA0, Enable AGC, 00, input amplifier gain channel 2 (2bits)

WriteL3(0xc0,0); //1100 0,000 : Extended addr(3bits), 000

WriteL3(0xe0,0); //111, 00000 : MA = 0dB

WriteL3(0xc1,0); //1100 0,001 : Extended addr(3bits), 001

WriteL3(0xe0,0); //111, 00000 : MB = 0dB

WriteL3(0xc2,0); //1100 0,010 : Extended addr(3bits), 010

WriteL3(0xf9,0); //111,1 10,11 : DATA0, MIC Amplifier Gain 27dB, input 1 X MA + input 2 X MB

//配置s3c2440的IIS寄存器

//预分频器为3,所以CDCLK=PCLK/(3+1)=16.928kHz

rIISPSR = 3<>

//无效DMA,输出空闲,预分频器有效

rIISCON = (0<><><><><<1);>

//PCLK为时钟源,输入模式,IIS模式,每个声道16位,CODECLK=384fs,SCLK=32fs

rIISMOD = (0<><><><><><><><<0);>

rIISFCON = (0<><<12);>

count=0;

//开启IIS

rIISCON |= 0x1;

while(stop==0)

{

if((rIISCON & (1<<6))==0)>

{

//FIFO中的数据为16位,深度为32

//当输入FIFO为满时,一次性读取FIFO中的32个16位数据

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

{

temp=rIISFIFO;

record_buffer[count+2*i]=(unsigned char)temp;

record_buffer[count+2*i+1]=(unsigned char)(temp>>8);

}

count+=64;

if(count>1000000)

stop=1; //当录制的数据超过数组长度时,退出

}

}

rIISCON=0; //关闭IIS

return count; //返回录制数据长度

}

void Main(void)

{

char play;

int bufferlength;

…… ……

//由于改变了PCLK,所以需要重新计算UART波特率因子

rUBRDIV0 = 36;

…… ……

stop=0;

cmd=0;

play=0;

while(1)

{

switch(cmd)

{

case 0×01: //录音

bufferlength=record(record_buffer);

play=1; //置录音标志

cmd=0;

break;

case 0×03: //放音

if(play)

playsound(record_buffer,bufferlength);

else //还没有录制音频数据

{

while(!(rUTRSTAT0 & 0×2));

rUTXH0 = 0xff;

}

cmd=0;

break;

}

}

}

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zhaocj/archive/2010/05/08/5570424.aspx

Responses to “s3c2440的IIS应用——放音与录音”

Leave a Reply

郑重声明:资讯 【s3c2440的IIS应用——放音与录音Lyping.gan】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——