use crate::gpio::*;
use crate::hal::adc::{Channel, OneShot};
use crate::pac::ADC;
use crate::rcc::Rcc;
#[derive(PartialEq)]
pub enum Align {
Right,
Left,
}
#[derive(Copy, Clone, PartialEq)]
pub enum Precision {
B_12 = 0b00,
B_10 = 0b01,
B_8 = 0b10,
B_6 = 0b11,
}
#[derive(Copy, Clone, PartialEq)]
pub enum SampleTime {
T_1_5 = 0b000,
T_3_5 = 0b001,
T_7_5 = 0b010,
T_12_5 = 0b011,
T_19_5 = 0b100,
T_39_5 = 0b101,
T_79_5 = 0b110,
T_160_5 = 0b111,
}
pub struct Adc {
rb: ADC,
sample_time: SampleTime,
align: Align,
precision: Precision,
}
impl Adc {
pub fn new(adc: ADC, rcc: &mut Rcc) -> Self {
rcc.rb.apb2enr.modify(|_, w| w.adcen().set_bit());
adc.cr.modify(|_, w| w.advregen().set_bit());
Self {
rb: adc,
sample_time: SampleTime::T_1_5,
align: Align::Right,
precision: Precision::B_12,
}
}
pub fn set_sample_time(&mut self, t_samp: SampleTime) {
self.sample_time = t_samp;
}
pub fn set_align(&mut self, align: Align) {
self.align = align;
}
pub fn set_precision(&mut self, precision: Precision) {
self.precision = precision;
}
fn power_up(&mut self) {
self.rb.isr.modify(|_, w| w.adrdy().set_bit());
self.rb.cr.modify(|_, w| w.aden().set_bit());
while self.rb.isr.read().adrdy().bit_is_clear() {}
}
fn power_down(&mut self) {
self.rb.cr.modify(|_, w| w.addis().set_bit());
self.rb.isr.modify(|_, w| w.adrdy().set_bit());
while self.rb.cr.read().aden().bit_is_set() {}
}
fn write_smpr(&mut self) {
self.rb
.smpr
.modify(|_, w| w.smp().bits(self.sample_time as u8));
}
pub fn release(self) -> ADC {
self.rb
}
}
pub trait AdcExt {
fn constrain(self, rcc: &mut Rcc) -> Adc;
}
impl AdcExt for ADC {
fn constrain(self, rcc: &mut Rcc) -> Adc {
Adc::new(self, rcc)
}
}
impl<WORD, PIN> OneShot<Adc, WORD, PIN> for Adc
where
WORD: From<u16>,
PIN: Channel<Adc, ID = u8>,
{
type Error = ();
fn read(&mut self, _pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
self.power_up();
self.rb.cfgr1.modify(|_, w| {
let w = w.res().bits(self.precision as u8);
w.align().bit(self.align == Align::Left)
});
self.write_smpr();
self.rb.chselr.write(|w|
unsafe { w.bits(0b1 << PIN::channel()) });
self.rb.isr.modify(|_, w| w.eos().set_bit());
self.rb.cr.modify(|_, w| w.adstart().set_bit());
while self.rb.isr.read().eos().bit_is_clear() {}
let res = self.rb.dr.read().bits() as u16;
let val = if self.align == Align::Left && self.precision == Precision::B_6 {
res << 8
} else {
res
};
self.power_down();
Ok(val.into())
}
}
macro_rules! int_adc {
($($Chan:ident: ($chan:expr, $en:ident)),+ $(,)*) => {
$(
pub struct $Chan;
impl $Chan {
pub fn new() -> Self {
Self {}
}
pub fn enable(&mut self, adc: &mut Adc) {
adc.rb.ccr.modify(|_, w| w.$en().set_bit());
}
pub fn disable(&mut self, adc: &mut Adc) {
adc.rb.ccr.modify(|_, w| w.$en().clear_bit());
}
}
impl Channel<Adc> for $Chan {
type ID = u8;
fn channel() -> u8 {
$chan
}
}
)+
};
}
macro_rules! adc_pins {
($($Chan:ty: ($pin:ty, $chan:expr)),+ $(,)*) => {
$(
impl Channel<Adc> for $pin {
type ID = u8;
fn channel() -> u8 { $chan }
}
)+
};
}
int_adc! {
VTemp: (18, tsen),
VRef: (17, vrefen),
}
adc_pins! {
Channel0: (gpioa::PA0<Analog>, 0u8),
Channel1: (gpioa::PA1<Analog>, 1u8),
Channel2: (gpioa::PA2<Analog>, 2u8),
Channel3: (gpioa::PA3<Analog>, 3u8),
Channel4: (gpioa::PA4<Analog>, 4u8),
Channel5: (gpioa::PA5<Analog>, 5u8),
Channel6: (gpioa::PA6<Analog>, 6u8),
Channel7: (gpioa::PA7<Analog>, 7u8),
Channel8: (gpiob::PB0<Analog>, 8u8),
Channel9: (gpiob::PB1<Analog>, 9u8),
}
#[cfg(all(feature = "stm32l052", any(feature = "lqfp64", feature = "tfbga64",),))]
adc_pins! {
Channel10: (gpioc::PC0<Analog>, 10u8),
Channel11: (gpioc::PC1<Analog>, 11u8),
Channel12: (gpioc::PC2<Analog>, 12u8),
}
#[cfg(all(
feature = "stm32l072",
any(
feature = "lqfp64",
feature = "lqfp100",
feature = "tfbga64",
feature = "ufbga64",
feature = "ufbg100",
feature = "wlcsp49",
),
))]
adc_pins! {
Channel10: (gpioc::PC0<Analog>, 10u8),
Channel11: (gpioc::PC1<Analog>, 11u8),
Channel12: (gpioc::PC2<Analog>, 12u8),
}
#[cfg(all(feature = "stm32l082", feature = "wlcsp49"))]
adc_pins! {
Channel10: (gpioc::PC0<Analog>, 10u8),
Channel11: (gpioc::PC1<Analog>, 11u8),
Channel12: (gpioc::PC2<Analog>, 12u8),
}
#[cfg(all(feature = "stm32l052", feature = "lqfp64"))]
adc_pins! {
Channel13: (gpioc::PC3<Analog>, 13u8),
}
#[cfg(all(
feature = "stm32l072",
any(feature = "lqfp64", feature = "lqfp100", feature = "ufbg100",),
))]
adc_pins! {
Channel13: (gpioc::PC3<Analog>, 13u8),
}
#[cfg(all(feature = "stm32l052", any(feature = "lqfp64", feature = "tfbga64",),))]
adc_pins! {
Channel14: (gpioc::PC4<Analog>, 14u8),
Channel15: (gpioc::PC5<Analog>, 15u8),
}
#[cfg(all(
feature = "stm32l072",
any(
feature = "lqfp64",
feature = "lqfp100",
feature = "tfbga64",
feature = "ufbga64",
feature = "ufbg100",
),
))]
adc_pins! {
Channel14: (gpioc::PC4<Analog>, 14u8),
Channel15: (gpioc::PC5<Analog>, 15u8),
}