Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Observable POC #157

Draft
wants to merge 11 commits into
base: staged-pac
Choose a base branch
from
Draft
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
10 changes: 6 additions & 4 deletions examples/comp_w_dac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod utils;
extern crate cortex_m_rt as rt;

use rt::entry;
use stm32g4xx_hal::observable::Observable;

#[entry]
fn main() -> ! {
Expand All @@ -30,15 +31,16 @@ 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 dac = dac1ch1.calibrate_buffer(&mut delay).enable();
let (mut dac, [dac_token]) = dac.observe();

let (comp1, _comp2, ..) = dp.COMP.split(&mut rcc);
let pa1 = gpioa.pa1.into_analog();

// Set up comparator with pa1 as positive, and the DAC as negative input
let comp = comp1.comparator(
&pa1,
&dac,
pa1,
dac_token,
comparator::Config::default().hysteresis(comparator::Hysteresis::None),
&rcc.clocks,
);
Expand All @@ -59,7 +61,7 @@ fn main() -> ! {
// * 0V at p1 => 0% duty
// * VDDA at p1 => 100% duty
loop {
dac.set_value(val);
dac.as_mut().set_value(val);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we even go as far as implementing Deref{Mut} for Observed?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, Deref will be a really good QoL feature.

match val {
0 => dir = Direction::Upcounting,
4095 => dir = Direction::Downcounting,
Expand Down
126 changes: 80 additions & 46 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::ObservationLock;
use crate::rcc::{Clocks, Rcc};
use crate::stm32::{COMP, EXTI};

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

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

/// Comparator negative input
pub trait NegativeInput<C> {
/// Does this input use the internal reference Vrefint
///
/// This only true for RefintInput
/// This only true for [`RefintInput`]
const USE_VREFINT: bool;

/// 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;
/// This is only relevant for [`RefintInput`] other than [`refint_input::VRefint`]
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 @@ -286,14 +307,10 @@ 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> {
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: ObservationLock<Peripheral = PP>,
N: ObservationLock<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: ObservationLock<Peripheral = PP>,
N: ObservationLock<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: ObservationLock<Peripheral = PP>,
N: ObservationLock<Peripheral = NP>,
{
comp.comparator(positive_input, negative_input, config, clocks)
}

Expand Down
3 changes: 3 additions & 0 deletions src/dac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ macro_rules! dac_helper {
}
}

impl<const MODE_BITS: u8, ED> crate::Sealed for $CX<MODE_BITS, ED> { }
impl<const MODE_BITS: u8, ED> crate::observable::Observable for $CX<MODE_BITS, ED> { }

impl<const MODE_BITS: u8, ED> $CX<MODE_BITS, ED> {
/// Calibrate the DAC output buffer by performing a "User
/// trimming" operation. It is useful when the VDDA/VREF+
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
Loading
Loading