Page 1 of 1

Real-time ADC processing

Posted: Sun Jan 31, 2021 12:39 am
by NeodymiumSunrise
Hello fellow ESP32 enthusiasts,

I am trying to build an interlock device that can quickly react to a change in a time-series signal. The goal is to read the ADC, and compare the reading to a threshold. If the reading surpasses a threshold, a GPIO pin is pulled up. My deadline is on the order of 50 microseconds, and needs to be deterministic. I'm hoping for 30-40 us max.

Right now I'm using i2s to read the ADC, and I have to read 8 samples due to buffer constraints on the i2s (as far as I can tell).

Anyways, doing a basic test with a heaviside step, I can measure the reaction time between the test signal's rise and that of the response signal using an oscilloscope's single-shot mode. I use this ideal test function to measure the effective lower bound for the reaction time: I suspect with the real signal it will likely be not as good. My results for this ideal test are as follows.

Using 150 kHz sampling rate:
N = 20 repeated trials
mean reaction time is 60 us
stdev reaction time is 16 us
median reaction time is 62 us

The next thing I did is crank up the sampling rate to 300 kHz (which I thought wouldn't work!). Then I measured
N = 20 repeated trials
mean reaction time is 40 us
stdev reaction time is 11 us
median reaction time is 42 us

I then pinned the task to APP CPU with maximum priority. Using this and 300 kHz again, I measured
N = 20 repeated trials
mean reaction time is 37 us
stdev reaction time is 12 us
median reaction time is 39 us

I also repeated this test using a critical section/mutex around the data processing/GPIO reaction (but not i2s_read), and that made no difference.

What concerns me is the massive variance. My question is: what is the best way to reduce it?

I can tell using vTaskList that my task is sometimes being blocked, sometimes by IDLE and sometimes by IPC, DPORT, etc. I don't know much about those tasks, but I know for sure IDLE shouldn't be blocking my top-priority task. I tried disabling FreeRTOS on this core, but I think this makes it unable to call the i2s drivers (i2s_read). When I ran it the kernel panic'd out.

I've also heard on this forum that the FreeRTOS ticks can add a 5us latency. Is there a way to disable these ticks whilst being able to run the i2s read driver?

Is there a better approach than i2s_read? I've seen some wonderful suggestions in similar posts, such as ditching FreeRTOS on APP CPU. But I fear this will breaks the i2s driver.

Final note: if I trust the sampling rate is 300kHz, then the fastest I should be able to read the minimum 8 samples is less than 27 us. But in some of the above test cases, I can see with my own eyes on the scope the end-to-end read + react time is less than this. (in the above trials, I observed 17 us, 20 us, and 22 us!) I witnessed the same thing when using the "reliable" 150 kHz sampling rate too. What's going on with that?

As far as I can tell, the variance problem mostly stems from ADC, which I don't know much about in i2s mode. I did an interrupt latency test yesterday and timed 1.4 us for pulling up the GPIO and this was precise; it read this for every trial I ran.

Thank you in advance, and I look forward to any impending discussion!

--NS