ALSA声卡_从零编写之参数设置(基于优龙FS2410开发板,UDA1341声卡)

发布者:快乐阳光最新更新时间:2024-07-11 来源: elecfans关键字:参数设置  FS2410开发板 手机看文章 扫描二维码
随时随地手机看文章

一、实验环境


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 目标


     之前在写裸板程序时,已经了解了怎样写代码来操作硬件,设置参数,传输数据。现在的任务就是按照ASOC的框架,来重新写这些代码(难点在于理解软件框架)


2.2 哪些地方的代码会涉及到参数设置


      根据之前“分析调用过程”那节视频中,用strace跟踪的结果,总结出以下几个地方的代码会涉及到参数设置:


1. soc_pcm_open依次调用cpu_dai, platform(dma), codec_dai, machine的open或startup函数,经查:


cpu_dai

       s3c24xx_i2s_dai.ops(即s3c24xx_i2s_dai_ops),无startup函数


platform(dma)

       samsung_asoc_platform.ops(即dma_ops).dma_open里:snd_pcm_hw_constraint_integer,snd_soc_set_runtime_hwparams(&dma_hardware)


codec_dai

       uda134x_dai_ops.startup即uda134x_startup 里:


       snd_pcm_hw_constraint_minmax(SNDRV_PCM_HW_PARAM_RATE), snd_pcm_hw_constraint_minmax(SNDRV_PCM_HW_PARAM_SAMPLE_BITS)


machine

       s3c24xx_uda134x_dai_link.ops(即s3c24xx_uda134x_ops).startup即s3c24xx_uda134x_startup里:


      主要工作是设置rate[]的值(算法原理可参考:在uda1341的i2s中256fs,384fs和512fs表示的实际意义和如何auto智能选择)


      通过分析这些函数可知,它们并没有涉及到硬件操作,所以我们把它们都归并到dma_open里实现


   2. soc_pcm_hw_params依次调用machine,codec_dai,cpu_dai,platform(dma)的hw_params函数


machine  

       s3c24xx_uda134x .hw_params 即s3c24xx_uda134x_hw_params


codec_dai

       uda134x_dai_ops.hw_params 即uda134x_hw_params


cpu_dai

       s3c24xx_i2s_dai_ops.hw_params 即s3c24xx_i2s_hw_params


platform(dma)

       samsung_asoc_platform.ops(即dma_ops). hw_params 即dma_hw_params


      通过分析这些函数可知,它们涉及到了硬件操作,所以我们需要分别在这些hw_params函数所属的驱动中实现


三、具体实现

3.1 实现dma_open

(参考:soundsocsamsungdma.c)


static const struct snd_pcm_hardware s3c2440_dma_hardware = {

.info = SNDRV_PCM_INFO_INTERLEAVED |

    SNDRV_PCM_INFO_BLOCK_TRANSFER |

    SNDRV_PCM_INFO_MMAP |

    SNDRV_PCM_INFO_MMAP_VALID |

    SNDRV_PCM_INFO_PAUSE |

    SNDRV_PCM_INFO_RESUME,

.formats = SNDRV_PCM_FMTBIT_S16_LE |

    SNDRV_PCM_FMTBIT_U16_LE |

    SNDRV_PCM_FMTBIT_U8 |

    SNDRV_PCM_FMTBIT_S8,

.channels_min = 2,

.channels_max = 2,

.buffer_bytes_max = 128*1024,

.period_bytes_min = PAGE_SIZE,

.period_bytes_max = PAGE_SIZE*2,

.periods_min = 2,

.periods_max = 128,

.fifo_size = 32,

};

static int s3c2440_dma_open(struct snd_pcm_substream *substream)

{

    struct snd_pcm_runtime *runtime = substream->runtime;

    int ret;

    //去掉了和prtd相关的代码,因为这是samsung自己定义的用于dma操作的数据结构,我们不使用,而是自己来实现dma操作

    /* 设置属性 */

    snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); //约束:采样周期必须是整数

    snd_soc_set_runtime_hwparams(substream, &s3c2440_dma_hardware); //后续的snd_pcm_hw_constraints_complete会使用runtime->hw里的信息来调用一系列的snd_pcm_hw_constraint_xxx

    return 0;

}


3.2 实现machine、codec_dai、cpu_dai、platform(dma)的hw_params函数

注:由于codec_dai(uda1341_hw_params)涉及代码最复杂,所以放在最后实现


3.2.1 实现s3c2440_uda1341.hw_params 即s3c2440_uda1341_hw_params

      分析内核的s3c24xx_uda134x_hw_params()可知:它主要是调用了snd_soc_dai_set_fmt、snd_soc_dai_set_sysclk、snd_soc_dai_set_clkdiv来设置cpu_dai和codec_dai的数据格式以及时钟,而这些工作可以拆开后分别放在cpu_dai(见下文s3c2440_i2s_hw_params)和codec_dai(见下文uda1341_hw_params ())中。所以s3c2440_uda1341_hw_params不用实现。


注:关于怎样根据app提供的rate来计算clk、clk_source、fs_mod、div,可参考:在uda1341的i2s中256fs,384fs和512fs表示的实际意义和如何auto智能选择


3.2.2 实现s3c2440_i2s_dai_ops.hw_params 即s3c2440_i2s_hw_params


struct s3c2440_iis_regs {

    unsigned int iiscon ;

    unsigned int iismod ;

    unsigned int iispsr ;

    unsigned int iisfcon;

    unsigned int iisfifo;

};

static volatile unsigned int *gpecon;

static volatile struct s3c2440_iis_regs *iis_regs;


static int s3c2440_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)

{

/* 根据params设置IIS控制器 */

/* 参考裸板程序soc/iis.c的iis_init */

    int tmp_fs;

    int i;

    int min = 0xffff;

    int pre = 0;

    unsigned int fs;

    struct clk *clk = clk_get(NULL, 'pclk');

    /* 配置GPIO用于IIS */

    *gpecon &= ~((3<<0) | (3<<2) | (3<<4) | (3<<6) | (3<<8));

    *gpecon |= ((2<<0) | (2<<2) | (2<<4) | (2<<6) | (2<<8));

    /* bit[9] : Master clock select, 0-PCLK

     * bit[8] : 0 = Master mode

     * bit[7:6] : 10 = Transmit mode

     * bit[4] : 0-IIS compatible format

     * bit[3] : serial bit clock frequency select,1: 32fs,这样可以兼容8bit 和16bit的serial data bit per channel

     * bit[2] : 384fs, 确定了MASTER CLOCK之后, fs = MASTER CLOCK/384

     * bit[1:0] : Serial bit clock frequency select, 32fs

     */

    if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)

        iis_regs->iismod = (2<<6) | (0<<4) | (1<<3) | (1<<2) | (1);

    else if (params_format(params) == SNDRV_PCM_FORMAT_S8)

        iis_regs->iismod = (2<<6) | (0<<4) | (0<<3) | (1<<2) | (1);

    else

        return -EINVAL;

/* 参考: s3c2440 datasheet: IIS prescaler(IISPSR) register

  * Master clock = PCLK/(n+1)

  * fs = Master clock / 384

  * fs = PCLK / (n+1) / 384

  */

//根据以上公式,对于app传入的fs采样率,计算出最接近的tmp_fs,以及对应的iispsr

fs = params_rate(params);

    for (i = 0; i <= 31; i++) //IISPSR controlA, data value:[0~31]

    {

        tmp_fs = clk_get_rate(clk)/384/(i+1);

        if (ABS(tmp_fs, fs) < min)

        {

            min = ABS(tmp_fs, fs);

            pre = i;

        }

    }

    iis_regs->iispsr = (pre << 5) | (pre);

    /*

     * bit15 : Transmit FIFO access mode select, 1-DMA

     * bit13 : Transmit FIFO, 1-enable

     */

    iis_regs->iisfcon = (1<<15) | (1<<13);

    /*

     * bit[5] : Transmit DMA service request, 1-enable

     * bit[1] : IIS prescaler, 1-enable

     */

    iis_regs->iiscon = (1<<5) | (1<<1) ;

    clk_put(clk);

    return 0;

}

static int s3c2440_iis_init(void)

{

    gpecon   = ioremap(0x56000040, 4);

    iis_regs = ioremap(0x55000000, sizeof(struct s3c2440_iis_regs));

    platform_device_register(&s3c2440_iis_dev);

    platform_driver_register(&s3c2440_iis_drv);

    return 0;

}

static void s3c2440_iis_exit(void)

{

    platform_device_unregister(&s3c2440_iis_dev);

    platform_driver_unregister(&s3c2440_iis_drv);

    iounmap(gpecon);

    iounmap(iis_regs);

}


3.2.3 实现s3c2440_dma_ops.hw_params 即s3c2440_dma_hw_params


      分析内核的dma_hw_params()可知:主要工作涉及到数据的传输,所以我们把s3c2440_dma_hw_params留到下一节“数据传输”再实现。


3.2.4 实现uda1341_dai_ops.hw_params 即uda1341_hw_params

(为了简单, 在uda1341_init_regs里就设置好固定的参数(比如时钟、格式),并且由uda1341_soc_probe一次性调用)


#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000

#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |

SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)

/* status control */

#define STAT0 (0x00)

#define STAT0_RST (1 << 6)

#define STAT0_SC_MASK (3 << 4)

#define STAT0_SC_512FS (0 << 4)

#define STAT0_SC_384FS (1 << 4)

#define STAT0_SC_256FS (2 << 4)

#define STAT0_IF_MASK (7 << 1)

#define STAT0_IF_I2S (0 << 1)

#define STAT0_IF_LSB16 (1 << 1)

#define STAT0_IF_LSB18 (2 << 1)

#define STAT0_IF_LSB20 (3 << 1)

#define STAT0_IF_MSB (4 << 1)

#define STAT0_IF_LSB16MSB (5 << 1)

#define STAT0_IF_LSB18MSB (6 << 1)

#define STAT0_IF_LSB20MSB (7 << 1)

#define STAT0_DC_FILTER (1 << 0)

#define STAT0_DC_NO_FILTER (0 << 0)


#define STAT1 (0x80)

#define STAT1_DAC_GAIN (1 << 6) /* gain of DAC */

#define STAT1_ADC_GAIN (1 << 5) /* gain of ADC */

#define STAT1_ADC_POL (1 << 4) /* polarity of ADC */

#define STAT1_DAC_POL (1 << 3) /* polarity of DAC */

#define STAT1_DBL_SPD (1 << 2) /* double speed playback */

#define STAT1_ADC_ON (1 << 1) /* ADC powered */

#define STAT1_DAC_ON (1 << 0) /* DAC powered */


/* data0 direct control */

#define DATA0 (0x00)

#define DATA0_VOLUME_MASK (0x3f)

#define DATA0_VOLUME(x) (x)


#define DATA1 (0x40)

#define DATA1_BASS(x) ((x) << 2)

#define DATA1_BASS_MASK (15 << 2)

#define DATA1_TREBLE(x) ((x))

#define DATA1_TREBLE_MASK (3)


#define DATA2 (0x80)

#define DATA2_PEAKAFTER (0x1 << 5)

#define DATA2_DEEMP_NONE (0x0 << 3)

#define DATA2_DEEMP_32KHz (0x1 << 3)

#define DATA2_DEEMP_44KHz (0x2 << 3)

#define DATA2_DEEMP_48KHz (0x3 << 3)

#define DATA2_MUTE (0x1 << 2)

#define DATA2_FILTER_FLAT (0x0 << 0)

#define DATA2_FILTER_MIN (0x1 << 0)

#define DATA2_FILTER_MAX (0x3 << 0)

/* data0 extend control */

#define EXTADDR(n) (0xc0 | (n))

#define EXTDATA(d) (0xe0 | (d))


#define EXT0 0

#define EXT0_CH1_GAIN(x) (x)

#define EXT1 1

#define EXT1_CH2_GAIN(x) (x)

#define EXT2 2

#define EXT2_MIC_GAIN_MASK (7 << 2)

#define EXT2_MIC_GAIN(x) ((x) << 2)

#define EXT2_MIXMODE_DOUBLEDIFF (0)

#define EXT2_MIXMODE_CH1 (1)

#define EXT2_MIXMODE_CH2 (2)

#define EXT2_MIXMODE_MIX (3)

#define EXT4 4

#define EXT4_AGC_ENABLE (1 << 4)

#define EXT4_INPUT_GAIN_MASK (3)

#define EXT4_INPUT_GAIN(x) ((x) & 3)

#define EXT5 5

#define EXT5_INPUT_GAIN(x) ((x) >> 2)

#define EXT6 6

#define EXT6_AGC_CONSTANT_MASK (7 << 2)

#define EXT6_AGC_CONSTANT(x) ((x) << 2)

[1] [2]
关键字:参数设置  FS2410开发板 引用地址:ALSA声卡_从零编写之参数设置(基于优龙FS2410开发板,UDA1341声卡)

上一篇:韦东山嵌入式Linux_3期之USB摄像头监控_手机App增加录像功能(二)
下一篇:ALSA声卡_从零编写之框架(基于优龙FS2410开发板,UDA1341声卡)

推荐阅读最新更新时间:2024-11-10 16:07

西门子MM440变频器的参数设置及使用
一、西门子公司的变频器品种规格齐全。功率小到几百瓦,大到数千千瓦;功能从低端到高端;额定电压从低压、中压到高压;分交流变频器和直流变频器等。本章文以西门子公司的通用变频器MM440系列为例,介绍西门子变频器的使用。 (1)西门子MM440变频器西门子MM440变频器是通用型变频器,由微处理器控制,并采用绝缘栅双极型晶体管(IGBT)作为功率输出器件,它具有很高的运行可靠性和功能多样性。脉冲宽度调制的开关频率也是可选的,降低了电动机运行的噪声。 (2)西门子MM440变频器的接线MM440变频器的线路框图如图2-1所示,控制端子定义见表2-2。 MM440控制端子定义 MM440变频器的线路框图 MM440变频器的核
[嵌入式]
西门子MM440变频器的<font color='red'>参数设置</font>及使用
伺服电机驱动器参数设置的方法与技巧
随着各种技术的不断更新,我国的数控系统和伺服驱动器在最近几年也有了较大的发展,现在伺服驱动器在自动化生产设备中经常用到,掌握伺服驱动器参数设置的方法是现代化生产中必备的一个技能。 伺服电机是自动控制装置中被用作执行元件的微特电机,其功能是将电信号转换成转轴的角位移或角速度。 在自动化设备中,经常用到伺服电机,特别是位置控制,大部分品牌的伺服电机都有位置控制功能,通过控制器发出脉冲来控制伺服电机运行,脉冲数对应转的角度,脉冲频率对应速度(与电子齿轮设定有关),当一个新的系统,参数不能工作时,首先设定位置增益,确保电机无噪音情况下,尽量设大些,转动惯量比也非常重要,可通过自学习设定的数来参考,然后设定速度增益和速度积分时间,确
[嵌入式]
伺服电机驱动器<font color='red'>参数设置</font>的方法与技巧
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved