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的芯片手册中定义了:
也就是除设备地址外,一个控制字由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可能跟采样率有关。
到此,WM8960基本上就配置好了,接下来就需要写数据了。
2.IIS配置
2.1 IIS时钟配置
在写数据前先检查IIS时钟设置。根据芯片手册得出,S5PV210有audio subsystem,I2S0,I2S1-2
这几块内容,其中I2S1-2不相干,所以不看,重点在前两个,首先引出I2S0的时钟图:
从此图中可以看出IIS0时钟是由2部分确定,左边的audio subsystem和I2S0自己的时钟选择。他们两个的连接有两个,一个是I2SCLK,一个是AUDIOBUSCLK,在此我们选择I2SCLK路线。先看一下音频子系统的时钟路线图:
这里由于我们要采用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公式还不理解)
修改如下几个寄存器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。
配置如下寄存器:
上图为时钟源选择开关配置配置好后值为1,下图为I2SCLK前的DIV设置,使用默认0则就是1分频。
接下来配置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文件,得出采样率和音频数据长度,我们就可以正确的进行播放了。
注意:芯片解码速率必须要和文件采样速率一致,否则播放速率会变快或者变慢。
- S5PV210+WM8960 IIS+IIC 字符设备驱动调试心得
- S5PV210调试WM8960 总结
- S5PV210调试WM8960 总结
- S5PV210调试WM8960 总结
- S5PV210 WM8960音频驱动 学习
- 基于字符设备的IIC驱动源代码
- IIC设备驱动实例
- S5PV210 WM8960 ASOC 移植
- S5PV210 I2C设备驱动
- S5PV210 I2C设备驱动
- 学习linux字符设备驱动心得
- Linux设备驱动 IIC驱动
- wince6.0 s5pv210 iic驱动 报错
- wince6.0 s5pv210 iic驱动 报错
- TCC8902 BSP IIC 调试心得
- LED字符设备驱动调试笔记
- linux中的IIC设备驱动
- linux中的IIC设备驱动
- Sdelayer注册
- java IO流学习总结
- Jsp页面接收解析后台传来的链表和对象
- redis.conf配置项说明
- 【UML】对象图(Object Diagram)
- S5PV210+WM8960 IIS+IIC 字符设备驱动调试心得
- 【POJ】-2406-Power Strings(KMP)
- Java 继承 - 字段不能被覆盖
- Android之Fragment懒加载
- poj1930(无限循环小数化成分数)
- c语言程序设计1-2章的知识点
- 我的作业v3.0
- 算法基础复习-QuickSort
- 10.31