Closed dhalbert closed 3 years ago
I think this should be 3.3, not 2.6: https://github.com/adafruit/Adafruit_CircuitPython_MagTag/blob/31c664cc2f5fa0d4b81067a9e64ecf0003e3c16e/adafruit_magtag/peripherals.py#L86
I don't have a MagTag, but AnalogIn measurements match multimeter on Saola and FeatherS2 (6.1.0-beta.1), with @hierophect's caveat noted in #3501 - the Espressif docs indicating full range analog reads from 0-3.3V at 11dB seem to be incorrect (at this time).
I got the numbers from some code I got from @ladyada, but hadn't done any verifications. So it's possible the numbers may need to be adjusted in the MagTag library.
My impression was that the ADC might not be linear, and that the range might be limited, but I haven't started testing yet. I think I read that previously.
@hierophect Will have context on this.
Should be linear enough between 150 ~ 2600 mV, which covers the range for 50% of LiPo voltage. AnalogIn does apply calibration based on device-specific data in efuse.
But whereas docs say we should be able to measure voltages from 0-3.3v at 11dB attenuation, I can't get quite to zero, or above about 2.7v, with the current build.
we divide by 2 fyi - so you should have full range
What specifically is wrong with the voltage in testing? There are a number of caveats to the S2 ADC readings.
The relevant section to the voltage limits problem is here. When I asked Espressif about this issue, they confirmed that their voltage readings capped out at 2.6V. The section also notes:
At 11 dB attenuation the maximum voltage is limited by VDDA, not the full scale voltage.
So I guess this could vary depending on whether the VDDA implemented at the module or client PCB level. @anecdata I don't see anywhere in the docs that indicates it the ESP32S2 will measure anything below 100mV, that's been an issue on the ESP32 as well, and it's noted in the above function docs.
The ESP_ADC_CAL component is supposed to fix some of this, but the implementation for the S2 is less fully implemented than for the ESP32. I've looked at the latest master for the esp_adc_cal component and they haven't added any additional features, so we aren't missing anything from a recent update either.
You can see some examples of the voltage curves on the ESP32 here. The ESP32 IDF implementation actually has the LUT lookup suggested by posters in that thread, that maps ADC readings to better values for nonlinear regions (though I'm not sure how much that can fix the low-end limit). But the ESP32 S2 doesn't have this implemented yet.
I can measure 0.000v-3.299v (calibrated) on ADC1 on the ESP32 (using CircuitPython!), so I think Espressif has solved it there.
But for 1/2 of the battery voltage, we are well within the recommended linear range on the ESP32-S2.
I may be missing something, but is the library calculation correct (see my first comment)? analogin
returns 0-65535 value for voltage relative to 3.3v if I'm reading it right, so the library should multiply by 3.3 (rather than 2.6) to get back to a voltage?
ADC1 on the ESP32 (using CircuitPython!)
???
I see what you mean in your comment now, though. Yes, I had it multiply by 3.3 to align with the ADC readings of other Circuitpython boards and the documentation, even if it can't get all the way up to the max at whatever VDDA we're supplying. So you're right, that later adjustment should be 3.3, not 2.6.
@dhalbert i havent tried this for a while, please see if you get good numbers now
@hierophect We have analogin in ESP32SPI-NINA :-)
@ladyada will do, and I'll also see about adding the calibration code to the -S2 implementation.
@dhalbert we already use the calibration code that's implemented in the IDF, which is just the basic calibration curve without an LUT. If we want our own LUT, we'll need to decide how to generate it.
I changed the multiplier, and the battery voltage is closer, but is reading about 0.15v low. I tried at 4.2, 3.7, and 3.35v, which are the variable values available from the Monsoon power monitor. I double-checked that the Monsoon is accurate with an external voltmeter.
I have not looked at the code yet.
It's suspicious to me that the voltage curve starts at 150mV and is also off by that amount. Maybe the calibration curve offset isn't being applied properly?
I did some instrumentation of esp_adc_cal_esp32s2.c
:
low_curve
and high_curve
tables are not used. In fact the comment makes it clear:
// these values are not used as the corresponding calibration themes are deprecated.
adc_calib_low
and adc_calib_high
. These values are non-zero, at least on my ESP32-S2. So the code does a characterize_using_two_point()
with those calibration values. Nevertheless, the resulting voltage values are off by about 150mV as noted.I haven't read all the support issues and surrounding doc yet.
On a Metro ESP32-S2, I fed its DAC to the ADC. I measured the voltage with the ADC, and also with a good multimeter and an ADS1115. I don't see a 150mV difference. The readers differ only by only a few mV, often only 3 or so. I did a similar test with a 1.5V battery on a MagTag, reading its voltage on D10 and also on a multimeter, with a similar minimal difference, certainly not 150mV
I'm thinking any issues with the voltage reading may have to do with the voltage divider and the capacitor.
AnalogIn
does 64x multisampling, so even though the capacitor helps hold the voltage during sampling, it may be sagging slightly.
I changed the multiplier, and the battery voltage is closer, but is reading about 0.15v low. I tried at 4.2, 3.7, and 3.35v, which are the variable values available from the Monsoon power monitor. I double-checked that the Monsoon is accurate with an external voltmeter.
I repeated these measurements in situ with a battery, and I don't see this 150mV offset. I'm not quite sure why I saw it the first time with the Monsoon, but I don't see any offset with the battery and a voltmeter, and the corrected library (https://github.com/adafruit/Adafruit_CircuitPython_MagTag/pull/33), which now uses the proper 3.3V multipler. So I'm going to close this for now.
hmm ok!
I just noticed this too while testing an Enviro+ FeatherWing. The voltage is read from its 3 gas sensors with 3 analogue inputs. The value differs to the one shown with a Feather nRF52840 Express hence my investigation. I was unaware of this 2.63V limit.
@kevinjwalters If you are seeing differing measurements below the 2.63V limit compared with another board, go ahead and open an issue with some example code and measurements. Thanks.
@dhalbert I've left the FeatherS2 side by side with an nRF52840. I may have a more accurate ADC somewhere, I'll rummage.
Is the ESP32-S2 behaving according to its documentation? It sounds like with -11dB to input signal it should be viable to read up to 3.3V but that's clearly not the case at the moment. Do Expressif have any sample code for reading 3.3V, I've not found any yet.
@anecdata Are you saying the ESP32 and ESP32-S2 differ here?
I think I've picked two inputs on the pair of ADCs and curiously there are different ceiling values coming out of these:
>>> a1v = a1.value ; d5a10v = d5a10.value ; print(a1v, bin(a1v)) ; print(d5a10v, bin(d5a10v))
52149 0b1100101110110101
51574 0b1100100101110110
BTW, is there a reason why the width is not set for ADC2?
Ah, that's just way it is, according to general ESP32 docs: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc.html#adc-rtc-mode
ESP32-S2 width is enforced to 13 bits. As far as I can tell, latest Espressif docs indicate ADC should be able to handle up to 3.3v (linearity may well suffer above 2.6v, even with the calibration). We either need to demonstrate 3.3v in another IDE (or demonstrate that it is similarly limited, and file an issue with Espressif), or ask someone at Espressif.
Wrote a little piece of code that read on A0 the voltage written on A1:
import board
import time
from analogio import AnalogOut, AnalogIn
analog_in = AnalogIn(board.A1)
analog_out = AnalogOut(board.A0)
while True:
for i in range(0, 65535, 512):
write = i
analog_out.value = write
time.sleep(0.02)
read=analog_in.value
print((write, read))
It show something linear until it reach a plateau:
(0, 1886) (512, 2124) (1024, 2561) ... (54784, 53758) (55296, 54056) (55808, 54413) (56320, 54413) ... (64512, 54413) (65024, 54413)
@dglaude Interesting, your FeatherS2 can "reach" higher (2.74V) than mine (2.63V):
(0, 2303)
(512, 2621)
(1024, 3038)
...
(53248, 51534)
(53760, 52010)
(54272, 52149)
(54784, 52149)
...
(64512, 52149)
(65024, 52149)
I'm not sure what the new issue is here - I confirmed with Espressif that the S2 cannot achieve readings above around 2.6V, so I think that's that. The ESP32 and ESP32S2 do differ in this regard, the original ESP32 has a more sophisticated calibration process including a lookup table (LUT) and the ESP32S2 does not. You could use a voltage divider and diode offset to put your measured voltages in a better range, if necessary.
I think the issue is that the Espressif docs are either: wrong, or; anticipating further development to get the ESP32-S2 to comparable ADC behavior as the ESP32. Espressif should go on record with an answer.
@anecdata where in the docs do you see the claim that Analog readings should be able to go to 3.3V? I'm going over the page and they say that it's 2.6V everywhere that I can find https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/peripherals/adc.html
When the analog voltage supply (VDDA) is 3.3 V: ... 11 dB attenuation (ADC_ATTEN_DB_11) gives full-scale voltage 3.9 V (see note below) ... Note At 11 dB attenuation the maximum voltage is limited by VDDA, not the full scale voltage.
Yeah I had also just landed on that. I think that this also doesn't imply that 3.3V should be possible, it's just written in a confusing way. I think it means that the maximum value of the integer value would correspond to 3.9V, as in the integer max of ~65535~ (edit, the 12 bit max of 4095), but it will platau before ever actually hitting that value. Correspondingly, the maximum voltage is limited by VDDA, but that doesn't necessarily mean it is VDDA. Definitely some word salad going on there.
The header functions above it, however, all refer to a max reading of 2.6V:
ADC_ATTEN_DB_11 = 3 The input voltage of ADC will be attenuated, extending the range of measurement to up to approx. 2600 mV.
Note that's the ESP32, not ESP32-S2 docs.
@dhalbert it's actually pretty obviously copy-pasted between the two, the ESP32S2 one is the same: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/peripherals/adc.html#_CPPv425adc1_config_channel_atten14adc1_channel_t11adc_atten_t
Again, I think they did that because it doesn't technically say what the actual maximums are. But this whole thing could absolutely be a lot more clear. They should really specify outright what the maximum voltages are at 3.3V VDDA and what linearity issues they have / how those are compensated for in the calibration process.
sorry, wrong link, esp32-s2 reads the same https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/peripherals/adc.html#_CPPv425adc1_config_channel_atten14adc1_channel_t11adc_atten_t
Ah, sorry, I should have checked the other doc.
The odd thing to me, helped along by confusing docs, is that people coming from ESP32 could read the docs and expect 3.3v just like ESP32.
@anecdata I agree. ESP32 says that the maximum "recommended" voltage is ~2.6mV, but can go above that, with caveats. ESP32S2 says the same thing but apparently cannot go above it at all.
@hierophect Is the statement from Espressif available somewhere for viewing? It seems odd they cripple the ESP32-S2 and make it incompatible with ESP32, did they say why they did this? And why are they referring to it as -11dB (i.e. 3.90V -> 1.10V) if it's not?
If you have a ticket open with them perhaps it's worth askign them to polish/clarify their documentation?
Perhaps that with a higher VDDA value than 3.3V, a higher voltage would be possible? But I don't know if that's even allowed by the voltage specifications.
It is a documentation issue, at least for now. ESP32 docs read the same, but with VDDA at 3.3v, you can still get 3.3v ADC read on ESP32. If this is permanent, the fix is easy for them. If it's a future feature to support full-range, you'd think they could indicate that.
@kevinjwalters It was an email chain, and I would hesitate to call it a statement, just that the engineer on the other end confirmed that the maximum value they could obtain from the device was 2.6V. It was an old ticket, from back last fall when I was implementing this.
Again, I don't think they're actually doing anything duplicitous here. The header functions do state that the maximum attainable voltage is 2.6V, and the 11dB measurement is on a scale up to 3.9V, it just doesn't actually hit every value in that range.
So, on the ESP32, you can actually hit a full 3.3V reliably, using these same functions? I just checked out the ESP32 page, and it also claims to cap out at 2.6V. If you're obtaining higher voltages than that, it might actually be considered to be undocumented/unofficial functionality.
In any case, there's a discrepancy here that should be laid out in more detail. I'll open a new ticket with them and see if I can clear any of this up.
@hierophect just for completeness on your ESP32 question... The documentation has evolved a bit over time in how they describe analog range in various sections, and looking at code history it looks like calibration functions evolved as well. I ran the same ADC1 example as above on a Feather ESP32 with current IDF, and it has a range of 142mV-3124mV (calibrated voltage from esp_adc_cal_raw_to_voltage()
; raw reading at the high end is 4095).
Most ESP32-S2 chips should have eFuse Two Point values, but we may still expect some chip-to-chip differences.
Hopefully Espressif can confirm the supported ADC voltage range (linearity aside), and align docs with that.
@anecdata Does it plateau at top end or is 3124mV actually equivalent to 3.300V?
@kevinjwalters Calibrated ADC read tops out at 3124mV on that ESP32 with current ESP-IDF. That corresponds to raw 12-bit reading of 4095. Meter-measured voltage is 3.3v.
(I think we might expect more chip-to-chip differences on ESP32 since there are more possibilities for eFuse calibration data types)
@anecdata But does metered 3.20V and 3.25V also correspond to ACD reading of 3124mV?
Yes, once the raw ADC bits are maxxed out, the ADC calibrated voltage gets no higher (e.g., 3124mV), regardless of increased voltage applied and read on meter.
In other words, meter reads near 3124mV when raw ADC is at 4095 (and calibrated voltage is at 3124mV) - meter then measures higher as voltage is increased, but ADC bits and calibrated voltage read are already maxxed out and don't change.
All actual meter-read voltages between 3124mV-3300mV are read by the ADC on that ESP32 as 4095 raw / 3124mV calibrated.
I re-did the test of the ESP32-S2, reporting raw and calibrated, and it's the same. All actual voltages above 2630mV register by the ADC as 8191 raw / 2630mV calibrated on that ESP32-S2.
@anecdata - I still don't understand, you're saying that the ADC actually reaches the maximum value of the bit range (0xFFF, 12 1s in binary) and it corresponds to 3124mV? I'm extremely confused by that, the full scale voltage is supposed to be 3.9V, and my raw returns never approach the full scale value, that's what I've meant by referring to the plateau. I don't see how that would correlate to the documentation in any of the interpretations we've discussed here. Can you elaborate?
What I see, using the Espressif ADC example, on ESP32 and ESP32-S2, is that the 12- or 13-bit ADC reading (64x multisampled) hits the maximum value (4095 or 8191) at some voltage well under 3.3V. Similarly, the calibrated value from esp_adc_cal_raw_to_voltage()
also hits its maximum value at that point. At that point, calibrated value roughly equals the meter-measured voltage. But, increasing the applied voltage cannot increase the raw value because all bits are 1
, and it does not increase the reported calibrated value.
Example 1: potentiometer turned so that applied voltage measured by meter is 3.1V (ESP32). The raw ADC reading is 4095, and the calibrated voltage is reported at ~3.1V.
Example 2: ...now the potentiometer is slowly raised up to a meter reading of 3.3V. The raw ADC value can't change b/c it's at its maximum value. The calibrated voltage is reported still at ~3.1V.
I think the 3.9V is a red herring and just a mathematical artifact. The datasheet says max VDDA is 3.6V, and in reality for us at least it's 3.3V.
As far as I can tell, circuitpython AnalogIn
is implemented like the example, and behaves like the example.
There appears to be an issue with ADC calibration or operation. (Reported by @ladyada)