While reading about analog-digital conversion (ADC) on the ESP32, I found many references and examples using I2S to sample a GPIO pin at a configurable rate. Most notably, github user zekageri had posted several questions in the esp32.com forums about glitches he was seeing in his streaming ADC data, and he shared this video of his ESP32-served web interface plotting data samples at 44.1kHz. What is this magic? WebSockets! A relatively new and highly streamlined TCP-based protocol, facilitating fast and efficient data transfer. Zekageri posted an early version of his code on github, but I couldn't get it to work out of the box. I basically started from scratch, using some of the general concepts from his project, and evolved it considerably.
Fast streaming data visualization
This fast-streaming data visualization will be key to tuning my demodulation code which I will start testing imminently. This data vis approach will also be a great tool to add to the tool box for fine tuning during operation later, i.g. to make sure incoming and outgoing audio streams are properly scaled and biased and not clipping.
I threw the ESP32 on a breadboard and wired up a bias circuit by coupling an audio cable to a potentiometer as a voltage divider, pulling the signal up to about midway between ground and the ESP32's 3.3V regulated pin so that the ADC can ingest the full signal without clipping the lower half. Here's the basic audio-in bias circuit:
I added that 8 Ohm speaker on the right channel for fun. I might incorporate a speaker into the final design later, with a proper amplifier.
Next, I plugged the audio cable into the speaker jack on my laptop and used this handy online tone generator to send audio signal to the ESP32. Before plugging in the ESP32, I tested the signal level with my oscilloscope and verified it was within the 0-3.3V measurement range of the ESP32 ADC.
Here's the data visualization code:
Basically, the ESP32 buffers many samples in DMA, via I2S, and the main loop periodically pulls that buffer and sends it over WebSocket as binary data. The ESP32 serves a webpage with a CanvasJS plotting method to dynamically plot incoming data.
It took a lot of work to understand an inversion issue and that the ESP32 puts random (okay maybe not random; I'm not sure what it is) ones and zeroes in the upper 4 bits of each 16 bit sample. The ADC measures in 12 bits, and I assumed the ESP32 would pack those 12-bit measurements into 16-bit values with zeroes in the upper bits, but I was wrong and that took a few frustrating hours to figure out. Anyways, that's fixed, and now I know how to sample audio efficiently.
Check out the demo:
This should be useful for so many projects..
I hope you found this useful. If so, please leave a comment! Thanks, 73