espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.66k stars 7.29k forks source link

How do I know the example in I2S peripheral of std mode works on my board? (IDFGH-10424) #11678

Closed misterb0407 closed 1 year ago

misterb0407 commented 1 year ago

Answers checklist.

General issue report

I have ESP-EYE board which is ESP32 type. It has a built in microphone, connected to ESP32 via I2S peripheral.

I tried sample in examples/peripherals/i2s/i2s_basic in simplex mode, and I update the GPIO number accordingly in i2s_example_init_std_simplex(), it build and run on the board and printing something like

Write Task: i2s write 2048 bytes Read Task: i2s read 2048 bytes ----------------------------------- [0] 0 [1] 0 [2] 0 [3] 0 [4] 0 [5] 0 [6] 0 [7] 0

I tried to speak over the microphone and the console still show i2s read buffer value of 0s like above.

So how can I know if my I2S init works as expected?

L-KAYA commented 1 year ago

If you're using simplex mode, the I2S gpio configuration will be overwritten by the latter port if you set the data line to a same GPIO, so you won't receive the loopback data in your console.

To check if the mic can work, you can just remove the initialization of the TX part and the writing task. Meanwhile, to monitor the data timely, you may want to reduce the polling time of the reading task. Here is the code for reference:

/*
 * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Unlicense OR CC0-1.0
 */

#include <stdint.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s_std.h"
#include "driver/gpio.h"
#include "esp_check.h"
#include "sdkconfig.h"

#define EXAMPLE_STD_BCLK_IO2    GPIO_NUM_22     // I2S bit clock io number
#define EXAMPLE_STD_WS_IO2      GPIO_NUM_23     // I2S word select io number
#define EXAMPLE_STD_DOUT_IO2    GPIO_NUM_25     // I2S data out io number
#define EXAMPLE_STD_DIN_IO2     GPIO_NUM_26     // I2S data in io number

#define EXAMPLE_BUFF_SIZE               2048

static i2s_chan_handle_t                rx_chan;        // I2S rx channel handler

static void i2s_example_read_task(void *args)
{
    uint8_t *r_buf = (uint8_t *)calloc(1, EXAMPLE_BUFF_SIZE);
    assert(r_buf); // Check if r_buf allocation success
    size_t r_bytes = 0;

    /* Enable the RX channel */
    ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));

    while (1) {
        /* Read i2s data */
        if (i2s_channel_read(rx_chan, r_buf, EXAMPLE_BUFF_SIZE, &r_bytes, 1000) == ESP_OK) {
            printf("Read Task: i2s read %d bytes\n-----------------------------------\n", r_bytes);
            printf("[0] %x [1] %x [2] %x [3] %x\n[4] %x [5] %x [6] %x [7] %x\n\n",
                   r_buf[0], r_buf[1], r_buf[2], r_buf[3], r_buf[4], r_buf[5], r_buf[6], r_buf[7]);
        } else {
            printf("Read Task: i2s read failed\n");
        }
        vTaskDelay(pdMS_TO_TICKS(10));
    }
    free(r_buf);
    vTaskDelete(NULL);
}

static void i2s_example_init_std_simplex(void)
{

    i2s_chan_config_t rx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
    ESP_ERROR_CHECK(i2s_new_channel(&rx_chan_cfg, NULL, &rx_chan));

    i2s_std_config_t rx_std_cfg = {
        .clk_cfg  = I2S_STD_CLK_DEFAULT_CONFIG(16000),
        .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_MONO),
        .gpio_cfg = {
            .mclk = I2S_GPIO_UNUSED,    // some codecs may require mclk signal, this example doesn't need it
            .bclk = EXAMPLE_STD_BCLK_IO2,
            .ws   = EXAMPLE_STD_WS_IO2,
            .dout = EXAMPLE_STD_DOUT_IO2,
            .din  = EXAMPLE_STD_DIN_IO2,
            .invert_flags = {
                .mclk_inv = false,
                .bclk_inv = false,
                .ws_inv   = false,
            },
        },
    };
    ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_chan, &rx_std_cfg));
}

void app_main(void)
{
    i2s_example_init_std_simplex();
    xTaskCreate(i2s_example_read_task, "i2s_example_read_task", 4096, NULL, 5, NULL);
}
misterb0407 commented 1 year ago

Hi @L-KAYA , thank you for the response, I did as you suggested, but I need to add ESP_ERROR_CHECK(i2s_channel_enable(rx_chan)); in app_main() after i2s_example_init_std_simplex() to make it work. Now I can see non 0s data in the I2S read buffer, but it is either 80s or 0s like following:

`D (341) i2s_common: rx channel is registered on I2S0 successfully
D (351) i2s_common: DMA malloc info: dma_desc_num = 6, dma_desc_buf_size = dma_frame_num * slot_num * data_bit_width = 480
D (361) i2s_std: Clock division info: [sclk] 160000000 Hz [mdiv] 14 [mclk] 11289600 Hz [bdiv] 8 [bclk] 1411200 Hz
D (371) i2s_std: The rx channel on I2S0 has been initialized to STD mode successfully
D (371) i2s_common: i2s rx channel enabled
I (381) main_task: Returned from app_main()
Read Task: i2s read 2048 bytes

[0] 0 [1] 80 [2] 0 [3] 80
[4] 0 [5] 80 [6] 0 [7] 80

Read Task: i2s read 2048 bytes
-----------------------------------
[0] 0 [1] 0 [2] 0 [3] 80
[4] 0 [5] 80 [6] 0 [7] 0`
.....
Read Task: i2s read 2048 bytes
-----------------------------------

[0] 0 [1] 0 [2] 0 [3] 80 [4] 0 [5] 80 [6] 0 [7] 0

The same series of values (i.e. 80s and 0s ) were printed regardless I speak over the phone or not. I was expecting different values should be printed to reflect the nature of the different sound recorded. Any idea if this is actually expected? I am still pretty new to I2S peripheral.

misterb0407 commented 1 year ago

A new finding, I comment out the part the change the slot to right so that it used the left channel, now the I2S read buffer seems to be more responsive toward the difference audio that I spoke to the microphone. How can I understand this? snippet:

i2s_example_init_std_simplex() { 
... 
//rx_std_cfg.slot_cfg.slot_mask = I2S_STD_SLOT_RIGHT;
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_chan, &rx_std_cfg));
}
L-KAYA commented 1 year ago

I found the data sheet of that MIC https://www.waveshare.net/w/upload/0/01/MSM261S4030H0R.pdf

Seems it only accepts 24bit data in 32bit slot using PHILIPS format. So the configuration can be updated to:

    i2s_std_config_t rx_std_cfg = {
        .clk_cfg  = I2S_STD_CLK_DEFAULT_CONFIG(16000),
        .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_24BIT, I2S_SLOT_MODE_MONO),
        .gpio_cfg = {
            .mclk = I2S_GPIO_UNUSED,    // some codecs may require mclk signal, this example doesn't need it
            .bclk = EXAMPLE_STD_BCLK_IO2,
            .ws   = EXAMPLE_STD_WS_IO2,
            .dout = EXAMPLE_STD_DOUT_IO2,
            .din  = EXAMPLE_STD_DIN_IO2,
            .invert_flags = {
                .mclk_inv = false,
                .bclk_inv = false,
                .ws_inv   = false,
            },
        },
    };
    rx_std_cfg.slot_cfg.slot_bit_width = I2S_SLOT_BIT_WIDTH_32BIT;
    rx_std_cfg.slot_cfg.slot_mask = I2S_STD_SLOT_LEFT; // The L/R pin of MIC is pulled down, which selects left slot
    ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_chan, &rx_std_cfg));
L-KAYA commented 1 year ago

ESP-EYS schematic link https://www.espressif.com.cn/sites/default/files/documentation/ESP-EYE_V2.1_Reference_Design_0.zip image image

L-KAYA commented 1 year ago

Does #11679 related to this? If no more issues, I'm going to close these two issues. BTW, please take care when you are using LCD or camera at the same time, because they are using I2S0. You can use I2S1 to driver the MIC instead.

misterb0407 commented 1 year ago

Thank you so much @L-KAYA , we can close this issue in this case. Issue #11679 is related to this, but could you give me a sample config that would work in PDM mode in that forum please like you did here? I tried to change according to change here, but still lead to same result.