于我而言,音频驱动是一个较为复杂的驱动子系统。前几年曾在嵌入式linux中开发过CS4344音频驱动,这款音频芯片跟AT73C213非常相似,所以驱动是“山寨”AT73C213驱动的,驱动开发异常顺利,几乎没有遇到什么问题。仅管如此,单理解这个驱动就费了不少劲,特别是理解linux中ALSA驱动子系统。

此外,音频驱动子系统中,还有很多概念需要理解,如PCM、音频采样频率、声道数目及其采样比特数等。

eCos中没有I2S驱动,也没有像USB、framebuf一样,提供一个音频IO子系统,但不代表我们无所作为。通过本次实现的eCos STM32 I2S驱动,可以了解到以下3个方面知识:

  1. 如何在eCos中添加一个新的驱动组件;
  2. 了解eCos中DMA + 中断 + 条件信号的应用;
  3. 了解eCos中如何实现一个设备驱动依赖于另一个设备驱动的实现;

我觉得以上3点是i2s驱动本身之外最重要的知识内容点。

STM32 I2S与SPI接口

STM32中有3个SPI接口和2个I2S接口,但是,2个I2S接口与2个SPI接口是复用的。这里我们使用的是I2S2接口。

音频硬件模块组成

首先了解下板子上音频系统由哪些硬件模块组成,确定要驱动哪些器件。如下图所示:

音频硬件系统框架

上图是来自安富莱开发板的音频系统,由3部组成:CPU、音频CODEC、音频输入输出。更具体的请参考安富莱开发板附带的原理图。

其中,wm8978是一个I2S接口立体声输出的音频codec,负责把I2S音频流转换输出到耳机或扬声器中,以及采集MIC或耳麦音频信号实现录音采集。AUX输入是FM收音机输入信号,通过它,可以实现FM收音机功能。

从上图可以看到,CPU通过I2C来控制wm8978,通过I2S把音频数据传送给WM8978。所以,我们要在eCos中实现两个驱动:

  • STM32 I2S驱动:主要负责stm32 CPU与WM8978之间音频数据流的传输,以及STM32 I2S接口的控制,如I2S模式、音频协议、采样速率、DMA和中断等设置;
  • WM8978驱动:通过I2C初始化和控制WM8978,如上电初始化、音量调节、声道选择、采样位数等;

eCos音频驱动框架

这里所说的音频驱动框架并不像USB、framebuf等那样完善,我们的目标是,让用户应用程序更好更方便地控制声卡驱动,从而实现音频播放。

从上面的描述,你是否发现:STM32 I2S驱动和WM8978驱动实际上有一定耦合关系。也就是:STM32 I2S驱动传输的音频数据流的对象是WM8978,而WM8978驱动则不负责音频数据流。此外,一些音频控制流数据如音频协议的设置需要同时提交给两者。

从这点出发,这两个驱动考虑有两种设计模式:分开设计模式和依赖设计模式。如下图所示。

STM32 I2S驱动和WM8978驱动设计模式

之所以搞得这么“复杂”,是因为eCos中没有像USB、framebuf一样提供一个“适配”音频IO层,所以换作直接使用eCos提供的一般IO层API,即read、write、set_config等API。从这里也看到,有一个“适配”IO层是一件多么好的事情,当然这是题外话,如果你有兴趣,你可以尝试写一个音频IO层。

分开设计模式

分开设计指的是STM32 I2S驱动和WM8978驱动互为独立,互不依赖,具体的音频控制和音频数据由用户应用程序管理。这种设计方式有个缺点就是:需要用户应用程序知道更多的控制细节。比如,设置采样速率,则需要同时设置这两个驱动的相关参数;而设置音量,则仅需要设置WM8978驱动的相关参数。

当然,也可以把所有需要设置的参数在两个驱动中都实现,用户程序设置某个参数时,同时设置两个驱动的参数。如果某个驱动不需要这个设置参数,留空则可!

依赖设计模式

所谓依赖设计模式是指:对于用户应用程序而言,它仅能看到一个声卡设备文件:/dev/dsp。所有的音频数据流和音频控制流都是对这个声卡设备的。STM32 I2S驱动和WM8978驱动作为一个整体,其中,把WM8978驱动视为用户程序能看到的声卡设备驱动,而把STM32 I2S驱动作为这个声卡设备的数据传输通道,关系上,STM32 I2S驱动作为WM8978驱动的依赖设备,类似于eCos中的tty驱动与serial驱动的关系。

哪种驱动模式好?

分开设计模式和依赖设计模式哪种方式更好呢?我最后的选择是依赖设计模式。一方面,简化用户应用程序设计,甚至如果设计的好,可以兼容linux上的程序;另一方面,两种设计模式,对于驱动而言,复杂度相当,这得益于eCos良好的驱动架构体系!

STM32 I2S驱动机制实现

由于STM32 I2S接口与SPI接口是复用的,所以I2S驱动在设计上直接借鉴了eCos STM32 SPI驱动,代码实现是以SPI驱动为模板。

不同的是,I2S驱动中去掉了SPI驱动中使用的POLL模式,而直接使用DMA中断方式来传输数据。

为保证音频数据流连续的传输,设计使用DMA双缓存,也就是所谓的DMA乒乓模式。当一个缓存数据传输完成后,产生中断,然后继续传输另一个缓存数据。与此同时,驱动主线程把剩余音频流数据装载到刚刚传输完成的缓存中,供下一次DMA传输使用。

wm8978驱动机制实现

WM8978驱动大部分是直接拷贝安富莱开发板例程中的WM8978 BSP驱动源码。

驱动调试经验

这次eCos音频驱动调试花费不了精力,虽然驱动初步可用,但依然还有这样那样的问题,因此还需要后续继续完善。总结下调试经验,如下所述:

  • 如果没有相关音频知识,建议先了解下相关音频知识,如音频采样速率、左右声道、I2S接口等;
  • 先阅读下STM32参考手册SPI章节中关于I2S的描述和使用(应该是23章节);
  • 了解下STM32参考手册DMA章节知识(应该是10章节);
  • 看懂开发板中某个音频相关的例程,并且下到板子上体验下;
  • WM8978的驱动直接拷贝自开发板例程,所以这个省事不少;
  • 调试的重点应该放在I2S DMA中断和数据传输上。我在这里范了个错误导致调试了很久:配置DMA传输数量时,配置的是要传输数据的字节数。实际上DMA是以16bit为传输单位,所以配置DMA传输数量时应该是要传输数据的半字数,比如音频数据流1024 bytes,则配置DMA传输数量为512 bytes,否则则会多传输数据。

驱动源码下载

本人编写的驱动编码下载地址:http://52ecos.net/thread-558-1-1.html

下节将介绍下STM32 I2S驱动和WM8978驱动的具体实现细节。

» 文章出处: reille博客—http://velep.com , 如果没有特别声明,文章均为reille博客原创作品
» 郑重声明: 原创作品未经允许不得转载,如需转载请联系reille#qq.com(#换成@)
分享到:

  3 Responses to “stm32移植ecos #28,ecos i2s driver,音频驱动(上)”

  1. 依赖设计模式。一方面,简化用户应用程序设计,甚至如果设计的好,可以兼容linux上的程序;

 Leave a Reply

(必须)

(我会替您保密的)(必须)

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.

   
© 2012 velep.com | reille blog | 管理| 粤ICP备15065318号-2| 谷歌地图| 百度地图| Suffusion theme|Sayontan Sinha

无觅相关文章插件,快速提升流量