请问一个音频 I2S 通讯中 DMA bufsize 最大为4092的相关问题。

lymark
Posts: 5
Joined: Fri Dec 30, 2022 11:12 am

请问一个音频 I2S 通讯中 DMA bufsize 最大为4092的相关问题。

Postby lymark » Sat Jun 15, 2024 1:52 pm

您好:
我正在使用 esp-idf-v5.2,为 esp32-s3 编译,开发板为ESP32-S3_DevKitM-1。
我在外部连接了pcm1808 芯片作为从机为S3传输音频帧。

我已经了解的如下:尽管pcm1808 发送的数据宽度为 I2S_DATA_BIT_WIDTH_24BIT (24位3字节),但实际ESP I2S DMA buffer仍然是按照每个数据4字节的宽度用i2s_dma_calloc申请到内存,我的应用中只需要I2S接收单声道音频,所以只需要一个左声道,由于 DMA bufsize 最大为4092,是否也就是限制了我的通道配置中dma_frame_num最大只能1023,也就是每帧最大1023个样本?
1023 *声道数*4字节位宽 = 4092

但事实上我需要在随后的音频帧处理中用到 ESP dsp库的FFT函数处理,FFT处理的样本数为2的n次方,1024个样本数是我需要的,512个显然对于我的应用不够。在这种情况下我是否无法从I2S DMA buffer得到1024个样本数据呢?如果是真的这样的话我也许只能再补0凑足1024个样本数再进行FFT计算。

我的I2S 初始化代码如下:
代码: 全选

Code: Select all

// 新建I2S通道配置、新建I2S通道,新建I2S std配置、初始换通道的std模式
static void i2s_example_init_std_duplex(void)
{   
    // i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_SLAVE);
    i2s_chan_config_t chan_cfg = {
        .id = I2S_NUM_AUTO,    
        .role = I2S_ROLE_MASTER,      
        .dma_desc_num = 2,                  
        .dma_frame_num = 1024,                                               
        .auto_clear = false,                 
        .intr_priority = 0,                  
    };

    ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, NULL, &rx_chan));

 
    i2s_std_config_t std_cfg = {
        // .clk_cfg  = I2S_STD_CLK_DEFAULT_CONFIG(PCM1808_SAMPLE_RATE),
        .clk_cfg.sample_rate_hz = PCM1808_SAMPLE_RATE,
        .clk_cfg.clk_src = I2S_CLK_SRC_DEFAULT, // I2S_CLK_SRC_EXTERNAL,
        .clk_cfg.mclk_multiple = I2S_MULTIPLE,

        .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_24BIT, I2S_SLOT_MODE_STEREO),
        .slot_cfg.slot_mode = I2S_SLOT_MODE_MONO,
        .slot_cfg.slot_mask = I2S_STD_SLOT_LEFT,

        .slot_cfg.bit_shift = true,
        .slot_cfg.left_align = false,

        .gpio_cfg = {
            .mclk = I2S_STD_MCLK_EXTERNAL_IO1, // some codecs may require mclk signal, this example doesn't need it
            .bclk = I2S_BCLK_IO1,
            .ws = I2S_STD_WS_IO1,
            .dout = I2S_STD_DOUT_IO1,
            .din = I2S_STD_DIN_IO1, // In duplex mode, bind output and input to a same gpio can loopback internally
            .invert_flags = {
                .mclk_inv = false,
                .bclk_inv = false,
                .ws_inv = false,
            },
        },
    };
    
    ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_chan, &std_cfg));
}
得到的调试信息包含:
D (34676) i2s_common: rx channel is registered on I2S0 successfully
W (34676) i2s_common: dma frame num is out of dma buffer size, limited to 10
D (34676) i2s_common: DMA malloc info: dma_desc_num = 2, dma_desc_buf_size = data_bit_width = 4092
D (34696) i2s_std: Clock division info: [sclk] 160000000 Hz [mdiv] 13 [mclk]] 1536000 Hz
D (34706) i2s_common: MCLK is pinned to GPIO42 on I2S0
D (34706) i2s_std: The rx channel on I2S0 has been initialized to STD mode successfully
D (34716) i2s_common: i2s rx channel enabled

我的另一个问题是:
以上初始化代码在编译中出现了警告:

In function 'i2s_example_init_std_duplex':
warning: initialized field overwritten [-Woverride-init]
70 | .slot_cfg.slot_mode = I2S_SLOT_MODE_MONO,
| ^~~~~~~~~~~~~~~~~~
note: (near initialization for 'std_cfg.slot_cfg.slot_mode')
warning: initialized field overwritten [-Woverride-init]
71 | .slot_cfg.slot_mask = I2S_STD_SLOT_LEFT,
| ^~~~~~~~~~~~~~~~~
note: (near initialization for 'std_cfg.slot_cfg.slot_mask')
warning: initialized field overwritten [-Woverride-init]
73 | .slot_cfg.bit_shift = true,
| ^~~~
note: (near initialization for 'std_cfg.slot_cfg.bit_shift')
warning: initialized field overwritten [-Woverride-init]
74 | .slot_cfg.left_align = false,

请问这是我代码中两个配置函数使用的顺序问题吗?

如果您能提供帮助非常感谢

lymark
Posts: 5
Joined: Fri Dec 30, 2022 11:12 am

补充一点

Postby lymark » Sat Jun 15, 2024 5:00 pm

经过我实验发现:
根据查看代码和以下debug输出:
i2s_common: DMA malloc info: dma_desc_num = 2, dma_desc_buf_size = dma_frame_num * slot_num * data_bit_width = 4092
即使在dma_frame_num赋值超过大于1023都会被按照1023执行,i2s_common.c中i2s_alloc_dma_desc函数虽然是按照1023*1声道*4字节数据宽=4092申请的内存,但是由于我在std_cfg.slot_cfg.ws_width = I2S_DATA_BIT_WIDTH_24BIT这样定义为3字节数据宽度,实际产生的效果是:
我用i2s_channel_read(...,...,3072,...,...)读取DMA缓冲区,实际上可以读取出1024个样本数量,1024*3=3072,也就是DMA缓冲区内实际上是24位3字节数据格式。(感觉ESP文档在这个问题上其实可以再说的详细一点)

另外warning: initialized field overwritten警告通过不使用宏命令定义i2s_std_config_t和i2s_chan_config_t可以解决。

谢谢各位

Who is online

Users browsing this forum: No registered users and 121 guests