ESP32 analog read resistor ladder isn't "stable" - Page 1
Forum section: electronics / general

author: bitman
author_rank: Unknown
timestamp: November 16, 2021, 03:19:01 pm
content: I have an extremely simple resistor ladder button PCB (see attachment for schematic)My ESP32 is used to drive quite a few things outside of this board, so having a single pin to sense 5 keys seemed like a good idea at the time. As long as I can tell each key from each-other it does what I need (and I do not need to sense multiple concurrent key-presses but this seems to allow me to do that).It works as is - pin 2 of this schematic is tied to GPIO33 on the ESP32, and analogRead returns values based on what is pressed. HOWEVER, I see rather large changes in values - I have a buffer of +/- 8 int values to ensure I detect the right key because the values coming back varies that much. That doesn't make sense and I'm posting here to see if I'm missing something obvious (just a hobbyist).My settings for the pin are as follows:analogReadResolution(10); // 0-1023analogSetAttenuation(ADC_11db);adcAttachPin(_sensePin);Outside of this it simply loops every 150ms to read the pin. The value is then encoded into the action associated with the key and this action is used by the rest of the code. All of that works - it's just that the analog values varies a lot more than I expected. My simple question is, if that's to be expected?

author: SiliconWizard
author_rank: Super Contributor
timestamp: November 16, 2021, 04:54:53 pm
content: You mean variations for a given button press? How much variation?Regarding the sampling: you say that there is a read every 150 ms. But that you buffer 8 samples if I got you right. Does that mean that you read 8 samples from the ADC every 150 ms? If so, what's the sample rate? (Period between each of the 8 samples?)

author: woofy
author_rank: Frequent Contributor
timestamp: November 16, 2021, 05:28:27 pm
content: The ESP32 ADC is not the most stable one on the planet, and you're not really giving yourself a fighting chance. The difference between SW1 and SW2 is only 0.1vI would go for a bigger difference, 0.6v or so.Forget the ladder, just take each switch from the sense line to ground via a resistor. Picking standard values, use 22k to 3v3.SW1 directly to 0v.SW2 via a 5k6SW3 15kSW4 33kSW5 100kThat will give you a decent gap to play with.

author: bitman
author_rank: Unknown
timestamp: November 16, 2021, 05:33:53 pm
content: Quote from: SiliconWizard on November 16, 2021, 04:54:53 pmHi - and thanks for the reply. I guess I wasn't as precise as I thought I was. Sorry about that.I read ONE time every 150ms. Looking at the returned value holding down a single button I get varying numbers - not just +/- 1 or 2. In other words, I have a sliding window I use to see if a number matches a given button, because I cannot tell which button it is if I just look for one particular value. When I first drafted the code, I expected a window of 2-4 - ie. +/- 2 at the worst. But I'm not seeing that.This is part of the code that defines the medium value mapped to each key press I'm interested in:KeyRange keyrange[] = {{ 1023, NO_KEY },{ 292, KEY_UP },{ 183 , KEY_UP | KEY_LEFT },{ 208 , KEY_UP | KEY_RIGHT },{ 255, KEY_UP | KEY_SEL },{ 554, KEY_DOWN },{ 304, KEY_DOWN | KEY_LEFT },{ 408, KEY_DOWN | KEY_RIGHT },{ 535, KEY_DOWN | KEY_SEL },{ 357, KEY_LEFT },{ 326, KEY_LEFT | KEY_SEL },{ 452, KEY_RIGHT },{ 428, KEY_RIGHT | KEY_SEL },{ 676, KEY_SEL }};The "mean" values are based on me monitoring/collecting debug data. So for instance if I push "key down" I get values around 554 - some a bit higher, some a bit lower.I get that between boards I would see variations - after all the resistors vary in precision - but I don't understand why a single PCB gives me different results - here's if a dump where each cycle tells me the value measured and the result of mapping it to a button:554Key Pressed: K:DOWN556Key Pressed: K:DOWN555Key Pressed: K:DOWN554Key Pressed: K:DOWN553Key Pressed: K:DOWN559Key Pressed: K:DOWN554Key Pressed: K:DOWN555Key Pressed: K:DOWN555Key Pressed: K:DOWN556Key Pressed: K:DOWN556Key Pressed: K:DOWN555Key Pressed: K:DOWN555Key Pressed: K:DOWN555Key Pressed: K:DOWN556Key Pressed: K:DOWN552Key Pressed: K:DOWN556Key Pressed: K:DOWN554Key Pressed: K:DOWN544557Key Pressed: K:DOWN558Key Pressed: K:DOWN556Key Pressed: K:DOWN558Key Pressed: K:DOWN555Key Pressed: K:DOWN564555Key Pressed: K:DOWN555Key Pressed: K:DOWN556Key Pressed: K:DOWN555Key Pressed: K:DOWN555Key Pressed: K:DOWN555Key Pressed: K:DOWN557Key Pressed: K:DOWN555Key Pressed: K:DOWN556Key Pressed: K:DOWN556Key Pressed: K:DOWN556Key Pressed: K:DOWN554Key Pressed: K:DOWN554Key Pressed: K:DOWN555Key Pressed: K:DOWN555Key Pressed: K:DOWN553Key Pressed: K:DOWN554Key Pressed: K:DOWN553Key Pressed: K:DOWN554Key Pressed: K:DOWNNotice how the value "jumps" - this is just me holding down a single button - no other actions. Notice the low value of 544 - it's actually OUTSIDE the 8 point buffer and hence doesn't register. And later there's a 564 which is outside on the other side.What I'm trying to understand is why I'm seeing such a large fluctuation. I'm somehow not convinced this is the ESP32 but something I'm doing, but I have no clue what that would be.

author: SiliconWizard
author_rank: Super Contributor
timestamp: November 16, 2021, 05:41:33 pm
content: Thanks for giving more details, and... sorry, but after saying your results, it's hard not to answer: "you must be kidding us".You have a variation of only a few LSBs, which is perfectly normal here. You'd never get better with this hardware and the ADC of an ESP32, unless taking additional measures both in hardware (adding some low-pass filtering for instance, buffering the output of the ladder...) and software (doing some averaging).Since there is absolutely no hardware filtering in your design, the result is absolutely not surprising even if the ADC was very good (which it's not.) Even just mechanical bouncing when pressing the buttons will get you variations.But as it is, it's absolutely not even a problem. THe only thing you need here is to be able to discriminate all button presses. Not get exact values! Never compare your samples to a fixed value. Compare them to some reasonable interval. You probably have done that already judging from your output, but just widen your intervals significantly. The only thing that matters again is discrimination.Now if there's still too much variation for proper discrimination - which I'm not convinced of - just change the ladder values as woofy suggested. But I would still add some capacitor to filter the output of the ladder.

author: bitman
author_rank: Unknown
timestamp: November 16, 2021, 07:49:27 pm
content: Quote from: SiliconWizard on November 16, 2021, 05:41:33 pmThanks - I guess what I need to learn here is WHY. You're quite right, this is as basic and "not complex" circuit as they get - I don't need precision but I also didn't expect a fluctuation that high. Granted, I have nothing to hold that expectation to other than other simple ADC designs I've done in the past. I realize that my hand on the PCB can impact the voltage - I tried to get around that with a large ground plane - but I guess that was for not.Do you have a resource where I can learn what's really going on? Why I'm seeing "large" fluctuations? In this case, as long as the windows I'm looking at doesn't overlap, I get exactly what I need, but for future projects I would definitely like to understand what's going on.Thanks again for the reply.

author: Benta
author_rank: Super Contributor
timestamp: November 16, 2021, 09:02:19 pm
content: I wonder about your resistor choices. Search for R-2R network instead.And what happens if several keys are pressed at once?

author: Lindley
author_rank: Regular Contributor
timestamp: November 16, 2021, 09:03:49 pm
content: You are limited in what you can achieve with the inbuilt ADC of any such typical micro controller, we recorded similar errors with Pics and Atmel chips, though from general web comment seems the ESPs are a little worse.As said you will always get some variation on the lowest one or two bits of the ADC result, averaging over x16 can reduce that , more so if you remove the two highest and two lowest readings before averaging.Increasing your window size to three or four times larger , though appearing poor, should not cause a problem.Adding a 100nf across the adc pin and 0v should help a little and you can try adding capacitors to the 3v3 rail that feeds the ladder, some will even add a totally separate voltage supply / using a voltage reference/diode circuit to ensure minimal errors.How long are the wires from the ESP to the switches and around the switches, could they be picking up lots of noise if unshielded ?What about your resistors, are you using 1% metal oxide, and the switches, many are made from conductive materials which never seem to give totally consistent results, try measuring them with an ohm meter and see if you get good results ?

author: bitman
author_rank: Unknown
timestamp: November 16, 2021, 09:56:50 pm
content: Quote from: Lindley on November 16, 2021, 09:03:49 pmSo I don't expect a lot of precision from something that costs $5 including shipping from across the whole world. I'm fine with something not being workable for precision stuff - that said, I expected the values just to be off and not show the true voltage vs. jumping as much as it does. Still learning though, so I'm taking this as a learning moment.Quote from: Lindley on November 16, 2021, 09:03:49 pmThis is a keypad for a small game - given the ESP states that you need to wait "a bit" between ADC reads I feel 150ms is long enough. I tried at 50ms early on that that didn't really produce results at all. It was all over the place. I've been adjusting my window size to allow 99% of the use to work even though I would still love to find a way to lower the fluctuations a bit.Quote from: Lindley on November 16, 2021, 09:03:49 pmWhen the other poster mentioned an RC filter I thought about that. Not sure how it helps since the line is pulled high when no buttons are pushed. But I did get rid of a lot of the 1K pulldown resistors and only use one shared one now. I'm powering this through a 5V/2A power supply; however this keypad gets it 3.3V power through the regular on the ESP32 board; I didn't think there was enough of a draw to make that something I had to think about. Perhaps I was wrong about that.Quote from: Lindley on November 16, 2021, 09:03:49 pmSo there's a 20 cm cable right now between the board the ESP32 is on and the keypad. I may get that down to 10cm but that would be the extreme. However, from a noise perspective there's plenty. There's a large 64x32 RGB LED display with refresh rates in the 20-40 FPS 1cm from the ESP32 board. Designing for noise where it would make a difference certainly would be needed. But to repeat myself a bit, I'm not looking for perfection - I just want to ensure that when SW1 is pushed, that I can reliably react to that in code. Bonus points if I can push two keys but that's not entirely required. Not for this version.I think I need to get in the habit of using basic filters on my boards. Initially I didn't even have one on the HUB75 I'm using until big letters in datasheets and blogs made it clear I'd overlooked an important 2200uF filter. Maybe I'll learn one day. I'm using 1206 SMD resistors that either say 1% or 5% - jelly beans, not precision. I didn't expect my calculations to be working the first time. Of course if I had to produce a lot of these, that would have to change. That's not my target though. So adjusting the code to fit reality isn't that much of an issue for me.

author: bitman
author_rank: Unknown
timestamp: November 16, 2021, 10:06:55 pm
content: Quote from: Benta on November 16, 2021, 09:02:19 pmI'm doing ADC - not DAC. So I don't think R-2R applies?When more than one button (I've only coded for 2 and not all combinations) is pushed, a parallel resistor pair is created and the voltage is hence much higher. So I get higher values that are far enough away from the other values that I can differentiate. And since I only scan for pushes every 150ms I haven't yet seen where a double push first produces one then the two button pushed as a result.As to my resistor choices - another post here pointed out that my SW1 -> SW2 switch-ladder resulted in just 0.1v difference - and to my chock I did the redid my calculation and could not figure out why I didn't see that. So I've replaced the 2K (R1) with a 220ohm resistor. Now the difference between each button is just about 0.5v - with 3.3v in that's plenty.

author: bitman
author_rank: Unknown
timestamp: November 16, 2021, 10:11:40 pm
content: Quote from: woofy on November 16, 2021, 05:28:27 pmI forgot to thank you for this. I deleted my original spreadsheet where I calculated the voltages but your post made me redo it, and you are absolutely right and I have no clue how I didn't see that. So I've replaced the 2k with a 220 (ohms, not kilo-ohms) one, but I still do a divider with a 1k. That allows me to push more than one button.I also wonder if using 33k and 100k will leave enough current for the ADC to work? Didn't try that - but if it's flimsy now wouldn't that make it worse?

author: bitman
author_rank: Unknown
timestamp: November 16, 2021, 10:31:53 pm
content: Quote from: bitman on November 16, 2021, 10:11:40 pmAnd just after I wrote this I realized WHY there's a 2k resistor. It's due to where the sense pin is. As a button is pushed, the _button_ of the resistor ladder increases adding the 330, 620 etc. to the bottom value (the 1k). This leaves a much higher difference between SW1 and SW2 but it's perhaps too small between SW4 and SW5, so I'll definitely revisit the resistor values. At least it explains what happened and why I had those values.

author: Benta
author_rank: Super Contributor
timestamp: November 16, 2021, 10:34:50 pm
content: Quote from: bitman on November 16, 2021, 10:06:55 pmYes, it does. Regard your switches as the input of the R-2R DAC and your ADC as the input. You'll get equidistant binary spacing between the different levels instead of... something, if you lay it out correctly (meaning your switch scheme is not optimal).But apart from that: why don't you just make a simple voltage divider with six (or seven) resistors in series and tap each switch voltage from there?

author: woofy
author_rank: Frequent Contributor
timestamp: November 16, 2021, 11:30:40 pm
content: Quote from: bitman on November 16, 2021, 10:11:40 pmEven with the 100k, it is in parallel with the 22k as far as impedance is concerned. That's 18k. A bit high, but if you follow siliconwizard's advice and add a filter capacitor that will also take care of any impedance issues by providing the ADC's sample current. I would connect a 100nF from sense line to 0v.

author: Doctorandus_P
author_rank: Super Contributor
timestamp: November 26, 2021, 10:24:52 pm
content: I did not read all the posts, but the way you connected your resistors is weird.Move the resistors from the top, to the bottom:R2 -> R3R4 -> R5R6 -> R7R8 -> R9(And then just wire R1 to all switches)The amount of jitter on the ADC is quite normal, (as has already been mentioned)Adding an RC filter to the "senseKey" (Best is close to your ESP8266) can improve this, but also averaging multiple ADC values helps.You could also do more complex filtering, for example:* Read 5 ADC values.* Throw away the biggest and the smallest value (Assume they are "outliers")* Average the other samples.Also:You do not need the "PWR_FLAG" everywhere on all power nets in KiCad. They are only needed for IC's that have a "Power Input" pin and if that power input pin is not connected to a "Power output pin" somewhere else on that net.You are also doubling up on you net labels. Why add a "GND" label if a wire is already connected to a GND symbol?(same for +3.3V)

author: bitman
author_rank: Unknown
timestamp: December 09, 2021, 06:33:02 pm
content: Sorry for the late reply, but I think this one needs a followup.Quote from: Doctorandus_P on November 26, 2021, 10:24:52 pmI'd actually done that shortly after getting the first couple of feedback posts here. So good adviceQuote from: Doctorandus_P on November 26, 2021, 10:24:52 pmSo this is an ESP32 but yes, I'll look at doing that. However, it cannot take half or a full second from a button push to detection since this is for a small game, so I'm not sure I'll ever get to use the average idea here. As long as the values don't overlap - that one button push cannot overlap an interval of another, this circuit will do fine. Of course once I do 2 key presses the chances of overlap increases dramatically. I may just keep the double-push thing out for now - not entirely needed.Quote from: Doctorandus_P on November 26, 2021, 10:24:52 pmSo while NOT a professional at this, KiCAD is pretty much the only tool I know detailed enough to be useful for PCB/Schematics. I certainly don't have experience from the closed source expensive design tools. So perhaps KiCAD just do things a bit differently. If I do not put PWR_FLAG on GND and +3.3V the ERC fails. If I should guess it's because the connector I use have the generic pins defined as passives. So yes, I am not a fan of PWR_FLAG at all, but I've not yet been able to make any schematic pass ERC without using them. Of course I could ignore them, but what do I know what's correct and not?I label the track in addition to using the power-symbol to have the net names listed correctly when I make the PCB. I cannot tell why there is a difference, but without a ground symbol I know people complain and without the label, I don't get the right net-names. For this very basic circuit it really didn't matter, but that's how I've made every circuit and often had to go back and add more labels, so the PCB net-names made sense vs. all the nonsense of "this is pin XY1C net". Perhaps the issue with PWR_FLAG is that I need to make special symbols for power connection, and I'll rather just have the extra flag than to maintain two of the same things with different attributes.

author: floobydust
author_rank: Super Contributor
timestamp: December 09, 2021, 07:46:46 pm
content: ESP32 ADChas a cramped measurement range, and the dead spot at the bottom end. A capacitor is pretty much mandatory to shunt RF and other noise, see graph there.What will your code do if two buttons are pressed simultaneously?

author: DavidAlfa
author_rank: Super Contributor
timestamp: December 09, 2021, 08:25:08 pm
content: When the ADC samples, it charges an internal 5-10pf capacitor with the external signal, and then the conversion starts.Anything causing the sampling capacitor to not fully charge, ex. Long wires, high input impedance, short adquisition time... will heavily affect the ADC readings.Have you checked the sampling/adquisition time is enough for that impedance? What about the ADC clock?Adding a 100pf resistor close to the ADC pin should help.