第一節 音頻播放原理
首先需要申明一下,本章的代碼來自網絡,參考了亞嵌教育李明老師(論壇ID:limingth)的帖子:
http://www.arm9home.net/read.php?tid=20515&page=1#175657
S5PV210通過i2s和i2c與音頻編解碼芯片wm8960進行交互,其中i2s負責只傳輸聲音數據,而i2c負責傳輸控制信息(如音量調節、靜音等),wm8960負責編解碼。
要驅動wm8960,我們需要做三件事:(1)初始化i2s,(2)初始化i2c,(3)初始化wm8960。
Mini210S相關的原理圖如下:
第二節 程序詳細講解
完整代碼見目錄詳細代碼下載鏈接。
1. Makefile
在makefile中,我們將程序的鏈接地址設置為0x21000000,也就是說程序只有
位於0x21000000才能正常運行,所有我們的程序一開始就必須被下載到內存0x21000000處。
2. main.c
代碼如下:
void main(void)
{
printf("Audio Test\r\n");
int offset = 0x2E; // 音頻數據開始的地方
short * p = (short *)0x22000000; // 音頻文件應該位於的位置
iic_init(); // 初始化i2c
wm8960_init(); // 初始化wm8960
iis_init(); // 初始化iis
// 循環播放音頻文件
while (1)
{
// polling Primary Tx FIFO0 full status indication.
while((IISCON & (1<<8)) == (1<<8));
IISTXD = *(p+offset); // 每次發送2byte
offset++;
if (offset > (882046-0x2e) /2) // 有多少個2byte = (文件大小-偏移)/2
offset = 0x2E;
}
}
main函數共做了4件事:
第一步 調用iic_init()初始化i2c;
第二步 調用wm8960_init()初始化wm8960;
第三步 調用iis_init()初始化i2s;
第四步 用i2s中發出聲音數據,循環播放音頻文件;
3. audio.c
audio.c里有幾個核心的函數,下面我們來逐個分析。
函數一 iic_init(),代碼如下:
void iic_init(void)
{
GPD1CON |= 0x22; // 配置引腳
GPD1PUD |= 0x5;
I2CCON0 = (1<<7) | (0<<6) | (1<<5) | (0xe);
I2CSTAT0 = 0x10;
}
初始化i2c很簡單,分三步:
第一步 配置引腳用於i2c功能;
第二步 配置i2c控制器,包括設置時鍾,使能ack等;
第三步 使能接收和發送功能;
函數二 iic_write (),代碼如下:
void iic_write(int slave_addr, int addr, int data)
{
// 地址
I2CDS0 = slave_addr;
// 發送s信號和地址
I2CSTAT0 = 0xf0;
// 等待
while ((I2CCON0 & 0x10) == 0); // 等待數據發送
while ((I2CSTAT0 & 0x1)); // 等待從機發來ACK
// 發7bit地址和9bit數據
I2CDS0 = addr<<1 | ((data>>8) & 0x0001);
I2CCON0 &= ~(1<<4); // 清中斷
while ((I2CCON0 & 0x10) == 0); // 等待數據發送
while ((I2CSTAT0 & 0x1)); // 等待從機發來ACK
I2CDS0 = (data & 0x00FF);
I2CCON0 &= ~(1<<4); // 清中斷
while ((I2CCON0 & 0x10) == 0); // 等待數據發送
while ((I2CSTAT0 & 0x1)); // 等待從機發來ACK
// 發p信息
I2CSTAT0 = 0xd0;
I2CCON0 &= ~(1<<4); // 清中斷
// 延時等待
int i=0;
for(i=0; i<50; i++);
return;
}
i2c的寫操作也不難,整體上分三步:
第一步 發s信號和設備地址, slave_addr的bit[0:6]是7bit的設備地址,bit[7]=0,表示發送;
然后需等待數據發送完成和等待ack應答;
第二步 發16bit的數據,其中前7bit是寄存器偏移地址,后9bit是寄存器的值;
第三步 發p信號,表示結束;
第四步 延時,等待p信號發送成功;
函數三 wm8960_init (),核心代碼如下:
void wm8960_init(void)
{
#define WM8960_DEVICE_ADDR 0x34 // 重置
iic_write(WM8960_DEVICE_ADDR, 0xf, 0x0); // 設置電源
iic_write(WM8960_DEVICE_ADDR, 0x19, 1<<8 | 1<<7 | 1<<6);
iic_write(WM8960_DEVICE_ADDR, 0x1a, 1<<8 | 1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<3);
iic_write(WM8960_DEVICE_ADDR, 0x2F, 1<<3 | 1<<2); // 設置時鍾
iic_write(WM8960_DEVICE_ADDR, 0x4, 0x0); // 設置ADC-DAC
iic_write(WM8960_DEVICE_ADDR, 0x5, 0x0);
…
}
wm8960_init()主要是調用了iic_write()來初始化wm8960芯片,具體的初始化步驟需要自行詳細閱讀wm8960的芯片手冊,
這里只是簡單了整理了網友limingth的初始化步驟:
第一步 確定wm8960的設備地址,查看wm8960的芯片手冊可知其設備地址為0x1a,左移1位且低位補0(表示發送)后,WM8960_DEVICE_ADDR = 0x34,reset;
第二步 設置power1 2 3;
第三步 設置時鍾;
第四步 設置ADC-DAC,注意設置非靜音;
第五步 設置audio interface;
第六步 設置volume;
第七步 設置mixer;
這些都是wm8960芯片手冊里相關的內容,需自行閱讀該芯片手冊。
函數四 iis_init (),核心代碼如下:
void iis_init(void)
{
int N;
// 配置引腳用於i2s功能
GPICON = 0x22222222;
// 設置i2s相關時鍾
EPLL_CON0 = 0xa8430303; // MPLL_FOUT = 67.7Mhz
EPLL_CON1 = 0xbcee; // from linux kernel setting
CLK_SRC0 = 0x10001111;
CLK_CON = 0x1; // 1 = FOUT_EPLL MUXI2S_A 00 = Main CLK
// 設置i2s控制器
N = 5;
IISPSR = 1<<15 | N<<8;
IISCON |= 1<<0 | (unsigned)1<<31;
IISMOD = 1<<9 | 0<<8 | 1<<10;
}
i2s的初始化整體上分為三個步驟:
第一步 配置引腳用於i2s功能;
第二步 設置i2s相關時鍾,具體包括設置EPLL_CON0、1使EPLL輸出67.7Mhz,設置時鍾開關CLK_SRC0;
第三步 設置i2s控制器,具體包括設置分頻,時鍾選擇和發送接收模式;
第三節 實驗現象
往開發板上插入耳機,就能重復地聽到windows xp啟動時的音樂了。
詳細代碼下載鏈接:http://down.51cto.com/data/933023
