Faster ADC Reading
Faster ADC Reading
I'm using a ESP32 with ESP-IDF and the fastest ADC reading that I can get is 17.20 us. That means 58KHz.
It doesn't matter the sample size, the resolution, the clock subdivision, I can't get faster reading.
I've read on the Technical Reference Manual that the ADC can be used as a DIG SAR Mode which is meant to be High performance "the clock is much faster, therefore, the sample rate is highly increased" but I just can't make it work.
http://espressif.com/sites/default/file ... ual_en.pdf
[ page 413: 22.3.5 DIG SAR ADC Controllers ]
There is no need for high precision or 12 bits. I just need speed in the sample rate.
Does anyone knows how do I do this?
Thank you guys in advance!
It doesn't matter the sample size, the resolution, the clock subdivision, I can't get faster reading.
I've read on the Technical Reference Manual that the ADC can be used as a DIG SAR Mode which is meant to be High performance "the clock is much faster, therefore, the sample rate is highly increased" but I just can't make it work.
http://espressif.com/sites/default/file ... ual_en.pdf
[ page 413: 22.3.5 DIG SAR ADC Controllers ]
There is no need for high precision or 12 bits. I just need speed in the sample rate.
Does anyone knows how do I do this?
Thank you guys in advance!
Re: Faster ADC Reading
One of the features still on our roadmap is to allow the I2S peripheral to read from a built-in ADC (in the same way you can already output to the built-in DAC). This is probably going to be the recommended approach for high frequency ADC input.
Unfortunately I don't have an ETA for you, sorry.
Unfortunately I don't have an ETA for you, sorry.
-
- Posts: 4
- Joined: Fri Sep 28, 2018 6:55 am
Re: Faster ADC Reading
Any news on the ADC DIG SAR Mode?
In my experiments I could sample the ADC faster (at about 104kHz for ADC1 and 98kHz for ADC2) using the ULP rather than main core(s), with this loop:
(using jumpr with r0 is faster than using stage_inc and jumps)
Then in main you need to realign the data, since it is 16bit data aligned on 32bit:
To sample from main, I used a task with IRAM_ATTR and the code below. With the CPU @ 80MHz (for other reasons..) and normal debugging it then achieves about 18.5 kHz with ADC1 and 21.0 kHz with ADC2 (both ADCs at 12bit).
Disabling the assertion/debug level and set the compiler optimizations it improves to 20.4 kHz on ADC1 and 23.3 kHz on ADC2. (sdkconfig: CONFIG_OPTIMIZATION_LEVEL_RELEASE=y and CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED=y ).
I have checked the esp-idf code for adc2_get_raw and adc1_get_raw. They both seem to unnecessarily set a lot of options each time again for a single ADC sample, however when I tried to remove some of these (just a quick try), I didn't get valid ADC samples anymore (0x0000).
In my experiments I could sample the ADC faster (at about 104kHz for ADC1 and 98kHz for ADC2) using the ULP rather than main core(s), with this loop:
Code: Select all
// ...
move r0, adc_data
measure:
adc r2, 0, adc_channel + 1
st r2,r0,0
add r0, r0, 1
jumpr measure, adc_data+ADC_WORDS,lt
Then in main you need to realign the data, since it is 16bit data aligned on 32bit:
Code: Select all
// ...
uint32_t* p_ulp_adc_data = &ulp_adc_data;
uint16_t adc_data[ADC_WORDS];
for (int i=0;i<ADC_WORDS;i++)
{
uint16_t w = (*p_ulp_adc_data) & 0xffff;
p_ulp_adc_data++;
adc_data[i] = w;
}
Disabling the assertion/debug level and set the compiler optimizations it improves to 20.4 kHz on ADC1 and 23.3 kHz on ADC2. (sdkconfig: CONFIG_OPTIMIZATION_LEVEL_RELEASE=y and CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED=y ).
Code: Select all
void IRAM_ATTR sampleAdcTask(void * pvParameters)
{
for (int i=0;i<ADC_WORDS;i++)
{
#ifdef USE_ADC1
adc_data[i] = adc1_get_raw(ADC_CHAN_SEL); // for ADC1
#else // ADC2
adc2_get_raw(ADC2_CHAN_SEL, ADC_WIDTH_12Bit, &adc_data[i]); // for ADC2
#endif
}
}
-
- Posts: 9764
- Joined: Thu Nov 26, 2015 4:08 am
Re: Faster ADC Reading
FWIW, the I2S driver supports ADC input now; there's an example in the ESP-IDF master tree. I've used it for up to 320Ksamps/second, and although I have no idea wrt the analog specs at that rate, it seemed to behave well.
-
- Posts: 4
- Joined: Fri Sep 28, 2018 6:55 am
Re: Faster ADC Reading
Okay, so you probably mean examples/peripherals/i2s_adc_dac ? Then main/app_main.c , function example_i2s_adc_dac ?
Is that right? I can't seem to get it to work in my isolated case, maybe you can clarify where I should look?
For my understanding, the following code should sample as many samples as half of i2s_read_len (because .bits_per_sample is set to 16):
But somehow it takes way too short to execute. I also don't understand why you set it like (16 * 1024) for the i2s_read_len. It definitely can't mean bits, since calloc even allocates per byte due to sizeof(char). With i2s_read_len=1024 and then subsequently calloc(1024, sizeof(uint16_t)); it would make sense to me.
If it is just bytes, it would mean the ADC is set to 8-bit mode, but EXAMPLE_I2S_SAMPLE_BITS is set to 16. What does that mean?
Can you clarify?
In the end, it is also completely unclear to me in which data format the i2s_read_buff would get filled, it seems to be only 8bit samples, which doesn't make sense if the ADC is set to 12bit (aligned to 16?). How is it supposed to work / how is the data aligned in the i2s_read_buff?
Thanks for clarifying. Maybe you can just write the few lines of code needed or guide me to another example...
Is that right? I can't seem to get it to work in my isolated case, maybe you can clarify where I should look?
For my understanding, the following code should sample as many samples as half of i2s_read_len (because .bits_per_sample is set to 16):
Code: Select all
char* i2s_read_buff = (char*) calloc(i2s_read_len, sizeof(char));
i2s_adc_enable(EXAMPLE_I2S_NUM);
i2s_read(EXAMPLE_I2S_NUM, (void*) i2s_read_buff, i2s_read_len, &bytes_read, portMAX_DELAY);
i2s_adc_disable(EXAMPLE_I2S_NUM);
If it is just bytes, it would mean the ADC is set to 8-bit mode, but EXAMPLE_I2S_SAMPLE_BITS is set to 16. What does that mean?
Can you clarify?
In the end, it is also completely unclear to me in which data format the i2s_read_buff would get filled, it seems to be only 8bit samples, which doesn't make sense if the ADC is set to 12bit (aligned to 16?). How is it supposed to work / how is the data aligned in the i2s_read_buff?
Thanks for clarifying. Maybe you can just write the few lines of code needed or guide me to another example...
-
- Posts: 9764
- Joined: Thu Nov 26, 2015 4:08 am
Re: Faster ADC Reading
I'm not that intimately familiar with the I2S driver, but this may be because the setup of the I2S driver already starts it up as well; the i2s_adc_enable call re-starts it, but there may still be buffers in the queue that your read call reads.bluesceada wrote: For my understanding, the following code should sample as many samples as half of i2s_read_len (because .bits_per_sample is set to 16):
<snip>
But somehow it takes way too short to execute.
My guess is that the dev just wanted a buffer of 16K, thinking more about memory usage than sample size, and used 16*1024 as a more readable way to write it than 16384.I also don't understand why you set it like (16 * 1024) for the i2s_read_len. It definitely can't mean bits, since calloc even allocates per byte due to sizeof(char). With i2s_read_len=1024 and then subsequently calloc(1024, sizeof(uint16_t)); it would make sense to me.
If it is just bytes, it would mean the ADC is set to 8-bit mode, but EXAMPLE_I2S_SAMPLE_BITS is set to 16. What does that mean?
The buffer will be filled with 16-bit samples (consisting of the 12 ADC bits with the top 4 bits filled with zeroes). Note that the pairs of 16-bit words are flipped around in the buffer, so if I take your example lines, you would do something like this to print out the actual ADC values:In the end, it is also completely unclear to me in which data format the i2s_read_buff would get filled, it seems to be only 8bit samples, which doesn't make sense if the ADC is set to 12bit (aligned to 16?). How is it supposed to work / how is the data aligned in the i2s_read_buff?
Code: Select all
uint16_t *i2s_read_samples=(uint16_t*)i2s_read_buff;
for (int i=0; i<bytes_read/sizeof(uint16_t); i++) printf(i2s_read_samples[i^1]);
-
- Posts: 4
- Joined: Fri Sep 28, 2018 6:55 am
Re: Faster ADC Reading
Thanks for some of the clarifications, but other things are still open, maybe someone else can help who knows more of the details?
Like, I would like to have something like a "start_adc_sampling();" call and "wait_for_adc_to_fill_buffer();". I guess there should be an interrupt that I can use as a buffer-full signal? And how can I start it? To my understanding it essentially starts already when it is setup with i2s_driver_install(..) ? Or at least after i2s_adc_enable(..)? Then I can control it with i2s_start(..) and i2s_stop(..)? However, after the first i2s_stop, it locks up for me...
Thanks if anyone can help further clarify these points!
Yeah I thought something similar, but being sure on it would really help. So, to rephrase the question: How can I synchronize at which point in time the ADC data starts filling up a buffer from buffer index 0?ESP_Sprite wrote:I'm not that intimately familiar with the I2S driver, but this may be because the setup of the I2S driver already starts it up as well; the i2s_adc_enable call re-starts it, but there may still be buffers in the queue that your read call reads.bluesceada wrote: For my understanding, the following code should sample as many samples as half of i2s_read_len (because .bits_per_sample is set to 16):
<snip>
But somehow it takes way too short to execute.
Like, I would like to have something like a "start_adc_sampling();" call and "wait_for_adc_to_fill_buffer();". I guess there should be an interrupt that I can use as a buffer-full signal? And how can I start it? To my understanding it essentially starts already when it is setup with i2s_driver_install(..) ? Or at least after i2s_adc_enable(..)? Then I can control it with i2s_start(..) and i2s_stop(..)? However, after the first i2s_stop, it locks up for me...
That was my guess, too. So he allocates 16K, but actually just uses the first 2K bytes (1K samples)? Is that what you mean? Again, maybe someone else can clarify.My guess is that the dev just wanted a buffer of 16K, thinking more about memory usage than sample size, and used 16*1024 as a more readable way to write it than 16384.
Thanks if anyone can help further clarify these points!
-
- Posts: 4
- Joined: Fri Sep 28, 2018 6:55 am
Re: Faster ADC Reading
*Bump*
Is there still no progress on this? So a simple application example would be: I want to press a button (let's say a variable is set from 0 to 1) and from that on it starts recording audio with the ADC. Then it should either stop after the buffer is full or the button is pressed again, whatever comes first.
Is there still no progress on this? So a simple application example would be: I want to press a button (let's say a variable is set from 0 to 1) and from that on it starts recording audio with the ADC. Then it should either stop after the buffer is full or the button is pressed again, whatever comes first.
-
- Posts: 9764
- Joined: Thu Nov 26, 2015 4:08 am
Re: Faster ADC Reading
There's nothing stopping you from doing that: set up the I2C driver to use the ADC with a modest DMA buffer size (4K or so), then have a larger buffer somewhere in your app. Then, in your code, pull data from the I2S driver into the larger buffer until it's full or the button is pressed.
-
- Posts: 118
- Joined: Tue Jun 26, 2018 3:09 am
Re: Faster ADC Reading
Hi, megomes
Please try the attachment
Please try the attachment
- Attachments
-
- i2s_adc_scale.tar.gz
- (22.12 KiB) Downloaded 3008 times
wookooho
Who is online
Users browsing this forum: No registered users and 60 guests