use crate::clock::GenericClockController;
use crate::ehal::adc::{Channel, OneShot};
use crate::gpio::*;
use crate::pac::{adc, ADC, PM};
pub use adc::avgctrl::SAMPLENUM_A as SampleRate;
pub use adc::ctrlb::PRESCALER_A as Prescaler;
pub use adc::ctrlb::RESSEL_A as Resolution;
pub use adc::inputctrl::GAIN_A as Gain;
pub use adc::refctrl::REFSEL_A as Reference;
pub struct Adc<ADC> {
adc: ADC,
}
impl Adc<ADC> {
#[allow(clippy::self_named_constructors)]
pub fn adc(adc: ADC, pm: &mut PM, clocks: &mut GenericClockController) -> Self {
pm.apbcmask.modify(|_, w| w.adc_().set_bit());
let gclk0 = clocks.gclk0();
clocks.adc(&gclk0).expect("adc clock setup failed");
while adc.status.read().syncbusy().bit_is_set() {}
adc.ctrla.modify(|_, w| w.swrst().set_bit());
while adc.status.read().syncbusy().bit_is_set() {}
adc.ctrlb.modify(|_, w| {
w.prescaler().div32();
w.ressel()._12bit()
});
while adc.status.read().syncbusy().bit_is_set() {}
adc.sampctrl.modify(|_, w| unsafe { w.samplen().bits(5) }); while adc.status.read().syncbusy().bit_is_set() {}
adc.inputctrl.modify(|_, w| w.muxneg().gnd()); while adc.status.read().syncbusy().bit_is_set() {}
let mut newadc = Self { adc };
newadc.samples(adc::avgctrl::SAMPLENUM_A::_1);
newadc.gain(adc::inputctrl::GAIN_A::DIV2);
newadc.reference(adc::refctrl::REFSEL_A::INTVCC1);
newadc
}
pub fn samples(&mut self, samples: SampleRate) {
use adc::avgctrl::SAMPLENUM_A;
self.adc.avgctrl.modify(|_, w| {
w.samplenum().variant(samples);
unsafe {
w.adjres().bits(match samples {
SAMPLENUM_A::_1 => 0,
SAMPLENUM_A::_2 => 1,
SAMPLENUM_A::_4 => 2,
SAMPLENUM_A::_8 => 3,
_ => 4,
})
}
});
while self.adc.status.read().syncbusy().bit_is_set() {}
}
pub fn gain(&mut self, gain: Gain) {
self.adc.inputctrl.modify(|_, w| w.gain().variant(gain));
while self.adc.status.read().syncbusy().bit_is_set() {}
}
pub fn reference(&mut self, reference: Reference) {
self.adc
.refctrl
.modify(|_, w| w.refsel().variant(reference));
while self.adc.status.read().syncbusy().bit_is_set() {}
}
pub fn prescaler(&mut self, prescaler: Prescaler) {
self.adc
.ctrlb
.modify(|_, w| w.prescaler().variant(prescaler));
while self.adc.status.read().syncbusy().bit_is_set() {}
}
pub fn resolution(&mut self, resolution: Resolution) {
self.adc.ctrlb.modify(|_, w| w.ressel().variant(resolution));
while self.adc.status.read().syncbusy().bit_is_set() {}
}
fn power_up(&mut self) {
while self.adc.status.read().syncbusy().bit_is_set() {}
self.adc.ctrla.modify(|_, w| w.enable().set_bit());
while self.adc.status.read().syncbusy().bit_is_set() {}
}
fn power_down(&mut self) {
while self.adc.status.read().syncbusy().bit_is_set() {}
self.adc.ctrla.modify(|_, w| w.enable().clear_bit());
while self.adc.status.read().syncbusy().bit_is_set() {}
}
fn convert(&mut self) -> u16 {
self.adc.swtrig.modify(|_, w| w.start().set_bit());
while self.adc.intflag.read().resrdy().bit_is_clear() {}
while self.adc.status.read().syncbusy().bit_is_set() {}
self.adc.intflag.modify(|_, w| w.resrdy().set_bit());
self.adc.swtrig.modify(|_, w| w.start().set_bit());
while self.adc.intflag.read().resrdy().bit_is_clear() {}
while self.adc.status.read().syncbusy().bit_is_set() {}
self.adc.result.read().result().bits()
}
}
impl<WORD, PIN> OneShot<ADC, WORD, PIN> for Adc<ADC>
where
WORD: From<u16>,
PIN: Channel<ADC, ID = u8>,
{
type Error = ();
fn read(&mut self, _pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
let chan = PIN::channel();
while self.adc.status.read().syncbusy().bit_is_set() {}
self.adc
.inputctrl
.modify(|_, w| unsafe { w.muxpos().bits(chan) });
self.power_up();
let result = self.convert();
self.power_down();
Ok(result.into())
}
}
macro_rules! adc_pins {
(
$(
$PinId:ident: $CHAN:literal
),+
) => {
$(
impl Channel<ADC> for Pin<$PinId, AlternateB> {
type ID = u8;
fn channel() -> u8 { $CHAN }
}
)+
}
}
#[cfg(feature = "samd11")]
adc_pins! {
PA02: 0,
PA04: 2,
PA05: 3,
PA14: 6,
PA15: 7
}
#[cfg(feature = "pins-d11d")]
adc_pins! {
PA03: 1,
PA06: 4,
PA07: 5,
PA10: 8,
PA11: 9
}
#[cfg(feature = "samd21")]
adc_pins! {
PA02: 0,
PA03: 1,
PA04: 4,
PA05: 5,
PA06: 6,
PA07: 7,
PA08: 16,
PA09: 17,
PA10: 18,
PA11: 19
}
#[cfg(feature = "has-pb00")]
adc_pins! { PB00: 8 }
#[cfg(feature = "has-pb01")]
adc_pins! { PB01: 9 }
#[cfg(feature = "has-pb02")]
adc_pins! { PB02: 10 }
#[cfg(feature = "has-pb03")]
adc_pins! { PB03: 11 }
#[cfg(feature = "has-pb04")]
adc_pins! { PB04: 12 }
#[cfg(feature = "has-pb05")]
adc_pins! { PB05: 13 }
#[cfg(feature = "pins-48")]
adc_pins! {
PB08: 2,
PB09: 3
}
#[cfg(feature = "pins-64")]
adc_pins! {
PB06: 14,
PB07: 15
}