diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-11-20 22:47:19 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-11-20 22:47:19 +0000 |
| commit | 766ec77ec5a9a5a0e4af32651c9eb0b6c8e93fed (patch) | |
| tree | 4b5648900e1ffbea3ef70fa46b808db02d8b6dbc | |
| parent | 382949e1ffee384db8f7d4279829337381f073fc (diff) | |
| parent | d1af6966051486fd605aff902b347b0346d2d889 (diff) | |
Merge pull request #2198 from adamgreig/stm32-opamp
STM32: Don't enable opamps in new(), wait until configured
| -rw-r--r-- | embassy-stm32/src/opamp.rs | 77 | ||||
| -rw-r--r-- | examples/stm32f334/src/bin/opamp.rs | 2 |
2 files changed, 41 insertions, 38 deletions
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index 89db6d14d..e1eb031d1 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs | |||
| @@ -31,12 +31,9 @@ impl From<OpAmpSpeed> for crate::pac::opamp::vals::OpampCsrOpahsm { | |||
| 31 | 31 | ||
| 32 | /// OpAmp external outputs, wired to a GPIO pad. | 32 | /// OpAmp external outputs, wired to a GPIO pad. |
| 33 | /// | 33 | /// |
| 34 | /// The GPIO output pad is held by this struct to ensure it cannot be used elsewhere. | ||
| 35 | /// | ||
| 36 | /// This struct can also be used as an ADC input. | 34 | /// This struct can also be used as an ADC input. |
| 37 | pub struct OpAmpOutput<'d, 'p, T: Instance, P: OutputPin<T>> { | 35 | pub struct OpAmpOutput<'d, T: Instance> { |
| 38 | _inner: &'d OpAmp<'d, T>, | 36 | _inner: &'d OpAmp<'d, T>, |
| 39 | _output: &'p mut P, | ||
| 40 | } | 37 | } |
| 41 | 38 | ||
| 42 | /// OpAmp internal outputs, wired directly to ADC inputs. | 39 | /// OpAmp internal outputs, wired directly to ADC inputs. |
| @@ -54,19 +51,12 @@ pub struct OpAmp<'d, T: Instance> { | |||
| 54 | impl<'d, T: Instance> OpAmp<'d, T> { | 51 | impl<'d, T: Instance> OpAmp<'d, T> { |
| 55 | /// Create a new driver instance. | 52 | /// Create a new driver instance. |
| 56 | /// | 53 | /// |
| 57 | /// Enables the OpAmp and configures the speed, but | 54 | /// Does not enable the opamp, but does set the speed mode on some families. |
| 58 | /// does not set any other configuration. | ||
| 59 | pub fn new(opamp: impl Peripheral<P = T> + 'd, #[cfg(opamp_g4)] speed: OpAmpSpeed) -> Self { | 55 | pub fn new(opamp: impl Peripheral<P = T> + 'd, #[cfg(opamp_g4)] speed: OpAmpSpeed) -> Self { |
| 60 | into_ref!(opamp); | 56 | into_ref!(opamp); |
| 61 | 57 | ||
| 62 | #[cfg(opamp_f3)] | ||
| 63 | T::regs().opampcsr().modify(|w| { | ||
| 64 | w.set_opampen(true); | ||
| 65 | }); | ||
| 66 | |||
| 67 | #[cfg(opamp_g4)] | 58 | #[cfg(opamp_g4)] |
| 68 | T::regs().opamp_csr().modify(|w| { | 59 | T::regs().opamp_csr().modify(|w| { |
| 69 | w.set_opaen(true); | ||
| 70 | w.set_opahsm(speed.into()); | 60 | w.set_opahsm(speed.into()); |
| 71 | }); | 61 | }); |
| 72 | 62 | ||
| @@ -74,24 +64,23 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 74 | } | 64 | } |
| 75 | 65 | ||
| 76 | /// Configure the OpAmp as a buffer for the provided input pin, | 66 | /// Configure the OpAmp as a buffer for the provided input pin, |
| 77 | /// outputting to the provided output pin. | 67 | /// outputting to the provided output pin, and enable the opamp. |
| 78 | /// | 68 | /// |
| 79 | /// The input pin is configured for analogue mode but not consumed, | 69 | /// The input pin is configured for analogue mode but not consumed, |
| 80 | /// so it may subsequently be used for ADC or comparator inputs. | 70 | /// so it may subsequently be used for ADC or comparator inputs. |
| 81 | /// | 71 | /// |
| 82 | /// The output pin is held within the returned [`OpAmpOutput`] struct, | 72 | /// The output pin is held within the returned [`OpAmpOutput`] struct, |
| 83 | /// preventing it being used elsewhere. The `OpAmpOutput` can then be | 73 | /// preventing it being used elsewhere. The `OpAmpOutput` can then be |
| 84 | /// directly used as an ADC input. | 74 | /// directly used as an ADC input. The opamp will be disabled when the |
| 85 | pub fn buffer_ext<'a, 'b, IP, OP>( | 75 | /// [`OpAmpOutput`] is dropped. |
| 86 | &'a mut self, | 76 | pub fn buffer_ext( |
| 87 | in_pin: &IP, | 77 | &'d mut self, |
| 88 | out_pin: &'b mut OP, | 78 | in_pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::sealed::Pin>, |
| 79 | out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::sealed::Pin> + 'd, | ||
| 89 | gain: OpAmpGain, | 80 | gain: OpAmpGain, |
| 90 | ) -> OpAmpOutput<'a, 'b, T, OP> | 81 | ) -> OpAmpOutput<'d, T> { |
| 91 | where | 82 | into_ref!(in_pin); |
| 92 | IP: NonInvertingPin<T> + crate::gpio::sealed::Pin, | 83 | into_ref!(out_pin); |
| 93 | OP: OutputPin<T> + crate::gpio::sealed::Pin, | ||
| 94 | { | ||
| 95 | in_pin.set_as_analog(); | 84 | in_pin.set_as_analog(); |
| 96 | out_pin.set_as_analog(); | 85 | out_pin.set_as_analog(); |
| 97 | 86 | ||
| @@ -122,24 +111,24 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 122 | w.set_opaen(true); | 111 | w.set_opaen(true); |
| 123 | }); | 112 | }); |
| 124 | 113 | ||
| 125 | OpAmpOutput { | 114 | OpAmpOutput { _inner: self } |
| 126 | _inner: self, | ||
| 127 | _output: out_pin, | ||
| 128 | } | ||
| 129 | } | 115 | } |
| 130 | 116 | ||
| 131 | /// Configure the OpAmp as a buffer for the provided input pin, | 117 | /// Configure the OpAmp as a buffer for the provided input pin, |
| 132 | /// with the output only used internally. | 118 | /// with the output only used internally, and enable the opamp. |
| 133 | /// | 119 | /// |
| 134 | /// The input pin is configured for analogue mode but not consumed, | 120 | /// The input pin is configured for analogue mode but not consumed, |
| 135 | /// so it may be subsequently used for ADC or comparator inputs. | 121 | /// so it may be subsequently used for ADC or comparator inputs. |
| 136 | /// | 122 | /// |
| 137 | /// The returned `OpAmpInternalOutput` struct may be used as an ADC input. | 123 | /// The returned `OpAmpInternalOutput` struct may be used as an ADC input. |
| 124 | /// The opamp output will be disabled when it is dropped. | ||
| 138 | #[cfg(opamp_g4)] | 125 | #[cfg(opamp_g4)] |
| 139 | pub fn buffer_int<'a, P>(&'a mut self, pin: &P, gain: OpAmpGain) -> OpAmpInternalOutput<'a, T> | 126 | pub fn buffer_int( |
| 140 | where | 127 | &'d mut self, |
| 141 | P: NonInvertingPin<T> + crate::gpio::sealed::Pin, | 128 | pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::sealed::Pin>, |
| 142 | { | 129 | gain: OpAmpGain, |
| 130 | ) -> OpAmpInternalOutput<'d, T> { | ||
| 131 | into_ref!(pin); | ||
| 143 | pin.set_as_analog(); | 132 | pin.set_as_analog(); |
| 144 | 133 | ||
| 145 | let (vm_sel, pga_gain) = match gain { | 134 | let (vm_sel, pga_gain) = match gain { |
| @@ -163,7 +152,21 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 163 | } | 152 | } |
| 164 | } | 153 | } |
| 165 | 154 | ||
| 166 | impl<'d, T: Instance> Drop for OpAmp<'d, T> { | 155 | impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> { |
| 156 | fn drop(&mut self) { | ||
| 157 | #[cfg(opamp_f3)] | ||
| 158 | T::regs().opampcsr().modify(|w| { | ||
| 159 | w.set_opampen(false); | ||
| 160 | }); | ||
| 161 | |||
| 162 | #[cfg(opamp_g4)] | ||
| 163 | T::regs().opamp_csr().modify(|w| { | ||
| 164 | w.set_opaen(false); | ||
| 165 | }); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> { | ||
| 167 | fn drop(&mut self) { | 170 | fn drop(&mut self) { |
| 168 | #[cfg(opamp_f3)] | 171 | #[cfg(opamp_f3)] |
| 169 | T::regs().opampcsr().modify(|w| { | 172 | T::regs().opampcsr().modify(|w| { |
| @@ -203,16 +206,16 @@ macro_rules! impl_opamp_external_output { | |||
| 203 | ($inst:ident, $adc:ident, $ch:expr) => { | 206 | ($inst:ident, $adc:ident, $ch:expr) => { |
| 204 | foreach_adc!( | 207 | foreach_adc!( |
| 205 | ($adc, $common_inst:ident, $adc_clock:ident) => { | 208 | ($adc, $common_inst:ident, $adc_clock:ident) => { |
| 206 | impl<'d, 'p, P: OutputPin<crate::peripherals::$inst>> crate::adc::sealed::AdcPin<crate::peripherals::$adc> | 209 | impl<'d> crate::adc::sealed::AdcPin<crate::peripherals::$adc> |
| 207 | for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P> | 210 | for OpAmpOutput<'d, crate::peripherals::$inst> |
| 208 | { | 211 | { |
| 209 | fn channel(&self) -> u8 { | 212 | fn channel(&self) -> u8 { |
| 210 | $ch | 213 | $ch |
| 211 | } | 214 | } |
| 212 | } | 215 | } |
| 213 | 216 | ||
| 214 | impl<'d, 'p, P: OutputPin<crate::peripherals::$inst>> crate::adc::AdcPin<crate::peripherals::$adc> | 217 | impl<'d> crate::adc::AdcPin<crate::peripherals::$adc> |
| 215 | for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P> | 218 | for OpAmpOutput<'d, crate::peripherals::$inst> |
| 216 | { | 219 | { |
| 217 | } | 220 | } |
| 218 | }; | 221 | }; |
diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs index 137fc9e66..10e7b3543 100644 --- a/examples/stm32f334/src/bin/opamp.rs +++ b/examples/stm32f334/src/bin/opamp.rs | |||
| @@ -39,7 +39,7 @@ async fn main(_spawner: Spawner) -> ! { | |||
| 39 | 39 | ||
| 40 | let mut vrefint = adc.enable_vref(&mut Delay); | 40 | let mut vrefint = adc.enable_vref(&mut Delay); |
| 41 | let mut temperature = adc.enable_temperature(); | 41 | let mut temperature = adc.enable_temperature(); |
| 42 | let mut buffer = opamp.buffer_ext(&p.PA7, &mut p.PA6, OpAmpGain::Mul1); | 42 | let mut buffer = opamp.buffer_ext(&mut p.PA7, &mut p.PA6, OpAmpGain::Mul1); |
| 43 | 43 | ||
| 44 | loop { | 44 | loop { |
| 45 | let vref = adc.read(&mut vrefint).await; | 45 | let vref = adc.read(&mut vrefint).await; |
