diff --git a/examples/comp.rs b/examples/comp.rs index 5893e6d0..e06635ec 100644 --- a/examples/comp.rs +++ b/examples/comp.rs @@ -15,7 +15,7 @@ use rt::entry; #[entry] fn main() -> ! { - use hal::comparator::{ComparatorExt, ComparatorSplit, Config, Hysteresis, RefintInput}; + use hal::comparator::{refint_input, ComparatorExt, ComparatorSplit, Config, Hysteresis}; use hal::gpio::GpioExt; use hal::prelude::OutputPin; use hal::rcc::RccExt; @@ -31,7 +31,7 @@ fn main() -> ! { let pa1 = gpioa.pa1.into_analog(); let pa0 = gpioa.pa0.into_analog(); - let comp1 = comp1.comparator(&pa1, pa0, Config::default(), &rcc.clocks); + let comp1 = comp1.comparator(pa1, pa0, Config::default(), &rcc.clocks); let comp1 = comp1.enable(); // led1 pa1 will be updated manually when to match comp1 value @@ -39,8 +39,8 @@ fn main() -> ! { let pa7 = gpioa.pa7.into_analog(); let comp2 = comp2.comparator( - &pa7, - RefintInput::VRefintM12, + pa7, + refint_input::VRefintM12, Config::default() .hysteresis(Hysteresis::None) .output_inverted(), diff --git a/src/comparator.rs b/src/comparator.rs index b5e80fc4..6b0bdbed 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -34,6 +34,7 @@ use crate::gpio::{ use crate::gpio::gpioc::{PC0, PC1}; use crate::gpio::gpioe::{PE7, PE8}; use crate::gpio::gpiof::PF1; +use crate::observable::IntoObservationToken; use crate::rcc::{Clocks, Rcc}; use crate::stm32::{COMP, EXTI}; @@ -140,7 +141,7 @@ pub enum Hysteresis { /// Comparator positive input pub trait PositiveInput { - fn setup(&self, comp: &C); + fn setup(comp: &mut C); } /// Comparator negative input @@ -153,21 +154,21 @@ pub trait NegativeInput { /// Does this input rely on dividing Vrefint using an internal resistor divider /// /// This is only relevant for `RefintInput` other than `RefintInput::VRefint` - fn use_resistor_divider(&self) -> bool; + const USE_RESISTOR_DIVIDER: bool = false; - fn setup(&self, comp: &C); + fn setup(comp: &mut C); } macro_rules! positive_input_pin { ($COMP:ident, $pin_0:ident, $pin_1:ident) => { - impl PositiveInput<$COMP> for &$pin_0 { - fn setup(&self, comp: &$COMP) { + impl PositiveInput<$COMP> for $pin_0 { + fn setup(comp: &mut $COMP) { comp.csr().modify(|_, w| w.inpsel().bit(false)); } } - impl PositiveInput<$COMP> for &$pin_1 { - fn setup(&self, comp: &$COMP) { + impl PositiveInput<$COMP> for $pin_1 { + fn setup(comp: &mut $COMP) { comp.csr().modify(|_, w| w.inpsel().bit(true)); } } @@ -208,11 +209,7 @@ macro_rules! negative_input_pin_helper { impl NegativeInput<$COMP> for $input { const USE_VREFINT: bool = false; - fn use_resistor_divider(&self) -> bool { - false - } - - fn setup(&self, comp: &$COMP) { + fn setup(comp: &mut $COMP) { comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) }); } } @@ -245,30 +242,54 @@ negative_input_pin! { COMP7: PD15, PB12, } -#[derive(Copy, Clone, Eq, PartialEq)] -pub enum RefintInput { +pub mod refint_input { /// VRefint * 1/4 - VRefintM14 = 0b000, + #[derive(Copy, Clone)] + pub struct VRefintM14; + /// VRefint * 1/2 - VRefintM12 = 0b001, + #[derive(Copy, Clone)] + pub struct VRefintM12; + /// VRefint * 3/4 - VRefintM34 = 0b010, + #[derive(Copy, Clone)] + pub struct VRefintM34; + /// VRefint - VRefint = 0b011, + #[derive(Copy, Clone)] + pub struct VRefint; + macro_rules! impl_vrefint { + ($t:ty, $bits:expr, $use_r_div:expr) => { + impl super::RefintInput for $t { + const BITS: u8 = $bits; + const USE_RESISTOR_DIVIDER: bool = $use_r_div; + } + + impl crate::observable::Observable for $t {} + impl crate::Sealed for $t {} + }; + } + + impl_vrefint!(VRefintM14, 0b000, true); + impl_vrefint!(VRefintM12, 0b001, true); + impl_vrefint!(VRefintM34, 0b010, true); + impl_vrefint!(VRefint, 0b011, false); +} + +pub trait RefintInput { + const BITS: u8; + const USE_RESISTOR_DIVIDER: bool; } macro_rules! refint_input { ($($COMP:ident, )+) => {$( - impl NegativeInput<$COMP> for RefintInput { + impl NegativeInput<$COMP> for REF { const USE_VREFINT: bool = true; + const USE_RESISTOR_DIVIDER: bool = ::USE_RESISTOR_DIVIDER; - fn use_resistor_divider(&self) -> bool { - *self != RefintInput::VRefint - } - - fn setup(&self, comp: &$COMP) { + fn setup(comp: &mut $COMP) { comp.csr() - .modify(|_, w| unsafe { w.inmsel().bits(*self as u8) }); + .modify(|_, w| unsafe { w.inmsel().bits(::BITS) }); } } )+}; @@ -289,11 +310,7 @@ macro_rules! dac_input_helper { impl NegativeInput<$COMP> for &dac::$channel<{ dac::$MODE }, ED> { const USE_VREFINT: bool = false; - fn use_resistor_divider(&self) -> bool { - false - } - - fn setup(&self, comp: &$COMP) { + fn setup(comp: &mut $COMP) { comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) }); } } @@ -371,27 +388,38 @@ pub struct Comparator { pub trait ComparatorExt { /// Initializes a comparator - fn comparator, N: NegativeInput>( + fn comparator( self, positive_input: P, negative_input: N, config: Config, clocks: &Clocks, - ) -> Comparator; + ) -> Comparator + where + PP: PositiveInput, + NP: NegativeInput, + P: IntoObservationToken, + N: IntoObservationToken; } macro_rules! impl_comparator { ($COMP:ty, $comp:ident, $Event:expr) => { impl ComparatorExt<$COMP> for $COMP { - fn comparator, N: NegativeInput<$COMP>>( - self, - positive_input: P, - negative_input: N, + fn comparator( + mut self, + _positive_input: P, // TODO: Store these + _negative_input: N, // TODO: Store these config: Config, clocks: &Clocks, - ) -> Comparator<$COMP, Disabled> { - positive_input.setup(&self); - negative_input.setup(&self); + ) -> Comparator<$COMP, Disabled> + where + PP: PositiveInput<$COMP>, + NP: NegativeInput<$COMP>, + P: IntoObservationToken, + N: IntoObservationToken, + { + PP::setup(&mut self); + PP::setup(&mut self); // Delay for scaler voltage bridge initialization for certain negative inputs let voltage_scaler_delay = clocks.sys_clk.raw() / (1_000_000 / 200); // 200us cortex_m::asm::delay(voltage_scaler_delay); @@ -399,9 +427,9 @@ macro_rules! impl_comparator { w.hyst() .bits(config.hysteresis as u8) .scalen() - .bit(N::USE_VREFINT) + .bit(NP::USE_VREFINT) .brgen() - .bit(negative_input.use_resistor_divider()) + .bit(NP::USE_RESISTOR_DIVIDER) .pol() .bit(config.inverted) }); @@ -415,13 +443,19 @@ macro_rules! impl_comparator { impl Comparator<$COMP, Disabled> { /// Initializes a comparator - pub fn $comp, N: NegativeInput<$COMP>>( + pub fn $comp( comp: $COMP, positive_input: P, negative_input: N, config: Config, clocks: &Clocks, - ) -> Self { + ) -> Self + where + PP: PositiveInput<$COMP>, + NP: NegativeInput<$COMP>, + P: IntoObservationToken, + N: IntoObservationToken, + { comp.comparator(positive_input, negative_input, config, clocks) } diff --git a/src/gpio.rs b/src/gpio.rs index 7bb05cef..00fdf28a 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,6 +1,7 @@ //! General Purpose Input / Output use core::marker::PhantomData; +use crate::observable::Observable; use crate::rcc::Rcc; use crate::stm32::EXTI; use crate::syscfg::SysCfg; @@ -379,6 +380,8 @@ macro_rules! gpio { } } + impl Observable for $PXi { } + impl $PXi { /// Configures the pin to operate as a floating input pin pub fn into_floating_input(self) -> $PXi> { diff --git a/src/lib.rs b/src/lib.rs index 93c12d07..57d0fabd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -84,6 +84,7 @@ pub mod exti; pub mod flash; pub mod gpio; pub mod i2c; +pub mod observable; pub mod opamp; pub mod prelude; pub mod pwm; diff --git a/src/observable.rs b/src/observable.rs new file mode 100644 index 00000000..969dc248 --- /dev/null +++ b/src/observable.rs @@ -0,0 +1,75 @@ +use crate::Sealed; +use core::marker::PhantomData; + +pub trait IntoObservationToken: Sized + crate::Sealed { + type Peripheral; + fn into_ot(self) -> ObservationToken; +} + +/// A struct to hold peripherals which are to be observed. +/// +/// This prevents the observed peripheral from being consumed. Thus +/// preventing things like a an observed gpio pin changing mode or an opamp from +/// being disabled. This makes sure the underlaying peripheral will not +/// change mode into something that is not compatible with what ever may be observing it. +pub struct Observed { + peripheral: P, +} + +impl Observed { + /// Release the observation of this peripheral + /// + /// This returns the underlaying perpheral type. Since it is no longer + /// observed, you are once again free to do what you want with it. + pub fn release(self, _data: [ObservationToken

; OBSERVER_COUNT]) -> P { + self.peripheral + } +} + +/// A struct to represent a registered observation of a peripheral of type `P` +/// +/// The existence of this type guarantees that the observed peripheral will not +/// change mode into something that is not compatibe with what ever is observing it +pub struct ObservationToken

{ + _p: PhantomData

, +} + +/// A trait providing an interface to make peripherals observed +/// +/// See [`Observed`] and [`ObservationToken`] +pub trait Observable: Sized { + fn observe(self) -> (Observed, [ObservationToken; N]) { + ( + Observed { peripheral: self }, + core::array::from_fn(|_| ObservationToken { _p: PhantomData }), + ) + } +} + +impl IntoObservationToken for P { + type Peripheral = P; + fn into_ot(self) -> ObservationToken { + let (_peripheral, [ot]) = self.observe(); + ot + } +} + +impl Sealed for ObservationToken

{} +impl IntoObservationToken for ObservationToken

{ + type Peripheral = P; + fn into_ot(self) -> Self { + self + } +} + +impl AsRef

for Observed { + fn as_ref(&self) -> &P { + &self.peripheral + } +} + +impl AsMut

for Observed { + fn as_mut(&mut self) -> &mut P { + &mut self.peripheral + } +}