Skip to content

Commit

Permalink
Implement Observable POC
Browse files Browse the repository at this point in the history
Co-authored-by: Adin Ackerman <[email protected]>
  • Loading branch information
usbalbin and AdinAck committed Dec 21, 2024
1 parent 899c279 commit 312436d
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 47 deletions.
8 changes: 4 additions & 4 deletions examples/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -31,16 +31,16 @@ 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
let mut led1 = gpioa.pa5.into_push_pull_output();

let pa7 = gpioa.pa7.into_analog();
let comp2 = comp2.comparator(
&pa7,
RefintInput::VRefintM12,
pa7,
refint_input::VRefintM12,
Config::default()
.hysteresis(Hysteresis::None)
.output_inverted(),
Expand Down
120 changes: 77 additions & 43 deletions src/comparator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -140,7 +141,7 @@ pub enum Hysteresis {

/// Comparator positive input
pub trait PositiveInput<C> {
fn setup(&self, comp: &C);
fn setup(comp: &mut C);
}

/// Comparator negative input
Expand All @@ -153,21 +154,21 @@ pub trait NegativeInput<C> {
/// 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<Analog> {
fn setup(&self, comp: &$COMP) {
impl PositiveInput<$COMP> for $pin_0<Analog> {
fn setup(comp: &mut $COMP) {
comp.csr().modify(|_, w| w.inpsel().bit(false));
}
}

impl PositiveInput<$COMP> for &$pin_1<Analog> {
fn setup(&self, comp: &$COMP) {
impl PositiveInput<$COMP> for $pin_1<Analog> {
fn setup(comp: &mut $COMP) {
comp.csr().modify(|_, w| w.inpsel().bit(true));
}
}
Expand Down Expand Up @@ -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) });
}
}
Expand Down Expand Up @@ -245,30 +242,54 @@ negative_input_pin! {
COMP7: PD15<Analog>, PB12<Analog>,
}

#[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<REF: RefintInput> NegativeInput<$COMP> for REF {
const USE_VREFINT: bool = true;
const USE_RESISTOR_DIVIDER: bool = <REF as RefintInput>::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(<REF as RefintInput>::BITS) });
}
}
)+};
Expand All @@ -289,11 +310,7 @@ macro_rules! dac_input_helper {
impl<ED> 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) });
}
}
Expand Down Expand Up @@ -371,37 +388,48 @@ pub struct Comparator<C, ED> {

pub trait ComparatorExt<COMP> {
/// Initializes a comparator
fn comparator<P: PositiveInput<COMP>, N: NegativeInput<COMP>>(
fn comparator<P, N, PP, NP>(
self,
positive_input: P,
negative_input: N,
config: Config,
clocks: &Clocks,
) -> Comparator<COMP, Disabled>;
) -> Comparator<COMP, Disabled>
where
PP: PositiveInput<COMP>,
NP: NegativeInput<COMP>,
P: IntoObservationToken<Peripheral = PP>,
N: IntoObservationToken<Peripheral = NP>;
}

macro_rules! impl_comparator {
($COMP:ty, $comp:ident, $Event:expr) => {
impl ComparatorExt<$COMP> for $COMP {
fn comparator<P: PositiveInput<$COMP>, N: NegativeInput<$COMP>>(
self,
positive_input: P,
negative_input: N,
fn comparator<P, N, PP, NP>(
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<Peripheral = PP>,
N: IntoObservationToken<Peripheral = NP>,
{
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);
self.csr().modify(|_, w| unsafe {
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)
});
Expand All @@ -415,13 +443,19 @@ macro_rules! impl_comparator {

impl Comparator<$COMP, Disabled> {
/// Initializes a comparator
pub fn $comp<P: PositiveInput<$COMP>, N: NegativeInput<$COMP>>(
pub fn $comp<P, N, PP, NP>(
comp: $COMP,
positive_input: P,
negative_input: N,
config: Config,
clocks: &Clocks,
) -> Self {
) -> Self
where
PP: PositiveInput<$COMP>,
NP: NegativeInput<$COMP>,
P: IntoObservationToken<Peripheral = PP>,
N: IntoObservationToken<Peripheral = NP>,
{
comp.comparator(positive_input, negative_input, config, clocks)
}

Expand Down
3 changes: 3 additions & 0 deletions src/gpio.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -379,6 +380,8 @@ macro_rules! gpio {
}
}

impl<MODE> Observable for $PXi<MODE> { }

impl<MODE> $PXi<MODE> {
/// Configures the pin to operate as a floating input pin
pub fn into_floating_input(self) -> $PXi<Input<Floating>> {
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
75 changes: 75 additions & 0 deletions src/observable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use crate::Sealed;
use core::marker::PhantomData;

pub trait IntoObservationToken: Sized + crate::Sealed {
type Peripheral;
fn into_ot(self) -> ObservationToken<Self::Peripheral>;
}

/// 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<P, const OBSERVER_COUNT: usize> {
peripheral: P,
}

impl<P, const OBSERVER_COUNT: usize> Observed<P, OBSERVER_COUNT> {
/// 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<P>; 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> {
_p: PhantomData<P>,
}

/// A trait providing an interface to make peripherals observed
///
/// See [`Observed`] and [`ObservationToken`]
pub trait Observable: Sized {
fn observe<const N: usize>(self) -> (Observed<Self, N>, [ObservationToken<Self>; N]) {
(
Observed { peripheral: self },
core::array::from_fn(|_| ObservationToken { _p: PhantomData }),
)
}
}

impl<P: Observable + Sealed> IntoObservationToken for P {
type Peripheral = P;
fn into_ot(self) -> ObservationToken<Self::Peripheral> {
let (_peripheral, [ot]) = self.observe();
ot
}
}

impl<P: Observable + Sealed> Sealed for ObservationToken<P> {}
impl<P: Observable + Sealed> IntoObservationToken for ObservationToken<P> {
type Peripheral = P;
fn into_ot(self) -> Self {
self
}
}

impl<P, const N: usize> AsRef<P> for Observed<P, N> {
fn as_ref(&self) -> &P {
&self.peripheral
}
}

impl<P, const N: usize> AsMut<P> for Observed<P, N> {
fn as_mut(&mut self) -> &mut P {
&mut self.peripheral
}
}

0 comments on commit 312436d

Please sign in to comment.