How to receive I2S data asynchronously? on_recv event callback seems to be only called when i2s_channel_read() is called

greengnu
Posts: 66
Joined: Wed May 08, 2019 8:45 pm

How to receive I2S data asynchronously? on_recv event callback seems to be only called when i2s_channel_read() is called

Postby greengnu » Mon Mar 24, 2025 3:14 pm

so i2s_channel_read() (like i2s_read() in the legacy driver) is blocking and is both waiting for the DMA buffer to be ready as well as copying the data to a new buffer.

This doesn't really make sense - what I want is for DMA to fill a buffer and then notify me so I can process the data with the CPU - waiting with the CPU for the data or copying it to another buffer makes no sense.

So in the new driver you can use

Code: Select all

    
    i2s_event_callbacks_t cbs = {
        .on_recv = i2s_rx_callback,
        .on_recv_q_ovf = NULL,
        .on_sent = NULL,
        .on_send_q_ovf = NULL,
    };
    i2s_channel_register_event_callback(rx_chan, &cbs, NULL)
The ESP-IDF I2S documentation states:
To send or receive data asynchronously, callbacks can be registered by i2s_channel_register_event_callback(). Users are able to access the DMA buffer directly in the callback function instead of transmitting or receiving by the two blocking functions.
and in the callback I indeed get a pointer to the actual DMA buffer - which is great - however, I noticed that this callback only gets called when I make a call to the blocking i2s_channel_read(). This again defeats the purpose, I shouldn't have to copy the DMA buffer into another buffer using the CPU before processing it if DMA already filled the data into memory for me - and what could I even use the callback for if I have copied the data anyway using i2s_channel_read()?

This seems to make no sense for me. How can I get a callback whenever a DMA buffer has been filled without having to make a call to i2s_channel_read() and without having to make a copy of the data?

MicroController
Posts: 2705
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: How to receive I2S data asynchronously? on_recv event callback seems to be only called when i2s_channel_read() is ca

Postby MicroController » Mon Mar 24, 2025 3:34 pm

How can I get a callback whenever a DMA buffer has been filled without having to make a call to i2s_channel_read() and without having to make a copy of the data?
Have you tried using i2s_channel_enable() instead of i2s_channel_read()?

greengnu
Posts: 66
Joined: Wed May 08, 2019 8:45 pm

Re: How to receive I2S data asynchronously? on_recv event callback seems to be only called when i2s_channel_read() is ca

Postby greengnu » Mon Mar 24, 2025 5:03 pm

i2s_channel_enable() has to be called before i2s_channel_read() (otherwise I couldn't receive any data in the first place), so yes, I am calling it - but without making subsequent calls to i2s_channel_read() I'm also not getting any callbacks. This is how I setup the I2S:

Code: Select all

    i2s_chan_handle_t rx_chan = NULL;
    i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_PORT, I2S_ROLE_MASTER);
    chan_cfg.dma_desc_num = 2;
    chan_cfg.dma_frame_num = 1024;
    i2s_new_channel(&chan_cfg, NULL, &rx_chan);
    i2s_std_config_t std_cfg = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(22050),
        .slot_cfg = {
            .data_bit_width = i2s_data_bit_width_t(16),
            .slot_bit_width = i2s_slot_bit_width_t(32),
            .slot_mode = I2S_SLOT_MODE_MONO,
            .slot_mask = I2S_STD_SLOT_LEFT,
            .ws_width = 32,
            .ws_pol = false,
            .bit_shift = true,
            .left_align = true,
            .big_endian = false,
            .bit_order_lsb = false,
        },
        .gpio_cfg = {
            .mclk = I2S_GPIO_UNUSED,
            .bclk = gpio_num_t(I2S_SCK),
            .ws = gpio_num_t(I2S_WS),
            .dout = I2S_GPIO_UNUSED,
            .din = gpio_num_t(I2S_SD),
            .invert_flags = {
                .mclk_inv = false,
                .bclk_inv = false,
                .ws_inv = false,
            },
        },
    };
    i2s_channel_init_std_mode(rx_chan, &std_cfg);
    i2s_event_callbacks_t cbs = {
        .on_recv = i2s_rx_callback,
        .on_recv_q_ovf = NULL,
        .on_sent = NULL,
        .on_send_q_ovf = NULL,
    };
    i2s_channel_register_event_callback(rx_chan, &cbs, NULL);
    i2s_channel_enable(rx_chan);

Who is online

Users browsing this forum: Bing [Bot], ChatGPT-User, PetalBot and 2 guests