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

More ergonomic opamp API, add lock and pga functionality #113

Merged
merged 20 commits into from
Sep 21, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 16 additions & 18 deletions examples/opamp.rs
Original file line number Diff line number Diff line change
@@ -5,12 +5,7 @@

use stm32g4xx_hal::adc::AdcClaim;
use stm32g4xx_hal::adc::ClockSource;
use stm32g4xx_hal::gpio::gpioa::*;
use stm32g4xx_hal::gpio::Analog;
use stm32g4xx_hal::opamp::opamp1::IntoPga as _;
use stm32g4xx_hal::opamp::opamp2::IntoPga as _;
use stm32g4xx_hal::opamp::NonInvertingGain;
use stm32g4xx_hal::opamp::PgaModeInternal;
use stm32g4xx_hal::opamp::{Gain, InternalOutput};
use stm32g4xx_hal::prelude::*;
use stm32g4xx_hal::pwr::PwrExt;

@@ -40,32 +35,36 @@ fn main() -> ! {
let (opamp1, opamp2, opamp3, ..) = dp.OPAMP.split(&mut rcc);

// Set up opamp1 and opamp2 in follower mode
let opamp1 = opamp1.follower(gpioa.pa1, Some(gpioa.pa2));
let opamp2 = opamp2.follower(gpioa.pa7, Option::<PA6<Analog>>::None);
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, Some(gpiob.pb1));
let opamp3 = opamp3.open_loop(gpiob.pb0, gpiob.pb2, gpiob.pb1);

// disable opamps
let (opamp1, pa1, some_pa2) = opamp1.disable();
let (opamp2, pa7, _none) = opamp2.disable();
let (opamp1, pa1, pa2) = opamp1.disable();
let (opamp2, pa7) = opamp2.disable();

let (_opamp3, _pb0, _pb2, _some_pb1) = opamp3.disable();
let (_opamp3, _pb0, _pb2, _pb1) = opamp3.disable();

// Configure opamp1 with pa1 as non-inverting input and set gain to x2
let _opamp1 = opamp1.pga(
pa1,
PgaModeInternal::gain(NonInvertingGain::Gain2),
some_pa2, // Route output to pin pa2
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,
PgaModeInternal::gain(NonInvertingGain::Gain4),
Option::<PA6<Analog>>::None, // Do not route output to any external pin, use internal AD instead
InternalOutput, // Do not route output to any external pin, use internal AD instead
Gain::Gain4,
);

// Lock opamp2. After the opamp is locked its registers cannot be written
// until the device is reset (even if using unsafe register accesses).
let opamp2 = opamp2.lock();

let mut delay = cp.SYST.delay(&rcc.clocks);
let mut adc = dp
.ADC2
@@ -86,8 +85,7 @@ fn main() -> ! {

#[allow(unreachable_code)]
{
let (_opamp1, _pa1, _mode) = _opamp1.disable();
let (_opamp2, _pa7, _mode) = opamp2.disable();
let (_opamp1, _pin) = _opamp1.disable();

loop {
delay.delay_ms(100);
54 changes: 25 additions & 29 deletions src/adc.rs
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ pub use crate::time::U32Ext as _;
use crate::{
dma::{mux::DmaMuxResources, traits::TargetAddress, PeripheralToMemory},
gpio::*,
opamp,
opamp::{self, InternalOutput},
rcc::{Enable, Rcc, Reset},
signature::{VtempCal130, VtempCal30, VDDA_CALIB},
stm32,
@@ -144,21 +144,25 @@ macro_rules! adc_pins {
};
}

macro_rules! adc_op_pga {
macro_rules! adc_opamp {
($($opamp:ty => ($adc:ident, $chan:expr)),+ $(,)*) => {
$(
impl<A, B> Channel<stm32::$adc> for $opamp {
impl<A> Channel<stm32::$adc> for opamp::Follower<$opamp, A, InternalOutput> {
type ID = u8;
fn channel() -> u8 { $chan }
}
)+
};
}

macro_rules! adc_op_follower {
($($opamp:ty => ($adc:ident, $chan:expr)),+ $(,)*) => {
$(
impl<A> Channel<stm32::$adc> for $opamp {
impl<A, B> Channel<stm32::$adc> for opamp::OpenLoop<$opamp, A, B, InternalOutput> {
type ID = u8;
fn channel() -> u8 { $chan }
}

impl<A> Channel<stm32::$adc> for opamp::Pga<$opamp, A, InternalOutput> {
type ID = u8;
fn channel() -> u8 { $chan }
}

impl Channel<stm32::$adc> for opamp::Locked<$opamp, InternalOutput> {
type ID = u8;
fn channel() -> u8 { $chan }
}
@@ -2722,21 +2726,13 @@ adc_pins!(
);

// See https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf#page=782
adc_op_pga!(
adc_opamp!(
// TODO: Add all opamp types: OpenLoop, Follower(for all opamps)
// TODO: Should we restrict type parameters A and B?
// TODO: Also allow AD-channels shared by pins
opamp::opamp1::Pga<A, B> => (ADC1, 13),
opamp::opamp2::Pga<A, B> => (ADC2, 16),

opamp::opamp3::Pga<A, B> => (ADC2, 18),
);

adc_op_follower!(
opamp::opamp1::Follower<A> => (ADC1, 13),
opamp::opamp2::Follower<A> => (ADC2, 16),

opamp::opamp3::Follower<A> => (ADC2, 18),
opamp::Opamp1 => (ADC1, 13),
opamp::Opamp2 => (ADC2, 16),
opamp::Opamp3 => (ADC2, 18),
);

#[cfg(any(
@@ -2747,16 +2743,16 @@ adc_op_follower!(
feature = "stm32g491",
feature = "stm32g4a1",
))]
adc_op_pga!(
opamp::opamp3::Pga<A, B> => (ADC3, 13),
opamp::opamp4::Pga<A, B> => (ADC5, 5),
opamp::opamp5::Pga<A, B> => (ADC5, 3),
opamp::opamp6::Pga<A, B> => (ADC4, 17),
adc_opamp!(
opamp::Opamp3 => (ADC3, 13),
opamp::Opamp4 => (ADC5, 5),
opamp::Opamp5 => (ADC5, 3),
opamp::Opamp6 => (ADC4, 17),
);

#[cfg(any(feature = "stm32g491", feature = "stm32g4a1",))]
adc_op_pga!(
opamp::opamp6::Pga<A, B> => (ADC3, 17),
adc_opamp!(
opamp::Opamp6 => (ADC3, 17),
);

#[cfg(any(feature = "stm32g491", feature = "stm32g4a1",))]
910 changes: 619 additions & 291 deletions src/opamp.rs

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion src/prelude.rs
Original file line number Diff line number Diff line change
@@ -24,7 +24,9 @@ pub use crate::delay::SYSTDelayExt as _;
pub use crate::exti::ExtiExt as _;
pub use crate::gpio::GpioExt as _;
pub use crate::i2c::I2cExt as _;
pub use crate::opamp::prelude::*;
pub use crate::opamp::IntoFollower as _;
pub use crate::opamp::IntoOpenLoop as _;
pub use crate::opamp::IntoPga as _;
pub use crate::opamp::OpampEx as _;
pub use crate::rcc::LSCOExt as _;
pub use crate::rcc::MCOExt as _;