Skip to content

Commit b244850

Browse files
authored
Merge pull request #75 from usbalbin/opamp_pga
Opamp pga-mode
2 parents 3745609 + fa3bfa1 commit b244850

File tree

3 files changed

+346
-3
lines changed

3 files changed

+346
-3
lines changed

examples/opamp.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//! Integrated opamps.
2+
3+
#![no_std]
4+
#![no_main]
5+
6+
use stm32g4xx_hal::adc::AdcClaim;
7+
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;
14+
use stm32g4xx_hal::prelude::*;
15+
16+
use utils::logger::info;
17+
18+
#[macro_use]
19+
mod utils;
20+
21+
#[cortex_m_rt::entry]
22+
fn main() -> ! {
23+
utils::logger::init();
24+
25+
// take peripherals
26+
let dp = stm32g4xx_hal::stm32::Peripherals::take().unwrap();
27+
let cp = cortex_m::Peripherals::take().expect("cannot take core peripherals");
28+
29+
// setup clock
30+
let config = stm32g4xx_hal::rcc::Config::hsi();
31+
let mut rcc = dp.RCC.freeze(config);
32+
33+
// split gpio
34+
let gpioa = dp.GPIOA.split(&mut rcc);
35+
let gpiob = dp.GPIOB.split(&mut rcc);
36+
37+
// setup opamps
38+
let (opamp1, opamp2, opamp3, ..) = dp.OPAMP.split(&mut rcc);
39+
40+
// Set up opamp1 and opamp2 in follower mode
41+
let opamp1 = opamp1.follower(gpioa.pa1, Some(gpioa.pa2));
42+
let opamp2 = opamp2.follower(gpioa.pa7, Option::<PA6<Analog>>::None);
43+
44+
// Set up opamp1 and opamp2 in open loop mode
45+
let opamp3 = opamp3.open_loop(gpiob.pb0, gpiob.pb2, Some(gpiob.pb1));
46+
47+
// disable opamps
48+
let (opamp1, pa1, some_pa2) = opamp1.disable();
49+
let (opamp2, pa7, _none) = opamp2.disable();
50+
51+
let (_opamp3, _pb0, _pb2, _some_pb1) = opamp3.disable();
52+
53+
// Configure opamp1 with pa1 as non-inverting input and set gain to x2
54+
let _opamp1 = opamp1.pga(
55+
pa1,
56+
PgaModeInternal::gain(NonInvertingGain::Gain2),
57+
some_pa2, // Route output to pin pa2
58+
);
59+
60+
// Configure op with pa7 as non-inverting input and set gain to x4
61+
let mut opamp2 = opamp2.pga(
62+
pa7,
63+
PgaModeInternal::gain(NonInvertingGain::Gain4),
64+
Option::<PA6<Analog>>::None, // Do not route output to any external pin, use internal AD instead
65+
);
66+
67+
let mut delay = cp.SYST.delay(&rcc.clocks);
68+
let mut adc = dp
69+
.ADC2
70+
.claim(ClockSource::SystemClock, &rcc, &mut delay, true);
71+
72+
loop {
73+
// Here we can sample the output of opamp2 as if it was a regular AD pin
74+
let sample = adc.convert(
75+
&mut opamp2,
76+
stm32g4xx_hal::adc::config::SampleTime::Cycles_640_5,
77+
);
78+
79+
let millivolts = adc.sample_to_millivolts(sample);
80+
info!("opamp2 thus 4x pa7: {}mV", millivolts);
81+
82+
delay.delay_ms(100);
83+
}
84+
85+
#[allow(unreachable_code)]
86+
{
87+
let (_opamp1, _pa1, _mode, _some_pa2) = _opamp1.disable();
88+
let (_opamp2, _pa7, _mode, _none) = opamp2.disable();
89+
90+
loop {}
91+
}
92+
}

src/adc.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub use crate::time::U32Ext as _;
1313
use crate::{
1414
dma::{mux::DmaMuxResources, traits::TargetAddress, PeripheralToMemory},
1515
gpio::*,
16+
opamp,
1617
rcc::{Enable, Rcc, Reset},
1718
signature::{VtempCal110, VtempCal30, VDDA_CALIB},
1819
stm32,
@@ -66,6 +67,17 @@ macro_rules! adc_pins {
6667
};
6768
}
6869

70+
macro_rules! adc_op {
71+
($($opamp:ty => ($adc:ident, $chan:expr)),+ $(,)*) => {
72+
$(
73+
impl<A, B> Channel<stm32::$adc> for $opamp {
74+
type ID = u8;
75+
fn channel() -> u8 { $chan }
76+
}
77+
)+
78+
};
79+
}
80+
6981
/// Contains types related to ADC configuration
7082
pub mod config {
7183
use embedded_hal::adc::Channel;
@@ -2338,6 +2350,28 @@ adc_pins!(
23382350
Vref => (ADC5, 18),
23392351
);
23402352

2353+
// See https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf#page=782
2354+
adc_op!(
2355+
// TODO: Add all opamp types: Follower, OpenLoop
2356+
// TODO: Should we restrict type parameters A and B?
2357+
// TODO: Also allow AD-channels shared by pins
2358+
opamp::opamp1::Pga<A, B> => (ADC1, 13),
2359+
opamp::opamp2::Pga<A, B> => (ADC2, 16),
2360+
opamp::opamp3::Pga<A, B> => (ADC2, 18),
2361+
);
2362+
2363+
#[cfg(any(
2364+
feature = "stm32g473",
2365+
feature = "stm32g474",
2366+
feature = "stm32g483",
2367+
feature = "stm32g484",
2368+
))]
2369+
adc_op!(
2370+
opamp::opamp4::Pga<A, B> => (ADC5, 5),
2371+
opamp::opamp5::Pga<A, B> => (ADC5, 3),
2372+
opamp::opamp6::Pga<A, B> => (ADC4, 17),
2373+
);
2374+
23412375
#[cfg(any(feature = "stm32g491", feature = "stm32g4a1",))]
23422376
adc_pins!(
23432377
gpioa::PA0<Analog> => (ADC1, 1),

0 commit comments

Comments
 (0)