Skip to content
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

[PoC] drivers/adc_ng: Common ADC API and implementation #13248

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

maribu
Copy link
Member

@maribu maribu commented Jan 31, 2020

Contribution description

This PR depends on and includes #13247. It adds:

  • An implementation of the existing ADC periph API on top of the new, so that new ADC-NG drivers can be used with existing code. (This also allows to use external ADCs with the existing API.)
  • An ADC NG driver for the ATmega ADC
  • A test application

Testing procedure

The test application can be used with an ATmega powered board. It drops you in a shell that allows you to test all of the functions of the ADC NG API exposed as separate shell commands. (Currently almost 3KiB RAM are used due to constant data being placed in RAM on AVR. Using PROGMEM could improve the situation to allow it running e.g. on the Arduino UNO; but that is out of scope.)

Issues/PRs references

#13247

@maribu maribu added State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet State: waiting for other PR State: The PR requires another PR to be merged first Area: drivers Area: Device drivers labels Jan 31, 2020
@maribu maribu force-pushed the adc branch 2 times, most recently from 4b40748 to f046143 Compare February 6, 2020 21:01
@gschorcht
Copy link
Contributor

@maribu Commit 2acba62 does not belong to this PR, right?

@maribu
Copy link
Member Author

maribu commented Feb 12, 2020

@maribu Commit 2acba62 does not belong to this PR, right?

After I rebase against current master, it will no longer be needed here :-)

FEATURES_PROVIDED += arch_8bit
FEATURES_PROVIDED += arch_avr8
FEATURES_PROVIDED += atmega_pcint0
FEATURES_PROVIDED += periph_adc_ng
Copy link
Contributor

@gschorcht gschorcht Feb 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be defined in board definitions. Otherwise, a board is not able to use only an external ADC if the feature is provided by the MCU because of the following condition in adc_ng.c:

#if (ADC_NG_NUMOF == 1) && defined(MODULE_PERIPH_ADC_NG)
See also #13247 (comment).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Features and modules are conceptional not the same, even though for most (all?) features with periph_% a module with the same name exists and is automatically used, if the corresponding feature is used.

So: Just because the feature is provided, it is not automatically used. The FEATURES_OPTIONAL += periph_adc_ng in drivers/Makefile.dep that is done when adc_ng is used would indeed pull that feature (and therefore) the corresponding module in. But that could be prevented by FEATURES_BLACKLIST += periph_adc_ng.

I'm not sure if this is super elegant. Maybe it would be better to provide an adc_ng_default pseudo-module that would pull in all ADC-NG backends supported by a board.

tests/adc_ng/main.c Outdated Show resolved Hide resolved
tests/adc_ng/main.c Outdated Show resolved Hide resolved
tests/adc_ng/main.c Outdated Show resolved Hide resolved
tests/adc_ng/main.c Outdated Show resolved Hide resolved
tests/adc_ng/main.c Outdated Show resolved Hide resolved
tests/adc_ng/main.c Outdated Show resolved Hide resolved
@maribu
Copy link
Member Author

maribu commented Feb 13, 2020

@maribu Commit 2acba62 does not belong to this PR, right?

After I rebase against current master, it will no longer be needed here :-)

I did the rebase, so that commit is no longer part of this PR.

@maribu
Copy link
Member Author

maribu commented Feb 13, 2020

The PoC was also updated to reflect the current state of the API. But I didn't manage to apply all feedback yet; I will do so tomorrow (hopefully)

@stale
Copy link

stale bot commented Aug 21, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions.

@stale stale bot added the State: stale State: The issue / PR has no activity for >185 days label Aug 21, 2020
@maribu maribu added the State: don't stale State: Tell state-bot to ignore this issue label Aug 21, 2020
@stale stale bot removed the State: stale State: The issue / PR has no activity for >185 days label Aug 21, 2020
@MrKevinWeiss MrKevinWeiss added this to the Release 2021.07 milestone Jun 21, 2021
@MrKevinWeiss MrKevinWeiss removed this from the Release 2021.07 milestone Jul 15, 2021
@Enoch247
Copy link
Contributor

One thing I noticed is that there is no provision to sample more than one channel per ADC without re-initializing it. The channel is selected in adc_ng_init(...) rather than as a parameter in the ADC reading functions. Alternatively, a channel struct could be added with a handle back to the ADC peripheral.

@maribu
Copy link
Member Author

maribu commented Jan 24, 2022

That's a valid point. There could be a footgun in that the ADC might not be able to switch between channels for a given configuration it is in. E.g. many ADCs have a channel that is wired to an internal NTC for temperature measurements. I read at least in one datasheet that stated one "must use" a particular reference voltage for it. Likely the result of none-compliance are just a high level of noise or so, but I'm not sure.

I guess a driver could have assert()s to ensure no channel that is invalid in the context of the current configuration is selected. I hope I can find some time to work on this PR this week. I will likely just drop the adc_ng_burst() function and let a better interface that allows for truly continuous sampling be added in a subsequent PR - possibly by someone else.

@maribu
Copy link
Member Author

maribu commented Jan 25, 2022

I spend some time thinking about this. I do not want to drop the channel argument from the initialization function. Some ADCs enable the ADC MUX when they are powered up no matter what, and some ADC MUXs can only select a valid input. In this case, the driver would have to blindly guess what channel to connect to. But not every channel is compatible with all settings, so this "default channel selection" can be a bit involved. If however the caller has to directly pass the channel it want to get the first sample from as argument, things are easy for the driver.

I also don't like adding a channel argument to the sample function. I would like to keep the function to retrieve a sample as trivial as possible. For ADCs that do not support DMA (or drivers that have not implemented it) requesting samples in a busy loop is the only option to get samples as fast as possible. Keeping this function trivial can increase the sample rate a bit. The sample rate will be particularly affected if assert()s are added to enforce only valid configurations - which I believe is the right thing to do.

How about this instead: Adding a dedicated function to swap the channel while keeping the ADC running? This should still be faster than re-initializing the ADC when a channel needs to be changed, but we can afford to pay for an assert() here, as often the level of noise is higher directly after switching the ADC channel and one often want to wait for that to stabilize again anyway.

@Enoch247
Copy link
Contributor

How about this instead: Adding a dedicated function to swap the channel while keeping the ADC running? This should still be faster than re-initializing the ADC when a channel needs to be changed, but we can afford to pay for an assert() here, as often the level of noise is higher directly after switching the ADC channel and one often want to wait for that to stabilize again anyway.

I think this could be a good idea. I was playing around with the SPI driver and noticed it has a use pattern where you must call spi_init to initialize the driver and then call spi_acquire and spi_release anytime you wish to use the bus. The bus speed is passed into the acquire function since a bus might use different speeds for each device on the bus. What do you think about doing something similar with the ADC?

Marian Buschsieweke added 3 commits April 26, 2022 22:03
This API aims to provided an alternative to the periph ADC API with the
following improvements:

- Support for multiple ADC devices (both external and peripheral ADCs)
- Support for selecting the reference voltage
- Convenience functions to convert into meaningful physical units

It is written to allow coexistence with the existing periph ADC API.
Implemented the periph/adc API on top of the adc_ng API. This allows application
using the periph ADC API to also use external ADCs.
@github-actions github-actions bot added Area: build system Area: Build system Area: cpu Area: CPU/MCU ports Area: tests Area: tests and testing framework Platform: AVR Platform: This PR/issue effects AVR-based platforms labels Apr 26, 2022
@Teufelchen1
Copy link
Contributor

Can this be a draft?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: build system Area: Build system Area: cpu Area: CPU/MCU ports Area: drivers Area: Device drivers Area: tests Area: tests and testing framework Platform: AVR Platform: This PR/issue effects AVR-based platforms State: don't stale State: Tell state-bot to ignore this issue State: waiting for other PR State: The PR requires another PR to be merged first State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants