Chinaunix首页 | 论坛 | 博客
  • 博客访问: 301086
  • 博文数量: 76
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 715
  • 用 户 组: 普通用户
  • 注册时间: 2015-05-20 20:38
文章分类
文章存档

2016年(20)

2015年(56)

分类: 嵌入式

2015-07-03 21:50:24

声卡驱动程序
15年6月22日09:01:18
在linux系统中,有3种音频设备的框架:OSS,ALSA和ASoC。
(一)音频设备硬件接口
(1)PCM接口
(2)IIS接口
IIS接口最先由PHILIPS采用,在一个LRCLK的信号机制中经过多路转换,将两路音频信号变成单一的数据队列,当LRCLK为高时,左声道数据被传输,LRCLK为低时,右声道数据被传输,IIS接口适合用于立体声系统。
(3)AC‘97接口
这里的声卡传输数据用的是IIS接口。别的暂时不看。

(二)OSS标准中有两个最基本的音频设备:mixer(混音器)和dsp(数字信号处理器)。
/dev/mixer和 /dev/dsp设备文件分别是应用程序对 mixer和dsp进行操作的软件接口。

(三)2440开发板里面,mini2440和TQ2440用的是 uda1341芯片,JZ2440用的是wm8976芯片。具体可以去看电路原理图。其中这两个芯片都用IIS接口来传输数据,并且IIS接口只是用来传输声音数据,而这两者的控制接口不同,其中,UDA1341用L3接口来控制,wm8976芯片用I2C或者3线接口来控制。
先讲 uda1341芯片,在内核中有对于uda1341的支持,详见s3c2410-uda1341.c。

在s3c2410_uda1341_init函数中,用driver_register(&s3c2410iis_driver);来向内核注册驱动程序。在s3c2410iis_driver 这个结构体中,如果名字对应的话,将要调用probe函数。
在probe函数中,比较重要的函数有以下几个:
    init_s3c2410_iis_bus();
    init_uda1341();
    audio_dev_dsp = register_sound_dsp(&smdk2410_audio_fops, -1);
    audio_dev_mixer = register_sound_mixer(&smdk2410_mixer_fops, -1);

int register_sound_mixer(const struct file_operations *fops, int dev);
上述函数用于注册一个混音器,第一个参数fops是 file_operations结构体,第二个参数dev是设备编号,如果填入-1,则系统自动分配一个设备编号。mixer是一个典型的字符设备,因此编码的主要工作是用来实现 file_operations结构体中的open(), ioctl()等函数。

int register_sound_dsp(const struct file_operations *fops, int dev);
上述函数用于注册一个dsp设备,第一个参数fops是 file_operations结构体,第二个参数dev是设备编号,如果填入-1,则系统自动分配一个设备编号。编码的主要工作是实现 file_operations结构体中的read(), write(), ioctl()等函数。

(四)OSS用户空间编程。
(四.1)dsp编程:
(1)打开设备文件/dev/dsp。
(2)如果有需要,设置缓冲区大小。调用ioctl()函数来对它的尺寸进行恰当的设置。一般默认即可。
(3)设置声道数量。可以设置为单声道和立体声。
(4)设置采样格式和采样频率。
(5)读/dev/dsp实现录音, 写/dev/dsp实现播放。
(四.2)mixer编程:对混音器的操作一般通过ioctl()系统调用来完成,所以的控制命令都以SOUND_MIXER或者MIXER开头。
对声卡的输入增益和输出增益进行调节是混音器的一个主要作用,目前大部分声卡采用的是8位或者16位的增益控制器,声卡驱动程序会将他们变换成百分比的形式,也就是说无论是输入增益还是输出增益,其取值范围都是0~100。

(五)关于这部分的讲解,还是看笔记吧:




(六)下面写wm8976的驱动程序:
就在uda1341驱动程序上面修改,看笔记可以知道,iis部分相同,只需要写出控制部分即可。
修改probe函数里面的 init_wm8976(void)函数。
写这个函数需要用到写寄存器函数,先将这个函数写出来:
static void wm8976_write_reg(unsigned char reg, unsigned int data)
{
    int i;
    unsigned long flags;
    unsigned short val = (reg << 9) | (data & 0x1ff);

    s3c2410_gpio_setpin(S3C2410_GPB2,1);
    s3c2410_gpio_setpin(S3C2410_GPB3,1);
    s3c2410_gpio_setpin(S3C2410_GPB4,1);

    local_irq_save(flags);

    for (i = 0; i < 16; i++)
    {
        if (val & (1 << 15))
        {
            s3c2410_gpio_setpin(S3C2410_GPB4,0);
            s3c2410_gpio_setpin(S3C2410_GPB3,1);
            udelay(1);
            s3c2410_gpio_setpin(S3C2410_GPB4,1);
        }
        else
        {
            s3c2410_gpio_setpin(S3C2410_GPB4,0);
            s3c2410_gpio_setpin(S3C2410_GPB3,0);
            udelay(1);
            s3c2410_gpio_setpin(S3C2410_GPB4,1);
        }
        
        val = val << 1;
    }

    s3c2410_gpio_setpin(S3C2410_GPB2,0);
    udelay(1);
    s3c2410_gpio_setpin(S3C2410_GPB2,1);
    s3c2410_gpio_setpin(S3C2410_GPB3,1);
    s3c2410_gpio_setpin(S3C2410_GPB4,1);    

    local_irq_restore(flags);

}

这个函数就是参考图3的时序图写出来的。
static void init_wm8976(void)
{
    uda1341_volume = 57;
    uda1341_boost = 0;

    /* software reset */
    wm8976_write_reg(0, 0);

    wm8976_write_reg(0x3, 0x6f);
    
    wm8976_write_reg(0x1, 0x1f);//biasen,BUFIOEN.VMIDSEL=11b  
    wm8976_write_reg(0x2, 0x185);//ROUT1EN LOUT1EN, inpu PGA enable ,ADC enable

    wm8976_write_reg(0x6, 0x0);//SYSCLK=MCLK  
    wm8976_write_reg(0x4, 0x10);//16bit         
    wm8976_write_reg(0x2B,0x10);//BTL OUTPUT  
    wm8976_write_reg(0x9, 0x50);//Jack detect enable  
    wm8976_write_reg(0xD, 0x21);//Jack detect  
    wm8976_write_reg(0x7, 0x01);//Jack detect
}

(七)写出来以后,需要测试声卡驱动程序能不能用:
测试WM8976:
1. 确定内核里已经配置了sound\soc\s3c24xx\s3c2410-uda1341.c
-> Device Drivers
  -> Sound
    -> Advanced Linux Sound Architecture  // 兼容OSS
      -> Advanced Linux Sound Architecture
        -> System on Chip audio support
        <*> I2S of the Samsung S3C24XX chips
2. 修改sound/soc/s3c24xx/Makefile
obj-y += s3c2410-uda1341.o
改为:
obj-y += s3c-wm8976.o   

3. make uImage
   使用新内核启动

4. ls -l /dev/dsp /dev/mixer
5. 播放:
   在WINDOWS PC里找一个wav文件,放到开发板根文件系统里
   cat Windows.wav > /dev/dsp
6. 录音:
   cat /dev/dsp > sound.bin  
   然后对着麦克风说话
   ctrl+c退出
   cat sound.bin > /dev/dsp  // 就可以听到录下的声音

使用madplay测试声卡:
1. 解压:
tar xzf libid3tag-0.15.1b.tar.gz  // 库
tar xzf libmad-0.15.1b.tar.gz     // 库
tar xzf madplay-0.15.2b.tar.gz    // APP

2. 编译 libid3tag-0.15.1b
mkdir tmp
cd libid3tag-0.15.1b
./configure --host=arm-linux --prefix=/work/drivers_and_test/21th_sound/tmp CPPFLAGS=-I/work/drivers_and_test/21th_sound/tmp/include LDFLAGS=-L/work/drivers_and_test/21th_sound/tmp/lib
make
make install
/* 在编译这个的过程中,需要先安装zlib库,参考网上的一个帖子安装的,那个帖子也复制下来了 */

3. 编译 libmad-0.15.1b
cd libmad-0.15.1b
./configure --host=arm-linux --prefix=/work/drivers_and_test/21th_sound/tmp
make
make install

4. 编译madplay
cd madplay-0.15.2b/
d./configure --host=arm-linux --prefix=/work/drivers_and_test/21th_sound/tmp LDFLAGS="-L/work/drivers_and_test/21th_sound/app/tmp/lib" CFLAGS="-I /work/drivers_and_test/21th_sound/app/tmp/include"
make
make install

5. 把tmp/bin/*  tmp/lib/*so* 复制到根文件系统:

6. 把一个mp3文件复制到根文件系统

7. madplay --tty-control /1.mp3
   播放过程中不断按小键盘的减号("-")会降低音量
             不断按小键盘的加号("+")会降低音量
阅读(1766) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~