i2s callback question

noweare
Posts: 77
Joined: Tue Jul 02, 2019 11:35 am

i2s callback question

Postby noweare » Tue Nov 05, 2024 9:28 pm

Hello,

As soon as I enable i2s tx channel the on_sent callback fires continuously.
I comment out i2s_channel_write statement to make sure nothing
is being written to the tx dma buffers.

Anyone have an idea why this would happen ?

Thank you

Code: Select all



/* I2S Speaker Example*/

static const char *TAG = "std_rec_example";

#define WAV_BITS_PER_SAMPLE 16 
#define SPI_DMA_CHAN SPI_DMA_CH_AUTO


TaskHandle_t writeTaskHandle, callback_status;

i2s_chan_handle_t tx_handle = NULL;

#define SAMPLE_SIZE (1440)

static int16_t samples[SAMPLE_SIZE]; // 1440 * 2

int my_int = 0;

bool flag = false;


static bool IRAM_ATTR tx_done_callback(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    vTaskNotifyGiveFromISR(callback_status, &xHigherPriorityTaskWoken);
    // vTaskNotifyGiveFromISR(writeTaskHandle, &xHigherPriorityTaskWoken);
    return false;
}

const i2s_event_callbacks_t cbs = {
    .on_recv = NULL,
    .on_recv_q_ovf = NULL,
    .on_sent = tx_done_callback,
    .on_send_q_ovf = NULL,
};

static void callback_status_task(void *args)
{
    static uint32_t count = 0;
    while (1)
    {
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
        ESP_LOGI(TAG, "count: %lu", count++);
    }
    vTaskDelete(NULL);
}

void init_speaker(void)
{    
    i2s_chan_config_t tx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
    tx_chan_cfg.auto_clear = true;
    tx_chan_cfg.auto_clear_before_cb = true;
    ESP_ERROR_CHECK(i2s_new_channel(&tx_chan_cfg, &tx_handle, NULL));

   
    i2s_std_config_t tx_std_cfg = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(CONFIG_EXAMPLE_SAMPLE_RATE),
        .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
        .gpio_cfg = {
            .mclk = I2S_GPIO_UNUSED, 
            .bclk = GPIO_NUM_22,
            .ws = GPIO_NUM_23,
            .dout = GPIO_NUM_21,
            .din = I2S_GPIO_UNUSED,
            .invert_flags = {
                .mclk_inv = false,
                .bclk_inv = false,
                .ws_inv = false,
            },
        },
    };
 
    tx_std_cfg.slot_cfg.slot_mask = I2S_STD_SLOT_LEFT;
    ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &tx_std_cfg));
}


static void i2s_example_write_task(void *args) // write to I2S dma -> bus, output to speaker
{
  
    FILE *f = fopen(SD_MOUNT_POINT "/record.wav", "r"); // open for reading;
    if (f == NULL)
    {
        ESP_LOGE(TAG, "Failed to open file for reading");
        return;
    }

    size_t bytes_written = 0;
    size_t sum = 0;
    size_t total_frames = 0;
    size_t count = 0;

  
    fseek(f, 44, SEEK_SET);  //reset file pointer to beginning of data
    
    while (count < 5) // play recording 5X
    {
          ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
        while (1) 
        {        
            size_t read = fread(samples, sizeof(int16_t), (size_t)1440, f); // read 2880 bytes from record.wav into samples

            if (read == 0)
                break;

            total_frames += read; // ESP_LOGI(TAG, "elements read: %u", read);

            //  i2s_channel_write(tx_handle, samples, (size_t)1440 * sizeof(int16_t), &bytes_written, portMAX_DELAY); // Write i2s data
           
            sum += bytes_written;
          
            ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // controlled by i2s_data_sent event

        } // if

        ESP_ERROR_CHECK(i2s_channel_disable(tx_handle));
        ESP_LOGI(TAG, "total frames read: %u", total_frames);
        ESP_LOGI(TAG, "total frames sent: %u", sum / 2);
        fseek(f, 44, SEEK_SET); // reset file pointer
        total_frames = 0;
        sum = 0;
        count++;
        vTaskDelay(pdMS_TO_TICKS(1000));
    } // while1

    fclose(f);
    esp_vfs_fat_sdcard_unmount(SD_MOUNT_POINT, card); // All done, unmount partition and disable SPI peripheral
    spi_bus_free(host.slot);                          // Deinitialize the bus after all devices are removed
    vTaskDelay(pdMS_TO_TICKS(10));
    vTaskDelete(NULL);
}

void app_main(void)
{
   
    mount_sdcard();

    init_speaker();

    const i2s_event_callbacks_t cbs = {
        .on_recv = NULL,
        .on_recv_q_ovf = NULL,
        .on_sent = tx_done_callback,
        .on_send_q_ovf = NULL,
    };

  
    i2s_channel_register_event_callback(tx_handle, &cbs, &temp);
   
    xTaskCreate(i2s_example_write_task, "i2s_example_write_task", 4096, NULL, 3, &writeTaskHandle);
    xTaskCreate(callback_status_task, "callback_status_task", 2048, NULL, 1, &callback_status);
    
}


ESP_Sprite
Posts: 9757
Joined: Thu Nov 26, 2015 4:08 am

Re: i2s callback question

Postby ESP_Sprite » Wed Nov 06, 2024 12:31 am

I2S will always send samples. If there's not enough data in the output buffers (because you're not writing anything in your program) it will either repeat the last sample data our output silence.

noweare
Posts: 77
Joined: Tue Jul 02, 2019 11:35 am

Re: i2s callback question

Postby noweare » Wed Nov 06, 2024 12:54 am

OK, that sounds like it would make it harder to control what gets tx'd out of the 12s bus but I will try some things.
Thanks

noweare
Posts: 77
Joined: Tue Jul 02, 2019 11:35 am

Re: i2s callback question

Postby noweare » Thu Nov 07, 2024 4:04 pm

What I found with callbacks.

To use i2s callbacks the i2s channel enable and disable statements need to go on either side of a write or read statement else the callback will fire continuously.

So enabling / disabling works fine and the callbacks become useful for synching reads and writes to i2s dma buffers.
However in my case it added noise to the output which is (for me) a speaker. Turning the speaker on and off before and after
the i2s channel enable/disable statement did not help.

The best audio quality obtained is when I enable once in the beginning and disable the channel at the end of my audio without using callbacks.

If your output is not a speaker then using callbacks makes sense.

Who is online

Users browsing this forum: No registered users and 80 guests