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

发布时间:2024-07-11  

一、实验环境

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数据手册


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

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>