stm32: add opamp mod and update pac
This commit is contained in:
		@@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user