您的位置:首页 > 其它

S3C2416裸机开发系列十八_音频驱动实现(2)

2014-06-10 09:50 218 查看

S3C2416裸机开发系列十八

音频驱动实现(2)

象棋小子 1048272975

IIS模块实现IIS.c如下:

#include"s3c2416.h"

#include "IIS.h"

#include"Exception.h"

#include"UART0.h"

#defineDEBUG_IIS

#ifdef DEBUG_IIS

#defineDebug(x...) Uart0_Printf(x)

#else

#defineDebug(x...)

#endif

staticunsigned char TX_Channel; // 发送音频的声道数

staticunsigned char TX_BitLen; // 发送位长

staticunsigned char RX_Channel; // 接收音频的声道数

staticunsigned char RX_BitLen; // 接收位长

staticvolatile unsigned char TxBufferFlag;

staticvolatile unsigned char RxBufferFlag;

staticunsigned int TxCount; // 播放时记录缓存中的写位置

staticunsigned int RxCount; // 录音时记录缓存中的读位置

// 插放与录音均采用双缓存,DMA传输的主存与cache会有数据一致性问题

// 音频DMA缓存分配到不开启cache的内存区域

staticunsigned int TxBuffer0[4*1024] __attribute__((section("No_Cache"),zero_init));

staticunsigned int TxBuffer1[4*1024] __attribute__((section("No_Cache"),zero_init));

staticunsigned int RxBuffer0[4*1024] __attribute__((section("No_Cache"),zero_init));

staticunsigned int RxBuffer1[4*1024] __attribute__((section("No_Cache"),zero_init));

static voidDMA_IRQ(void)

{

static unsigned char TxBufferChannel = 0;

static unsigned char RxBufferChannel = 0;

unsigned int DMA_Channel;

DMA_Channel = rSUBSRCPND;

if (DMA_Channel &(1<<SUBINT_DMA0)) { // DMA0中断请求, IIS TX

if (TxBufferChannel == 0) {

rDISRC0 = ((unsigned int)TxBuffer1);// 开始使用Buffer1缓存

TxBufferFlag &= ~(1<<0);// 发送标志0位清空,说明Buffer0数据需填充

TxBufferChannel = 1; // 正在发送Buffer1缓存

} else {

rDISRC0 = ((unsignedint)TxBuffer0);// 开始使用Buffer0缓存

TxBufferFlag &= ~(1<<1);// 发送标志1位清空,说明Buffer1数据需填充

TxBufferChannel = 0; // 正在发送Buffer0缓存

}

rDCON0 = (rDCON0&(~0xfffff)) |(sizeof(TxBuffer0)/4);

rDMASKTRIG0 = (1<<1); // IIS TX打开DMA0通道

rSUBSRCPND |= (1<<SUBINT_DMA0);

}

if (DMA_Channel &(1<<SUBINT_DMA1)) { // DMA1中断请求, IIS RX

if (RxBufferChannel == 0) {

rDIDST1 = ((unsigned int)RxBuffer1);// DMA1目的地址

RxBufferFlag |= (1<<0); // 接收缓存0位置位,说明Buffer0数据准备好

RxBufferChannel = 1; // 下一次使用Buffer1

} else {

rDIDST1 = ((unsigned int)RxBuffer0);// DMA1目的地址

RxBufferFlag |= (1<<1); // 接收缓存1位置位,说明Buffer1数据准备好

RxBufferChannel = 0; // 下一次使用Buffer0

}

rDCON1 = (rDCON1&(~0xfffff)) |(sizeof(RxBuffer0)/4);

rDMASKTRIG1 = (1<<1); // IIS RX打开DMA1通道

rSUBSRCPND |= (1<<SUBINT_DMA1);

}

rSRCPND1 |= (1 << INT_DMA);

rINTPND1 |= (1 << INT_DMA);

}

unsignedint IIS_WriteBuffer(unsigned char *pData, unsigned int MaxLen)

{

unsigned int i;

unsigned int nCount; // 能写入buffer中数据长度(以字计,fifo 32位长)

unsigned int *pBuffer;

unsigned char *pTemp = pData;

if (pTemp==0 || MaxLen==0) {

return 0; // 参数错误,数据未写入缓存

}

if ((TxBufferFlag&0x3) == 0x3) {

return 0; // Buffer0,Buffer1均已写满

}

if (!(TxBufferFlag & (1<<0))) { //Buffer0需填充

pBuffer = &TxBuffer0[TxCount];

} else { // Buffer1需填充

pBuffer = &TxBuffer1[TxCount];

}

nCount = (sizeof(TxBuffer0)/4) - TxCount;

switch (TX_BitLen) {

case 8:

if (TX_Channel != 1) { // 双声道

if (MaxLen/2 == 0) {// 左右声道fifo中有两个8位有效音频数据

pTemp += MaxLen; // 不足一个采样2字节数据,丢弃写入buffer中

}

MaxLen = MaxLen/2; // 32位的fifo中有两个8位有效音频数据

if (MaxLen < nCount) {

nCount = MaxLen;

}

for (i=0; i<nCount; i++) {

*pBuffer++ = (((unsignedint)pTemp[1]<<16)+

((unsignedint)pTemp[0]<<0));

pTemp += 2; // 2个8位的声道数据已写入buffer中

}

} else { // 单声道

if (MaxLen < nCount) {// 32位的fifo中有一个8位有效音频数据

nCount = MaxLen;

}

for (i=0; i<nCount; i++) {

*pBuffer++ = (unsignedint)pTemp[0]<<0;

pTemp += 1; // 1个8位的声道数据已写入FIFO中

}

}

break;

case 16:

if (TX_Channel != 1) { // 双声道

if (MaxLen/4 == 0) {// 左右声道fifo中有四个8位有效音频数据

pTemp += MaxLen; // 不足一个采样4字节数据,丢弃写入buffer中

}

MaxLen = MaxLen/4; // 32位的fifo中有四个8位有效音频数据

if (MaxLen < nCount) {

nCount = MaxLen;

}

for (i=0; i<nCount; i++) {

*pBuffer++ = (((unsignedint)pTemp[0]<<0) +

((unsignedint)pTemp[1]<<8)) +

(((unsigned int)pTemp[2]<<16) +

((unsignedint)pTemp[3]<<24));

pTemp += 4; // 4个8位的声道数据已写入FIFO中

}

} else { // 单声道

if (MaxLen/2 == 0) {// 单声道fifo中有两个8位有效音频数据

pTemp += MaxLen; // 不足一个采样2字节数据,丢弃写入buffer中

}

MaxLen = MaxLen/2; // 32位的fifo中有两个8位有效音频数据

if (MaxLen < nCount) {

nCount = MaxLen;

}

for (i=0; i<nCount; i++) {

*pBuffer++ = (((unsignedint)pTemp[1]) << 8) + pTemp[0];

pTemp += 2; // 2个8位的声道数据已写入FIFO中

}

}

break;

case 24:

if (TX_Channel != 1) { // 双声道

if (MaxLen/3 == 0) {// 左右声道fifo中有六个8位有效音频数据

pTemp += MaxLen; // 一个声道采样3字节数据,丢弃写入buffer中

}

MaxLen = MaxLen/3; // 每个声道fifo中有三个8位有效音频数据

if (MaxLen < nCount) {

nCount = MaxLen;

}

for (i=0; i<nCount; i++) {

*pBuffer++ =((pTemp[0]<<0)+

((unsignedint)pTemp[1]<<8))+((unsigned int)pTemp[2]<<16);

pTemp += 3; // 3个8位的声道数据已写入FIFO中

}

} else { // 单声道

if (MaxLen/3 == 0) {// 单声道fifo中只有三个8位有效音频数据

pTemp += MaxLen; // 不足一个采样3字节数据,丢弃写入buffer中

}

MaxLen = MaxLen/3;

if (MaxLen < nCount) {

nCount = MaxLen;

}

if (nCount == 1) {

pTemp += 3;

}

for (i=0; i<nCount/2; i++) {

*pBuffer++ =((pTemp[0]<<0)+

((unsignedint)pTemp[1]<<8))+((unsigned int)pTemp[2]<<16);

*pBuffer++ = 0; // 另一声道静音

pTemp += 3; // 3个8位的声道数据已写入FIFO中

}

}

break;

default:

break;

}

TxCount += nCount; // 记录这一次写后缓存的位置

if (TxCount >= sizeof(TxBuffer0)/4) { // 到达缓存结尾

TxCount = 0; // 标记缓存写满并切换到另一个缓存

if (!(TxBufferFlag & (1<<0))){

TxBufferFlag |= (1<<0); // Buffer0写滿

} else {

TxBufferFlag |= (1<<1); //Buffer1写滿

}

}

return ((unsigned int)(pTemp-pData)); // 返回写入缓存中的字节数

}

unsignedint IIS_ReadBuffer(unsigned char *pData, unsigned int MaxLen)

{

unsigned int i;

unsigned int nCount;

unsigned int Value;

unsigned int *pBuffer;

unsigned char *pTemp = pData;

if (pTemp==0 || MaxLen==0) {

return 0; // 参数错误,数据未写入缓存

}

if ((RxBufferFlag&0x3) == 0x0) {

return 0; // Buffer0,Buffer1均未准备好

}

if (RxBufferFlag & (1<<0)) { //Buffer0准备好

pBuffer = &RxBuffer0[RxCount];

} else { // Buffer1准备好

pBuffer = &RxBuffer1[RxCount];

}

// 剩余缓存的长度

nCount = (sizeof(RxBuffer0)/4) - RxCount;

switch (RX_BitLen) {

case 8:

if (RX_Channel != 1) { // 双声道

if (MaxLen/2 == 0) {// 左右声道fifo中有两个8位有效音频数据

pTemp += MaxLen; // 不足一个采样2字节存储空间,丢弃存入

}

MaxLen = MaxLen/2; // 32位的fifo中有两个8位有效音频数据

if (MaxLen < nCount) {

nCount = MaxLen;

}

for (i=0; i<nCount; i++) {

Value = *pBuffer++;

pTemp[0] = (unsignedchar)(Value>>0);

pTemp[1] = (unsignedchar)(Value>>16);

pTemp += 2; // 2个8位的声道数据已从buffer中读取

}

} else { // 单声道

if (MaxLen < nCount) {// 32位的fifo中有一个8位有效音频数据

nCount = MaxLen;

}

for (i=0; i<nCount; i++) {

Value = *pBuffer++;

pTemp[0] = (unsigned char)(Value>>0);

pTemp += 1; // 1个8位的声道数据已写入FIFO中

}

}

break;

case 16:

if (RX_Channel != 1) { // 双声道

if (MaxLen/4 == 0) {// 左右声道fifo中有四个8位有效音频数据

pTemp += MaxLen; // 不足一个采样4字节存储空间,丢弃存入

}

MaxLen = MaxLen/4; // 32位的fifo中有四个8位有效音频数据

if (MaxLen < nCount) {

nCount = MaxLen;

}

for (i=0; i<nCount; i++) {

Value = *pBuffer++;

pTemp[0] = (unsigned char)Value;

pTemp[1] = (unsignedchar)(Value>>8);

pTemp[2] = (unsignedchar)(Value>>16);

pTemp[3] = (unsigned char)(Value>>24);

pTemp += 4; // 4个8位的声道数据已从FIFO中读取

}

} else { // 单声道

if (MaxLen/2 == 0) {// 单声道fifo中有两个8位有效音频数据

pTemp += MaxLen; // 不足一个采样2字节存储空间,丢弃存入

}

MaxLen = MaxLen/2; // 32位的fifo中有两个8位有效音频数据

if (MaxLen < nCount) {

nCount = MaxLen;

}

for (i=0; i<nCount; i++) {

Value = *pBuffer++;

pTemp[0] = (unsigned char)Value;

pTemp[1] = (unsignedchar)(Value>>8);

pTemp += 2; // 2个8位的声道数据已从FIFO中读取

}

}

break;

case 24:

if (RX_Channel != 1) { // 双声道

if (MaxLen/3 == 0) {// 左右声道fifo中有六个8位有效音频数据

pTemp += MaxLen; // 不足一个采样6字节存储空间,丢弃存入

}

MaxLen = MaxLen/3; // 左右声道fifo中有六个8位有效音频数据

if (MaxLen < nCount) {

nCount = MaxLen;

}

for (i=0; i<nCount; i++) {

Value = *pBuffer++;

pTemp[0]= (unsigned char)Value;

pTemp[1] = (unsignedchar)(Value>>8);

pTemp[2] = (unsignedchar)(Value>>16);

pTemp += 3; // 3个8位的声道数据已从FIFO中读取

}

} else { // 单声道

if (MaxLen/3 == 0) {// 单声道fifo中只有三个8位有效音频数据

pTemp += MaxLen; // 不足一个采样3字节存储空间,丢弃存入

}

MaxLen = MaxLen/3;

if (MaxLen < nCount) {

nCount = MaxLen;

}

if (nCount == 1) {

pTemp += 3;

}

for (i=0; i<nCount/2; i++) {

Value = *pBuffer++;

pTemp[0] = (unsigned char)Value;

pTemp[1] = (unsignedchar)(Value>>8);

pTemp[2] = (unsignedchar)(Value>>16);

pTemp += 3; // 3个8位的声道数据已从FIFO中读取

Value = *pBuffer++; // 下一声道数据无需保存

}

}

break;

default:

break;

}

// 记录下一次读时缓存的位置

RxCount += nCount;

if (RxCount >= sizeof(RxBuffer0)/4) { // 读完一个缓存

RxCount = 0;

if (RxBufferFlag & (1<<0)) {

RxBufferFlag &= ~(1<<0);// Buffer0未准备好

} else {

RxBufferFlag &= ~(1<<1);// Buffer1未准备好

}

}

return ((unsigned int)(pTemp-pData)); // 返回读取buffer的字节数

}

voidIIS_RxPause()

{

rIISCON |= (1<<5);

rIISCON &= ~((1<<0) |(1<<1));

}

voidIIS_RxStart()

{

rIISCON &= ~(1<<5);

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

}

voidIIS_TxPause()

{

rIISCON |= (1<<6);

rIISCON &= ~((1<<0) |(1<<2));

}

voidIIS_TxStart()

{

rIISCON &= ~(1<<6);

rIISCON |= (1<<0) | (1<<2);

}

voidIIS_TxInit(unsigned int Sample, unsigned char BitLen, unsigned char Channel)

{

unsigned int Mode;

unsigned int Scaler;

TX_Channel = Channel; // 单声道/双声道

TX_BitLen = BitLen; // 每声道的字长

rIISFIC |= (1<<15); // TX fifo flush

rIISFIC &= ~(1<<15);

TxBufferFlag = 0;

TxCount = 0;

// Master mode audio clock=96M

// codec clcok 256fs,bit clock 32fs,

Mode = (0x0<<16) + (1<<10);//IISSDO1,IISSDO2不使用,即不会写FIFO1,2

if (((rIISMOD>>8) & 0x3) == 1) {

Mode |= (0x2<<8); // 已在接收模式,转到同时接收发送

}

Mode |= (0x0<<5); // IIS format format

Mode |= (0x2<<3); // 384fs

switch (BitLen) {

case 8: // 8位采样数也配置成16位进行传输

case 16:

Mode |= (0x0 << 13);

Mode |= (0x0 << 1); // 32fs

break;

case 24:

Mode |= (0x2 << 13);

Mode |= (0x1 << 1); // 48fs

break;

default:

TX_BitLen = 16; // 其它默认为16位

Mode |= (0x0 << 13);

Mode |= (0x0 << 1); // 32fs

break;

}

rIISMOD = Mode;

if (Sample != 0) {

Scaler =(96000000/384+(Sample>>1))/Sample; // codec clcok 384fs

rIISPSR = (1<<15) + ((Scaler-1)<<8); // 预分频输出

}

rDMASKTRIG0 = (1<<1); // IIS TX打开DMA0通道

Debug("Player sampling rate: %dHZ, Bitlength: %d, Channel: ", Sample, BitLen);

Debug((Channel!=1)?"dual\r\n":"single\r\n");

Debug("CodeClk = %dHZ\r\n", 96000000/(((rIISPSR>>8)&0x3f)+1));

}

voidIIS_RxInit(unsigned int Sample, unsigned char BitLen, unsigned char Channel)

{

unsigned int Mode;

unsigned int Scaler;

RX_Channel = Channel; // 录音的声道数

RX_BitLen = BitLen; // 录音的每声道位长

rIISFIC |= (1<<7); // RX fifo flush

rIISFIC &= ~(1<<7);

RxBufferFlag = 0;

RxCount = 0;

// 16bit,Master mode audio clock=96M,IISformat

// codec clcok 256fs,bit clock 32fs

Mode = (0x0<<16) + (1<<10);

if (((rIISMOD>>8) & 0x3) == 0) {

Mode |= (0x2<<8); // 已在发送模式,转到同时接收发送

} else {

Mode |= (0x1<<8); // 接收模式

}

Mode |= (0x0<<5); // // IIS formatformat

Mode |= (0x2<<3); // 384fs

switch (BitLen) {

case 8:

case 16:

Mode |= (0x0 << 13);

Mode |= (0x0 << 1); // 32fs

break;

case 24:

Mode |= (0x2 << 13);

Mode |= (0x1 << 1); // 48fs

break;

default:

RX_BitLen = 16; // 其它默认为16位

Mode |= (0x0 << 13);

Mode |= (0x0 << 1); // 32fs

break;

}

rIISMOD = Mode;

if (Sample != 0) {

Scaler = 96000000/384/Sample; // codecclcok 384fs

rIISPSR = (1<<15) + ((Scaler-1)<<8); // 预分频输出

}

rDMASKTRIG1 = (1<<1); // IIS RX打开DMA1通道

Debug("Recorder sampling rate: %dHZ,Bit length: %d, Channel: ", Sample, BitLen);

Debug((Channel!=1)?"dual\r\n":"single\r\n");

Debug("CodeClk = %dHZ\r\n",96000000/(((rIISPSR>>8)&0x3f)+1));

}

voidIIS_Init()

{

// 配置IIS接口引脚

rGPECON &= ~(0x3ff << 0);

rGPECON |= 0x2aa;

rGPEUDP &= ~(0x3ff << 0); // 禁止上下位

rCLKDIV1 &= ~(0xf<<12);

rCLKDIV1 |= (0<<12); // IIS clock 96M

rIISCON = 0;

rDMAREQSEL0 = (4<<1) | (1<<0);// IIS TX通过DMA0传输

rDMAREQSEL1 = (5<<1) | (1<<0);// IIS RX通过DMA1传输

rDISRC0 = (unsigned int)TxBuffer0; // DMA0源地址

rDISRC1 = (unsigned int)&rIISRXD; //DMA1源地址为RX FIFO寄存器地址

rDISRCC0 = (0<<1) | (0<<0); //DMA0源地址在AHB总线上,DMA访问后地址自增

rDISRCC1 = (1<<1) | (1<<0); //DMA1源地址在APB总线上,地址固定

rDIDST0 = (unsigned int)&rIISTXD; //DMA0目的地址为TX FIFO寄存器地址

rDIDST1 = ((unsigned int)RxBuffer0); // DMA1目的地址

rDIDSTC0 = (0<<2) | (1<<1) |(1<<0); // DMA0目的地址在APB上,固定,计数0中断

rDIDSTC1 = (0<<2) | (0<<1) |(0<<0); // DMA1目的地址在AHB上,自增,计数0中断

// Word transferred, count 16KB/4 word,handshake mode

// no auto reload, single service, enable tcinterrupt,

rDCON0 = 0xe0000000 | (1<<22) |(1<<24) | (2<<20) | ((sizeof(TxBuffer0)/4)<<0);

rDCON1 = 0xe0000000 | (1<<22) |(1<<24) | (2<<20) | ((sizeof(RxBuffer0)/4)<<0);

TxBufferFlag = 0; // 发送缓存0,1需填充

RxBufferFlag = 0;

TxCount = 0;

RxCount = 0;

IRQ_Register(INT_DMA, DMA_IRQ);// DMA中断入口函数加入到向量表

rINTSUBMSK &= ~((1<<SUBINT_DMA0) |(1<<SUBINT_DMA1)); // 开启DMA0与DMA1子中断

rINTMOD1 &= ~(1 << INT_DMA); //DMA IRQ

rINTMSK1 &= ~(1 << INT_DMA); //DMA开启中断

}

IIS模块头文件IIS.h如下:

#ifndef __IIC_H__

#define __IIC_H__

#ifdef __cplusplus

extern "C" {

#endif

#define ArbitrationFailed (1<<3)// 总线仲裁失败

#define AddressMatche (1<<2)// 从机地址相配

#define AddressZeros (1<<1)// 接收的地址为0

#define NoAck (1<<0)// 没有回复信号

extern int IIC_WriteBytes(unsigned char SlaveAddr, unsigned char WriteAddr,

unsigned char *pData, int Length);

extern int IIC_ReadBytes(unsigned char SlaveAddr, unsigned char ReadAddr,

unsigned char *pData, int Length);

extern void IIC_Init(void);

#ifdef __cplusplus

}

#endif

#endif /*__IIC_H__*/

5. 附录

WM8960.rar,包含音频驱动模块相关源码,WM8960.c/WM8960.h为音频编解码器驱动模块,IIS.c/IIS.h为音频接口IIS驱动模块,IIC.c/IIC.h为IIC接口驱动模块(需通过IIC控制WM8960),由于音频驱动是从工程应用角度实现,实现适用于不同采样频率、采样位数、声道数,并通过DMA的方式传输音频,采用双缓存的概念来实现音频的驱动,相对代码较长,但已经是直入主题,尽可能简单明了。

http://pan.baidu.com/s/1c0iXLhI
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: