Skip to content

Commit

Permalink
Make use of frozen pins
Browse files Browse the repository at this point in the history
  • Loading branch information
usbalbin committed Sep 21, 2024
1 parent 2cf31fc commit 1b80d08
Show file tree
Hide file tree
Showing 7 changed files with 525 additions and 517 deletions.
2 changes: 1 addition & 1 deletion examples/comp_w_dac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ fn main() -> ! {
// Set up DAC to output to pa4 and to internal signal Dac1IntSig1
// which just so happens is compatible with comp1
let dac1ch1 = dp.DAC1.constrain((gpioa.pa4, Dac1IntSig1), &mut rcc);
let mut dac = dac1ch1.calibrate_buffer(&mut delay).enable();
let mut dac = dac1ch1.calibrate_buffer(&mut delay).enable().freeze();

let (comp1, _comp2, ..) = dp.COMP.split(&mut rcc);
let pa1 = gpioa.pa1.into_analog();
Expand Down
44 changes: 16 additions & 28 deletions examples/opamp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,35 +31,25 @@ fn main() -> ! {
let gpioa = dp.GPIOA.split(&mut rcc);
let gpiob = dp.GPIOB.split(&mut rcc);

// setup opamps
let (opamp1, opamp2, opamp3, ..) = dp.OPAMP.split(&mut rcc);

// Set up opamp1 and opamp2 in follower mode
let opamp1 = opamp1.follower(gpioa.pa1, gpioa.pa2);
let opamp2 = opamp2.follower(gpioa.pa7, InternalOutput);

// Set up opamp1 and opamp2 in open loop mode
let opamp3 = opamp3.open_loop(gpiob.pb0, gpiob.pb2, gpiob.pb1);
let pa1 = gpioa.pa1.into_analog();
let pa2 = gpioa.pa2.into_analog();
let pa7 = gpioa.pa7.into_analog();

// disable opamps
let (opamp1, pa1, pa2) = opamp1.disable();
let (opamp2, pa7) = opamp2.disable();
let pb0 = gpiob.pb0.into_analog();
let pb1 = gpiob.pb1.into_analog();
let pb2 = gpiob.pb2.into_analog();

let (_opamp3, _pb0, _pb2, _pb1) = opamp3.disable();
// setup opamps
let (opamp1, opamp2, opamp3, ..) = dp.OPAMP.split(&mut rcc);

// Configure opamp1 with pa1 as non-inverting input and set gain to x2
let _opamp1 = opamp1.pga(
pa1,
pa2, // Route output to pin pa2
Gain::Gain2,
);

// Configure op with pa7 as non-inverting input and set gain to x4
let opamp2 = opamp2.pga(
pa7,
InternalOutput, // Do not route output to any external pin, use internal AD instead
Gain::Gain4,
);
let _opamp1 = opamp1.pga(&pa1, pa2, Gain::Gain2);

// Set up opamp2 in follower mode with output routed to internal ADC
let opamp2 = opamp2.follower(&pa7, InternalOutput);

// Set up opamp3 in open loop mode
let _opamp3 = opamp3.open_loop(&pb0, pb2, pb1);

// Lock opamp2. After the opamp is locked its registers cannot be written
// until the device is reset (even if using unsafe register accesses).
Expand All @@ -78,15 +68,13 @@ fn main() -> ! {
);

let millivolts = adc.sample_to_millivolts(sample);
info!("opamp2 thus 4x pa7: {}mV", millivolts);
info!("opamp2 thus pa7: {}mV", millivolts);

delay.delay_ms(100);
}

#[allow(unreachable_code)]
{
let (_opamp1, _pin) = _opamp1.disable();

loop {
delay.delay_ms(100);
}
Expand Down
120 changes: 87 additions & 33 deletions src/comparator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@
//! This code has been taken from the stm32g0xx-hal project and modified slightly to support
//! STM32G4xx MCUs.
use core::borrow::Borrow;
use core::marker::PhantomData;

use crate::dac;
use crate::exti::{Event as ExtiEvent, ExtiExt};
use crate::gpio::{FrozenPin, IsFrozen};
use crate::gpio::{
gpioa::{PA0, PA1, PA11, PA12, PA2, PA3, PA4, PA5, PA6, PA7},
gpiob::{PB0, PB1, PB14, PB15, PB2, PB6, PB7, PB8, PB9},
gpioc::PC2,
gpiof::PF4,
Analog, Alternate, AlternateOD, SignalEdge, AF2, AF3, AF8,
Alternate, AlternateOD, Analog, SignalEdge, AF2, AF3, AF8,
};

#[cfg(any(
Expand Down Expand Up @@ -139,12 +141,17 @@ pub enum Hysteresis {
}

/// Comparator positive input
pub trait PositiveInput<C> {
fn setup(&self, comp: &C);
pub trait PositiveInput<C>: crate::Sealed {
/// Setup comaprator to use this as its positive input
///
/// # Safety
///
/// Internal use only
unsafe fn setup(&self, comp: &mut C);
}

/// Comparator negative input
pub trait NegativeInput<C> {
pub trait NegativeInput<C>: crate::Sealed {
/// Does this input use the internal reference Vrefint
///
/// This only true for RefintInput
Expand All @@ -155,19 +162,36 @@ pub trait NegativeInput<C> {
/// This is only relevant for `RefintInput` other than `RefintInput::VRefint`
fn use_resistor_divider(&self) -> bool;

fn setup(&self, comp: &C);
/// Setup comaprator to use this as its negative input
///
/// # Safety
///
/// Internal use only
unsafe fn setup(&self, 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, IsFrozen> {
unsafe fn setup(&self, comp: &mut $COMP) {
comp.csr().modify(|_, w| w.inpsel().bit(false))
}
}

impl PositiveInput<$COMP> for $pin_0<Analog> {
unsafe fn setup(&self, 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, IsFrozen> {
unsafe fn setup(&self, comp: &mut $COMP) {
comp.csr().modify(|_, w| w.inpsel().bit(true))
}
}

impl PositiveInput<$COMP> for $pin_1<Analog> {
unsafe fn setup(&self, comp: &mut $COMP) {
comp.csr().modify(|_, w| w.inpsel().bit(true))
}
}
Expand Down Expand Up @@ -212,7 +236,7 @@ macro_rules! negative_input_pin_helper {
false
}

fn setup(&self, comp: &$COMP) {
unsafe fn setup(&self, comp: &mut $COMP) {
comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) })
}
}
Expand Down Expand Up @@ -257,6 +281,9 @@ pub enum RefintInput {
VRefint = 0b011,
}

impl FrozenPin<RefintInput> for RefintInput {}
impl crate::Sealed for RefintInput {}

macro_rules! refint_input {
($($COMP:ident, )+) => {$(
impl NegativeInput<$COMP> for RefintInput {
Expand All @@ -266,7 +293,7 @@ macro_rules! refint_input {
*self != RefintInput::VRefint
}

fn setup(&self, comp: &$COMP) {
unsafe fn setup(&self, comp: &mut $COMP) {
comp.csr()
.modify(|_, w| unsafe { w.inmsel().bits(*self as u8) })
}
Expand All @@ -285,15 +312,27 @@ refint_input!(COMP1, COMP2, COMP3, COMP4,);
refint_input!(COMP5, COMP6, COMP7,);

macro_rules! dac_input_helper {
($COMP:ident: $channel:ident, $MODE:ident, $bits:expr) => {
impl<ED> NegativeInput<$COMP> for &dac::$channel<{ dac::$MODE }, ED> {
($COMP:ident: $channel:ident, $MODE:ident, $ED:ty, $bits:expr) => {
impl NegativeInput<$COMP> for &dac::$channel<{ dac::$MODE }, $ED, IsFrozen> {
const USE_VREFINT: bool = false;

fn use_resistor_divider(&self) -> bool {
false
}

fn setup(&self, comp: &$COMP) {
unsafe fn setup(&self, comp: &mut $COMP) {
comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) })
}
}

impl NegativeInput<$COMP> for dac::$channel<{ dac::$MODE }, $ED> {
const USE_VREFINT: bool = false;

fn use_resistor_divider(&self) -> bool {
false
}

unsafe fn setup(&self, comp: &mut $COMP) {
comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) })
}
}
Expand All @@ -302,8 +341,10 @@ macro_rules! dac_input_helper {

macro_rules! dac_input {
($COMP:ident: $channel:ident, $bits:expr) => {
dac_input_helper!($COMP: $channel, M_MIX_SIG, $bits);
dac_input_helper!($COMP: $channel, M_INT_SIG, $bits);
dac_input_helper!($COMP: $channel, M_MIX_SIG, dac::Enabled, $bits);
dac_input_helper!($COMP: $channel, M_MIX_SIG, dac::WaveGenerator, $bits);
dac_input_helper!($COMP: $channel, M_INT_SIG, dac::Enabled, $bits);
dac_input_helper!($COMP: $channel, M_INT_SIG, dac::WaveGenerator, $bits);
};
}

Expand Down Expand Up @@ -371,37 +412,46 @@ pub struct Comparator<C, ED> {

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

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<PP, NP, P, N>(
mut self,
positive_input: PP,
negative_input: NP,
config: Config,
clocks: &Clocks,
) -> Comparator<$COMP, Disabled> {
positive_input.setup(&self);
negative_input.setup(&self);
) -> Comparator<$COMP, Disabled>
where
PP: FrozenPin<P> + PositiveInput<$COMP>,
NP: FrozenPin<N> + NegativeInput<$COMP>
{
unsafe {
positive_input.borrow().setup(&mut self);
negative_input.borrow().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(negative_input.borrow().use_resistor_divider())
.pol()
.bit(config.inverted)
});
Expand All @@ -415,13 +465,17 @@ macro_rules! impl_comparator {

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

Expand Down
Loading

0 comments on commit 1b80d08

Please sign in to comment.