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...)#endifstaticunsigned 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 TXif (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 RXif (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 flushrIISFIC &= ~(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,2if (((rIISMOD>>8) & 0x3) == 1) {Mode |= (0x2<<8); // 已在接收模式,转到同时接收发送}Mode |= (0x0<<5); // IIS format formatMode |= (0x2<<3); // 384fsswitch (BitLen) {case 8: // 8位采样数也配置成16位进行传输case 16:Mode |= (0x0 << 13);Mode |= (0x0 << 1); // 32fsbreak;case 24:Mode |= (0x2 << 13);Mode |= (0x1 << 1); // 48fsbreak;default:TX_BitLen = 16; // 其它默认为16位Mode |= (0x0 << 13);Mode |= (0x0 << 1); // 32fsbreak;}rIISMOD = Mode;if (Sample != 0) {Scaler =(96000000/384+(Sample>>1))/Sample; // codec clcok 384fsrIISPSR = (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 flushrIISFIC &= ~(1<<7);RxBufferFlag = 0;RxCount = 0;// 16bit,Master mode audio clock=96M,IISformat// codec clcok 256fs,bit clock 32fsMode = (0x0<<16) + (1<<10);if (((rIISMOD>>8) & 0x3) == 0) {Mode |= (0x2<<8); // 已在发送模式,转到同时接收发送} else {Mode |= (0x1<<8); // 接收模式}Mode |= (0x0<<5); // // IIS formatformatMode |= (0x2<<3); // 384fsswitch (BitLen) {case 8:case 16:Mode |= (0x0 << 13);Mode |= (0x0 << 1); // 32fsbreak;case 24:Mode |= (0x2 << 13);Mode |= (0x1 << 1); // 48fsbreak;default:RX_BitLen = 16; // 其它默认为16位Mode |= (0x0 << 13);Mode |= (0x0 << 1); // 32fsbreak;}rIISMOD = Mode;if (Sample != 0) {Scaler = 96000000/384/Sample; // codecclcok 384fsrIISPSR = (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 96MrIISCON = 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 IRQrINTMSK1 &= ~(1 << INT_DMA); //DMA开启中断}
IIS模块头文件IIS.h如下:
#ifndef __IIC_H__#define __IIC_H__#ifdef __cplusplusextern "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的方式传输音频,采用双缓存的概念来实现音频的驱动,相对代码较长,但已经是直入主题,尽可能简单明了。
