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
Show file tree
Hide file tree
Changes from 11 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
30 changes: 14 additions & 16 deletions examples/opamp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{InternalOutput, NonInvertingGain, PgaModeInternal};
use stm32g4xx_hal::prelude::*;
use stm32g4xx_hal::pwr::PwrExt;

Expand Down Expand Up @@ -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
);

// 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
);

// 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
Expand All @@ -86,8 +85,7 @@ fn main() -> ! {

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

loop {
delay.delay_ms(100);
Expand Down
54 changes: 25 additions & 29 deletions src/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -80,21 +80,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, B> Channel<stm32::$adc> for opamp::Pga<$opamp, A, B, InternalOutput> {
type ID = u8;
fn channel() -> u8 { $chan }
}

impl Channel<stm32::$adc> for opamp::Locked<$opamp, InternalOutput> {
type ID = u8;
fn channel() -> u8 { $chan }
}
Expand Down Expand Up @@ -2658,21 +2662,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(
Expand All @@ -2683,16 +2679,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",))]
Expand Down
Loading
Loading