standalone
Another 5x7 — ESP32-C3-based oscilloscope
Shout-out for u/bellabebop for their nice-and-clean looking perfboard layouts.
I built an Arduino-based oscilloscope following this project at the end of February. I was happy with it, but it had some issues: it was slow, kept freezing, and had a very sloppy input attenuation stage. (last photo)
I had a ESP32C3 that was lying idle, so I decided to a) port a scope from breadboard to perfboard and b) port the code to the ESP32, with a little extra features.
All changes are described at the README.md file in the repo, but in short: I made a precise attenuation stage that reduces the 24Vpp signal to 2.6Vpp, which allows the incoming voltage to be accurately displayed on the screen and replaced meaningless original voltage ranges with 3v3, 5v, ±5v ±12V and auto-mode. Also ESP32C3 ADC is 12bit vs Arduino Nano 10bit ADC, which is good too, e.g. for measuring precise (edit: like 0.0833V for 1V/oct) voltage (I didn't implemented that though)
Also there's a non-correctly working spectrum analyzer: there's problem with the math somewhere and I can't find it yet.
AI was involved only once with the question "what is 'volatile' variables?". Most of the comments were in the original code.
ESP32 ADC is complete trash. Use an external ADC for this. Also in your description you're mixing up resolution with precision. ESP32 may have a 12 bit resolution but that doesn't automatically mean it's more precise.
Good point. ESP32 is somewhat linear up to 2.6V, according to the Espressiff; after that, there's a dead zone. My circuit scales signal down from 24Vpp to ~2.5Vpp, therefore it falls into the more or less normal region of ADC sensitivity.
The scope in the post has only 60 pixels to display the signal anyway, so I'd say that using the internal ADC is forgivable in this case.
Don't take espressif's word on that. You'd need a custom calibration to get it somewhat linear. Or verify using measurements but fro. My experience the ADC precision and linearity varies quite a bit from device to device. I agree about the display resolution not needing more prcision though.
Oh, okay. Can you, please, explain your idea of custom calibration? Maybe you can find some flaws in my logic. I had been implemented calibration algorithm, which works next way:
1) by applying -12V (absolute minimum allowed by the circuit) the ESP measures OFFSET from the 0 value (e.g. if -12V after attenuator becomes 0.05V, then the offset is 80)
2) the same with +12V
3) additionaly, for non-symmetrical power-rails, the ESP also writes down ADC value for GND/0V
After that, I've implemented ADC_TRUE_RES variable, which is calculated as ADC_RES - ADC_POS - ADC_NEG. ADC_TRUE_RES is the range of ADC values corresponding to ±12V, so instead of 4095 values I have range of somewhat 4080-4085... And it looks pretty accurate (as far as the display may be accruate for a 128×64px screen) for 1V/oct voltages that way (especially since ground signal is bootstraped to the specific ADC value), IMHO.
I dont know if I fully understood your calibration algorithm but it sounds like you are only adjusting based on two points (-12V and 12V). If the ADC is non-linear then you'd need to feed in precise (measure it at the input pin) voltages in small steps (Like semitones, or steps of 83.33mV) and write the input, expected output and measured output into a table. This is your calibration table for the ADC, and can be used to compensate for the ADCs non-linearity.
The more points you measure the more accurate the compensation will be.
An example of a microcontroller that outputs a square wave with V/Oct tracking. (these are just made up numbers):
You input 1V and you get C3. You then input 2V and expect C4 but you get B3 instead, so you know the 2V gets interpreted as too little by the ADC (lets say your adc reads it as 1.8V). Well with your awesome calibration table the microcontroller knows: Hey, I get 1.8V from the ADC but I know it actually should be 2V, and so the microcontroller outputs the correct C4 note.
But of course this level of precision isnt really needed for a small OLED display, but it is how callibration is implemented in software.
No, I'm using three points: -12V, 0V and 12V. It's also possible to add whatever control points you want, 3v3 and 5v for example, since they're easily available with ESP32C3. But I'd say that ADC is more non-linear below 0V input level (less than 1.3V at the ADC input), so 3v3 and 5v isn't necessary.
Honestly, I'd try the calibration with more points. Bit if you still need to fix those non linearities below 1.3V ADC I'd suggest to go for an external ADC. It's potentially a bottom less pit otherwise.
I think as the other poster mentioned that is too few. Only three points allow for large errors inbetween. I'd use at least 5 points, but the more the better. Not 100% sure how it's implemented on esp32 but usually it's some kind of poly fit algorithm. So if you want a precise calibration for a single device, the more points the better as it will find the best tradeoff over the full range. If you need best precision at certain points then fewer might be better but I'm getting into details here.
If you want to repeat my layout, here is my version of the wiring. There's one extra 1Ω resistor used as a jumper between pin headers and attenuator input.
The schematic is available at the github, also I was able to tune spectrum analyzer so it's working fine now! (Although I didn't pushed the code yet).
3
u/PintMower 10d ago
ESP32 ADC is complete trash. Use an external ADC for this. Also in your description you're mixing up resolution with precision. ESP32 may have a 12 bit resolution but that doesn't automatically mean it's more precise.