Open marcusletric opened 1 year ago
Could be this happening because of samples are lost while I copy them to the memory? Seems like sampling rate is much more precise when I2S is used with extra buffers. If that's the case, probably this issue can be closed...
For what it's worth, I think that I might be experiencing the same issue, also with an ESP32. Powered via USB, project built and flashed on Linux from the command line. IDF 5.0.1.
I use a DMA buffer size (conv_frame_size
) of 1024 * sizeof (adc_digi_output_data_t)
. My ring buffer (max_store_buf_size
) is three times that size. I set the sampling rate to 116000
Hz. I use two channels, 6 and 7, on the first ADC. I then do adc_continuous_read()
in a tight loop to read conv_frame_size
-many bytes in each loop iteration.
I use dsp_get_cpu_cycle_count()
to determine how long one loop iteration takes. I get ~94 loop iterations per second. However, I would have expected 116000 / 1024 = ~113 loop iterations per second. (It doesn't matter whether I clock the CPU with 160 MHz or with 240 MHz.)
And ~94 * ~1.20 = ~113. Which seems to match what @marcusletric is seeing.
Any additional data I could collect to help debug this?
The math in adc_hal_digi_sample_freq_config()
seems to be correct. I added some debug logging real quick:
I (320) XXX: freq 116000
I (330) XXX: bclk_div 16, bclk 232000, mclk 3712000, mclk_div 43
And 43 * 3712000 = 159616000, which is pretty close to 160 MHz.
Further down in the HAL in i2s_ll_tx_set_mclk()
I also seem to get the correct fraction:
I (330) XXX: mclk_div 43, numerator 3, denominator 29
And (43 + 3 / 29) * 3712000 = 160000000.
@uncle-betty in my project I have abandoned this approach in favour of I2S read which seems to be sampling at a correct rate.
I also need to mention that this is true for
I used the following I2S config
i2s_config_t adcI2SConfig = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S_LSB,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 20,
.dma_buf_len = SAMPLE_STEP,
.use_apll = true, // Probably this is the most consistent sampling clock
.tx_desc_auto_clear = false,
.fixed_mclk = 0
};
With this I needed to make sure that my buffer processing is faster than the buffer fills otherwise I missed some of the data.
Oh, great! Thank you for sharing your workaround, @marcusletric. I appreciate it and I'll give it a try.
I can confirm this issue is happening on ESP32 with v5.2.1 IDF.
Answers checklist.
IDF version.
v5.0
Operating System used.
Windows
How did you build your project?
VS Code IDE
If you are using Windows, please specify command line type.
CMD
Development Kit.
ESP32 -WROOM-32 - Custom board
Power Supply used.
USB
What is the expected behavior?
Using the continuous ADC read example from https://github.com/espressif/esp-idf/blob/master/examples/peripherals/adc/continuous_read/main/continuous_read_main.c#L65
I expected that the sample rate would be 20000Hz
What is the actual behavior?
The sample rate is about 0.8 times less than the configured number in
adc_continuous_config_t dig_cfg
Steps to reproduce.
Preparations: Audio to sample: 60BPM metronome https://www.youtube.com/watch?v=ymJIXzvDvj4 OR Using a DAW make a song in 4/4 on 60BPM that has only tone pulses on quarter beats
This would give a sound that has a tone on every second
Modify the example https://github.com/espressif/esp-idf/blob/master/examples/peripherals/adc/continuous_read/main/continuous_read_main.c#L65 so that the main function stores 60000 samples in heap and it logs the values only after sampling (I have provided the modified sample in the more info section)
Sample the wav above (I used my mobile phone as a player and the balanced jack as output, plus raised the level with a voltage divider before the ADC pin) and write the output to a file
idf_monitor.py -p COM4 -b 115200 >> dump.csv
Remove every line except the ADC value logs
Using a python file convert the logs into wav and open it in a wav editor (Audacity) (I have provided the py file in the more info section)
Cut off the first silence period and check that the beginning of the notes are less than 1 second
Debug Logs.
No response
More Information.
Modified sample Please note the multiplication in
adc_continuous_config_t dig_cfg
to correct for the issue I describe herePython to convert output logs to wav file