diff options
| author | xoviat <[email protected]> | 2023-10-03 16:34:13 -0500 |
|---|---|---|
| committer | xoviat <[email protected]> | 2023-10-03 16:34:13 -0500 |
| commit | e561e673c2ad6ef403f808ffa8ad33a6c74a86b7 (patch) | |
| tree | 8f5509f039c04583e8747e108ac2d4475ff832ea | |
| parent | b012a67df7b5c95cce0e09eb66e3952bbc021bcc (diff) | |
stm32: add opamp mod and update pac
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 14 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/opamp.rs | 133 | ||||
| -rw-r--r-- | examples/stm32f334/src/bin/opamp.rs | 59 |
5 files changed, 210 insertions, 2 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 87f9083b3..ab1cae891 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -59,7 +59,7 @@ sdio-host = "0.5.0" | |||
| 59 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | 59 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } |
| 60 | critical-section = "1.1" | 60 | critical-section = "1.1" |
| 61 | atomic-polyfill = "1.0.1" | 61 | atomic-polyfill = "1.0.1" |
| 62 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ee2862086886cd8ebaf5fd5e3bd6cfbe5baa840" } | 62 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-06d13dfd245cc9bf86fd88c35b401bdb84c079c4" } |
| 63 | vcell = "0.1.3" | 63 | vcell = "0.1.3" |
| 64 | bxcan = "0.7.0" | 64 | bxcan = "0.7.0" |
| 65 | nb = "1.0.0" | 65 | nb = "1.0.0" |
| @@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 78 | [build-dependencies] | 78 | [build-dependencies] |
| 79 | proc-macro2 = "1.0.36" | 79 | proc-macro2 = "1.0.36" |
| 80 | quote = "1.0.15" | 80 | quote = "1.0.15" |
| 81 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ee2862086886cd8ebaf5fd5e3bd6cfbe5baa840", default-features = false, features = ["metadata"]} | 81 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-06d13dfd245cc9bf86fd88c35b401bdb84c079c4", default-features = false, features = ["metadata"]} |
| 82 | 82 | ||
| 83 | 83 | ||
| 84 | [features] | 84 | [features] |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index ed5fa84d6..f825dbeeb 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -810,6 +810,20 @@ fn main() { | |||
| 810 | } | 810 | } |
| 811 | } | 811 | } |
| 812 | 812 | ||
| 813 | if regs.kind == "opamp" { | ||
| 814 | if !pin.signal.starts_with("VP") { | ||
| 815 | continue; | ||
| 816 | } | ||
| 817 | |||
| 818 | let peri = format_ident!("{}", p.name); | ||
| 819 | let pin_name = format_ident!("{}", pin.pin); | ||
| 820 | let ch: u8 = pin.signal.strip_prefix("VP").unwrap().parse().unwrap(); | ||
| 821 | |||
| 822 | g.extend(quote! { | ||
| 823 | impl_opamp_pin!( #peri, #pin_name, #ch); | ||
| 824 | }) | ||
| 825 | } | ||
| 826 | |||
| 813 | // DAC is special | 827 | // DAC is special |
| 814 | if regs.kind == "dac" { | 828 | if regs.kind == "dac" { |
| 815 | let peri = format_ident!("{}", p.name); | 829 | let peri = format_ident!("{}", p.name); |
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index bd77fae41..e883678b5 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -49,6 +49,8 @@ pub mod i2s; | |||
| 49 | pub mod ipcc; | 49 | pub mod ipcc; |
| 50 | #[cfg(feature = "low-power")] | 50 | #[cfg(feature = "low-power")] |
| 51 | pub mod low_power; | 51 | pub mod low_power; |
| 52 | #[cfg(opamp)] | ||
| 53 | pub mod opamp; | ||
| 52 | #[cfg(quadspi)] | 54 | #[cfg(quadspi)] |
| 53 | pub mod qspi; | 55 | pub mod qspi; |
| 54 | #[cfg(rng)] | 56 | #[cfg(rng)] |
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs new file mode 100644 index 000000000..7b388aefe --- /dev/null +++ b/embassy-stm32/src/opamp.rs | |||
| @@ -0,0 +1,133 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 3 | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||
| 4 | |||
| 5 | use crate::Peripheral; | ||
| 6 | |||
| 7 | #[cfg(opamp_f3)] | ||
| 8 | pub struct OpAmpOutput<'d, 'p, T: Instance, P: NonInvertingPin<T>> { | ||
| 9 | _inner: &'d OpAmp<'d, T>, | ||
| 10 | _input: &'p mut P, | ||
| 11 | } | ||
| 12 | |||
| 13 | pub struct OpAmp<'d, T: Instance> { | ||
| 14 | _inner: PeripheralRef<'d, T>, | ||
| 15 | } | ||
| 16 | |||
| 17 | impl<'d, T: Instance> OpAmp<'d, T> { | ||
| 18 | pub fn new(opamp: impl Peripheral<P = T> + 'd) -> Self { | ||
| 19 | Self::new_inner(opamp) | ||
| 20 | } | ||
| 21 | |||
| 22 | fn new_inner(opamp: impl Peripheral<P = T> + 'd) -> Self { | ||
| 23 | into_ref!(opamp); | ||
| 24 | |||
| 25 | #[cfg(opamp_f3)] | ||
| 26 | T::regs().opampcsr().modify(|w| { | ||
| 27 | w.set_opampen(true); | ||
| 28 | }); | ||
| 29 | |||
| 30 | #[cfg(opamp_g4)] | ||
| 31 | T::regs().opamp_csr().modify(|w| { | ||
| 32 | w.set_opaen(true); | ||
| 33 | }); | ||
| 34 | |||
| 35 | Self { _inner: opamp } | ||
| 36 | } | ||
| 37 | |||
| 38 | #[cfg(opamp_f3)] | ||
| 39 | pub fn buffer_for<'a, 'b, P>(&'a mut self, pin: &'b mut P) -> OpAmpOutput<'a, 'b, T, P> | ||
| 40 | where | ||
| 41 | P: NonInvertingPin<T>, | ||
| 42 | { | ||
| 43 | #[cfg(opamp_f3)] | ||
| 44 | T::regs().opampcsr().modify(|w| { | ||
| 45 | w.set_vp_sel(pin.channel()); | ||
| 46 | }); | ||
| 47 | |||
| 48 | OpAmpOutput { | ||
| 49 | _inner: self, | ||
| 50 | _input: pin, | ||
| 51 | } | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | pub trait Instance: sealed::Instance + 'static {} | ||
| 56 | |||
| 57 | pub(crate) mod sealed { | ||
| 58 | pub trait Instance { | ||
| 59 | fn regs() -> crate::pac::opamp::Opamp; | ||
| 60 | } | ||
| 61 | |||
| 62 | pub trait NonInvertingPin<T: Instance> { | ||
| 63 | fn channel(&self) -> u8; | ||
| 64 | } | ||
| 65 | |||
| 66 | pub trait InvertingPin<T: Instance> { | ||
| 67 | fn channel(&self) -> u8; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {} | ||
| 72 | |||
| 73 | pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {} | ||
| 74 | |||
| 75 | #[cfg(opamp_f3)] | ||
| 76 | macro_rules! impl_opamp_output { | ||
| 77 | ($inst:ident, $adc:ident, $ch:expr) => { | ||
| 78 | impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::sealed::AdcPin<crate::peripherals::$adc> | ||
| 79 | for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P> | ||
| 80 | { | ||
| 81 | fn channel(&self) -> u8 { | ||
| 82 | $ch | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::AdcPin<crate::peripherals::$adc> | ||
| 87 | for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P> | ||
| 88 | { | ||
| 89 | } | ||
| 90 | }; | ||
| 91 | } | ||
| 92 | |||
| 93 | #[cfg(opamp_f3)] | ||
| 94 | foreach_peripheral!( | ||
| 95 | (opamp, OPAMP1) => { | ||
| 96 | impl_opamp_output!(OPAMP1, ADC1, 3); | ||
| 97 | }; | ||
| 98 | (opamp, OPAMP2) => { | ||
| 99 | impl_opamp_output!(OPAMP2, ADC2, 3); | ||
| 100 | }; | ||
| 101 | (opamp, OPAMP3) => { | ||
| 102 | impl_opamp_output!(OPAMP3, ADC3, 1); | ||
| 103 | }; | ||
| 104 | (opamp, OPAMP4) => { | ||
| 105 | impl_opamp_output!(OPAMP4, ADC4, 3); | ||
| 106 | }; | ||
| 107 | ); | ||
| 108 | |||
| 109 | foreach_peripheral! { | ||
| 110 | (opamp, $inst:ident) => { | ||
| 111 | impl sealed::Instance for crate::peripherals::$inst { | ||
| 112 | fn regs() -> crate::pac::opamp::Opamp { | ||
| 113 | crate::pac::$inst | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | impl Instance for crate::peripherals::$inst { | ||
| 118 | |||
| 119 | } | ||
| 120 | }; | ||
| 121 | } | ||
| 122 | |||
| 123 | #[allow(unused_macros)] | ||
| 124 | macro_rules! impl_opamp_pin { | ||
| 125 | ($inst:ident, $pin:ident, $ch:expr) => { | ||
| 126 | impl crate::opamp::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {} | ||
| 127 | impl crate::opamp::sealed::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin { | ||
| 128 | fn channel(&self) -> u8 { | ||
| 129 | $ch | ||
| 130 | } | ||
| 131 | } | ||
| 132 | }; | ||
| 133 | } | ||
diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs new file mode 100644 index 000000000..72263bab8 --- /dev/null +++ b/examples/stm32f334/src/bin/opamp.rs | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::info; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::adc::{Adc, SampleTime}; | ||
| 8 | use embassy_stm32::opamp::OpAmp; | ||
| 9 | use embassy_stm32::peripherals::ADC2; | ||
| 10 | use embassy_stm32::rcc::AdcClockSource; | ||
| 11 | use embassy_stm32::time::mhz; | ||
| 12 | use embassy_stm32::{adc, bind_interrupts, Config}; | ||
| 13 | use embassy_time::{Delay, Duration, Timer}; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | bind_interrupts!(struct Irqs { | ||
| 17 | ADC1_2 => adc::InterruptHandler<ADC2>; | ||
| 18 | }); | ||
| 19 | |||
| 20 | #[embassy_executor::main] | ||
| 21 | async fn main(_spawner: Spawner) -> ! { | ||
| 22 | let mut config = Config::default(); | ||
| 23 | config.rcc.sysclk = Some(mhz(64)); | ||
| 24 | config.rcc.hclk = Some(mhz(64)); | ||
| 25 | config.rcc.pclk1 = Some(mhz(32)); | ||
| 26 | config.rcc.pclk2 = Some(mhz(64)); | ||
| 27 | config.rcc.adc = Some(AdcClockSource::PllDiv1); | ||
| 28 | |||
| 29 | let mut p = embassy_stm32::init(config); | ||
| 30 | |||
| 31 | info!("create adc..."); | ||
| 32 | |||
| 33 | let mut adc = Adc::new(p.ADC2, Irqs, &mut Delay); | ||
| 34 | let mut opamp = OpAmp::new(p.OPAMP2); | ||
| 35 | |||
| 36 | adc.set_sample_time(SampleTime::Cycles601_5); | ||
| 37 | |||
| 38 | info!("enable vrefint..."); | ||
| 39 | |||
| 40 | let mut vrefint = adc.enable_vref(&mut Delay); | ||
| 41 | let mut temperature = adc.enable_temperature(); | ||
| 42 | let mut buffer = opamp.buffer_for(&mut p.PA7); | ||
| 43 | |||
| 44 | loop { | ||
| 45 | let vref = adc.read(&mut vrefint).await; | ||
| 46 | info!("read vref: {} (should be {})", vref, vrefint.value()); | ||
| 47 | |||
| 48 | let temp = adc.read(&mut temperature).await; | ||
| 49 | info!("read temperature: {}", temp); | ||
| 50 | |||
| 51 | let buffer = adc.read(&mut buffer).await; | ||
| 52 | info!("read buffer: {}", buffer); | ||
| 53 | |||
| 54 | let pin_mv = (buffer as u32 * vrefint.value() as u32 / vref as u32) * 3300 / 4095; | ||
| 55 | info!("computed pin mv: {}", pin_mv); | ||
| 56 | |||
| 57 | Timer::after(Duration::from_millis(500)).await; | ||
| 58 | } | ||
| 59 | } | ||
