mini2440硬件篇之IIS

IIS(集成音频接口)于上个世纪80年代首先被Philips公司用于消费产品的音频设备。被广泛运用于CD、数字音频磁带、数字音频处理器和数字TV音频。

IIS的组成一般来说包括4个管脚:串行数据输入(IISDI)、串行数据输出(IISDO)、左/右通道选择(IISLRCK)、串行位时钟(IISCLK);产生IISLRCK和IISCLK的是主控器。在S3C2440上和IIS相关的接口还有一个用于提供CODEC时钟的管脚。就时序信号工作来说,当IISSCLK提供不间断的时钟信号的时候IISLRCK会以“数据位 + 1”的宽度方式产生周期信号。低电平时期表示左声道,高电平时期表示右声道。然后IISDI或者IISDO就按照一定的格式不断的发送/接收数据。

至于这种数据的格式,根据S3C2440的芯片资料的说明可以知道这样以MSB为首位可以让传输器和接收器不用知道对方的字长。数据还是按照各自的字长进行截取,如果不能匹配就会造成截断或者添0(意思是如果系统字长为32位而传输器的字长为16位那么传输的时候32位的系统数据就会被折成16位的)反正就是数据位从高到低的传输。至于MSB对齐格式,和上面的时序区别在于MSB总是被首先的传输在左右声道切换的时候。

1. 芯片手册

语音芯片UDA1341TS

/* -----------------------------------------------------------------------------------

 *地址模式时序,掌握几个要点 

 *数据传输的时候保证L3MODE为低 

 *数据传输开始的信号是保证L3MODE为低L3CLOCK为高 

 *数据传输结束的信号是保证L3MODE为高L3CLOCK为高 

 *数据传输过程中一个L3CLOCK的周期传一个数据位 

 *数据模式时序,掌握几个要点 

 *数据传输的时候保证L3MODE为低 

 *数据传输开始的信号是保证L3MODE为高L3CLOCK为高 

 *数据传输结束的信号是保证L3MODE为高L3CLOCK为高 

 *数据传输过程中一个L3CLOCK的周期传一个数据位 

 *------------------------------------------------------------------------------------*/

 

2. mini2440电路图

3. S3C2440寄存器

s3C2440A的IIS总线接口用于实现一个CODEC接口来扩展8/16位立体声CODEC芯片到便携式应用。IIS总线接口支持IIS总线数据格式和MSB对齐数据格式。接口提供DMA传输模式用于FIFO访问代替一个中断。它能同步的传输和接收数据如同选择单独传输或者接收数据一样好。

时序的速率和音频数据的采样速率相关,因为IIS传输的是数字采样信号。所以数据的传输必须要达到采样速率。这里以一个wav文件作为例子(采样频率44.1KHz、声道数2、数据位数16)。该文件的声音要得到还原,那么数据必须以44.1KHz的速率传输。但是数据是串行传输的,为了在指定时间传输到数据,所以传输速率必须要乘以16才能一个数据以44.1KHz的速率传输,然后由于声道数位2,所以有两个通道要同时传输数据。但是传输通道只有一个,所以为了保证同时,还要在此基础上乘以2。根据上面的时序可以知道是SCLK在控制整个时序,所以得出IISSCLK=采样频率×采样位数×通道数。这里为了简便起见,采样频率记为fs。于是IISSCLK为32fs。知道一个管脚的时序,其他时序也就好确定了。

在S3C2440下,IIS的配置都是通过寄存器来完成的。下面总结一些S3C2440使用IIS接口需要做的一些配置工作。

IIS相关的寄存器:

IISCON寄存器

功能名称

说明

LR_CH_INDEX

[8]

/右声道索引

0——

1——

TRANS_FIFO_RFLAG

[7]

传输FIFO准备标识

0——

1——非空

RECV_FIFO_RFLAG

[6]

接收FIFO准备标识

0——

1——非满

TRANS_DMA_EN

[5]

传输DMA服务请求

0——关闭

1——使能

RECV_DMA_EN

[4]

接收DMA服务请求

0——关闭

1——使能

TRANS_CH_IDLE_CMD

[3]

Idle状态IISLRCK是非活动的(暂停Tx

0——Not idle

1——Idle

RECV_CH_IDLE_CMD

[2]

Idle状态IISLRCK是非活动的(暂停Rx

0——Not idle

1——Idle

IIS_PRESCALER

[1]

IIS预分频

0——关闭

1——开启

IIS_EN

[0]

IIS接口使能

0——关闭

1——开启

IISMOD寄存器

功能名称

说明

MA_CLK_SELECT

[9]

主时钟选择

0——PCLK

1——MPLLin

MA_SL_MODE

[8]

/从模式选择

0——主模式(IISLRCKIISCLK是输出模式)

1——从模式(IISLRCKIISCLK是输入模式)

TX_RX_MODE

[7:6]

传输/接收模式选择

00——无传输

01——接收模式

10——传输模式

11——传输和接收模式

LR_CH_EN

[5]

左右声道使能

0——右声道

1——左声道

SER_FORMAT

 [4]

串行接口格式

0——IIS兼容格式

1——MSB对齐格式(最高位左对齐)

SER_DATA_BIT

[3]

串行数据位数

0——8

1——16

MA_CLK_FS

[2]

主时钟频率选择

0——256fs

1——384fs

fs:采样频率)

SCLK

[1:0]

串行时钟频率选择

00——16fs

01——32fs

10——48fs

11——保留

IISPSR寄存器

功能名称

说明

PRE_A

[9:5]

预分频器A的值

PRE_B

[4:0]

预分频器B的值

注意:选择IIS的时钟源(PCLK或者MPLLin)后,经过两个预分频器处理后会分别得到IISSCLKIISLRCKCDCLK(预分频器A得到IISSCLKIISLRCK;预分频器B得到CDCLK)。一般来说,这两个预分频器的值N相等。这里通过CDCLK来计算预分频器BN值来推知预分频器AN值,计算公式为CDCLK=时钟源/(N+1)

IISFCON寄存器

功能名称

说明

TX_FIFO_MODE

[15]

传输FIFO访问模式选择

0——普通

1——DMA

RX_FIFO_MODE

[14]

接收FIFO访问模式选择

0——普通

1——DMA

TX_FIFO_EN

[13]

传输FIFO使能位

0——关闭

1——使能

RX_FIFO_EN

[12]

接收FIFO使能位

0——关闭

1——使能

传输FIFO数据计数

[11:6]

数据计数值0~32

接收FIFO数据计数

[5:0]

数据计数值0~32

IISFIFO寄存器

功能名称

说明

FENTRY

[15:0]

IIS FIFO寄存器保存传输或者接收的音频数据值

 

3.1. DMA

S3C2440支持4通道位于系统总线和外围设备总线之间的DMA控制器。每个DMA控制器通道能执行数据搬运在系统总线设备和/或外围总线设备之间而没有限制。换句话说,每个通道能处理下面4种情形:

1. 源和目地都在系统总线里

2. 源在系统总线目地在外围总线

3. 源在外围总线目地在系统总线

4. 源和目地都在外围总线

DMA的优势是它在传输数据的时候不需要CPU的干预。DMA操作能被软件初始化,或者响应来自内部外围总线或者扩展请求管脚。

DMA请求资源

各个DMA控制器的通道能选择其中一个DMA请求资源,如果H/W DMA请求模式被DCON寄存器选择(注意如果S/W请求模式被选择,这个DMA请求资源无任何意义)。表8-1展示了4个DMA资源于各个通道。

 

 DMA操作

空闲时:DMA_ACK = 0;INT_REQ = 0;

单服务:知道CURR_TC计数变为0;

全服务:完成一次原子操作;

完成后:DMA_ACK =1;INT_REQ = 1;

传输大小

单元(unit)和突发(Burst)

iis.h

/*******************************************************************
 * Copyright (C),2011-2012, XXX.
 * FileName: iis.h 
 * Author:HuangYinqing
 * Version:1.0
 * Date::2012-08-12
 * Description:iis音频驱动.
 * Function List:
 * History:
 ******************************************************************/

/*IIS调试等级*/
#define	DBG_IIS_LEVEL	1

/*采样频率选择*/
#define FRQ_SELECT	4

/*使用DMA传输数据*/
//#define	IIS_USE_DMA

/*引脚定义*/
#define L3C		(1<<4)              //GPB4 = L3CLOCK
#define L3D		(1<<3)              //GPB3 = L3DATA
#define L3M		(1<<2)              //GPB2 = L3MODE

#define MIN_VOLUME	0x01
#define MID_VOLUME	0x20
#define	MAX_VOLUME	0x3e	 //==音量最大值

/*缓冲区产度*/
#define SOUND_DATA_LEN		243552

/*函数原型*/

/***************************************************************
 ** 函数名称:void SoundRecord(unsigned char *pucRecBuf, unsigned long ulSize)
 ** 函数功能:录音
 ** 入口参数:pucPlayBuf:放音缓冲区;ulSize:缓冲区大小
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
void SoundRecord(unsigned char *pucRecBuf, unsigned long ulSize);


/***************************************************************
 ** 函数名称:void SoundPlay(unsigned char *pucPlayBuf, unsigned long ulSize)
 ** 函数功能:放音
 ** 入口参数:pucPlayBuf:放音缓冲区;ulSize:缓冲区大小
 ** 出口参数:无
 ** 返    回值:无
 ***************************************************************/
void SoundPlay(unsigned char *pucPlayBuf, unsigned long ulSize);


/***************************************************************
 ** 函数名称:void SoundTest(void)
 ** 函数功能:录音和放音测试
 ** 入口参数:无
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
void SoundTest(void);

iis.c

/*******************************************************************
 * Copyright (C),2011-2012, XXX.
 * FileName: iis.c 
 * Author:HuangYinqing
 * Version:1.0
 * Date::2012-08-12
 * Description:iis音频驱动.
 * Function List:
 * History:
 ******************************************************************/
#include "common.h"
#include "core.h"
#include "iis.h"
#include "WindowsXP_Wav.h"
//#include "AudioDrv.h"

static int read_dma = 1;
static int play_dma = 1;

static struct{
	U16 Freq;
	U32 MPLL;
	U16 PreScaler;
	U8	ofs;
}CodecPara[7] = 
{
	{8000 , (123<<12) | (6<<4) | 0, (23<<5) | 23, 0},
	{11025, (229<<12) | (5<<4) | 1, (11<<5) | 11, 1},
	{16000, (123<<12) | (6<<4) | 0, (11<<5) | 11, 0},
	{22050, (229<<12) | (5<<4) | 1, (5<<5)  | 5 , 1},
	{32000, (123<<12) | (6<<4) | 0, (5<<5)  | 5 , 0},
	{44100, (229<<12) | (5<<4) | 1, (2<<5)  | 2 , 1},
	{48000, (123<<12) | (6<<4) | 0, (3<<5)  | 3 , 0}
};



/***************************************************************
 ** 函数名称:static void __irq DMA2_play_done(void)
 ** 函数功能:放音DMA2中断
 ** 入口参数:无
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
static void __irq DMA2_play_done(void)
{
	//清除悬挂的DMA2中断
	ClearPending(BIT_DMA2);     //Clear pending bit

	play_dma = 0;
}


/***************************************************************
 ** 函数名称:static void DMA2_play_close(void)
 ** 函数功能:关闭DMA2
 ** 入口参数:无
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
static void DMA2_play_close(void)
{
	//DMA MASK TRIGGER
	// 2 - STOP - Stop the DMA operation. - 1: DMA stops as soon as the current atomic transfer ends. If there
	//											is no current running atomic transfer, DMA stops immediately
	rDMASKTRIG2 = (1<<2);

	DisableIrq(BIT_DMA2);
}


/***************************************************************
 ** 函数名称:static void DMA2_play_init(U32 src_addr , U32 dst_addr , U32 len)
 ** 函数功能:初始化DMA2为输入放音功能
 ** 入口参数:src_addr:源地址;dst_addr:目标地址;len:需要传输的数据长度
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
static void DMA2_play_init(U32 src_addr , U32 dst_addr , U32 len)
{
	/*DMA触发屏蔽,关闭DMA*/
	// 2 - STOP - Stop the DMA operation. - 1: DMA stops as soon as the current atomic transfer ends. If there
	//											is no current running atomic transfer, DMA stops immediately
	rDMASKTRIG2 = (1<<2);

	/*DMA2初始源,放音源是内存*/
	rDISRC2 = src_addr;

	/*DMA2初始源控制*/
	// 1 - LOC - 0: the destination is in the system bus (AHB)
	// 0 - INC - Bit 0 is used to select the address increment. - 0 = Increment
	rDISRCC2 = (0 << 1) | (0 << 0);

	/*初始目标,放音目标是IIS外设FIFO*/
	rDIDST2 = dst_addr;

	/*DMA初始目标控制*/
	// 2 - CHK_INT - Select interrupt occurrence time when auto reload is setting - 1: Interrupt will occur after auto-reload is performed
	// 1 - LOC - 1: the source is in the peripheral bus (APB)
	// 0 - INC - Bit 0 is used to select the address increment. - 1= Fixed
	rDIDSTC2 = (1 << 2) | (1 << 1) | (1 << 0);

	/*DMA控制*/
	// 31 - DMD_HS - 1: Handshake mode will be selected.
	// 30 - SYNC - 0: DREQ and DACK are synchronized to PCLK (APB clock).
	// 29 - INT - 1: Interrupt request is generated when all the transfer is done
	// 28 - TSZ - 0: A unit transfer is performed.
	// 27 - SERVMODE - 0: Single service mode is selected in which after each atomic
	//						transfer (single or burst of length four) DMA stops and waits for
	//						another DMA request.
	// 26:24 - HWSRCSEL - Select DMA request source for each DMA - 000:I2SSDO
	// 23 - SWHW_SEL - Select the DMA source between software (S/W request mode) and
	//					   hardware (H/W request mode)
	//					   1: DMA source selected by bit[26:24] triggers the DMA operation
	// 22 - RELOAD - 1: DMA channel (DMA REQ) is turned off when a current value of
	//					  transfer count becomes 0. The channel on/off bit (DMASKTRIGn[1])
	//					  is set to 0 (DREQ off) to prevent unintended further start of new DMA operation.
	// 21:20 - DSZ - 01 = Half word
	rDCON2 = (1 << 31) | (0 << 30) | (1 << 29) | (0 << 28) | (0 << 27) | (0 << 24) | (1 << 23) | (1 << 22) | (1 << 20);

 	//设置要传输的数据次数
	rDCON2 &= ~0xfffff;
	rDCON2 |= len & 0xfffff;

	//设置DMA传输完成后的中断服务函数
	pISR_DMA2 = (U32)DMA2_play_done;

	//开启DMA的中断
	EnableIrq( BIT_DMA2);

	//DMA MASK TRIGGER
	// 2 - STOP - Stop the DMA operation. - 0 = Don't Stop
	// 1 - ON_OFF - DMA channel on/off bit - 1: DMA channel is turned on and the DMA request is handled
	// 0 - SW_TRIG - 0 = Hardware control it
	rDMASKTRIG2 = (0 << 2) | (1 << 1) | (0 << 0);
}


/***************************************************************
 ** 函数名称:static void __irq DMA2_read_done(void)
 ** 函数功能:录音DMA2中断
 ** 入口参数:无
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
static void __irq DMA2_read_done(void)
{
	//清除悬挂的DMA2中断
	ClearPending(BIT_DMA2);     //Clear pending bit

	read_dma = 0;
}


/***************************************************************
 ** 函数名称:static void DMA2_read_close(void)
 ** 函数功能:关闭DMA2
 ** 入口参数:无
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
static void DMA2_read_close(void)
{
	//DMA MASK TRIGGER
	// 2 - STOP - Stop the DMA operation. - 1: DMA stops as soon as the current atomic transfer ends. If there
	//											is no current running atomic transfer, DMA stops immediately
	rDMASKTRIG2 = (1<<2);

	DisableIrq(BIT_DMA2);
}

/***************************************************************
 ** 函数名称:static void DMA_read_init(U32 src_addr , U32 dst_addr , U32 len)
 ** 函数功能:初始化DMA2为输入录音功能
 ** 入口参数:src_addr:源地址;dst_addr:目标地址;len:需要传输的数据长度
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
static void DMA2_read_init(U32 src_addr , U32 dst_addr , U32 len)
{
	/*DMA触发屏蔽,关闭DMA*/
	// 2 - STOP - Stop the DMA operation. - 1: DMA stops as soon as the current atomic transfer ends. If there
	//											is no current running atomic transfer, DMA stops immediately
	rDMASKTRIG2 = (1<<2);

	/*DMA2初始源,录音源是外设*/
	rDISRC2 = src_addr;

	/*DMA2初始源控制*/
	// 1 - LOC - 1:  the source is in the peripheral bus (APB)
	// 0 - INC - Bit 0 is used to select the address increment. - 1= Fixed
	rDISRCC2 = (1 << 1) | (1 << 0);

	/*初始目标,录音目标是内存*/
	rDIDST2 = dst_addr;

	/*DMA初始目标控制*/
	// 2 - CHK_INT - Select interrupt occurrence time when auto reload is setting - 1: Interrupt will occur after auto-reload is performed
	// 1 - LOC - 0: the destination is in the system bus (AHB)
	// 0 - INC -  Bit 0 is used to select the address increment. - 0 = Increment
	rDIDSTC2 = (1 << 2) | (0 << 1) | (0 << 0);

	/*DMA控制*/
	// 31 - DMD_HS - 1: Handshake mode will be selected.
	// 30 - SYNC - 0: DREQ and DACK are synchronized to PCLK (APB clock).
	// 29 - INT - 1: Interrupt request is generated when all the transfer is done
	// 28 - TSZ - 0: A unit transfer is performed.
	// 27 - SERVMODE - 0: Single service mode is selected in which after each atomic
	//						transfer (single or burst of length four) DMA stops and waits for
	//						another DMA request.
	// 26:24 - HWSRCSEL - Select DMA request source for each DMA - 000:I2SSDO
	// 23 - SWHW_SEL - Select the DMA source between software (S/W request mode) and
	//					   hardware (H/W request mode)
	//					   1: DMA source selected by bit[26:24] triggers the DMA operation
	// 22 - RELOAD - 1: DMA channel (DMA REQ) is turned off when a current value of
	//					  transfer count becomes 0. The channel on/off bit (DMASKTRIGn[1])
	//					  is set to 0 (DREQ off) to prevent unintended further start of new DMA operation.
	// 21:20 - DSZ - 01 = Half word
	rDCON2 = (1 << 31) | (0 << 30) | (1 << 29) | (0 << 28) | (0 << 27) | (1 << 24) | (1 << 23) | (1 << 22) | (1 << 20);

 	//设置要传输的数据次数
	rDCON2 &= ~0xfffff;
	rDCON2 |= len & 0xfffff;

	//设置DMA传输完成后的中断服务函数
	pISR_DMA2 = (U32)DMA2_read_done;

	//开启DMA的中断
	EnableIrq( BIT_DMA2);

	//DMA MASK TRIGGER
	// 2 - STOP - Stop the DMA operation. - 0 = Don't Stop
	// 1 - ON_OFF - DMA channel on/off bit - 1: DMA channel is turned on and the DMA request is handled
	// 0 - SW_TRIG - 0 = Hardware control it
	rDMASKTRIG2 = (0 << 2) | (1 << 1) | (0 << 0);
}


/* -----------------------------------------------------------------------------------
 *地址模式时序,掌握几个要点 
 *数据传输的时候保证L3MODE为低 
 *数据传输开始的信号是保证L3MODE为低L3CLOCK为高 
 *数据传输结束的信号是保证L3MODE为高L3CLOCK为高 
 *数据传输过程中一个L3CLOCK的周期传一个数据位 
 *数据模式时序,掌握几个要点 
 *数据传输的时候保证L3MODE为低 
 *数据传输开始的信号是保证L3MODE为高L3CLOCK为高 
 *数据传输结束的信号是保证L3MODE为高L3CLOCK为高 
 *数据传输过程中一个L3CLOCK的周期传一个数据位 
 *------------------------------------------------------------------------------------*/ 

/***************************************************************
 ** 函数名称:static void WrL3Data(U8 data,int halt)
 ** 函数功能:通过L3接口写数据到UDA1341
 ** 入口参数:data:数值
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
static void WrL3Data(U8 data, int halt)
{
    S32 i,j;

    if(halt)
    {
        rGPBDAT  = rGPBDAT & ~(L3D | L3M | L3C) | L3C;
        for(j=0;j<4;j++);                                //tstp(L3) > 190ns
    }

    //将L3D,L3M,L3C这3个位清0后将L3C和L3M位置1
    rGPBDAT  = rGPBDAT & ~(L3D | L3M | L3C) | (L3C | L3M);

    //tsu(L3)D时序,需要190ns
    for(j=0;j<4;j++);

      //GPB[4:2]=L3C:L3D:L3M
    for(i=0;i<8;i++)
    {
      	//如果数据为1
        if(data & 0x1)
        {
           rGPBDAT &= ~L3C; 
           rGPBDAT |= L3D; 
            //L3C需要在低位保持250ns
           for(j=0;j<4;j++);
           rGPBDAT |= (L3C | L3D);
            //L3C需要在高位保持250ns
           for(j=0;j<4;j++);
        }
	//数据为0
        else
        {
           rGPBDAT &= ~L3C;  
           rGPBDAT &= ~L3D;   
            //L3C需要在低位保持250ns
           for(j=0;j<4;j++);     
           rGPBDAT |= L3C;    
           rGPBDAT &= ~L3D; 
            //L3C需要在高位保持250ns
           for(j=0;j<4;j++);          
        }
	//传送下一位数据
        data >>= 1;                  
    }
    rGPBDAT  = rGPBDAT & ~(L3D | L3M | L3C) | (L3C | L3M); 
}


/***************************************************************
 ** 函数名称:static void WrL3Addr(U8 data)
 ** 函数功能:通过L3接口写地址到UDA1341
 ** 入口参数:data:地址值
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
static void WrL3Addr(U8 data)
{       
    S32 i,j;

    //清除L3D,L3M,L3C这3个位之后置L3C位为1
    rGPBDAT  = rGPBDAT & ~(L3D | L3M | L3C) | L3C; 

    //将L3M置为0之后需要需要190ns的时序才能降低L3C
    for(j=0;j<4;j++);                   //tsu(L3) > 190ns

    for(i=0;i<8;i++)                    //LSB first
    {
    	//如果数据为1
        if(data & 0x1)        
        {
            rGPBDAT &= ~L3C;   
            rGPBDAT |= L3D;    
            //L3C需要在低位保持250ns
            for(j=0;j<4;j++);   
            rGPBDAT |= L3C;  
           	rGPBDAT |= L3D;  
            //L3C需要在高位保持250ns
            for(j=0;j<4;j++);   
        }
	//数据为0
        else                      
        {
            rGPBDAT &= ~L3C;  
            rGPBDAT &= ~L3D;    
            //L3C需要在低位保持250ns
            for(j=0;j<4;j++);         
            rGPBDAT |= L3C;       
            rGPBDAT &= ~L3D; 
            //L3C需要在高位保持250ns
            for(j=0;j<4;j++);           
        }
	//传送下一位数据
        data >>= 1;
    }
    rGPBDAT  = rGPBDAT & ~(L3D | L3M | L3C) | (L3C | L3M);  
}


/***************************************************************
 ** 函数名称:static void AdjVolume(unsigned char volume)	
 ** 函数功能:调整音量
 ** 入口参数:volume:音量值
 ** 出口参数:无
 ** 返    回:无
 ***************************************************************/
static void AdjVolume(unsigned char volume)	
{	 
	WrL3Addr(0x14 + 0);			
   	WrL3Data(MAX_VOLUME-volume, 0);
}


/***************************************************************
 ** 函数名称:void UDA1341_play_init(void)
 ** 函数功能:UDA1341放音初始化
 ** 入口参数:无
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
void UDA1341_play_init(void)
{	
/*------------------------写状态----------------------------*/	
	//STATUS (000101xx+10)
	WrL3Addr(0x14 + 2);	//==写状态,复位
	//0,1,10,000,0 : Status 0,Reset,256fs,IIS-bus,no DC-filtering
	//0,1,10,000,0--UDA1341TS设备重启,系统时钟设置为256fs,数据输入格式设置IIS总线,没有DC滤波
	WrL3Data(0x60,0);
	
	//STATUS (000101xx+10)
	WrL3Addr(0x14 + 2);	//==写状态,频率384fs
	//0,0,01,000,0 : Status 0,No reset,384fs,IIS-bus,no DC-filtering
	//0,0,01,000,0--UDA1341TS设备不重启,系统时钟设置为384fs,数据输入格式设置为IIS总线,没有DC滤波
	WrL3Data(0x10,0);

	STATUS (000101xx+10)
	WrL3Addr(0x14 + 2);	//==写状态,DAC输出6DB增益
	//1,1,0,0, 0,0,01
	//Status 1,Gain of DAC 6 dB,Gain of ADC 0dB,ADC non-inverting,DAC non-inverting
	//,Single speed playback,ADC-Off DAC-On
	//1,1,0,0,0,0,01--DAC输出增益选择为6db(OGS),ADC输入增益选择为0db(IGS),ADC极性不翻转,DAC极性不翻转,倍速回放关闭,ADC关闭DAC启动
	WrL3Data(0xc1,0);
			 
#if 0
	WrL3Addr(0x14 + 0);
	/*-------直接地址操作-------*/
	// - 设置音量
	WrL3Data( 0x10, 0);
#endif
}


/***************************************************************
 ** 函数名称:void UDA1341_record_init(void)
 ** 函数功能:UDA1341录音初始化
 ** 入口参数:无
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
void UDA1341_record_init(void)
{	
/*---------------------------写状态------------------------*/
	/*写状态,复位*/
	WrL3Addr(0x14 + 2);	
		//0,1,10, 000,0 : Status 0,Reset,256fs,IIS-bus,no DC-filtering
	WrL3Data(0x60,0);
	
	/*写状态,设置频率*/
	WrL3Addr(0x14 + 2);
	//0 - Status 0
	//0 - No reset,
	//01 - 384fs,
	//000 - IIS-bus
	//0 - no DC-filtering
	WrL3Data(0x10,0);

	/*写状态,ADC输入6DB增益*/
	WrL3Addr(0x14 + 2);
	//1,0,0,0, 0,0,01
	//Status 1,Gain of DAC 0 dB,Gain of ADC 6dB,ADC non-inverting,DAC non-inverting
	//,Single speed playback,ADC-On DAC-Off
	WrL3Data(0xa2,0);

/*-----------------------------写DATA0----------------------------*/
	WrL3Addr(0x14 + 0);
 #if 0
	/*-------直接地址操作-------*/
	// - 设置音量
	WrL3Data( 30, 0);

	// - 设置高低音,01,11 1011--低音18~24,高音6dB
	WrL3Data( 0x7b, 0);	

	// - 峰值检测,去加重,静音,音频滤波模式,
	

	/*-------间接地址操作-------*/
	// - 寄存器一,设置通道一的混频增益;MA = 0dB
	WrL3Data(0xc0,0);
	WrL3Data(0xe0,0);
	
	// - 寄存器二,设置通道二的混频增益;MB = 0dB
	WrL3Data(0xc1,0);
	WrL3Data(0xe0,0);	
#endif	
	// - 寄存器三,设置麦克风灵敏度和混频器模式
	// 111,1 10,11:MIC Amplifier Gain 27dB, input 1 X MA + input 2 X MB
	WrL3Data(0xc2,0);
	WrL3Data(0xe2,0);
	
	// - 寄存器四和五,设置AGC
	//111,1 00,00 : DATA0, Enable AGC, 00, input amplifier gain channel 2 (2bits)
	WrL3Data(0xc4,0);
	WrL3Data(0xf3,0);
	WrL3Data(0xc5,0);
	WrL3Data(0xff,0);
#if 0
	// - 寄存器六,设置自动增益时间控制常数
	// 
	WrL3Data(0x00,0);
	WrL3Data(0x00,0);
#endif

}


/***************************************************************
 ** 函数名称:void IIS_transmit_init(void)
 ** 函数功能:IIS传输数据初始化
 ** 入口参数:无
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
void IIS_transmit_init(void)
{
	//IIS PRESCALER
	//Prescaler control A - 5
	//Prescaler control B - 5
	rIISPSR  = CodecPara[FRQ_SELECT].PreScaler;

	//IIS CONTROL
	// 5 - Transmit DMA service request - 1 =Enable
	// 4 - Receive DMA service request - 0 =Disable
	// 3 - Transmit channel idle command - 0 = Not idle
	// 2 - Receive channel idle command - 1 = Idle
	// 1 - IIS prescaler - 1 =Enable
	// 0 - IIS interface - 0 =Disable (stop)
	rIISCON  = (0<<5) | (0<<4) | (0<<3) | (1<<2) | (1<<1);
#ifdef IIS_USE_DMA
	rIISCON |= 1<<5;
#endif
	
	//IIS MODE REGISTER
	// 9 - Master clock select - 0 = PCLK
	// 8 - Master/slave mode select - 0 = Master mode (IISLRCK and IISCLK are output mode).
	// 7:6 - Transmit/receive mode select - 10 = Transmit mode
	// 5 - Active level of left/right channel - 0 = Low for left channel (High for right channel)
	// 4 - Serial interface format - 0 = IIS compatible format
	// 3 - Serial data bit per channel - 1 = 16-bit
	// 2 - Master clock frequency -select - 1 = 384fs (fs: sampling frequency)
	// 1:0 - Serial bit clock frequency select - 01 = 32fs
	rIISMOD  = (0<<9) | (0<<8) | (2<<6) | (0<<5) | (0<<4) | (1<<3) | (1<<2) | (1<<0);	

	//IIS FIFO CONTROL
	// 15 - Transmit FIFO access mode select - 1 = DMA
	// 14 - Receive FIFO access mode select - 0 = Normal
	// 13 - Transmit FIFO - 1 = Enable
	// 12 - Receive FIFO - 0 = Disable
	//rIISFCON = (1<<15) + (1<<13);    
	rIISFCON = (0<<15) | (0<<14) |  (1<<13) | (0<<12);    
#ifdef IIS_USE_DMA
	rIISFCON |= 1<<15;
#endif
	//IIS interface - Enable (run)
	rIISCON |= 0x1;    		      

}


/***************************************************************
 ** 函数名称:void IIS_receive_init(void)
 ** 函数功能:IIS接收采样数据初始化
 ** 入口参数:无
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
void IIS_receive_init(void)
{
	//IIS PRESCALER
	//Prescaler control A - 5
	//Prescaler control B - 5
	rIISPSR  = CodecPara[FRQ_SELECT].PreScaler;

	//IIS CONTROL
	// 5 - Transmit DMA service request -0 =Disable
	// 4 - Receive DMA service request - 1 =Enable
	// 3 - Transmit channel idle command - 1 =Idle
	// 2 - Receive channel idle command - 0 =Not Idle
	// 1 - IIS prescaler - 1 =Enable
	// 0 - IIS interface - 0 =Disable (stop)
	rIISCON  = (0<<5) | (0<<4) | (1<<3) | (0<<2) | (1<<1);
#ifdef IIS_USE_DMA
	rIISCON |= 1<<4;
#endif	
	//IIS MODE REGISTER
	// 9 - Master clock select - 0 = PCLK
	// 8 - Master/slave mode select - 0 = Master mode (IISLRCK and IISCLK are output mode).
	// 7:6 - Transmit/receive mode select - 01 = Receive mode
	// 5 - Active level of left/right channel - 0 = Low for left channel (High for right channel)
	// 4 - Serial interface format - 0 = IIS compatible format
	// 3 - Serial data bit per channel - 1 = 16-bit
	// 2 - Master clock frequency -select - 1 = 384fs (fs: sampling frequency)
	// 1:0 - Serial bit clock frequency select - 01 = 32fs
	rIISMOD  = (0<<9) | (0<<8)  | (1<<6) | (0<<5) | (0<<4) | (1<<3) | (1<<2) | (1<<0);	

	//IIS FIFO CONTROL
	// 15 - Transmit FIFO access mode select - 0 = Normal
	// 14 - Receive FIFO access mode select - 1 = DMA
	// 13 - Transmit FIFO - 0 = Disable
	// 12 - Receive FIFO - 1 = Enable
	rIISFCON = (0<<15) | (0<<14) | (0<<13) | (1<<12);    
#ifdef IIS_USE_DMA
	rIISFCON |= 1<<14;
#endif
	//IIS interface - Enable (run)
	rIISCON |= 0x1;    		      
}


/***************************************************************
 ** 函数名称:void SoundGPIOInit(void)
 ** 函数功能:IIS和L3引脚初始化
 ** 入口参数:无
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
void SoundGPIOInit(void)
{
//----------------------------------------------------------
// 
//Ports  :   GPB4    GPB3   GPB2  
//Signal :  L3CLOCK L3DATA L3MODE
//Setting:   OUTPUT OUTPUT OUTPUT 
//           [9:8]   [7:6}  [5:4]
//Binary :     01  ,   01    01 
//----------------------------------------------------------    
	//设置GPB234为输出功能
	rGPBCON = rGPBCON & ~(0x3f<<4) | (0x15<<4);   

	//禁止GPB234的上拉功能
	rGPBUP  = rGPBUP  & ~(0x7<<2) | (0x7<<2);     

	
//----------------------------------------------------------
// 
//Ports  :  GPE4    GPE3   GPE2  GPE1    GPE0 
//Signal : I2SSDO  I2SSDI CDCLK I2SSCLK I2SLRCK 
//Binary :   10  ,   10     10 ,  10      10    
//----------------------------------------------------------
	//禁止GPE01234的上拉功能
	rGPEUP  = rGPEUP  & ~(0x1f)  | 0x1f;   
	//设置GPE01234的功能为
	//GPE0 - I2SLRCK
	//GPE1 - I2SSCLK
	//GPE2 - CDCLK
	//GPE3 - I2SDI
	//GPE4 - I2SDO
	rGPECON = rGPECON & ~(0x3ff) | 0x2aa;  
}


/***************************************************************
 ** 函数名称:void SoundPlay(unsigned char *pucRecBuf, unsigned long ulSize)
 ** 函数功能:放音
 ** 入口参数:pucPlayBuf:放音缓冲区;ulSize:缓冲区大小
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
void SoundPlay(unsigned char *pucRecBuf, unsigned long ulSize)
{
	/*轮询方式需要的变量*/
#ifndef IIS_USE_DMA
	int i;
	int count = 0;
	unsigned char *pData = pucRecBuf;
#endif
	
	DbgPrintX( DBG_IIS_LEVEL, "\rSound play test\n");

	//初始化UDA1341为录音状态
	UDA1341_play_init();

	//初始化IIS为录音状态
	IIS_transmit_init();
	
#ifdef IIS_USE_DMA	
	DMA2_play_init( (U32)pucRecBuf, (U32)IISFIFO, ulSize/2);
	while( play_dma )
	{
	}
	
	play_dma = 1;
	DMA2_play_close();
#else
	while(count < ulSize)
	{
		//检测输入缓冲区是否满了
		if( (rIISCON & (1 << 7))==0 )
		{
			for(i=0; i<32; i++)
			{
				rIISFIFO = *pData + (*(pData+1)<<8);
				pData += 2;
			}

			count += 64;
		}
	}	
#endif 
}


/***************************************************************
 ** 函数名称:void SoundRecord(unsigned char *pucRecBuf, unsigned long ulSize)
 ** 函数功能:录音
 ** 入口参数:pucPlayBuf:放音缓冲区;ulSize:缓冲区大小
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
void SoundRecord(unsigned char *pucRecBuf, unsigned long ulSize)
{
	/*轮询方式需要的变量*/
#ifndef IIS_USE_DMA
	int i;
	int count = 0;
	unsigned short tmp_data;
	unsigned char *pData = pucRecBuf;
#endif
	
	DbgPrintX( DBG_IIS_LEVEL, "\rSound record test\n");

	//初始化UDA1341为录音状态
	UDA1341_record_init();

	//初始化IIS为录音状态
	IIS_receive_init();
	
#ifdef IIS_USE_DMA	
	DMA2_read_init( (U32)IISFIFO, (U32)pucRecBuf, ulSize/2);
	while( read_dma )
	{
	}
	
	read_dma = 1;
	DMA2_read_close();
#else
	while(count < ulSize)
	{
		//检测输入缓冲区是否满了
		if( (rIISCON & (1 << 6))==0 )
		{
			for(i=0; i<32; i++)
			{
				tmp_data = rIISFIFO;
				*pData++ = tmp_data & 0xff;
				*pData++ = ((tmp_data>>8) & 0xff);
			}

			count += 64;
		}
	}	
#endif 
}


/***************************************************************
 ** 函数名称:void SoundTest(void)
 ** 函数功能:录音和放音测试
 ** 入口参数:无
 ** 出口参数:无
 ** 返        回:无
 ***************************************************************/
void SoundTest(void)
{
	unsigned char key;
	unsigned int volume = 30;
	int count = 5; 				//==测试次数
	unsigned long sound_size;	//==缓冲区大小
	unsigned char *sound_data;	//==缓冲区指针

	unsigned int saveMpll = rMPLLCON;  //==保存时钟配置值

	sound_size = SOUND_DATA_LEN;
	sound_data = (unsigned char *)_NONCACHE_STARTADDRESS;

	rMPLLCON = CodecPara[FRQ_SELECT].MPLL;	 //==配置时钟

	SoundGPIOInit();   //==引脚初始化
#if 0  /*放音,音量调节测试,只支持DMA方式*/
	while(1)
	{
		DbgPrintX( DBG_IIS_LEVEL, "\rSound play test\n");  //==调试
	
		//初始化UDA1341为输出状态
		UDA1341_play_init();
	
		//初始化IIS为输出状态
		IIS_transmit_init();
		
		key = Uart0GetChar();

		if( key == ESC_KEY )
				break;

		if( (key == '+') && (volume <= MAX_VOLUME) )
		{
			volume += 4;
			AdjVolume(volume);
		}

		if( (key == '-') && (volume >= MIN_VOLUME) )
		{
			volume -= 4;
			AdjVolume(volume);		
		}		

		DMA2_play_init( (U32)WindowsXP_Wav, (U32)IISFIFO, sizeof(WindowsXP_Wav)/2);

		while( play_dma )
		{
		}

		play_dma =1;
		DMA2_play_close();

	//	delay(1); 
	}
#else  /*录音、放音测试*/
	while(count--)
	{
		SoundRecord(sound_data, sound_size);
		SoundPlay(sound_data, sound_size);
		delay(1); 
	}
#endif
	rMPLLCON = saveMpll;
}


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值