I2S built in DAC - i'm a bit confused...

hugo_98
Posts: 4
Joined: Wed Mar 11, 2020 8:17 am

I2S built in DAC - i'm a bit confused...

Postby hugo_98 » Wed Apr 08, 2020 9:12 pm

Hi everyone,

I started with ESP32 one moth ago and I spent this time working around examples and reading esp idf guide and going through the headers and source files. However I'm lacking of doc and I don't know how to configure my I2S to work properly with built in DAC mode

What have I done ?

I've tried to configure it by myself using guides etc... to play my own files :

sample rate 16kHz, mono, unsigned 8bits and 16kHz, mono, signed 16 bits.

The I2S driver apparently doesn't carry unsigned 8bits data since the DMA only carries 16bits or 32bits data (according to what I read in the source files of i2s_adc_dac example and on this forum). So I tried to output my 16kHz, mono, signed 16bits file. Fails.
To carry on my inquiry, I went back to the original example, and using the nice supplied python tool for file formatting I generated an array, which contains the audio data, converted to the proper format.

Without any other changes in the example, I was able to output the expected sound. Unfortunately, the way It was played was weird. The sound duration is shorter than the original from the example.

So I've many questions related to this short piece of code :

Code: Select all

i2s_config_t i2s_config = {
		.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
		.sample_rate = BEAT_AUDIO_SAMPLE_RATE,
		.bits_per_sample = BEAT_I2S_BITS_PER_SAMPLE,		
		.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,	
		.communication_format = I2S_COMM_FORMAT_PCM,
		.intr_alloc_flags = 0,
		.dma_buf_count = BEAT_I2S_DMA_BUF_COUNT,												
		.dma_buf_len = BEAT_I2S_DMA_BUF_LEN,											
		.use_apll = true
	};
  • bits per sample : is it the total bit length of a sample (ie bits per sample for a single channel * number of channels) or bits per sample regardless of the number of channels ?

    channel format : what if I choose I2S_CHANNEL_FMT_ALL_RIGHT and I give the DMA stereo 16 bits per sample for a single channel (so 32 bits is one sample including all channels) data ? Will only DAC1 output the 8 highest bits of these 32 ?

    communication format : which format for the built in DAC ? PCM for it look great, MSB and PCM_SHORT too. What the determinant factors to choose one ?
I have a last question about the DMA : once its empty, is the DAC value set to 127 to maintain the average audio signal value or simply 0, or even the last value it's been written to ?

Many questions, i'm sorry.. But the documentation let me a bit confused :oops:
hugo

hugo_98
Posts: 4
Joined: Wed Mar 11, 2020 8:17 am

Re: I2S built in DAC - i'm a bit confused...

Postby hugo_98 » Sat Apr 11, 2020 9:18 pm

Hello I've worked around and it's a bit clearer for me. However I can't understand why, once data has been written o DMA, the data stays in its buffer and the dac keeps outputting the whole data... Shouldn't the driver stop transferring data once the dma buffer is empty/has been fully read ? :geek:

here is the i2s config

Code: Select all

i2s_config_t i2s_config = {
        .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
        .sample_rate = 16000,
        .bits_per_sample = 16,
        .communication_format = I2S_COMM_FORMAT_PCM,
        .channel_format =I2S_CHANNEL_FMT_LEFT_RIGHT
        .intr_alloc_flags = 0,
        .dma_buf_count = 2,
        .dma_buf_len = 1024,
        .use_apll = 1,
     };

Code: Select all

 //4. Play an example audio file(file format: 8bit/16khz/single channel)
        printf("Playing file example: \n");
        
        int offset = 0;
        int tot_size = sizeof(audio_table);
        while (offset < tot_size) {
            int play_len = ((tot_size - offset) > (4 * 1024)) ? (4 * 1024) : (tot_size - offset);
            int i2s_wr_len = example_i2s_dac_data_scale(i2s_write_buff, (uint8_t*)(audio_table + offset), play_len);
            i2s_write(EXAMPLE_I2S_NUM, i2s_write_buff, i2s_wr_len, &bytes_written, portMAX_DELAY);
            offset += play_len;
        }
        vTaskDelay(pdMS_TO_TICKS(2000)); // wait the sound to be played entirely
	ESP_LOGV(TAG, "stopped");
        i2s_stop(EXAMPLE_I2S_NUM);
	vTaskDelay(pdMS_TO_TICKS(3000));
        ESP_LOGV(TAG, "started");
        i2s_start(EXAMPLE_I2S_NUM);
	vTaskDelay(pdMS_TO_TICKS(2000));
The code comes from the i2s_adc_dac example. I slightly modified it and the sound I output lasts 200ms . The data is written to DMA in the while loop and then I stop and restart the i2s driver. And surprisingly it starts to output the sound again whilst the dma buffer has been read entirely... What do I miss ? :roll:

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

Re: I2S built in DAC - i'm a bit confused...

Postby ESP_Sprite » Sun Apr 12, 2020 8:47 am

No, the I2S driver works with a pool of DMA buffers the sound is stored in, and will read them all in sequence over and over again. If you continuously write new data into it, you will hear that; if not, the last buffers will repeat.

hugo_98
Posts: 4
Joined: Wed Mar 11, 2020 8:17 am

Re: I2S built in DAC - i'm a bit confused...

Postby hugo_98 » Mon Apr 13, 2020 1:20 pm

Is there any doc around it or should I go through the IDF source files ? I would like to play a short sound repeatedly at a defined interval (its basically a metronome).

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

Re: I2S built in DAC - i'm a bit confused...

Postby ESP_Sprite » Tue Apr 14, 2020 2:58 pm

In that case, the way to go would be to feed the I2S logic the sound sample when needed and 0-samples in between. This is also good for timing, as you will have code that is driven by the I2S clock and not be affected by latencies in your code.

hugo_98
Posts: 4
Joined: Wed Mar 11, 2020 8:17 am

Re: I2S built in DAC - i'm a bit confused...

Postby hugo_98 » Thu Apr 16, 2020 11:37 pm

Thanks for your help ! I'll try to do like this. I've tried to use the .tx_desc_auto_clear = true option and it stops to output the buffers in loop as expected, though, the sound starts and ends with a pulse... is it because of the voltage dropping from 0 to the average value of the sound signal and falling back to 0 when the DMA gets cleared ?

Who is online

Users browsing this forum: Baidu [Spider], Bing [Bot], Google [Bot] and 13 guests