音频 :i2s 与pdma 设备树相关

Recording WAVE 'test.wav' : [  137.530635] =========nau8822_set_dai_sysclk clk_id:0,freq:12288000
Signed 16 bit Little Endian, Rat[  137.539005] @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@nau8822_hw_params val_len:0x0,val_rate:0x0
e 48000 Hz, Stereo
[  137.550268] =======nau8822_set_bias_level:2
[  137.557970] =======nau8822_set_bias_level:3
[  137.562349] ==============nau8822_mute:0
[  137.567276] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  137.700319] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  137.708499] ==========default_read_copy
[  137.713440] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  137.833330] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  137.841502] ==========default_read_copy
[  137.846292] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  137.966340] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  137.974564] ==========default_read_copy
[  137.979420] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  138.099356] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  138.107542] ==========default_read_copy
[  138.112395] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  138.232371] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  138.240536] ==========default_read_copy
[  138.245348] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  138.365401] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  138.373584] ==========default_read_copy
[  138.378445] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  138.498411] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  138.506545] ==========default_read_copy
[  138.511380] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  138.631423] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  138.639600] ==========default_read_copy
[  138.644365] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  138.764434] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  138.772596] ==========default_read_copy
[  138.777439] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  138.897447] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  138.905579] ==========default_read_copy
[  138.910384] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  139.030457] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  139.038683] ==========default_read_copy
[  139.043492] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  139.163475] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  139.171665] ==========default_read_copy
[  139.176485] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  139.296492] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  139.304701] ==========default_read_copy
[  139.309542] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  139.429518] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  139.437688] ==========default_read_copy
[  139.442532] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  139.562528] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  139.570700] ==========default_read_copy
[  139.575457] =======__snd_pcm_lib_xfer size:6000,data:0x31940,interleaved:1,in_kernel:0
[  139.695540] k510_peridma_interrupt: process Transfer done irq of phy ch0, int_status(1)
[  139.703705] ==========default_read_copy
[  139.708673] ==============nau8822_mute:1
[  139.713264] =======nau8822_set_bias_level:2
[  139.719924] =======nau8822_set_bias_level:1

 

 audio codec 每个寄存器占用2个字节。

#define NAU8822_REG_INPUT_CONTROL		0x2C
static const struct snd_kcontrol_new nau8822_right_input_mixer[] = {
	SOC_DAPM_SINGLE("R2 Switch", NAU8822_REG_INPUT_CONTROL, 6, 1, 0),
	SOC_DAPM_SINGLE("MicN Switch", NAU8822_REG_INPUT_CONTROL, 5, 1, 0),
	SOC_DAPM_SINGLE("MicP Switch", NAU8822_REG_INPUT_CONTROL, 4, 1, 0),
};
#define AUDIO_BASE_ADDR				(0x96060000U)
volatile audio_in_reg_s  *audio_in_reg  = (volatile audio_in_reg_s *)(long)(AUDIO_BASE_ADDR+0x400);
#define AUDIO_BASE_ADDR				(0x96060000U)

audio_i2s_in_init
0x96060400+0x21c = 0x9606061c
devmem 0x9606061c w   ->  0x00000001


i2s_init
ier
devmem 0x96060000 w  -> 0x00000001
irer
devmem 0x96060004 w  ->0x00000001
iter
devmem 0x96060008 w  ->0x00000001
ccr 
0x96060000 + 0x10
devmem 0x96060010 w -> 0x00000B30         ? 0x00000730

imr [0-3 channel]
0x96060000+0x3c+0x40(*0-3)
devmem 0x9606003c w  -> 0x00000033        
devmem 0x9606007c w  -> 0x00000033
devmem 0x960600bc w  -> 0x00000033
devmem 0x960600fc w  -> 0x00000033

ter [0-3 channel]
0x96060000+0x2c+0x40(*0-3)
devmem 0x9606002c w   -> 0x00000001
devmem 0x9606006c w  ->0x00000000
devmem 0x960600ac w  -> 0x00000000
devmem 0x960600ec  w   -> 0x00000000

rer [0-3 channel]
0x96060000+0x28+0x40(*0-3)
devmem 0x96060028 w   -> 0x00000001
devmem 0x96060068 w  ->0x00000000
devmem 0x960600a8 w  -> 0x00000000
devmem 0x960600e8 w   -> 0x00000000

i2s_rx_channel_config
i2s_set_rx_word_length
rcr [0-3 channel]
0x96060000+0x30+0x40(*0-3)   
devmem 0x96060030 w   -> 0x00000005   ?0x00000002
devmem 0x96060070 w   -> 0x00000005
devmem 0x960600b0 w   -> 0x00000005
devmem 0x960600f0 w   ->  0x00000005

i2s_set_tx_word_length
tcr [0-3 channel]
0x96060000+0x34+0x40(*0-3)   
devmem 0x96060034 w   -> 0x00000005  ?0x00000002
devmem 0x96060074 w   -> 0x00000005
devmem 0x960600b4 w   -> 0x00000005
devmem 0x960600f4 w   ->  0x00000005

RFCRx[0-3 channel]
0x96060000+0x48+0x40(*0-3)  
devmem 0x96060048 w   ->0x00000003
devmem 0x96060088 w   ->0x00000005
devmem 0x960600c8 w   ->0x00000005
devmem 0x96060108 w   ->0x00000005
	
TFCRx[0-3 channel]
0x96060000+0x4c+0x40(*0-3)  
devmem 0x9606004c w   ->0x00000003
devmem 0x9606008c w   ->0x00000003
devmem 0x960600cc w   ->0x00000003
devmem 0x9606010c w   ->0x00000003
        	


audio_i2s_out_init
devmem 0x96060000 w   ->0x00000001


x

dma将内存buffer数据拷贝到i2s 的transfer fifo中时,
内存buffer的结构:如果是16位数据,则通过设置i2s_set_dma_divide_16后,可将左右声道各16位拼接到一个32位里面,格式与wav/pcm音频格式相同。
i2s拷贝后完成后将32位数据分离成左右声道各16位(split 32bit data to two 16 bit data and filled in left  and right channel),再按照i2s的协议将
数据放到左右声道中。
 

一).整体流程总结:

  1).引脚设置

     查看原理图,设置指定引脚为以下功能:WCLK(采样时钟),BCKL(位时钟),SDIN(数据输入),SDOUT(数据输出)

  2).设置codec参数(nau8822 音频codec)

     设置采样率,word length(每个声道传输多少位),i2s传输模式(左对齐,右对齐,标准),其他音频链路的控制(adc input,adc mix,dac out,dacmix )。

     以此可以保证:i2s in channel fifo上已经有实时的adc转换后的数据,可以随时通多dma拷贝到内存中使用。如果codec没初始化ok,该fifo上的数据拷贝到内存中始终为0.

     i2s out channel fifo上等待输入数据,如果有数据,则触发dac转换,通过audio codec播放。

  3).I2S数据时钟设置(实际就是BCLK)

     时钟配置,通过配置时钟(SYSCTL_CLK_AUDIO_OUT_SERIAL:I2S out channel,SYSCTL_CLK_AUDIO_IN_SERIAL:i2s in channel),

     可以精确控制i2s每秒采样位数,对应于pin:BCK.比如48k,双声道,每个声道16位/32cycle,则时钟为:48000*2(2个声道)*32(每个声道32位,其中16位有效)

  4).设置soc中i2s参数(与codec设置要一致)

     设置word length(每个声道采样位数),word cycles(每个声道采样时钟),传输模式(左对齐,右对齐,标准)等。

  5).启动dma

      1)数据采集: 1)手动配置dma,数据流向:I2S->buffer,启动dma

                             2)触发中断完成内存拷贝后,再次进入步骤1,如此无限循环。

      2) 数据播放:    1)手动配置dma,数据流向:buffer->I2S,启动dma

                             2)触发中断完成内存拷贝后,再次进入步骤1,如此无限循环。

  二).注意事项总结:

     1.数据采集和数据播放可以单独运行也可以同时运行。同时运行时,使用2个不同的dma通道,使用ping pongbuffer会导致延迟极低,不容易听到自己说话声。可以通过 ring buffer来调整延迟。

     2.i2s参数的修改,大部分参数修改2个位置:audio codec 和 soc中i2s模块,且两者修改后要保持一致。比如修改采样率,两边都要修改。

     3.内存分配:

        1)每个声道16位/32cycle的配置,i2s 输入通道默认配置:左声道(低16位有效,高16位为静音数据,值为0或0xffff两者不断切换),右声道同左声道。

        2)每个声道32位/32cycle的配置,i2s 输入通道默认配置:左声道(32位,32位有效),右声道同左声道。

        3)fpga以前的裸机程序每个声道32位/32cycle的,而实际驱动程序使用中都是16位/32cycle的。

            在linux系统下,通过aplay 播放一个wav文件,实际文件为16位/16cycle的格式,如何变成16/32cycle同时避免cpu拷贝内存,可使用i2s函数:i2s_set_dma_divide_16.

           (split 32bit data to two 16 bit data and filled in left and right channel).该函数仅仅适合音频播放(数据从buffer到i2s,指的是buffer中的数据).音频采集无效,采集到的数据仍为(16位/32cycle)。

     4.音频codec:包括音频的控制和数据的传输。数据的传输通过I2S协议。音频的控制(复位,音量,音频参数设置等)通过I2C协议。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Linux 设备树是描述硬件信息的一种数据结构。DMA(Direct Memory Access,直接内存访问)是一种硬件机制,它允许外设直接访问系统内存而不需要 CPU 的干预。在设备树,DMA 控制器和外设需要进行正确的配置才能实现 DMA 的功能。 下面是一个示例设备树节点的 DMA 配置: ``` dma-channel@0 { compatible = "arm,pl330", "arm,primecell"; reg = <0x7e001000 0x1000>; interrupts = <0 47 4>; #dma-cells = <1>; dma-channels = <8>; }; ``` 其: - `dma-channel@0` 是节点名称,在系统应该是唯一的。 - `compatible` 属性指定了该节点所对应的 DMA 控制器的类型。 - `reg` 属性指定了该节点所对应的 DMA 控制器的物理地址和大小。 - `interrupts` 属性指定了该节点所对应的 DMA 控制器的断信息。 - `#dma-cells` 属性指定了该节点所对应的 DMA 控制器的单个 DMA 通道所需要的参数个数。在本例,只需要一个参数表示 DMA 通道号。 - `dma-channels` 属性指定了该节点所对应的 DMA 控制器的可用 DMA 通道数量。 对于外设的 DMA 配置,可以在该外设的设备树节点添加 `dma` 属性,例如: ``` spi@ff1a0000 { compatible = "rockchip,rk3066-spi"; reg = <0xff1a0000 0x1000>; interrupts = <0 13 4>; clocks = <&cru SCLK_SPI0>; dmas = <&pdma0 4 3>, <&pdma0 5 3>; dma-names = "rx", "tx"; }; ``` 其: - `dmas` 属性指定了该外设使用的 RX 和 TX DMA 通道。 - `dma-names` 属性指定了 `dmas` 属性指定的 DMA 通道的名称。 以上是一些简单的示例,实际的设备树节点配置可能更加复杂,需要根据硬件的具体情况进行配置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunxiaopengsun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值