Skip to content

Commit 312436d

Browse files
usbalbinAdinAck
andcommitted
Implement Observable POC
Co-authored-by: Adin Ackerman <[email protected]>
1 parent 899c279 commit 312436d

File tree

5 files changed

+160
-47
lines changed

5 files changed

+160
-47
lines changed

examples/comp.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rt::entry;
1515

1616
#[entry]
1717
fn main() -> ! {
18-
use hal::comparator::{ComparatorExt, ComparatorSplit, Config, Hysteresis, RefintInput};
18+
use hal::comparator::{refint_input, ComparatorExt, ComparatorSplit, Config, Hysteresis};
1919
use hal::gpio::GpioExt;
2020
use hal::prelude::OutputPin;
2121
use hal::rcc::RccExt;
@@ -31,16 +31,16 @@ fn main() -> ! {
3131

3232
let pa1 = gpioa.pa1.into_analog();
3333
let pa0 = gpioa.pa0.into_analog();
34-
let comp1 = comp1.comparator(&pa1, pa0, Config::default(), &rcc.clocks);
34+
let comp1 = comp1.comparator(pa1, pa0, Config::default(), &rcc.clocks);
3535
let comp1 = comp1.enable();
3636

3737
// led1 pa1 will be updated manually when to match comp1 value
3838
let mut led1 = gpioa.pa5.into_push_pull_output();
3939

4040
let pa7 = gpioa.pa7.into_analog();
4141
let comp2 = comp2.comparator(
42-
&pa7,
43-
RefintInput::VRefintM12,
42+
pa7,
43+
refint_input::VRefintM12,
4444
Config::default()
4545
.hysteresis(Hysteresis::None)
4646
.output_inverted(),

src/comparator.rs

Lines changed: 77 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use crate::gpio::{
3434
use crate::gpio::gpioc::{PC0, PC1};
3535
use crate::gpio::gpioe::{PE7, PE8};
3636
use crate::gpio::gpiof::PF1;
37+
use crate::observable::IntoObservationToken;
3738
use crate::rcc::{Clocks, Rcc};
3839
use crate::stm32::{COMP, EXTI};
3940

@@ -140,7 +141,7 @@ pub enum Hysteresis {
140141

141142
/// Comparator positive input
142143
pub trait PositiveInput<C> {
143-
fn setup(&self, comp: &C);
144+
fn setup(comp: &mut C);
144145
}
145146

146147
/// Comparator negative input
@@ -153,21 +154,21 @@ pub trait NegativeInput<C> {
153154
/// Does this input rely on dividing Vrefint using an internal resistor divider
154155
///
155156
/// This is only relevant for `RefintInput` other than `RefintInput::VRefint`
156-
fn use_resistor_divider(&self) -> bool;
157+
const USE_RESISTOR_DIVIDER: bool = false;
157158

158-
fn setup(&self, comp: &C);
159+
fn setup(comp: &mut C);
159160
}
160161

161162
macro_rules! positive_input_pin {
162163
($COMP:ident, $pin_0:ident, $pin_1:ident) => {
163-
impl PositiveInput<$COMP> for &$pin_0<Analog> {
164-
fn setup(&self, comp: &$COMP) {
164+
impl PositiveInput<$COMP> for $pin_0<Analog> {
165+
fn setup(comp: &mut $COMP) {
165166
comp.csr().modify(|_, w| w.inpsel().bit(false));
166167
}
167168
}
168169

169-
impl PositiveInput<$COMP> for &$pin_1<Analog> {
170-
fn setup(&self, comp: &$COMP) {
170+
impl PositiveInput<$COMP> for $pin_1<Analog> {
171+
fn setup(comp: &mut $COMP) {
171172
comp.csr().modify(|_, w| w.inpsel().bit(true));
172173
}
173174
}
@@ -208,11 +209,7 @@ macro_rules! negative_input_pin_helper {
208209
impl NegativeInput<$COMP> for $input {
209210
const USE_VREFINT: bool = false;
210211

211-
fn use_resistor_divider(&self) -> bool {
212-
false
213-
}
214-
215-
fn setup(&self, comp: &$COMP) {
212+
fn setup(comp: &mut $COMP) {
216213
comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) });
217214
}
218215
}
@@ -245,30 +242,54 @@ negative_input_pin! {
245242
COMP7: PD15<Analog>, PB12<Analog>,
246243
}
247244

248-
#[derive(Copy, Clone, Eq, PartialEq)]
249-
pub enum RefintInput {
245+
pub mod refint_input {
250246
/// VRefint * 1/4
251-
VRefintM14 = 0b000,
247+
#[derive(Copy, Clone)]
248+
pub struct VRefintM14;
249+
252250
/// VRefint * 1/2
253-
VRefintM12 = 0b001,
251+
#[derive(Copy, Clone)]
252+
pub struct VRefintM12;
253+
254254
/// VRefint * 3/4
255-
VRefintM34 = 0b010,
255+
#[derive(Copy, Clone)]
256+
pub struct VRefintM34;
257+
256258
/// VRefint
257-
VRefint = 0b011,
259+
#[derive(Copy, Clone)]
260+
pub struct VRefint;
261+
macro_rules! impl_vrefint {
262+
($t:ty, $bits:expr, $use_r_div:expr) => {
263+
impl super::RefintInput for $t {
264+
const BITS: u8 = $bits;
265+
const USE_RESISTOR_DIVIDER: bool = $use_r_div;
266+
}
267+
268+
impl crate::observable::Observable for $t {}
269+
impl crate::Sealed for $t {}
270+
};
271+
}
272+
273+
impl_vrefint!(VRefintM14, 0b000, true);
274+
impl_vrefint!(VRefintM12, 0b001, true);
275+
impl_vrefint!(VRefintM34, 0b010, true);
276+
impl_vrefint!(VRefint, 0b011, false);
277+
}
278+
279+
pub trait RefintInput {
280+
const BITS: u8;
281+
const USE_RESISTOR_DIVIDER: bool;
258282
}
259283

260284
macro_rules! refint_input {
261285
($($COMP:ident, )+) => {$(
262-
impl NegativeInput<$COMP> for RefintInput {
286+
impl<REF: RefintInput> NegativeInput<$COMP> for REF {
263287
const USE_VREFINT: bool = true;
288+
const USE_RESISTOR_DIVIDER: bool = <REF as RefintInput>::USE_RESISTOR_DIVIDER;
264289

265-
fn use_resistor_divider(&self) -> bool {
266-
*self != RefintInput::VRefint
267-
}
268-
269-
fn setup(&self, comp: &$COMP) {
290+
fn setup(comp: &mut $COMP) {
270291
comp.csr()
271-
.modify(|_, w| unsafe { w.inmsel().bits(*self as u8) });
292+
.modify(|_, w| unsafe { w.inmsel().bits(<REF as RefintInput>::BITS) });
272293
}
273294
}
274295
)+};
@@ -289,11 +310,7 @@ macro_rules! dac_input_helper {
289310
impl<ED> NegativeInput<$COMP> for &dac::$channel<{ dac::$MODE }, ED> {
290311
const USE_VREFINT: bool = false;
291312

292-
fn use_resistor_divider(&self) -> bool {
293-
false
294-
}
295-
296-
fn setup(&self, comp: &$COMP) {
313+
fn setup(comp: &mut $COMP) {
297314
comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) });
298315
}
299316
}
@@ -371,37 +388,48 @@ pub struct Comparator<C, ED> {
371388

372389
pub trait ComparatorExt<COMP> {
373390
/// Initializes a comparator
374-
fn comparator<P: PositiveInput<COMP>, N: NegativeInput<COMP>>(
391+
fn comparator<P, N, PP, NP>(
375392
self,
376393
positive_input: P,
377394
negative_input: N,
378395
config: Config,
379396
clocks: &Clocks,
380-
) -> Comparator<COMP, Disabled>;
397+
) -> Comparator<COMP, Disabled>
398+
where
399+
PP: PositiveInput<COMP>,
400+
NP: NegativeInput<COMP>,
401+
P: IntoObservationToken<Peripheral = PP>,
402+
N: IntoObservationToken<Peripheral = NP>;
381403
}
382404

383405
macro_rules! impl_comparator {
384406
($COMP:ty, $comp:ident, $Event:expr) => {
385407
impl ComparatorExt<$COMP> for $COMP {
386-
fn comparator<P: PositiveInput<$COMP>, N: NegativeInput<$COMP>>(
387-
self,
388-
positive_input: P,
389-
negative_input: N,
408+
fn comparator<P, N, PP, NP>(
409+
mut self,
410+
_positive_input: P, // TODO: Store these
411+
_negative_input: N, // TODO: Store these
390412
config: Config,
391413
clocks: &Clocks,
392-
) -> Comparator<$COMP, Disabled> {
393-
positive_input.setup(&self);
394-
negative_input.setup(&self);
414+
) -> Comparator<$COMP, Disabled>
415+
where
416+
PP: PositiveInput<$COMP>,
417+
NP: NegativeInput<$COMP>,
418+
P: IntoObservationToken<Peripheral = PP>,
419+
N: IntoObservationToken<Peripheral = NP>,
420+
{
421+
PP::setup(&mut self);
422+
PP::setup(&mut self);
395423
// Delay for scaler voltage bridge initialization for certain negative inputs
396424
let voltage_scaler_delay = clocks.sys_clk.raw() / (1_000_000 / 200); // 200us
397425
cortex_m::asm::delay(voltage_scaler_delay);
398426
self.csr().modify(|_, w| unsafe {
399427
w.hyst()
400428
.bits(config.hysteresis as u8)
401429
.scalen()
402-
.bit(N::USE_VREFINT)
430+
.bit(NP::USE_VREFINT)
403431
.brgen()
404-
.bit(negative_input.use_resistor_divider())
432+
.bit(NP::USE_RESISTOR_DIVIDER)
405433
.pol()
406434
.bit(config.inverted)
407435
});
@@ -415,13 +443,19 @@ macro_rules! impl_comparator {
415443

416444
impl Comparator<$COMP, Disabled> {
417445
/// Initializes a comparator
418-
pub fn $comp<P: PositiveInput<$COMP>, N: NegativeInput<$COMP>>(
446+
pub fn $comp<P, N, PP, NP>(
419447
comp: $COMP,
420448
positive_input: P,
421449
negative_input: N,
422450
config: Config,
423451
clocks: &Clocks,
424-
) -> Self {
452+
) -> Self
453+
where
454+
PP: PositiveInput<$COMP>,
455+
NP: NegativeInput<$COMP>,
456+
P: IntoObservationToken<Peripheral = PP>,
457+
N: IntoObservationToken<Peripheral = NP>,
458+
{
425459
comp.comparator(positive_input, negative_input, config, clocks)
426460
}
427461

src/gpio.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! General Purpose Input / Output
22
use core::marker::PhantomData;
33

4+
use crate::observable::Observable;
45
use crate::rcc::Rcc;
56
use crate::stm32::EXTI;
67
use crate::syscfg::SysCfg;
@@ -379,6 +380,8 @@ macro_rules! gpio {
379380
}
380381
}
381382

383+
impl<MODE> Observable for $PXi<MODE> { }
384+
382385
impl<MODE> $PXi<MODE> {
383386
/// Configures the pin to operate as a floating input pin
384387
pub fn into_floating_input(self) -> $PXi<Input<Floating>> {

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ pub mod exti;
8484
pub mod flash;
8585
pub mod gpio;
8686
pub mod i2c;
87+
pub mod observable;
8788
pub mod opamp;
8889
pub mod prelude;
8990
pub mod pwm;

src/observable.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use crate::Sealed;
2+
use core::marker::PhantomData;
3+
4+
pub trait IntoObservationToken: Sized + crate::Sealed {
5+
type Peripheral;
6+
fn into_ot(self) -> ObservationToken<Self::Peripheral>;
7+
}
8+
9+
/// A struct to hold peripherals which are to be observed.
10+
///
11+
/// This prevents the observed peripheral from being consumed. Thus
12+
/// preventing things like a an observed gpio pin changing mode or an opamp from
13+
/// being disabled. This makes sure the underlaying peripheral will not
14+
/// change mode into something that is not compatible with what ever may be observing it.
15+
pub struct Observed<P, const OBSERVER_COUNT: usize> {
16+
peripheral: P,
17+
}
18+
19+
impl<P, const OBSERVER_COUNT: usize> Observed<P, OBSERVER_COUNT> {
20+
/// Release the observation of this peripheral
21+
///
22+
/// This returns the underlaying perpheral type. Since it is no longer
23+
/// observed, you are once again free to do what you want with it.
24+
pub fn release(self, _data: [ObservationToken<P>; OBSERVER_COUNT]) -> P {
25+
self.peripheral
26+
}
27+
}
28+
29+
/// A struct to represent a registered observation of a peripheral of type `P`
30+
///
31+
/// The existence of this type guarantees that the observed peripheral will not
32+
/// change mode into something that is not compatibe with what ever is observing it
33+
pub struct ObservationToken<P> {
34+
_p: PhantomData<P>,
35+
}
36+
37+
/// A trait providing an interface to make peripherals observed
38+
///
39+
/// See [`Observed`] and [`ObservationToken`]
40+
pub trait Observable: Sized {
41+
fn observe<const N: usize>(self) -> (Observed<Self, N>, [ObservationToken<Self>; N]) {
42+
(
43+
Observed { peripheral: self },
44+
core::array::from_fn(|_| ObservationToken { _p: PhantomData }),
45+
)
46+
}
47+
}
48+
49+
impl<P: Observable + Sealed> IntoObservationToken for P {
50+
type Peripheral = P;
51+
fn into_ot(self) -> ObservationToken<Self::Peripheral> {
52+
let (_peripheral, [ot]) = self.observe();
53+
ot
54+
}
55+
}
56+
57+
impl<P: Observable + Sealed> Sealed for ObservationToken<P> {}
58+
impl<P: Observable + Sealed> IntoObservationToken for ObservationToken<P> {
59+
type Peripheral = P;
60+
fn into_ot(self) -> Self {
61+
self
62+
}
63+
}
64+
65+
impl<P, const N: usize> AsRef<P> for Observed<P, N> {
66+
fn as_ref(&self) -> &P {
67+
&self.peripheral
68+
}
69+
}
70+
71+
impl<P, const N: usize> AsMut<P> for Observed<P, N> {
72+
fn as_mut(&mut self) -> &mut P {
73+
&mut self.peripheral
74+
}
75+
}

0 commit comments

Comments
 (0)