-
Notifications
You must be signed in to change notification settings - Fork 233
Adc
API
#10
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
Comments
Looking only at STM micros the trait for single conversion mode would have to look like this: trait Adc {
type Bits;
type Error;
/// Starts a single ADC conversion (on a single channel)
fn start(&self) -> Self::Error;
/// Reads the converted value (Adc.start must be called first)
fn read(&self) -> nb::Result<Self::Bits, Self::Error>;
}
adc.start().unwrap(); // SWSTART = 1
let value: u16 = block!(adc.read()).unwrap(); Anything more complicated (multiple channels or continuous conversion mode) will probably require something DMA based. Thoughts @adamgreig? |
I've been thinking about how I'd want an ADC trait to look for a few days now but keep running into various issues. I think your concept above is reasonably nice for the single conversion case, though:
I think in general ADCs are commonly used either:
I'd be interested to hear of use cases for ADCs different to those two. There's things like analogue watchdogs where the ADC interrupts after going above/below a threshold, but I think that's again a case of a bunch of device-specific configuration followed by an interrupt, so doesn't make sense in the |
Thanks for the input @adamgreig I think it may make sense to have three traits then: one for single conversion, trait Single {
type Error;
type Sample;
fn start(&self) -> Result<(), Self::Error>;
fn convert(&self) -> nb::Result<Self::Sample, Self::Error>;
}
single.start();
let sample = block!(single.convert()).unwrap();
trait Continuous {
type Sample;
fn read(&self) -> Self::Sample;
}
let sample = continuous.read();
trait Select {
type Channel;
type Error;
fn select(&self, channel: Self::Channel) -> Result<(), Self::Error>;
} I was wondering about failure modes of the continuous conversion mode. I suppose
As for |
In continuous mode it'd be an error if the ADC wasn't running at all, and I don't think you can statically assert that it is? read() couldn't start the ADC if not started since then it'd have to block until the first sample arrives, which means returning a Result anyway. Perhaps it just panics in that case. |
That's probably doable using session types or other type level wizardy but would probably complicate the trait too much, or may not even be abstractable into a trait. We could add a check to fn foo<A>(adc: A) where A: adc::Continuous {
if !adc.is_enabled() {
adc.enable();
delay(100);
}
loop {
let sample = adc.read();
..;
}
} |
2 fairly common things that I remember doing when I was using ADCs in PICs was setting the sample rate and the analogue reference. Those are more configuration options, so might be better in a sub struct but the sample rate is a pain in Arduino, but the Ref is a straight function call. Also, Read Resolution might be handy to have around. On continuous readings, I think there should be an error returned if you try to read without starting the ADC. Maybe have another function read_fast() that doesn't have the checks and is intended for fast operations. |
Lines 51 to 54 in 62a5dc6
This can now be an associated constant as the upstream issue was fixed. |
Maybe this could be solved similarly to how digital IO is handled? So, there'd be a trait that can be implemented for IO pins let dp = my_hal::Peripherals::take().unwrap();
let pins = my_hal::pins!(dp);
let adc = dp.ADC1.start();
let a1 = pins.pb6.into_continuous_analog(adc.channel2); This way, the compiler verifies statically that no channel is reused, and that the adc is started. |
10: update ci r=japaric a=japaric Co-authored-by: Jorge Aparicio <[email protected]>
This API has not been designed yet. What methods should it provide?
The text was updated successfully, but these errors were encountered: