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

来源:互联网 发布:桌面壁纸 知乎 编辑:程序博客网 时间:2024/04/29 19:26

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

 


0 0