stm32: add opamp mod and update pac
This commit is contained in:
parent
b012a67df7
commit
e561e673c2
@ -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]
|
||||
|
@ -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);
|
||||
|
@ -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
133
embassy-stm32/src/opamp.rs
Normal 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
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
59
examples/stm32f334/src/bin/opamp.rs
Normal file
59
examples/stm32f334/src/bin/opamp.rs
Normal 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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user