ALSA声卡_从零编写之添加录音功能(基于优龙FS2410开发板,UDA1341声卡)

来源: 电子工程世界
新闻行业新闻

一、实验环境

1.1 虚拟机环境

    a) Vmware版本:Vmware Workstation 12.5.7

    b) Ubuntu版本:9.10

    c) 内核版本:2.6.31.14

    d) toolchain版本:arm-linux-gcc 4.3.2

1.2 开发板

    优龙FS2410开发板,UDA1341声卡

    内核版本:3.4.2

二、修改代码

2.1 修改s3c2440_dma.c

1) static volatile struct s3c_dma_regs *dma_regs;

    改为:

    static volatile struct s3c_dma_regs *dma_regs_ch1; //for playback
     static volatile struct s3c_dma_regs *dma_regs_ch2; //for capture

    相应的,修改所有涉及到DMA寄存器操作的函数,根据substream->stream的类型,来选择对应的dma_regs_chx,

2) 添加preallocate_dma_buffer(),修改s3c2440_dma_new(),为playback substream和capture substream分别分配DMA缓冲区

3) 把原先定义的全局变量struct s3c2440_dma_info playback_dma_info改为在s3c2440_dma_open()里


static int s3c2440_dma_open(struct snd_pcm_substream *substream)

{


    struct s3c2440_dma_info *prtd;

    ...

    prtd = kzalloc(sizeof(struct s3c2440_dma_info), GFP_KERNEL);

    runtime->private_data = prtd;

    ...

}


    相应的,修改所有访问playback_dma_info的函数,改为访问substream->runtime->private_data


2.2(这是后来调试时才发现要加的)


   参考内核的s3c24xx-i2s.c,修改s3c2440-i2s.c:


   添加s3c2440_snd_txctrl()、s3c2440_snd_rxctrl(),然后修改s3c2440_i2s_trigger()


static int s3c2440_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)

{

    int ret = 0;

    switch (cmd) {

case SNDRV_PCM_TRIGGER_START:

case SNDRV_PCM_TRIGGER_RESUME:

case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:

    //s3c2440_iis_start();

    if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)

s3c2440_snd_rxctrl(1);

    else

s3c2440_snd_txctrl(1);

    break;

case SNDRV_PCM_TRIGGER_STOP:

case SNDRV_PCM_TRIGGER_SUSPEND:

case SNDRV_PCM_TRIGGER_PAUSE_PUSH:

default:

            //s3c2440_iis_stop();

    if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)

s3c2440_snd_rxctrl(0);

    else

s3c2440_snd_txctrl(0);

    ret = -EINVAL;

    break;

    }


exit_err:

    return ret;

}


三、调试


1. 编译、安装驱动,过程略,详见:韦东山嵌入式Linux视频教程_3期项目实战之ALSA声卡_从零编写之调试(基于优龙FS2410开发板,UDA1341声卡)


2. 执行aplay windows.wav 后,耳机里是高频杂音!


    / # cat /proc/interrupts 可见确实发生了DMA中断


    CPU0


    25: 0 s3c s3c2410-wdt


    30: 26510 s3c S3C2410 Timer Tick


    35: 2 s3c  myalsa for playback


    …


    经查,需要在s3c2440_dma_hw_params()中加上:


    prtd->phy_addr = substream->dma_buffer.addr;


    原先是 playback_dma_info.phy_addr,在s3c2440_dma_new()中直接作为dma_alloc_writecombine的输出参数被初始化的:


    playback_dma_info.virt_addr = (unsigned int)dma_alloc_writecombine(pcm->card->dev, s3c2440_dma_hardware.buffer_bytes_max,

                                                                                                                     &playback_dma_info.phy_addr, GFP_KERNEL);


    重新编译加载驱动,然后再次执行aplay windows.wav 后,耳机里终于能听到声音了!

3. 执行arecord -d 5 my1.wav,但过了5秒钟没有任何反应!强制ctrl-c后,报:


    Recording WAVE 'stdin' : Unsigned 8 bit, Rate 8000 Hz, Mono


    ^CAborted by signal Interrupt...


    arecord: pcm_read:2031: read error: Interrupted system call


    / # cat /proc/interrupts 没有发生任何DMA中断


4. 用devmem2 查看寄存器DISRC1(0x4B000040), DIDST1(0x4B000048), IISCON(0x55000000)的值:


  (注:双箭头的左边是执行arecord之前的值,右边是执行arecord后的值)


    / # devmem2 0x4B000040


      Value at address 0x4B000040 (0xb6fba040): 0x0 <==> 0x55000010


    / # devmem2 0x4B000048


    Value at address 0x4B000048 (0xb6f46048): 0x0 <==> 0x33B80000


    / # devmem2 0x55000000


    Value at address 0x55000000 (0xb6fc6000): 0x100<==> 0x122 Bit[0]=0 即IIS interface disable,说明这位的1没写进去!


    查内核自带的soundsocsamsung s3c24xx-i2s.c,发现除了要操作IISCON之外,还要操作IISMOD、IISFCO。


    遂参考内核的s3c24xx-i2s.c,修改s3c2440-i2s.c:


    添加s3c2440_snd_txctrl()、s3c2440_snd_rxctrl(),然后修改s3c2440_i2s_trigger()。


5. 重新编译加载驱动,然后再次执行arecord -d 5 my1.wav,这次5秒后正常退出,没有报错。


    查看IISCON的值:


    / # devmem2 0x55000000


    Value at address 0x55000000 (0xb6fbd000): 0x10B ,说明bit[0]的1写进去了!


    / # cat /proc/interrupts


    CPU0


    25: 0 s3c s3c2410-wdt


    30: 139493 s3c S3C2410 Timer Tick


    34: 1 s3c  my alsa for capture  说明DMA中断发生了


    执行aplay my1.wav,能够播放声音!说明录音成功!


6. 在JZ2440,wm8976声卡上测试,也是成功的。而程序的修改,只需要把s3c2440_dma.c和s3c2440_iis.c拷贝覆盖过去即可。


附:源代码


myalsa_FS2410_can_record


myalsa_JZ2440_can_record


四、参考资料


1. 韦东山 嵌入式Linux视频教程_3期项目实战之ALSA声卡


2. 李兰溪  S3C24XX DMA框架源码分析


3. linux 3.4.2 内核源代码


4. s3c2440数据手册


文章来源于: 电子工程世界原文链接

本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。