IIS模块实现IIS.c如下:

  1. #include"s3c2416.h"
  2. #include "IIS.h"
  3. #include"Exception.h"
  4. #include"UART0.h"
  5. #defineDEBUG_IIS
  6. #ifdef DEBUG_IIS
  7. #defineDebug(x...) Uart0_Printf(x)
  8. #else
  9. #defineDebug(x...)
  10. #endif
  11. staticunsigned char TX_Channel; // 发送音频的声道数
  12. staticunsigned char TX_BitLen; // 发送位长
  13. staticunsigned char RX_Channel; // 接收音频的声道数
  14. staticunsigned char RX_BitLen; // 接收位长
  15. staticvolatile unsigned char TxBufferFlag;
  16. staticvolatile unsigned char RxBufferFlag;
  17. staticunsigned int TxCount; // 播放时记录缓存中的写位置
  18. staticunsigned int RxCount; // 录音时记录缓存中的读位置
  19. // 插放与录音均采用双缓存,DMA传输的主存与cache会有数据一致性问题
  20. // 音频DMA缓存分配到不开启cache的内存区域
  21. staticunsigned int TxBuffer0[4*1024] __attribute__((section("No_Cache"),zero_init));
  22. staticunsigned int TxBuffer1[4*1024] __attribute__((section("No_Cache"),zero_init));
  23. staticunsigned int RxBuffer0[4*1024] __attribute__((section("No_Cache"),zero_init));
  24. staticunsigned int RxBuffer1[4*1024] __attribute__((section("No_Cache"),zero_init));
  25. static voidDMA_IRQ(void)
  26. {
  27. static unsigned char TxBufferChannel = 0;
  28. static unsigned char RxBufferChannel = 0;
  29. unsigned int DMA_Channel;
  30. DMA_Channel = rSUBSRCPND;
  31. if (DMA_Channel &(1<<SUBINT_DMA0)) { // DMA0中断请求, IIS TX
  32. if (TxBufferChannel == 0) {
  33. rDISRC0 = ((unsigned int)TxBuffer1);// 开始使用Buffer1缓存
  34. TxBufferFlag &= ~(1<<0);// 发送标志0位清空,说明Buffer0数据需填充
  35. TxBufferChannel = 1; // 正在发送Buffer1缓存
  36. } else {
  37. rDISRC0 = ((unsignedint)TxBuffer0);// 开始使用Buffer0缓存
  38. TxBufferFlag &= ~(1<<1);// 发送标志1位清空,说明Buffer1数据需填充
  39. TxBufferChannel = 0; // 正在发送Buffer0缓存
  40. }
  41. rDCON0 = (rDCON0&(~0xfffff)) |(sizeof(TxBuffer0)/4);
  42. rDMASKTRIG0 = (1<<1); // IIS TX打开DMA0通道
  43. rSUBSRCPND |= (1<<SUBINT_DMA0);
  44. }
  45. if (DMA_Channel &(1<<SUBINT_DMA1)) { // DMA1中断请求, IIS RX
  46. if (RxBufferChannel == 0) {
  47. rDIDST1 = ((unsigned int)RxBuffer1);// DMA1目的地址
  48. RxBufferFlag |= (1<<0); // 接收缓存0位置位,说明Buffer0数据准备好
  49. RxBufferChannel = 1; // 下一次使用Buffer1
  50. } else {
  51. rDIDST1 = ((unsigned int)RxBuffer0);// DMA1目的地址
  52. RxBufferFlag |= (1<<1); // 接收缓存1位置位,说明Buffer1数据准备好
  53. RxBufferChannel = 0; // 下一次使用Buffer0
  54. }
  55. rDCON1 = (rDCON1&(~0xfffff)) |(sizeof(RxBuffer0)/4);
  56. rDMASKTRIG1 = (1<<1); // IIS RX打开DMA1通道
  57. rSUBSRCPND |= (1<<SUBINT_DMA1);
  58. }
  59. rSRCPND1 |= (1 << INT_DMA);
  60. rINTPND1 |= (1 << INT_DMA);
  61. }
  62. unsignedint IIS_WriteBuffer(unsigned char *pData, unsigned int MaxLen)
  63. {
  64. unsigned int i;
  65. unsigned int nCount; // 能写入buffer中数据长度(以字计,fifo 32位长)
  66. unsigned int *pBuffer;
  67. unsigned char *pTemp = pData;
  68. if (pTemp==0 || MaxLen==0) {
  69. return 0; // 参数错误,数据未写入缓存
  70. }
  71. if ((TxBufferFlag&0x3) == 0x3) {
  72. return 0; // Buffer0,Buffer1均已写满
  73. }
  74. if (!(TxBufferFlag & (1<<0))) { //Buffer0需填充
  75. pBuffer = &TxBuffer0[TxCount];
  76. } else { // Buffer1需填充
  77. pBuffer = &TxBuffer1[TxCount];
  78. }
  79. nCount = (sizeof(TxBuffer0)/4) - TxCount;
  80. switch (TX_BitLen) {
  81. case 8:
  82. if (TX_Channel != 1) { // 双声道
  83. if (MaxLen/2 == 0) {// 左右声道fifo中有两个8位有效音频数据
  84. pTemp += MaxLen; // 不足一个采样2字节数据,丢弃写入buffer中
  85. }
  86. MaxLen = MaxLen/2; // 32位的fifo中有两个8位有效音频数据
  87. if (MaxLen < nCount) {
  88. nCount = MaxLen;
  89. }
  90. for (i=0; i<nCount; i++) {
  91. *pBuffer++ = (((unsignedint)pTemp[1]<<16)+
  92. ((unsignedint)pTemp[0]<<0));
  93. pTemp += 2; // 2个8位的声道数据已写入buffer中
  94. }
  95. } else { // 单声道
  96. if (MaxLen < nCount) {// 32位的fifo中有一个8位有效音频数据
  97. nCount = MaxLen;
  98. }
  99. for (i=0; i<nCount; i++) {
  100. *pBuffer++ = (unsignedint)pTemp[0]<<0;
  101. pTemp += 1; // 1个8位的声道数据已写入FIFO中
  102. }
  103. }
  104. break;
  105. case 16:
  106. if (TX_Channel != 1) { // 双声道
  107. if (MaxLen/4 == 0) {// 左右声道fifo中有四个8位有效音频数据
  108. pTemp += MaxLen; // 不足一个采样4字节数据,丢弃写入buffer中
  109. }
  110. MaxLen = MaxLen/4; // 32位的fifo中有四个8位有效音频数据
  111. if (MaxLen < nCount) {
  112. nCount = MaxLen;
  113. }
  114. for (i=0; i<nCount; i++) {
  115. *pBuffer++ = (((unsignedint)pTemp[0]<<0) +
  116. ((unsignedint)pTemp[1]<<8)) +
  117. (((unsigned int)pTemp[2]<<16) +
  118. ((unsignedint)pTemp[3]<<24));
  119. pTemp += 4; // 4个8位的声道数据已写入FIFO中
  120. }
  121. } else { // 单声道
  122. if (MaxLen/2 == 0) {// 单声道fifo中有两个8位有效音频数据
  123. pTemp += MaxLen; // 不足一个采样2字节数据,丢弃写入buffer中
  124. }
  125. MaxLen = MaxLen/2; // 32位的fifo中有两个8位有效音频数据
  126. if (MaxLen < nCount) {
  127. nCount = MaxLen;
  128. }
  129. for (i=0; i<nCount; i++) {
  130. *pBuffer++ = (((unsignedint)pTemp[1]) << 8) + pTemp[0];
  131. pTemp += 2; // 2个8位的声道数据已写入FIFO中
  132. }
  133. }
  134. break;
  135. case 24:
  136. if (TX_Channel != 1) { // 双声道
  137. if (MaxLen/3 == 0) {// 左右声道fifo中有六个8位有效音频数据
  138. pTemp += MaxLen; // 一个声道采样3字节数据,丢弃写入buffer中
  139. }
  140. MaxLen = MaxLen/3; // 每个声道fifo中有三个8位有效音频数据
  141. if (MaxLen < nCount) {
  142. nCount = MaxLen;
  143. }
  144. for (i=0; i<nCount; i++) {
  145. *pBuffer++ =((pTemp[0]<<0)+
  146. ((unsignedint)pTemp[1]<<8))+((unsigned int)pTemp[2]<<16);
  147. pTemp += 3; // 3个8位的声道数据已写入FIFO中
  148. }
  149. } else { // 单声道
  150. if (MaxLen/3 == 0) {// 单声道fifo中只有三个8位有效音频数据
  151. pTemp += MaxLen; // 不足一个采样3字节数据,丢弃写入buffer中
  152. }
  153. MaxLen = MaxLen/3;
  154. if (MaxLen < nCount) {
  155. nCount = MaxLen;
  156. }
  157. if (nCount == 1) {
  158. pTemp += 3;
  159. }
  160. for (i=0; i<nCount/2; i++) {
  161. *pBuffer++ =((pTemp[0]<<0)+
  162. ((unsignedint)pTemp[1]<<8))+((unsigned int)pTemp[2]<<16);
  163. *pBuffer++ = 0; // 另一声道静音
  164. pTemp += 3; // 3个8位的声道数据已写入FIFO中
  165. }
  166. }
  167. break;
  168. default:
  169. break;
  170. }
  171. TxCount += nCount; // 记录这一次写后缓存的位置
  172. if (TxCount >= sizeof(TxBuffer0)/4) { // 到达缓存结尾
  173. TxCount = 0; // 标记缓存写满并切换到另一个缓存
  174. if (!(TxBufferFlag & (1<<0))){
  175. TxBufferFlag |= (1<<0); // Buffer0写滿
  176. } else {
  177. TxBufferFlag |= (1<<1); //Buffer1写滿
  178. }
  179. }
  180. return ((unsigned int)(pTemp-pData)); // 返回写入缓存中的字节数
  181. }
  182. unsignedint IIS_ReadBuffer(unsigned char *pData, unsigned int MaxLen)
  183. {
  184. unsigned int i;
  185. unsigned int nCount;
  186. unsigned int Value;
  187. unsigned int *pBuffer;
  188. unsigned char *pTemp = pData;
  189. if (pTemp==0 || MaxLen==0) {
  190. return 0; // 参数错误,数据未写入缓存
  191. }
  192. if ((RxBufferFlag&0x3) == 0x0) {
  193. return 0; // Buffer0,Buffer1均未准备好
  194. }
  195. if (RxBufferFlag & (1<<0)) { //Buffer0准备好
  196. pBuffer = &RxBuffer0[RxCount];
  197. } else { // Buffer1准备好
  198. pBuffer = &RxBuffer1[RxCount];
  199. }
  200. // 剩余缓存的长度
  201. nCount = (sizeof(RxBuffer0)/4) - RxCount;
  202. switch (RX_BitLen) {
  203. case 8:
  204. if (RX_Channel != 1) { // 双声道
  205. if (MaxLen/2 == 0) {// 左右声道fifo中有两个8位有效音频数据
  206. pTemp += MaxLen; // 不足一个采样2字节存储空间,丢弃存入
  207. }
  208. MaxLen = MaxLen/2; // 32位的fifo中有两个8位有效音频数据
  209. if (MaxLen < nCount) {
  210. nCount = MaxLen;
  211. }
  212. for (i=0; i<nCount; i++) {
  213. Value = *pBuffer++;
  214. pTemp[0] = (unsignedchar)(Value>>0);
  215. pTemp[1] = (unsignedchar)(Value>>16);
  216. pTemp += 2; // 2个8位的声道数据已从buffer中读取
  217. }
  218. } else { // 单声道
  219. if (MaxLen < nCount) {// 32位的fifo中有一个8位有效音频数据
  220. nCount = MaxLen;
  221. }
  222. for (i=0; i<nCount; i++) {
  223. Value = *pBuffer++;
  224. pTemp[0] = (unsigned char)(Value>>0);
  225. pTemp += 1; // 1个8位的声道数据已写入FIFO中
  226. }
  227. }
  228. break;
  229. case 16:
  230. if (RX_Channel != 1) { // 双声道
  231. if (MaxLen/4 == 0) {// 左右声道fifo中有四个8位有效音频数据
  232. pTemp += MaxLen; // 不足一个采样4字节存储空间,丢弃存入
  233. }
  234. MaxLen = MaxLen/4; // 32位的fifo中有四个8位有效音频数据
  235. if (MaxLen < nCount) {
  236. nCount = MaxLen;
  237. }
  238. for (i=0; i<nCount; i++) {
  239. Value = *pBuffer++;
  240. pTemp[0] = (unsigned char)Value;
  241. pTemp[1] = (unsignedchar)(Value>>8);
  242. pTemp[2] = (unsignedchar)(Value>>16);
  243. pTemp[3] = (unsigned char)(Value>>24);
  244. pTemp += 4; // 4个8位的声道数据已从FIFO中读取
  245. }
  246. } else { // 单声道
  247. if (MaxLen/2 == 0) {// 单声道fifo中有两个8位有效音频数据
  248. pTemp += MaxLen; // 不足一个采样2字节存储空间,丢弃存入
  249. }
  250. MaxLen = MaxLen/2; // 32位的fifo中有两个8位有效音频数据
  251. if (MaxLen < nCount) {
  252. nCount = MaxLen;
  253. }
  254. for (i=0; i<nCount; i++) {
  255. Value = *pBuffer++;
  256. pTemp[0] = (unsigned char)Value;
  257. pTemp[1] = (unsignedchar)(Value>>8);
  258. pTemp += 2; // 2个8位的声道数据已从FIFO中读取
  259. }
  260. }
  261. break;
  262. case 24:
  263. if (RX_Channel != 1) { // 双声道
  264. if (MaxLen/3 == 0) {// 左右声道fifo中有六个8位有效音频数据
  265. pTemp += MaxLen; // 不足一个采样6字节存储空间,丢弃存入
  266. }
  267. MaxLen = MaxLen/3; // 左右声道fifo中有六个8位有效音频数据
  268. if (MaxLen < nCount) {
  269. nCount = MaxLen;
  270. }
  271. for (i=0; i<nCount; i++) {
  272. Value = *pBuffer++;
  273. pTemp[0]= (unsigned char)Value;
  274. pTemp[1] = (unsignedchar)(Value>>8);
  275. pTemp[2] = (unsignedchar)(Value>>16);
  276. pTemp += 3; // 3个8位的声道数据已从FIFO中读取
  277. }
  278. } else { // 单声道
  279. if (MaxLen/3 == 0) {// 单声道fifo中只有三个8位有效音频数据
  280. pTemp += MaxLen; // 不足一个采样3字节存储空间,丢弃存入
  281. }
  282. MaxLen = MaxLen/3;
  283. if (MaxLen < nCount) {
  284. nCount = MaxLen;
  285. }
  286. if (nCount == 1) {
  287. pTemp += 3;
  288. }
  289. for (i=0; i<nCount/2; i++) {
  290. Value = *pBuffer++;
  291. pTemp[0] = (unsigned char)Value;
  292. pTemp[1] = (unsignedchar)(Value>>8);
  293. pTemp[2] = (unsignedchar)(Value>>16);
  294. pTemp += 3; // 3个8位的声道数据已从FIFO中读取
  295. Value = *pBuffer++; // 下一声道数据无需保存
  296. }
  297. }
  298. break;
  299. default:
  300. break;
  301. }
  302. // 记录下一次读时缓存的位置
  303. RxCount += nCount;
  304. if (RxCount >= sizeof(RxBuffer0)/4) { // 读完一个缓存
  305. RxCount = 0;
  306. if (RxBufferFlag & (1<<0)) {
  307. RxBufferFlag &= ~(1<<0);// Buffer0未准备好
  308. } else {
  309. RxBufferFlag &= ~(1<<1);// Buffer1未准备好
  310. }
  311. }
  312. return ((unsigned int)(pTemp-pData)); // 返回读取buffer的字节数
  313. }
  314. voidIIS_RxPause()
  315. {
  316. rIISCON |= (1<<5);
  317. rIISCON &= ~((1<<0) |(1<<1));
  318. }
  319. voidIIS_RxStart()
  320. {
  321. rIISCON &= ~(1<<5);
  322. rIISCON |= (1<<0) | (1<<1);
  323. }
  324. voidIIS_TxPause()
  325. {
  326. rIISCON |= (1<<6);
  327. rIISCON &= ~((1<<0) |(1<<2));
  328. }
  329. voidIIS_TxStart()
  330. {
  331. rIISCON &= ~(1<<6);
  332. rIISCON |= (1<<0) | (1<<2);
  333. }
  334. voidIIS_TxInit(unsigned int Sample, unsigned char BitLen, unsigned char Channel)
  335. {
  336. unsigned int Mode;
  337. unsigned int Scaler;
  338. TX_Channel = Channel; // 单声道/双声道
  339. TX_BitLen = BitLen; // 每声道的字长
  340. rIISFIC |= (1<<15); // TX fifo flush
  341. rIISFIC &= ~(1<<15);
  342. TxBufferFlag = 0;
  343. TxCount = 0;
  344. // Master mode audio clock=96M
  345. // codec clcok 256fs,bit clock 32fs,
  346. Mode = (0x0<<16) + (1<<10);//IISSDO1,IISSDO2不使用,即不会写FIFO1,2
  347. if (((rIISMOD>>8) & 0x3) == 1) {
  348. Mode |= (0x2<<8); // 已在接收模式,转到同时接收发送
  349. }
  350. Mode |= (0x0<<5); // IIS format format
  351. Mode |= (0x2<<3); // 384fs
  352. switch (BitLen) {
  353. case 8: // 8位采样数也配置成16位进行传输
  354. case 16:
  355. Mode |= (0x0 << 13);
  356. Mode |= (0x0 << 1); // 32fs
  357. break;
  358. case 24:
  359. Mode |= (0x2 << 13);
  360. Mode |= (0x1 << 1); // 48fs
  361. break;
  362. default:
  363. TX_BitLen = 16; // 其它默认为16位
  364. Mode |= (0x0 << 13);
  365. Mode |= (0x0 << 1); // 32fs
  366. break;
  367. }
  368. rIISMOD = Mode;
  369. if (Sample != 0) {
  370. Scaler =(96000000/384+(Sample>>1))/Sample; // codec clcok 384fs
  371. rIISPSR = (1<<15) + ((Scaler-1)<<8); // 预分频输出
  372. }
  373. rDMASKTRIG0 = (1<<1); // IIS TX打开DMA0通道
  374. Debug("Player sampling rate: %dHZ, Bitlength: %d, Channel: ", Sample, BitLen);
  375. Debug((Channel!=1)?"dual\r\n":"single\r\n");
  376. Debug("CodeClk = %dHZ\r\n", 96000000/(((rIISPSR>>8)&0x3f)+1));
  377. }
  378. voidIIS_RxInit(unsigned int Sample, unsigned char BitLen, unsigned char Channel)
  379. {
  380. unsigned int Mode;
  381. unsigned int Scaler;
  382. RX_Channel = Channel; // 录音的声道数
  383. RX_BitLen = BitLen; // 录音的每声道位长
  384. rIISFIC |= (1<<7); // RX fifo flush
  385. rIISFIC &= ~(1<<7);
  386. RxBufferFlag = 0;
  387. RxCount = 0;
  388. // 16bit,Master mode audio clock=96M,IISformat
  389. // codec clcok 256fs,bit clock 32fs
  390. Mode = (0x0<<16) + (1<<10);
  391. if (((rIISMOD>>8) & 0x3) == 0) {
  392. Mode |= (0x2<<8); // 已在发送模式,转到同时接收发送
  393. } else {
  394. Mode |= (0x1<<8); // 接收模式
  395. }
  396. Mode |= (0x0<<5); // // IIS formatformat
  397. Mode |= (0x2<<3); // 384fs
  398. switch (BitLen) {
  399. case 8:
  400. case 16:
  401. Mode |= (0x0 << 13);
  402. Mode |= (0x0 << 1); // 32fs
  403. break;
  404. case 24:
  405. Mode |= (0x2 << 13);
  406. Mode |= (0x1 << 1); // 48fs
  407. break;
  408. default:
  409. RX_BitLen = 16; // 其它默认为16位
  410. Mode |= (0x0 << 13);
  411. Mode |= (0x0 << 1); // 32fs
  412. break;
  413. }
  414. rIISMOD = Mode;
  415. if (Sample != 0) {
  416. Scaler = 96000000/384/Sample; // codecclcok 384fs
  417. rIISPSR = (1<<15) + ((Scaler-1)<<8); // 预分频输出
  418. }
  419. rDMASKTRIG1 = (1<<1); // IIS RX打开DMA1通道
  420. Debug("Recorder sampling rate: %dHZ,Bit length: %d, Channel: ", Sample, BitLen);
  421. Debug((Channel!=1)?"dual\r\n":"single\r\n");
  422. Debug("CodeClk = %dHZ\r\n",96000000/(((rIISPSR>>8)&0x3f)+1));
  423. }
  424. voidIIS_Init()
  425. {
  426. // 配置IIS接口引脚
  427. rGPECON &= ~(0x3ff << 0);
  428. rGPECON |= 0x2aa;
  429. rGPEUDP &= ~(0x3ff << 0); // 禁止上下位
  430. rCLKDIV1 &= ~(0xf<<12);
  431. rCLKDIV1 |= (0<<12); // IIS clock 96M
  432. rIISCON = 0;
  433. rDMAREQSEL0 = (4<<1) | (1<<0);// IIS TX通过DMA0传输
  434. rDMAREQSEL1 = (5<<1) | (1<<0);// IIS RX通过DMA1传输
  435. rDISRC0 = (unsigned int)TxBuffer0; // DMA0源地址
  436. rDISRC1 = (unsigned int)&rIISRXD; //DMA1源地址为RX FIFO寄存器地址
  437. rDISRCC0 = (0<<1) | (0<<0); //DMA0源地址在AHB总线上,DMA访问后地址自增
  438. rDISRCC1 = (1<<1) | (1<<0); //DMA1源地址在APB总线上,地址固定
  439. rDIDST0 = (unsigned int)&rIISTXD; //DMA0目的地址为TX FIFO寄存器地址
  440. rDIDST1 = ((unsigned int)RxBuffer0); // DMA1目的地址
  441. rDIDSTC0 = (0<<2) | (1<<1) |(1<<0); // DMA0目的地址在APB上,固定,计数0中断
  442. rDIDSTC1 = (0<<2) | (0<<1) |(0<<0); // DMA1目的地址在AHB上,自增,计数0中断
  443. // Word transferred, count 16KB/4 word,handshake mode
  444. // no auto reload, single service, enable tcinterrupt,
  445. rDCON0 = 0xe0000000 | (1<<22) |(1<<24) | (2<<20) | ((sizeof(TxBuffer0)/4)<<0);
  446. rDCON1 = 0xe0000000 | (1<<22) |(1<<24) | (2<<20) | ((sizeof(RxBuffer0)/4)<<0);
  447. TxBufferFlag = 0; // 发送缓存0,1需填充
  448. RxBufferFlag = 0;
  449. TxCount = 0;
  450. RxCount = 0;
  451. IRQ_Register(INT_DMA, DMA_IRQ);// DMA中断入口函数加入到向量表
  452. rINTSUBMSK &= ~((1<<SUBINT_DMA0) |(1<<SUBINT_DMA1)); // 开启DMA0与DMA1子中断
  453. rINTMOD1 &= ~(1 << INT_DMA); //DMA IRQ
  454. rINTMSK1 &= ~(1 << INT_DMA); //DMA开启中断
  455. }

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

  1. #ifndef __IIC_H__
  2. #define __IIC_H__
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. #define ArbitrationFailed (1<<3)// 总线仲裁失败
  7. #define AddressMatche (1<<2)// 从机地址相配
  8. #define AddressZeros (1<<1)// 接收的地址为0
  9. #define NoAck (1<<0)// 没有回复信号
  10. extern int IIC_WriteBytes(unsigned char SlaveAddr, unsigned char WriteAddr,
  11. unsigned char *pData, int Length);
  12. extern int IIC_ReadBytes(unsigned char SlaveAddr, unsigned char ReadAddr,
  13. unsigned char *pData, int Length);
  14. extern void IIC_Init(void);
  15. #ifdef __cplusplus
  16. }
  17. #endif
  18. #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