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总是被首先的传输在左右声道切换的时候。
芯片手册
语音芯片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——主模式(IISLRCK和IISCLK是输出模式) 1——从模式(IISLRCK和IISCLK是输入模式) |
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)后,经过两个预分频器处理后会分别得到IISSCLK、IISLRCK和CDCLK(预分频器A得到IISSCLK、IISLRCK;预分频器B得到CDCLK)。一般来说,这两个预分频器的值N相等。这里通过CDCLK来计算预分频器B的N值来推知预分频器A的N值,计算公式为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;
}
上一篇:mini2440硬件篇之SPI
下一篇:mini2440硬件篇之RTC
推荐阅读最新更新时间:2024-03-16 15:22