wm8960驅動:裸機代碼研讀

網上已經有基本的wm8960驅動的demo。可以播放特定頻率的wav文件。這個程序很具有參考性。
我們知道,初始化wm8960,需要大概的步驟如下:
1.初始化I2C總線,通過I2C接口給wm8960下配置命令。
2.將聲音文件加載到memory中
3.初始化I2S,並把內存中的數據通過I2S總線送給wm8960,從而wm8960通過解碼播放出聲音
我們大概來看一下,這個代碼的實現過程:

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 > (WAV_SIZE2-0x2e) /2)       // 有多少個2byte = (文件大小-偏移)/2
            offset = 0x2E;
    }
}

其中 wm8960_init()用來初始化wm8960.具體代碼:


void wm8960_init(void)
{
    // bit[7:1]: 0x1a
    // bit[0]:0: write
#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);


    // 設置時鐘
    //Mclk--div1-->SYSCLK---DIV256--->DAC/ADC sample Freq=11.289(MCLK)/256=44.1KHZ
    iic_write(WM8960_DEVICE_ADDR, 0x4, 0x0);

    // 設置ADC-DAC
    iic_write(WM8960_DEVICE_ADDR, 0x5, 0x0);

    // 設置audio interface
    //I2S format 16 bits word length
    iic_write(WM8960_DEVICE_ADDR, 0x7, 0x2);

    // 設置OUTPUTS
    iic_write(WM8960_DEVICE_ADDR, 0x2, 0xFF | 0x100);
    iic_write(WM8960_DEVICE_ADDR, 0x3, 0xFF | 0x100);

    // 設置DAC VOLUME
    iic_write(WM8960_DEVICE_ADDR, 0xa, 0xFF | 0x100);
    iic_write(WM8960_DEVICE_ADDR, 0xb, 0xFF | 0x100);

    // 設置mixer
    iic_write(WM8960_DEVICE_ADDR, 0x22, 1<<8 | 1<<7);
    iic_write(WM8960_DEVICE_ADDR, 0x25, 1<<8 | 1<<7);

    return;

}

I2S的初始化:

void iis_init(void)
{
    int N;
    // 配置引腳用於i2s功能
    GPICON = 0x22222222;

    // 設置i2s相關時鐘
    // step 1: EPLL output 67.7Mhz (see p361 of s5pv210.pdf)
    // EPLL_CON0/ EPLL_CON1, R/W, Address = 0xE010_0110/0xE010_0114)
    // FOUT = (MDIV+K/65536) X FIN / (PDIV X 2SDIV)
    // Fout = (0x43+0.7)*24M / (3*2^3) = 80*24M/24 = 67.7Mhz
#define EPLL_CON0   (*(volatile unsigned int *)0xe0100110)
#define EPLL_CON1   (*(volatile unsigned int *)0xe0100114)
    EPLL_CON0 = 0xa8430303;     // MPLL_FOUT = 67.7Mhz
    EPLL_CON1 = 0xbcee;     // from linux kernel setting


    // step 2: Mux_I2S  AUDIO subsystem clock selection (see P1868 P1875 of s5pv210.pdf)
#define CLK_CON     (*(volatile unsigned int *)0xEEE10000)
    CLK_CON = 0x1;      // 1 = FOUT_EPLL        MUXI2S_A 00 = Main CLK


    // 設置i2s控制器
    // step 3:  Divider of IIS (67.7 -> 11.289Mhz)
    // N + 1 = (67.7Mhz) / (256 * 44.1Khz) = 5.99
    // IISCDCLK  11.289Mhz = 44.1K * 256fs
    // IISSCLK    1.4112Mhz = 44.1K * 32fs
    // IISLRCLK   44.1Khz
    N = 5;
    IISPSR = 1<<15 | N<<8;

    // IIS interface active (start operation).  1 = Active
    IISCON |= 1<<0 | (unsigned)1<<31;

    // [9:8] 10 = Transmit and receive simultaneous mode
    // 1 = Using I2SCLK     (use EPLL)
    IISMOD = 1<<9 | 0<<8 | 1<<10;

}

I2S的初始化,主要完成時鐘的初始化.
MPLL_FOUT=67.7Mhz
Codec clock=11.289Mhz—–也稱作MCLK=256*fs
I2S SerialCLK(I2SSLK)=1.4122Mhz =2* fs *採樣位數
I2S LRCLK ==44.1KHZ

不同採樣位數的wav文件,對應的時鐘信號有所不同~


這裏詳細展開下wm8960和s5pv210的時鐘配置.
選擇s5pv210爲主設備,wm8960爲從設備。
1. wm8960的時鐘
scaler作爲Master, codec作爲從設備,scaler要向codec提供IIS root clock (codec clock)
還有Bit clock.
2. 產生這些clk需要時鐘源,使用三星S5PV210的話,具體的時鐘路由如下:
這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

1) 獲得FOUTEPLL ,XXTI是外部晶振,從外部晶振獲得FINPLL,由FINPLL經過EPLL模塊倍頻後,產生
2) 獲得IISSCLK,先通過CLKMUX_ASS選擇FOUTEPLL時鐘爲Main CLK,再通過MUXIISA選擇MAIN clk爲IISCLKSRC,然後通過預分頻設定分頻,最後產生IISCLK
3) 最終痛過RCLKSRC選擇 IIS CLK爲 RCLKSRC,再通過分頻器分出RCLK,也成爲Root clk,或者codec clk.
4) 同時root clk再次通過分頻器分出BCLK ,也稱作bit clock/serial clk

到此爲止,scaler產生MCLK和BCLK給codec.scaler端的時鐘設置完畢.

Codec端設置:
同理,codec端也需要配置:
1) 設置SYSCLK由MCLK分頻1產生
2) 設置DAC/ADC 頻率由SYSCLK分頻256產生
頻率44100hz 16bit的wav文件
LRCLK =音頻本身的頻率(44.1Khz)
BCLK =2*fs*採樣位數(1.411Mhz)
MCLK=256*fs(11.289Mhz)


s5pv210寄存器配置:
這裏寫圖片描述
Fout = (0x43+0.7)*24M / (3*2^3) = 80*24M/24 = 67.7Mhz
EPLL_CON0 = 0xa8430303;
EPLL_CON1 = 0xbcee;
到此爲止:FOUTEPLL已經配置完成,此時FOUTEPLL=67.7Mhz

這裏寫圖片描述

這邊通過配置 AUDIO SUBSYSTEMCLK SRC REG(AUDIO_CLK)
AUDIO_CLK =0x01;
Main clk由 CLKMUX_ASS選擇器選擇源時鐘爲上面得到的FOUTEPLL時鐘,同時MUXI2S_A選擇器設置爲00,選擇得到的main clk爲I2SCLK的源時鐘.
寄存器AUDIO_SUBSYSTEMCLK DIV中 I2S_A_RATIO 默認爲0,也就是說I2SCLK=上面得到的I2SCLK的時鐘源分頻1

這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述

上面是I2SCON寄存器
I2SCON =1<<0 | (unsigned)1<<31;

這裏寫圖片描述
這裏寫圖片描述
這是IISMOD寄存器,其中bit0無意義,所以不列出

我們已經得到了I2SCLK,那麼用它幹啥?
這裏寫圖片描述

在獲得RCLKSRC時我們需要配置IISMOD[10],選擇I2SCLK爲時鐘源,所以
IISMOD[10]=1 //use I2SCLK
這邊的配置基本上就差不多了:RCLKSRC經過一個分頻器獲得RCLK,RCLK在經過一個分頻器獲得BCLKmaster.
1) 我們設置scaler爲Master模式.codec爲slave模式,所以有IISMOD[11]=0
2) SDF描述了IIS信號的傳輸格式,IIS,左對齊,右對齊,這邊選擇IIS模式,所以有IISMOD[6:5]=0
3) TXR描述傳輸方向,選擇同時支持發送和接收,所以有IISMOD[9:8]=10
4) CDCLKCON選擇codec的時鐘,我們是IC內部提供CDCLK給codec.這裏的CDCLK指的就是RCLK(root clk),所以有IISMOD[12]=0
5) BLC 描述了每個聲道傳送的bit數,我們配置爲16bits per channel,這裏有IISMOD[14:13]=00
6) CDD1,CDD2描述發送端是否丟棄數據,我們選擇不丟棄,IISMOD[21:20]=0.IISMOD[19:18]=0
7) BLC_S, BLC_P描述second,primary fifo的每個通道的bit數,16bit,所以有IISMOD[27:26]=0,IISMOD[25:24]=0
8) OP_MUX_SEL描述了數據獲取方式是從寄存器還是內部的DMA,我們選擇前者,所以有IISMOD[20]=0
9) OP_CLK 描述了時鐘輸出的方向,scaler向外部codec輸出時鐘,所以有IISMOD[31:30]=0

繼續前面的例子,音頻44.1Khz.—–Codec的clk=256*fs =11.2896Mhz
所以此時的N+1=67.738/11.2896=6
這裏寫圖片描述

這裏設置所謂的預分頻RCLK= RCLKSRC/(N+1)=11.2896Mhz
所以IISPSR= 1<<15 | 5<<8;
到此爲止,codec的時鐘已經產生,但還需要其他幾個時鐘,一個是SCLK/bit clk,另一個是LRSCLK:
這裏寫圖片描述

這兩個時鐘配置在IISMOD寄存器釐米那設置:
一個是RFS(IIS Root clk freq select),一個是BFS(bit clock freq select )

這裏寫圖片描述

這裏寫圖片描述

所以RFS=256,也就是說Rootclk是 fs的256倍數
BFS選擇爲32*fs,也就是說Bit clk是fs的32倍數

這邊的設置還是有些疑問的,首先我們的所有頻率都是根據輸入的*.wav的rate和bit決定的。所以我們纔有了最開始的前提:44100Khz 16bit的wav文件。16bit的音頻,BFS可以選擇32或者48,這裏我們選擇32.
確定BFS 分頻係數後,RFS可以選擇256FS,384FS,512FS,768FS。這裏我們選擇256FS

所以最開始的FOUTepll我們是根據RFS,BFS確定之後纔得到的頻率。
我們確定BFS,RFS後,開始反向推導
BFS :bit clock frequency select
我們設置BFS=32,所以BCLK/SCLK =32*fs=1.4112MHZ
RFS:root clock frequency select
我們設置RFS=256,所以 RCLK/MCLK =256*fs =11.2896MHZ
所以我們的fs是最先獲得的參數,只有根據fs,才能獲得BCLK,MCLK,LRCLK等頻率
fs參數包含在*.wav文件描述中,通過一定的格式展開獲得.
這樣就清晰起來了。RCLK獲得方式上面已經講過,不再贅述。


Codec端時鐘設置:
這裏寫圖片描述

這裏寫圖片描述
SYSCLK SRC選擇爲MCLK的時鐘,也就是11.2896Mhz
SYSCLK的CLKDIV選擇1,SYSCLK=MCLK=11.2896Mhz
DACDIV=ADCDIV=SYSCLK/256=44.1Khz
0x4=0;

這裏寫圖片描述
0x5=0
這裏寫圖片描述
選擇I2S format,word length 16 bit
0x7=2;
這裏寫圖片描述
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章