s3c2440的IIS应用——放音与录音

发布者:SereneMeadow7最新更新时间:2016-05-30 来源: eefocus关键字:s3c2440  IIS应用  放音与录音 手机看文章 扫描二维码
随时随地手机看文章
       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 = (150<<12) | (5<<4) | 0;。
 
       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 = L3CLOCK
#define L3D (1<<3)             //GPB3 = L3DATA
#define L3M (1<<2)             //GPB2 = L3MODE
 
//纯音频信号数据数组
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(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(0xc1,0);           //1,1,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<<5|3;
       //无效DMA,输入空闲,预分频器有效
rIISCON  = (0<<5)|(0<<4)|(0<<3)|(1<<2)|(1<<1);   
       //PCLK为时钟源,输出模式,IIS模式,每个声道16位,CODECLK=384fs,SCLK=32fs
       rIISMOD  = (0<<9)|(0<<8)|(2<<6)|(0<<5)|(0<<4)|(1<<3)|(1<<2)|(1<<0);     
       rIISFCON = (0<<15)|(1<<13);           //输出FIFO正常模式,输出FIFO使能
      
       flag=1;
       count=0;
       //开启IIS
       rIISCON |= 0x1;
       while(flag)
       {
      
              if((rIISCON & (1<<7))==0)               //检查输出FIFO是否为空
              {    
                     //FIFO中的数据为16位,深度为32
                     //当输出FIFO为空时,一次性向FIFO写入32个16位数据
for(i=0;i<32;i++)
                     {
                            rIISFIFO=(buffer[2*i+count])+(buffer[2*i+1+count]<<8);
                     }                  
count+=64;
                     if(count>length)
                            flag=0;                  //音频数据传输完,则退出
              }
       }
       rIISCON = 0x0;            //关闭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) | (5<<4) | 0;
      
//配置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 = L3CLOCK
#define L3D (1<<3)              //GPB3 = L3DATA
#define L3M (1<<2)              //GPB2 = L3MODE
 
unsigned char record_buffer[1000000];                     //用于存放录制的音频数据
char stop,cmd;
 
//UART中断
void __irq uartISR(void)
{
       char ch;
       rSUBSRCPND |= 0x1;
       rSRCPND |= 0x1<<28;
       rINTPND |= 0x1<<28;
       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<<5|3;
       //无效DMA,输出空闲,预分频器有效
rIISCON  = (0<<5)|(0<<4)|(1<<3)|(0<<2)|(1<<1);   
       //PCLK为时钟源,输入模式,IIS模式,每个声道16位,CODECLK=384fs,SCLK=32fs
rIISMOD = (0<<9)|(0<<8)|(1<<6)|(0<<5)|(0<<4)|(1<<3)|(1<<2)|(1<<0);
       rIISFCON = (0<<14)|(1<<12);           //输入FIFO正常模式,输入FIFO使能
      
       count=0;
 
       //开启IIS
       rIISCON |= 0x1;
       while(stop==0)
       {
      
              if((rIISCON & (1<<6))==0)               //检查输入FIFO是否为满
              {    
                     //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 0x01:                    //录音
                            bufferlength=record(record_buffer);
                            play=1;          //置录音标志
                            cmd=0;
                            break;
                     case 0x03:                    //放音
                            if(play)
                                   playsound(record_buffer,bufferlength);
                            else                //还没有录制音频数据
                            {
                                   while(!(rUTRSTAT0 & 0x2));
                                   rUTXH0 = 0xff;
                            }
                            cmd=0;
                            break;
              }
}
}



 
 
补充:
 
应大家的要求,我把UDA1341的L3通信协议详细介绍一下。
 
       顾名思义,L3就是line 3(3条线)的意思,它只有L3DATA(数据线:用于传输数据)、L3MODE(模式线:用于选择模式)、L3CLOCK(时钟线:用于传输时钟)。L3一共有两个模式:地址模式和数据传输模式,先传输地址模式数据,再传输数据模式数据。L3MODE为低时是地址模式,L3MODE为高时是数据传输模式。L3DATA和L3CLOCK相互作用,完成8位数据的传输,传输的顺序是先低位数据,再高位数据。
 
地址模式是用于选择设备和定义目标寄存器,在这种模式下,8位数据的含义是:高6位是设备地址(UDA1341的地址为000101),低两位是后面数据模式下寄存器的类型(00:DATA0,01:DATA1,10:STATUS)。只要没有再改变地址模式下的数据,则数据模式下的数据始终是传输到上一个地址模式所定义的寄存器内。
 
在传输数据模式下,STATUS是用于设置复位,系统时钟频率、数据输入模式、DC滤波等内容。DATA0分为直接寻址模式和扩展寻址模式,直接寻址模式是直接进行模式的控制,包括音量、静音等等,而扩展寻址模式是在直接寻址模式下先设置3位扩展地址,再在直接寻址模式下设置5位扩展数据。在DATA1下,可以读取到被检测峰值。至于具体的DATA0、DATA1、STATUS下,每一位数据具体的含义,还请自己查阅手册。
关键字:s3c2440  IIS应用  放音与录音 引用地址:s3c2440的IIS应用——放音与录音

上一篇:s3c2440的DMA应用
下一篇:s3c2440的SD/MMC的应用

推荐阅读最新更新时间:2024-03-16 14:55

U-Boot补丁 S3C2440
# tar xvf u-boot-1.1.6.tar.bz2 //解压 # cd u-boot-1.1.6/ 制作补丁文件 # diff -urN u-boot-1.1.6 u-boot-1.1.6.new u-boot-1.1.6_jz2440.patch 打补丁 # patch -p1 u-boot-1.1.6_jz2440.patch p1:忽略补丁文件第一个”/”之前的内容(也就是如下:u-boot-1.1.6) # head u-boot-1.1.6_jz2440.patch diff -urN u-boot-1.1.6/board/100ask24x0/100ask24x0.c u-boo
[单片机]
S3C2440启动代码执行顺序
一张mini2440启动代码执行顺序表
[单片机]
<font color='red'>S3C2440</font>启动代码执行顺序
S3C2440通过J-Link直接往SDRAM中烧程序
由于S3C2440核心板以及主板均为实验室自制,使用友善之臂的H-Jtag不能操作,因此使用J-Link来测试焊接完的核心板是否工作正常 步骤: 1. 连接好核心板,并开电 2. 使用J-Link自带的J-Link commander(安装J-Link时已经安装了) 启动J-Link commander,如果没检测到CPU,执行usb命令连接JLink,注意,S3C2440 CPU的ID是:0x0032409D 3. 在J-Link commander下载运行特制的程序 对于S3C2410、S3C2440处理器,它们内部有4K的SRAM,当使用Nor Flash启动时,地址为0x40000000;当使用Nan
[单片机]
<font color='red'>S3C2440</font>通过J-Link直接往SDRAM中烧程序
s3c2440裸机-LCD编程(四、实现显示功能)
1.让LCD显示满屏红色 我们想要在LCD上显示出数据,所需步骤如下: a. 初始化LCD b. 使能LCD c. 获取LCD参数: fb_base, xres, yres, bpp d. 往framebuffer中写数据 1.初始化LCD工作我们在前面一节框架准备和LCD初始化已经详细介绍了。 2.使能LCD void lcd_enable() { lcd_controller_enalbe(); //会间接调用s3c2440_lcd_controller_enalbe } 3.获取LCD参数 void get_lcd_params(unsigned int *fb_base, int *xres, int
[单片机]
s3c2440IIS(4)S3C2440的I2S控制器
一、I2S控制器结构框图 S3C2440A的Inter-IC Sound (IIS)总线接口作为一个编解码接口连接外部8/16位立体声音频解码IC用于迷你碟机和可携式应用。IIS总线接口支持IIS总线数据格式和MSB-justified数据格式。该接口对FIFO的访问采用了DMA模式取代了中断。它可以在同一时间接收和发送数据。 图1 结构框图 1 、总线接口,寄存器组和状态机(BRFC):总线接口逻辑和FIFO 访问由状态机控制。 2、5 位双预定标器(IPSR):一个预定标器用于IIS 总线接口的主时钟发生器,另外一个用作外部编解码时钟发生器。 3、64 位FI
[单片机]
<font color='red'>s3c2440</font>之<font color='red'>IIS</font>(4)<font color='red'>S3C2440</font>的I2S控制器
ARM总线架构(S3C2440
S3C2440集成了丰富了外设控制器(LCD控制器、USB Device控制器、USB Host控制器、NAND FLASH控制器、I2C控制器、SPI控制器等)。要控制这些外设就要设置相应控制器的寄存器以产生相应的驱动时序。学习S3C2440,主要是如何配置寄存器。下面是S3C2440特殊功能寄存器地址: #define rBANKCON0 (*(volatileunsigned *)0x48000004) //Boot ROM control #define rBANKCON1 (*(volatileunsigned *)0x48000008) //BANK1 control #define rBANKCON2 (*(vo
[单片机]
ARM总线架构(<font color='red'>S3C2440</font>)
s3c2440头文件之mmu.h
************************************************ NAME : MMU.H DESC : Revision: 02.28.2002 ver 0.0 ************************************************/ #include 2440slib.h #ifndef __MMU_H__ #define __MMU_H__ #ifdef __cplusplus extern C { #endif #define DESC_SEC (0x2|(1 4)) #define CB (3 2) //cache_on, write_back
[单片机]
s3c2440的LCD应用
1、时序 LCD一般需要三个时序信号:VSYNC、HSYNC和VCLK。VSYNC是垂直同步信号,在每进行一个帧(即一个屏)的扫描之前,该信号就有效一次,由该信号可以确定LCD的场频,即每秒屏幕刷新的次数(单位Hz)。HSYNC是水平同步信号,在每进行一行的扫描之前,该信号就有效一次,由该信号可以确定LCD的行频,即每秒屏幕从左到右扫描一行的次数(单位Hz)。VCLK是像素时钟信号。 s3c2440处理LCD的时钟源是HCLK,通过寄存器LCDCON1中的CLKVAL可以调整VCLK频率大小,它的公式为: VCLK=HCLK 例如,HCLK的频率为100MHz,要想驱动像素时钟信号为6.4MHz的LCD屏,则通过上
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多每日新闻
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved