espressif / esp-idf

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

I2S on ESP32-S3 setup with TDM PCM 16-bit single port generates 0s with every second sample (IDFGH-9244) #10630

Open BitSalat opened 1 year ago

BitSalat commented 1 year ago

Answers checklist.

IDF version.

v5.1-dev-2066-g7869f4e151

Operating System used.

Windows

How did you build your project?

Eclipse IDE

If you are using Windows, please specify command line type.

None

Development Kit.

Custom Board

Power Supply used.

USB

What is the expected behavior?

Our board uses a MAX9860 Codec with 16bit/S, 16kS/s and Mono output on I2S. Codec is programmed to short WS (LRCLK, 16kHz), 1MHz BCLK with only slot 0 generated (16bits) Writing I2S to a WAV file expectation is to see one single channel (mono) with 16bit samples for each WS clock

What is the actual behavior?

Instead, we see a WAV file with one single channel however 2 samples per Sample clock with one sample always being 0 and second sample valid.

WAV file: image

  1. sample: 0x0000
  2. sample: 0x0000
  3. sample: 0x0723
  4. sample: 0xFFFF = -1
  5. sample: 0x06D4
  6. sample: 0x0000 etc.

Audacity: Audacity_I2SIssue_01

So we always have one 0-Sample, then valid sample, again 0-sample etc.

Error does not occur when writing WAV file but wrong data are already generated by the I2S driver. Here are some data from the sample buffer, every second sample is 0 or -1

Name: SA08G Type: SDHC/SDXC Speed: 20.00 MHz (limit: 20.00 MHz) Size: 7580MB CSD: ver=2, sector_size=512, capacity=15523840 read_bl_len=9 SSR: bus_width=4 I (606) Audio: Opening file [0] 0 [1] 0 [2] 16315 [3]-1 ... [0] 1704 [1] 0 [2] 2236 [3]0 ... [0] 1552 [1] 0 [2] 3012 [3]0 ... [0] -3929 [1] -1 [2] -5265 [3]-1 ... [0] -3192 [1] 0 [2] -2917 [3]-1 ... ...

Steps to reproduce.

Setup I2S Port on ESP32-S3 fed by an Codec with mono output.

void audio_sense_microphone_setup(void) { i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_SLAVE); chan_cfg.auto_clear = true; // Auto clear the legacy data in the DMA buffer ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, NULL, &rx_handle)); i2s_tdm_config_t std_cfg = { .clk_cfg = I2S_TDM_CLK_DEFAULT_CONFIG(16000), .slot_cfg = I2S_TDM_PHILIP_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO, I2S_TDM_SLOT0), .gpio_cfg = { .mclk = GPIO_NUM_38, .bclk = GPIO_NUM_39, .ws = GPIO_NUM_40, // .dout = GPIO_NUM_42, .dout = -1, .din = GPIO_NUM_41, .invert_flags = { .mclk_inv = false, .bclk_inv = false, .ws_inv = false, }, }, };

Behaviour does not change when using I2S_TDM_PCM_SHORT_SLOT_DEFAULT_CONFIG instead of I2S_TDM_PHILIP_SLOT_DEFAULT_CONFIG

Debug Logs.

No response

More Information.

No response

L-KAYA commented 1 year ago

May I ask if you tried STD mode? Seems STD is more appropriate for your case. And for the slot sequence of STD mode, you can refer to std-rx-mode in programming guide. You can choose mono and left slot mask in your case. I'll look into the issue in TDM mode, thanks!

BitSalat commented 1 year ago

Yes, we also switched to STD Mode, Mono as well as Stereo (as the MAX9860 codec allows to generate data on L/R slots) With TDM Mono we see the same effect as described above, with TDM Stereo we see L/R in audacity but no data on R instead always 2 L/R samples on L in sequence. We never see valid data on 2nd slot (Slot#1 or R)

L-KAYA commented 1 year ago

One more question, are the i2s receiving buffer and the sd writing buffer a same buffer? If not, how you copy the data to the writing buffer? I just want to make sure it's not a simple buffer type error, thanks!

Error does not occur when writing WAV file but wrong data are already generated by the I2S driver. Here are some data from the sample buffer, every second sample is 0 or -1

Are the data incorrect in the receiving buffer already?

BitSalat commented 1 year ago

We do not copy, it's the same buffer:

    while (flash_wr_size < flash_rec_time) {
        // Read the RAW samples from the microphone
        i2s_channel_read(rx_handle,i2s_readraw_buff, SAMPLE_SIZE, &bytes_read, 1000);
        // scale the data (otherwise the sound is too quiet)
        //for (int x = 0; x < SAMPLE_SIZE/2; x++) {
        //i2s_readraw_buff[x] = (i2s_readraw_buff[x]) * 8;
       // }
        // Write the samples to the WAV file
        fwrite(i2s_readraw_buff, 1, bytes_read, f);
        flash_wr_size += bytes_read;
    }

And yes the data are not correct already in the receiving buffer

BitSalat commented 1 year ago

Dear L-Kaya, any news on this? We have tried several setups for the I2S channel but always see invalid samples either on the second slot in stereo or as every second sample in mono as shown above. Our guess is that I2S data acquisition is ok but DMA access goes wrong for any reason. We are considering implementing a routine throwing away every second sample but that's not our preferred solution.

BitSalat commented 1 year ago

Just for those running in similar issues - we have now implemented a workaround function which only writes every second sample (onlay valid sample) to file:

    // Start recording
    while (flash_wr_size < flash_rec_time) {
        // Read the RAW samples from the microphone
        i2s_channel_read(rx_handle,i2s_readraw_buff, SAMPLE_SIZE, &bytes_read, 1000);
        //
        printf("[0] %d [1] %d [2] %d [3] %d [4] %d ...\n", i2s_readraw_buff[0], i2s_readraw_buff[1], i2s_readraw_buff[2], 
        i2s_readraw_buff[3], i2s_readraw_buff[4]);
        //
        // Write the samples to the WAV file
        int i = 0;
        int i_workaround = 0;
        for (i=0; i <= bytes_read; i+=2) {
            buf_workaround[i_workaround]=i2s_readraw_buff[i];
            i_workaround++;
        }
        fwrite(buf_workaround, 1, bytes_read/2, f);
        flash_wr_size += bytes_read/2;
    }

    ESP_LOGI(TAG, "Recording done!");
    fclose(f);
    ESP_LOGI(TAG, "File written on SDCard");

Now we get exactly the file we had expected:

image

Jabooby commented 1 year ago

I have the same issue but with 24bit recording. I am using a pcm1804. Any updates on a solution?

BitSalat commented 1 year ago

@Jabooby - no update so far, we are still on our workaraound solution but honestly have to say that we did not check with latest idf master.

L-KAYA commented 1 year ago

I wrote an example for TDM RX mono mode, and found there is no ws signal while only one slot is enabled, I guess the codec can still work by sending 16 bits every 32 bits bclk, so the slot_bit_width might actually be 32 while data_bit_width is still 16.

Still trying to figure out a solution, will update here if there is any fix

matti122 commented 10 months ago

@L-KAYA The bug is still there in latest IDF 5.1. Will there be any solution available in the future?