-
-
Notifications
You must be signed in to change notification settings - Fork 8.5k
Implement consistent machine.ADC with read_u16() method #5033
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
I like the idea of returning the type of the ADC data. How do you distinguish between pin and channel on devices that have both pins and channels? Is the 'source' argument compounded? Or just whatever the device can do somehow? |
For an already-constructed ADC object you can't tell the difference. I don't really see a need for this because a pin source is really just a pin (in analog mode) connected to a specific channel (at least that's how it works on stm32, which has both internal and pin-connected channels).
It's up to a port/device to decide what the "source" argument means, and the ADC constructor is in general overloaded to accept different types for "source". All ports should allow a pin to be passed in as the source, and the corresponding ADC "channel" (if a port has such a concept) will then be selected. And then usually passing in an integer would select a channel. |
Got it, thanks. I'm working with the ESP32 and an ADC class implementation described here, would you have a look? Apparently there are two SAR's, each associated with a specific set of pins. So it seems like in your implementation the appropriate SAR would be derived from the pin number instead of being specified directly there as 'unit'? There is also a 'chan' argument, not sure what that does. |
Yes, correct. Although there are currently no plans to implement ADC2 because it's used by the WiFi (but it could fit into this API in the future). |
I use ADC2 in one of my applications, so I would hope that it be included. It uses LoRa instead of WiFi. That ties up a lot of pins for SPI, also using I2C and various other pins for sensors and indicators, so I need access to all of the pins. Is there a need for a 'deinit' method? I have a situation where I connect an analog sensor to a pin that is set up to interrupt on a 0-1 state transition. I also want to be able to measure the voltage on the pin when an interrupt occurs, and then go back to the state transition mode. Does this require a deinit? |
I see that you are also working on the PWM class, and there you are including a 'block' parameter in the init method. Not the case for ADC? |
That PWM proposal shows an alternative way of specifying "blocks". But I do prefer what is proposed in #4213, where a block is exposed as an actual object/class like |
So in the 4213 PR there are two forms of the ADC class. One is 'generic' and intended to provide basic commonly used setups and the xxxBlock() class would be an alternative with platform-specific settings? That seems reasonable to me. I'm concerned that the resolution of this class signature semantics issue is taking a long time - going on a year. And until it does get resolved none of the PR's can be completed and closed, it is a log jam. What can be done to move it to resolution? |
The |
You would fit ADC2 in as
|
I use an ADC2 pin successfully in an application (loboris port) when WiFi isn't activated. That's because literally all the other ADC-capable pins are already assigned and in use. So really I think there is no reason to not include it, let the developer make the choice. |
What's the consequence when WiFi is in use? Is it just an IDF error? |
I don't know, I reboot with a different setup if I need WiFi and don't activate that pin. |
There's some variation in how an ADC sample that's smaller than 16 bits is converted to that width. A straight shift: micropython/ports/nrf/modules/machine/adc.c Line 185 in ef9fde7
Something more elaborate putting some values in the lsbs: micropython/ports/esp32/machine_adc.c Lines 96 to 97 in 8e048d2
Is that as intended? |
Yes that's intended. Both those examples above are the same, it's just that the nrf one is simplified when
|
Oh, I somehow misread the nrf one as return I've been having a look at the various Espressif ADCs and we were discussing whether MicroPython applied a correction in the code to the rather shoddy raw ADC output, hence my interest in the code. Some graphs in Adafruit Forums: Feather ADC comparison including 2.6V limited ESP32-S2 if you're interested. I think the regular ESP users all know this but I got surprised by the ESP32-S2 giving some confusing results with an analogue peripheral. |
No reason, it could be changed to 12 bits (and maybe given an option to select the bits, following esp32). |
This PR implements the beginnings of a revised machine.ADC class which is intended to make the ADC class more standardised across ports. See #3943 and #4213 for background discussion.
The PR here implements the following (simple) API for stm32, esp8266, esp32 and nrf ports:
On stm32 the source can be any pin that has ADC support, or a constant
ADC.CORE_VREF
,ADC.CORE_VBAT
,ADC.CORE_TEMP
for internal channels. It will pick the correct ADC peripheral that supports that source (eg ADC1, ADC2 or ADC3). Other ports support taking a pin and/or a channel number.The method
read_u16()
is named to emphasise the units, that it's an unsigned 16-bit number, and is the raw ADC reading scaled to 16 bits.The aim of this PR is to make basic ADC functionality available in a consistent way across ports. Other things (eg setting resolution, sample time, selecting ADC peripheral block) can be added later, but at least construction and reading (implemented by this PR) are necessary features and the approach taken here is hopefully obvious and not controversial (up to perhaps the name
read_u16
). In other words, it should be possible to decide on the API presented here regardless of how additional features (mentioned above) might be implemented and exposed to the user.Comments/discussion are very welcome.