Skip to content

Commit 5405840

Browse files
authored
More ergonomic opamp API, add lock and pga functionality (#113)
* Checkpoint * Checkpoint * Example compiles * Initial lock functionality * Constrain so opamp output can only be used when configured as an internal output * Checkpoint * Checkpoint * Checkpoint * Rename opamp structs (correct case) * Add traits to prelude * Remove unwrap * Add remaining PGA modes * Fix incorrect use of register write (s.b. modify) * Simplify PGA implementation * Compiles, some trait duplication * Simplify a little * Rename associated types for linter * Fix additional linter error
1 parent 67b13be commit 5405840

File tree

4 files changed

+663
-339
lines changed

4 files changed

+663
-339
lines changed

examples/opamp.rs

+16-18
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@
55

66
use stm32g4xx_hal::adc::AdcClaim;
77
use stm32g4xx_hal::adc::ClockSource;
8-
use stm32g4xx_hal::gpio::gpioa::*;
9-
use stm32g4xx_hal::gpio::Analog;
10-
use stm32g4xx_hal::opamp::opamp1::IntoPga as _;
11-
use stm32g4xx_hal::opamp::opamp2::IntoPga as _;
12-
use stm32g4xx_hal::opamp::NonInvertingGain;
13-
use stm32g4xx_hal::opamp::PgaModeInternal;
8+
use stm32g4xx_hal::opamp::{Gain, InternalOutput};
149
use stm32g4xx_hal::prelude::*;
1510
use stm32g4xx_hal::pwr::PwrExt;
1611

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

4237
// Set up opamp1 and opamp2 in follower mode
43-
let opamp1 = opamp1.follower(gpioa.pa1, Some(gpioa.pa2));
44-
let opamp2 = opamp2.follower(gpioa.pa7, Option::<PA6<Analog>>::None);
38+
let opamp1 = opamp1.follower(gpioa.pa1, gpioa.pa2);
39+
let opamp2 = opamp2.follower(gpioa.pa7, InternalOutput);
4540

4641
// Set up opamp1 and opamp2 in open loop mode
47-
let opamp3 = opamp3.open_loop(gpiob.pb0, gpiob.pb2, Some(gpiob.pb1));
42+
let opamp3 = opamp3.open_loop(gpiob.pb0, gpiob.pb2, gpiob.pb1);
4843

4944
// disable opamps
50-
let (opamp1, pa1, some_pa2) = opamp1.disable();
51-
let (opamp2, pa7, _none) = opamp2.disable();
45+
let (opamp1, pa1, pa2) = opamp1.disable();
46+
let (opamp2, pa7) = opamp2.disable();
5247

53-
let (_opamp3, _pb0, _pb2, _some_pb1) = opamp3.disable();
48+
let (_opamp3, _pb0, _pb2, _pb1) = opamp3.disable();
5449

5550
// Configure opamp1 with pa1 as non-inverting input and set gain to x2
5651
let _opamp1 = opamp1.pga(
5752
pa1,
58-
PgaModeInternal::gain(NonInvertingGain::Gain2),
59-
some_pa2, // Route output to pin pa2
53+
pa2, // Route output to pin pa2
54+
Gain::Gain2,
6055
);
6156

6257
// Configure op with pa7 as non-inverting input and set gain to x4
6358
let opamp2 = opamp2.pga(
6459
pa7,
65-
PgaModeInternal::gain(NonInvertingGain::Gain4),
66-
Option::<PA6<Analog>>::None, // Do not route output to any external pin, use internal AD instead
60+
InternalOutput, // Do not route output to any external pin, use internal AD instead
61+
Gain::Gain4,
6762
);
6863

64+
// Lock opamp2. After the opamp is locked its registers cannot be written
65+
// until the device is reset (even if using unsafe register accesses).
66+
let opamp2 = opamp2.lock();
67+
6968
let mut delay = cp.SYST.delay(&rcc.clocks);
7069
let mut adc = dp
7170
.ADC2
@@ -86,8 +85,7 @@ fn main() -> ! {
8685

8786
#[allow(unreachable_code)]
8887
{
89-
let (_opamp1, _pa1, _mode) = _opamp1.disable();
90-
let (_opamp2, _pa7, _mode) = opamp2.disable();
88+
let (_opamp1, _pin) = _opamp1.disable();
9189

9290
loop {
9391
delay.delay_ms(100);

src/adc.rs

+25-29
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub use crate::time::U32Ext as _;
1313
use crate::{
1414
dma::{mux::DmaMuxResources, traits::TargetAddress, PeripheralToMemory},
1515
gpio::*,
16-
opamp,
16+
opamp::{self, InternalOutput},
1717
rcc::{Enable, Rcc, Reset},
1818
signature::{VtempCal130, VtempCal30, VDDA_CALIB},
1919
stm32,
@@ -144,21 +144,25 @@ macro_rules! adc_pins {
144144
};
145145
}
146146

147-
macro_rules! adc_op_pga {
147+
macro_rules! adc_opamp {
148148
($($opamp:ty => ($adc:ident, $chan:expr)),+ $(,)*) => {
149149
$(
150-
impl<A, B> Channel<stm32::$adc> for $opamp {
150+
impl<A> Channel<stm32::$adc> for opamp::Follower<$opamp, A, InternalOutput> {
151151
type ID = u8;
152152
fn channel() -> u8 { $chan }
153153
}
154-
)+
155-
};
156-
}
157154

158-
macro_rules! adc_op_follower {
159-
($($opamp:ty => ($adc:ident, $chan:expr)),+ $(,)*) => {
160-
$(
161-
impl<A> Channel<stm32::$adc> for $opamp {
155+
impl<A, B> Channel<stm32::$adc> for opamp::OpenLoop<$opamp, A, B, InternalOutput> {
156+
type ID = u8;
157+
fn channel() -> u8 { $chan }
158+
}
159+
160+
impl<A> Channel<stm32::$adc> for opamp::Pga<$opamp, A, InternalOutput> {
161+
type ID = u8;
162+
fn channel() -> u8 { $chan }
163+
}
164+
165+
impl Channel<stm32::$adc> for opamp::Locked<$opamp, InternalOutput> {
162166
type ID = u8;
163167
fn channel() -> u8 { $chan }
164168
}
@@ -2811,21 +2815,13 @@ adc_pins!(
28112815
);
28122816

28132817
// See https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf#page=782
2814-
adc_op_pga!(
2818+
adc_opamp!(
28152819
// TODO: Add all opamp types: OpenLoop, Follower(for all opamps)
28162820
// TODO: Should we restrict type parameters A and B?
28172821
// TODO: Also allow AD-channels shared by pins
2818-
opamp::opamp1::Pga<A, B> => (ADC1, 13),
2819-
opamp::opamp2::Pga<A, B> => (ADC2, 16),
2820-
2821-
opamp::opamp3::Pga<A, B> => (ADC2, 18),
2822-
);
2823-
2824-
adc_op_follower!(
2825-
opamp::opamp1::Follower<A> => (ADC1, 13),
2826-
opamp::opamp2::Follower<A> => (ADC2, 16),
2827-
2828-
opamp::opamp3::Follower<A> => (ADC2, 18),
2822+
opamp::Opamp1 => (ADC1, 13),
2823+
opamp::Opamp2 => (ADC2, 16),
2824+
opamp::Opamp3 => (ADC2, 18),
28292825
);
28302826

28312827
#[cfg(any(
@@ -2836,16 +2832,16 @@ adc_op_follower!(
28362832
feature = "stm32g491",
28372833
feature = "stm32g4a1",
28382834
))]
2839-
adc_op_pga!(
2840-
opamp::opamp3::Pga<A, B> => (ADC3, 13),
2841-
opamp::opamp4::Pga<A, B> => (ADC5, 5),
2842-
opamp::opamp5::Pga<A, B> => (ADC5, 3),
2843-
opamp::opamp6::Pga<A, B> => (ADC4, 17),
2835+
adc_opamp!(
2836+
opamp::Opamp3 => (ADC3, 13),
2837+
opamp::Opamp4 => (ADC5, 5),
2838+
opamp::Opamp5 => (ADC5, 3),
2839+
opamp::Opamp6 => (ADC4, 17),
28442840
);
28452841

28462842
#[cfg(any(feature = "stm32g491", feature = "stm32g4a1",))]
2847-
adc_op_pga!(
2848-
opamp::opamp6::Pga<A, B> => (ADC3, 17),
2843+
adc_opamp!(
2844+
opamp::Opamp6 => (ADC3, 17),
28492845
);
28502846

28512847
#[cfg(any(feature = "stm32g491", feature = "stm32g4a1",))]

0 commit comments

Comments
 (0)