Merge pull request #1973 from xoviat/opamp

stm32: add opamp
This commit is contained in:
xoviat 2023-10-03 22:01:46 +00:00 committed by GitHub
commit 8ac5c1a963
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 213 additions and 2 deletions

3
ci.sh
View file

@ -201,6 +201,9 @@ cargo batch \
$BUILD_EXTRA
rm out/tests/stm32wb55rg/wpan_mac
rm out/tests/stm32wb55rg/wpan_ble
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
echo No teleprobe token found, skipping running HIL tests

View file

@ -59,7 +59,7 @@ sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1"
atomic-polyfill = "1.0.1"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ee2862086886cd8ebaf5fd5e3bd6cfbe5baa840" }
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-06d13dfd245cc9bf86fd88c35b401bdb84c079c4" }
vcell = "0.1.3"
bxcan = "0.7.0"
nb = "1.0.0"
@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies]
proc-macro2 = "1.0.36"
quote = "1.0.15"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ee2862086886cd8ebaf5fd5e3bd6cfbe5baa840", default-features = false, features = ["metadata"]}
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-06d13dfd245cc9bf86fd88c35b401bdb84c079c4", default-features = false, features = ["metadata"]}
[features]

View file

@ -810,6 +810,20 @@ fn main() {
}
}
if regs.kind == "opamp" {
if !pin.signal.starts_with("VP") {
continue;
}
let peri = format_ident!("{}", p.name);
let pin_name = format_ident!("{}", pin.pin);
let ch: u8 = pin.signal.strip_prefix("VP").unwrap().parse().unwrap();
g.extend(quote! {
impl_opamp_pin!( #peri, #pin_name, #ch);
})
}
// DAC is special
if regs.kind == "dac" {
let peri = format_ident!("{}", p.name);

View file

@ -49,6 +49,8 @@ pub mod i2s;
pub mod ipcc;
#[cfg(feature = "low-power")]
pub mod low_power;
#[cfg(opamp)]
pub mod opamp;
#[cfg(quadspi)]
pub mod qspi;
#[cfg(rng)]

133
embassy-stm32/src/opamp.rs Normal file
View file

@ -0,0 +1,133 @@
#![macro_use]
use embassy_hal_internal::{into_ref, PeripheralRef};
use crate::Peripheral;
#[cfg(opamp_f3)]
pub struct OpAmpOutput<'d, 'p, T: Instance, P: NonInvertingPin<T>> {
_inner: &'d OpAmp<'d, T>,
_input: &'p mut P,
}
pub struct OpAmp<'d, T: Instance> {
_inner: PeripheralRef<'d, T>,
}
impl<'d, T: Instance> OpAmp<'d, T> {
pub fn new(opamp: impl Peripheral<P = T> + 'd) -> Self {
Self::new_inner(opamp)
}
fn new_inner(opamp: impl Peripheral<P = T> + 'd) -> Self {
into_ref!(opamp);
#[cfg(opamp_f3)]
T::regs().opampcsr().modify(|w| {
w.set_opampen(true);
});
#[cfg(opamp_g4)]
T::regs().opamp_csr().modify(|w| {
w.set_opaen(true);
});
Self { _inner: opamp }
}
#[cfg(opamp_f3)]
pub fn buffer_for<'a, 'b, P>(&'a mut self, pin: &'b mut P) -> OpAmpOutput<'a, 'b, T, P>
where
P: NonInvertingPin<T>,
{
#[cfg(opamp_f3)]
T::regs().opampcsr().modify(|w| {
w.set_vp_sel(pin.channel());
});
OpAmpOutput {
_inner: self,
_input: pin,
}
}
}
pub trait Instance: sealed::Instance + 'static {}
pub(crate) mod sealed {
pub trait Instance {
fn regs() -> crate::pac::opamp::Opamp;
}
pub trait NonInvertingPin<T: Instance> {
fn channel(&self) -> u8;
}
pub trait InvertingPin<T: Instance> {
fn channel(&self) -> u8;
}
}
pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {}
pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {}
#[cfg(opamp_f3)]
macro_rules! impl_opamp_output {
($inst:ident, $adc:ident, $ch:expr) => {
impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::sealed::AdcPin<crate::peripherals::$adc>
for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P>
{
fn channel(&self) -> u8 {
$ch
}
}
impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::AdcPin<crate::peripherals::$adc>
for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P>
{
}
};
}
#[cfg(opamp_f3)]
foreach_peripheral!(
(opamp, OPAMP1) => {
impl_opamp_output!(OPAMP1, ADC1, 3);
};
(opamp, OPAMP2) => {
impl_opamp_output!(OPAMP2, ADC2, 3);
};
(opamp, OPAMP3) => {
impl_opamp_output!(OPAMP3, ADC3, 1);
};
(opamp, OPAMP4) => {
impl_opamp_output!(OPAMP4, ADC4, 3);
};
);
foreach_peripheral! {
(opamp, $inst:ident) => {
impl sealed::Instance for crate::peripherals::$inst {
fn regs() -> crate::pac::opamp::Opamp {
crate::pac::$inst
}
}
impl Instance for crate::peripherals::$inst {
}
};
}
#[allow(unused_macros)]
macro_rules! impl_opamp_pin {
($inst:ident, $pin:ident, $ch:expr) => {
impl crate::opamp::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {}
impl crate::opamp::sealed::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {
fn channel(&self) -> u8 {
$ch
}
}
};
}

View file

@ -0,0 +1,59 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use defmt::info;
use embassy_executor::Spawner;
use embassy_stm32::adc::{Adc, SampleTime};
use embassy_stm32::opamp::OpAmp;
use embassy_stm32::peripherals::ADC2;
use embassy_stm32::rcc::AdcClockSource;
use embassy_stm32::time::mhz;
use embassy_stm32::{adc, bind_interrupts, Config};
use embassy_time::{Delay, Duration, Timer};
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
ADC1_2 => adc::InterruptHandler<ADC2>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
let mut config = Config::default();
config.rcc.sysclk = Some(mhz(64));
config.rcc.hclk = Some(mhz(64));
config.rcc.pclk1 = Some(mhz(32));
config.rcc.pclk2 = Some(mhz(64));
config.rcc.adc = Some(AdcClockSource::PllDiv1);
let mut p = embassy_stm32::init(config);
info!("create adc...");
let mut adc = Adc::new(p.ADC2, Irqs, &mut Delay);
let mut opamp = OpAmp::new(p.OPAMP2);
adc.set_sample_time(SampleTime::Cycles601_5);
info!("enable vrefint...");
let mut vrefint = adc.enable_vref(&mut Delay);
let mut temperature = adc.enable_temperature();
let mut buffer = opamp.buffer_for(&mut p.PA7);
loop {
let vref = adc.read(&mut vrefint).await;
info!("read vref: {} (should be {})", vref, vrefint.value());
let temp = adc.read(&mut temperature).await;
info!("read temperature: {}", temp);
let buffer = adc.read(&mut buffer).await;
info!("read buffer: {}", buffer);
let pin_mv = (buffer as u32 * vrefint.value() as u32 / vref as u32) * 3300 / 4095;
info!("computed pin mv: {}", pin_mv);
Timer::after(Duration::from_millis(500)).await;
}
}