S5PV210+WM8960 IIS+IIC 字符设备驱动调试心得

来源:互联网 发布:河朔三镇 知乎 编辑:程序博客网 时间:2024/06/12 20:20

本人闲来无事就捣鼓了一下S5PV210开发板上的WM8960的音频模块(一捣鼓就是1个礼拜T_T)。
WM8960在硬件接法上采用IIS发送音频数据,IIC发送控制指令来配置WM8960芯片。所以我们要弄通音频,就必须要先去配置IIC和IIS,要了解他们的寄存器,以及他们的时钟源配置,特别是IIS的时钟源配置,稍稍会有点复杂,但不对也出不来正确的声音。
在此板子上是用I2C0和I2S0控制wm8960,以下所有配置都是基于此条件。

1.IIC配置

1.1 IIC时钟配置
在此我写的是基于字符驱动的驱动而不是裸机驱动,所以需要注意

CLK_GATE_IP3这个时钟寄存器中的CLK_I2C0[7] 位要置1=pass 使能I2C0时钟,否则通过ioremap操作的时候寄存器无法操作,读取到的值都为0。因为内核启动后可能会把I2c时钟关掉。省电?

1.2 IIC寄存器配置
对于IIC寄存器配置,我们只关心几个主要的寄存器IICCON,IICMOD,IICDS这3个寄存器,在此我只使用其发送功能。
初始化代码如下:

void IIC_init(void){      volatile unsigned long *CLK_GATE_IP3=NULL;      //      set GPIO pin function as IICSCL, IICSDA      //GPD1CON[1]  0010 = I2C0_SCL ,GPD1CON[0]  0010 = I2C0_SDA       *GPD1CON &=~0xff;           *GPD1CON |=0x22;      *GPD1PUD &= ~0xfff;                    *GPD1PUD |= 0xaaa;              //Pull-up enable    /******Open I2C CLOCK**************/    CLK_GATE_IP3=ioremap(0xE010046C,4);    //open i2c i2sclock    writel(readl(CLK_GATE_IP3) | (1<<7 |(1 <<4)|1),CLK_GATE_IP3);     iounmap(CLK_GATE_IP3);CLK_GATE_IP3=NULL;    /**********************************************/    // Enable ACK, Prescaler IICCLK=PCLK/16,     //Enable interrupt, Transmit clock value Tx clock=IICCLK/16    writel( (1<<7) | (0<<6) | (1<<5) | (0xe),IICCON);    // Enable IIC bus    //IIC bus data output enable(Rx/Tx)    writel(readl(IICSTAT)|0x10,IICSTAT);}

上述初始化代码主要就是配置GPIO管脚功能,设置IIC寄存器的初始功能。
发送代码如下:

/*I2c write*/void IIC_write(int slave_addr, int addr, int data){    writel( (1<<7) | (0<<6) | (1<<5) | (0xe),IICCON);//防止I2c发送失败     writel(slave_addr,IICDS);//从机地址    *IICSTAT = 0xf0;//起始信号    while ((readl(IICCON) & 0x10) == 0) ;   //wait send  INT    while ((*IICSTAT & 0x1)) ;  // ACK    // 7 bit addr & 9 bit data    *IICDS = addr<<1 | ((data>>8) & 0x0001);    *IICCON &= ~(1<<4);//clear int     while ((readl(IICCON) & 0x10) == 0) ;   //wait send  INT    while ((*IICSTAT & 0x1));   // ACK    *IICDS = (data & 0x00FF);    *IICCON &= ~(1<<4);//clear int     while ((readl(IICCON) & 0x10) == 0) ;   //wait send  INT    while ((*IICSTAT & 0x1));   // ACK    *IICSTAT = 0xd0;    // stop write    *IICCON &= ~(1<<4);//clear int     return;}

上述代码按照I2C协议每发送一个字节等待一个ack信号。上面代码中为什么第二个字节是addr<<1 | ((data>>8) & 0x0001),是因为在WM8960的芯片手册中定义了:
图1
也就是除设备地址外,一个控制字由2个字节[16]Bit组成,其中7位寄存器地址,9位数据。因此[15]-[9]为寄存器地址,也就是addr<<1,而| ((data>>8)则是发送数据位的最高位,和前面的地址一起凑够8位。在此提一下,I2C默认是按MSB(高位先出)的顺序按位发送的,所以这样操作并不会改变寄存器的地址。
I2C发送方法完成后接下来就是WM8960的简单初始化,代码如下:

void WM8960_init(void){#define WM8960_DEVICE_ADDR  0x34    // reset    IIC_write(WM8960_DEVICE_ADDR, 0xf, 0x0);    // power1 2 3    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);    // clock CLKSEL = 0 : no PLL -> SYSCLK using MCLK     IIC_write(WM8960_DEVICE_ADDR, 0x4, 0x0);            // no mute  ok    IIC_write(WM8960_DEVICE_ADDR, 0x5, 0x0);// set no mute    // audio interface 00 = 16bits,  10 = IIS format    IIC_write(WM8960_DEVICE_ADDR, 0x7, 0x2);    // volume -73db ok    IIC_write(WM8960_DEVICE_ADDR, 0x2, 0x6F | 0x100);// WM8960_LOUT1    IIC_write(WM8960_DEVICE_ADDR, 0x3, 0x6F | 0x100);// WM8960_ROUT1    //Left DAC volume    IIC_write(WM8960_DEVICE_ADDR, 0xa, 0xFF | 0x100);    //Right DAC volume    IIC_write(WM8960_DEVICE_ADDR, 0xb, 0xFF | 0x100);    // mixer control    // Left output mixer control    IIC_write(WM8960_DEVICE_ADDR, 0x22, 1<<8 | 1<<7);       // Right output mixer control       IIC_write(WM8960_DEVICE_ADDR, 0x25, 1<<8 | 1<<7);           return;}

这些配置不多说,因为我也不太懂,^_^。主要就是注意音量和非静音的设置还有时钟的设置,这里因为输入的时钟是11.289Mhz,所以设置为NOPLL(接口是MCLK并且与IISCDCLK对应),直接采用输入时钟。44.1k可能跟采样率有关。

图2

到此,WM8960基本上就配置好了,接下来就需要写数据了。

2.IIS配置

2.1 IIS时钟配置

在写数据前先检查IIS时钟设置。根据芯片手册得出,S5PV210有audio subsystem,I2S0,I2S1-2
这几块内容,其中I2S1-2不相干,所以不看,重点在前两个,首先引出I2S0的时钟图:

图3

从此图中可以看出IIS0时钟是由2部分确定,左边的audio subsystem和I2S0自己的时钟选择。他们两个的连接有两个,一个是I2SCLK,一个是AUDIOBUSCLK,在此我们选择I2SCLK路线。先看一下音频子系统的时钟路线图:

图4

这里由于我们要采用FOUT_EPLL的输出,所以我们需要CLKMUX_ASS=1,MUXi2sA=0这条路线产生I2SCLK。在此DIVi2sA使用1,也就是I2SCLK等于FOUT_EPLL的时钟,便于后续分频。
至此I2S0的时钟配置总体路线图就出来了。FOUT_EPLL–>Main_CLK–>I2SCLK –>I2S0。

首先配置EPLL,如下表,配置成输出67Mhz。(近似选择67.73759,因为计算到67Mhz公式还不理解)

图5

修改如下几个寄存器EPLLCON0 ,CLK_SRC0和EPLLCON1:
这里写图片描述

// 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    EPLL_CON0 =ioremap(0xe0100110,4);    EPLL_CON1 =ioremap(0xe0100114,4);    writel(0xa8430303,EPLL_CON0);//S=P=3 M=67 VSEL=1 MPLL_FOUT = 67.7Mhz    writel(0xbcee,EPLL_CON1);//K=48339 from linux kernel setting// MUX_EPLL = 1 -> SCLK_EPLL = 67.7Mhz (see p361 of s5pv210.pdf)    // CLK_SRC0, R/W, Address = 0xE010_0200    // 0xe0100200: 10001111    // EPLL_SEL  [8]  Control MUXEPLL (0:FINPLL, 1:FOUTEPLL)     CLK_SRC0 =ioremap(0xE0100200,4);    writel(readl(CLK_SRC0)|(0x1<<8),CLK_SRC0);

这样FOUT_EPLL就准备好了,继续配置音频子系统,打通I2SCLK。
配置如下寄存器:

图7

上图为时钟源选择开关配置配置好后值为1,下图为I2SCLK前的DIV设置,使用默认0则就是1分频。

图8

接下来配置I2S0的时钟输入。
2.2 IIS寄存器配置
IIS初始化代码如下:

// IIS SFRs
// Divider of IIS (67.7 -> 11.289Mhz)
// N + 1 = (67.7Mhz) / (256 * 44.1Khz) = 5.99
// IISCDCLK 11.289Mhz = 44.1K * 256fs (RFS IISMOD[4:3])
// IISSCLK 1.4112Mhz = 44.1K * 32fs (BFS IISMOD[2:1])
// IISLRCLK 44.1Khz
//44.1khz为采样率,N可以通过改变这个值来计算
//比如22050的采样率可以设置为10,此时能按正常的速度播放
//N对IISCDCLK,IISSCLK,IISLRCLK的影响不太明白。
N = 5;
writel(1<<15 | N<<8,IISPSR);

// Now we set IIS SFR// IIS interface active (start operation).  1 = Active  writel(readl(IISCON)|(1<<0 | (unsigned)1<<31),IISCON);// [9:8] 10 = Transmit and receive simultaneous mode    // 1 = Using I2SCLK     (use EPLL)writel(1<<9 | 0<<8 | 1<<10 ,IISMOD);

上述代码实现,IISMOD选择时钟为I2SCLK,I2SPSR设置预分频器N,(M就不知道了,不用设置)。到此,IIS0已经配置完成,接下来就只需要发送音频数据了。由于在此I2SMOD中的BLC我采用默认值,所以一次向IIS写入4个字节数据16位左耳数据,16位右耳数据(有可能需要文件支持)。
写入需要使用IISTXD寄存器。写入方式如下:

while((*IISCON & (1<<8)) == (1<<8));//判断Tx FIFO缓冲区有没有满,没满继续写入。        *IISTXD = audiobuf; //BLC = 0 左右耳数据都为16位

Audiobuf为四个字节音频数据。

至此,我们只需要解析一个wav文件,得出采样率和音频数据长度,我们就可以正确的进行播放了。

注意:芯片解码速率必须要和文件采样速率一致,否则播放速率会变快或者变慢。

0 0
原创粉丝点击