韦东山嵌入式Linux视频教程_3期项目实战之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没写进去!

    查内核自带的sound\soc\samsung\ 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数据手册

上一篇:Linux安全加固


下一篇:java学习笔记day07