1#![macro_use]
3
4use embassy_hal_internal::{into_ref, PeripheralRef};
5
6use crate::pac::opamp::vals::*;
7use crate::Peripheral;
8
9#[allow(missing_docs)]
11#[derive(Clone, Copy)]
12pub enum OpAmpGain {
13 Mul1,
14 Mul2,
15 Mul4,
16 Mul8,
17 Mul16,
18}
19
20#[allow(missing_docs)]
22#[derive(Clone, Copy)]
23pub enum OpAmpSpeed {
24 Normal,
25 HighSpeed,
26}
27
28#[cfg(opamp_g4)]
29impl From<OpAmpSpeed> for crate::pac::opamp::vals::Opahsm {
30 fn from(v: OpAmpSpeed) -> Self {
31 match v {
32 OpAmpSpeed::Normal => crate::pac::opamp::vals::Opahsm::NORMAL,
33 OpAmpSpeed::HighSpeed => crate::pac::opamp::vals::Opahsm::HIGH_SPEED,
34 }
35 }
36}
37
38pub struct OpAmpOutput<'d, T: Instance> {
42 _inner: &'d OpAmp<'d, T>,
43}
44
45#[cfg(opamp_g4)]
49pub struct OpAmpInternalOutput<'d, T: Instance> {
50 _inner: &'d OpAmp<'d, T>,
51}
52
53pub struct OpAmp<'d, T: Instance> {
55 _inner: PeripheralRef<'d, T>,
56}
57
58impl<'d, T: Instance> OpAmp<'d, T> {
59 pub fn new(opamp: impl Peripheral<P = T> + 'd, #[cfg(opamp_g4)] speed: OpAmpSpeed) -> Self {
63 into_ref!(opamp);
64
65 #[cfg(opamp_g4)]
66 T::regs().csr().modify(|w| {
67 w.set_opahsm(speed.into());
68 });
69
70 Self { _inner: opamp }
71 }
72
73 pub fn buffer_ext(
84 &mut self,
85 in_pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>,
86 out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin>,
87 gain: OpAmpGain,
88 ) -> OpAmpOutput<'_, T> {
89 into_ref!(in_pin);
90 into_ref!(out_pin);
91 in_pin.set_as_analog();
92 out_pin.set_as_analog();
93
94 let (vm_sel, pga_gain) = match gain {
96 OpAmpGain::Mul1 => (0b11, 0b00),
97 OpAmpGain::Mul2 => (0b10, 0b00),
98 OpAmpGain::Mul4 => (0b10, 0b01),
99 OpAmpGain::Mul8 => (0b10, 0b10),
100 OpAmpGain::Mul16 => (0b10, 0b11),
101 };
102
103 T::regs().csr().modify(|w| {
104 w.set_vp_sel(VpSel::from_bits(in_pin.channel()));
105 w.set_vm_sel(VmSel::from_bits(vm_sel));
106 w.set_pga_gain(PgaGain::from_bits(pga_gain));
107 #[cfg(opamp_g4)]
108 w.set_opaintoen(Opaintoen::OUTPUT_PIN);
109 w.set_opampen(true);
110 });
111
112 OpAmpOutput { _inner: self }
113 }
114 #[cfg(opamp_g4)]
122 pub fn buffer_dac(
123 &mut self,
124 out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin>,
125 ) -> OpAmpOutput<'_, T> {
126 into_ref!(out_pin);
127 out_pin.set_as_analog();
128
129 T::regs().csr().modify(|w| {
130 use crate::pac::opamp::vals::*;
131
132 w.set_vm_sel(VmSel::OUTPUT);
133 w.set_vp_sel(VpSel::DAC3_CH1);
134 w.set_opaintoen(Opaintoen::OUTPUT_PIN);
135 w.set_opampen(true);
136 });
137
138 OpAmpOutput { _inner: self }
139 }
140
141 #[cfg(opamp_g4)]
150 pub fn buffer_int(
151 &mut self,
152 pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>,
153 gain: OpAmpGain,
154 ) -> OpAmpInternalOutput<'_, T> {
155 into_ref!(pin);
156 pin.set_as_analog();
157
158 let (vm_sel, pga_gain) = match gain {
160 OpAmpGain::Mul1 => (0b11, 0b00),
161 OpAmpGain::Mul2 => (0b10, 0b00),
162 OpAmpGain::Mul4 => (0b10, 0b01),
163 OpAmpGain::Mul8 => (0b10, 0b10),
164 OpAmpGain::Mul16 => (0b10, 0b11),
165 };
166
167 T::regs().csr().modify(|w| {
168 use crate::pac::opamp::vals::*;
169 w.set_vp_sel(VpSel::from_bits(pin.channel()));
170 w.set_vm_sel(VmSel::from_bits(vm_sel));
171 w.set_pga_gain(PgaGain::from_bits(pga_gain));
172 w.set_opaintoen(Opaintoen::ADCCHANNEL);
173 w.set_opampen(true);
174 });
175
176 OpAmpInternalOutput { _inner: self }
177 }
178}
179
180impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> {
181 fn drop(&mut self) {
182 T::regs().csr().modify(|w| {
183 w.set_opampen(false);
184 });
185 }
186}
187
188#[cfg(opamp_g4)]
189impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> {
190 fn drop(&mut self) {
191 T::regs().csr().modify(|w| {
192 w.set_opampen(false);
193 });
194 }
195}
196
197pub(crate) trait SealedInstance {
198 fn regs() -> crate::pac::opamp::Opamp;
199}
200
201pub(crate) trait SealedNonInvertingPin<T: Instance> {
202 fn channel(&self) -> u8;
203}
204
205pub(crate) trait SealedInvertingPin<T: Instance> {
206 #[allow(unused)]
207 fn channel(&self) -> u8;
208}
209
210pub(crate) trait SealedOutputPin<T: Instance> {}
211
212#[allow(private_bounds)]
214pub trait Instance: SealedInstance + 'static {}
215#[allow(private_bounds)]
217pub trait NonInvertingPin<T: Instance>: SealedNonInvertingPin<T> {}
218#[allow(private_bounds)]
220pub trait InvertingPin<T: Instance>: SealedInvertingPin<T> {}
221#[allow(private_bounds)]
223pub trait OutputPin<T: Instance>: SealedOutputPin<T> {}
224
225macro_rules! impl_opamp_external_output {
226 ($inst:ident, $adc:ident, $ch:expr) => {
227 foreach_adc!(
228 ($adc, $common_inst:ident, $adc_clock:ident) => {
229 impl<'d> crate::adc::SealedAdcChannel<crate::peripherals::$adc>
230 for OpAmpOutput<'d, crate::peripherals::$inst>
231 {
232 fn channel(&self) -> u8 {
233 $ch
234 }
235 }
236
237 impl<'d> crate::adc::AdcChannel<crate::peripherals::$adc>
238 for OpAmpOutput<'d, crate::peripherals::$inst>
239 {
240 }
241 };
242 );
243 };
244}
245
246foreach_peripheral!(
247 (opamp, OPAMP1) => {
248 impl_opamp_external_output!(OPAMP1, ADC1, 3);
249 };
250 (opamp, OPAMP2) => {
251 impl_opamp_external_output!(OPAMP2, ADC2, 3);
252 };
253 (opamp, OPAMP3) => {
254 impl_opamp_external_output!(OPAMP3, ADC1, 12);
255 impl_opamp_external_output!(OPAMP3, ADC3, 1);
256 };
257 (opamp, OPAMP4) => {
259 impl_opamp_external_output!(OPAMP4, ADC1, 11);
260 impl_opamp_external_output!(OPAMP4, ADC4, 3);
261 };
262 (opamp, OPAMP5) => {
264 impl_opamp_external_output!(OPAMP5, ADC5, 1);
265 };
266 (opamp, OPAMP6) => {
268 impl_opamp_external_output!(OPAMP6, ADC1, 14);
269 impl_opamp_external_output!(OPAMP6, ADC2, 14);
270 };
271);
272
273#[cfg(opamp_g4)]
274macro_rules! impl_opamp_internal_output {
275 ($inst:ident, $adc:ident, $ch:expr) => {
276 foreach_adc!(
277 ($adc, $common_inst:ident, $adc_clock:ident) => {
278 impl<'d> crate::adc::SealedAdcChannel<crate::peripherals::$adc>
279 for OpAmpInternalOutput<'d, crate::peripherals::$inst>
280 {
281 fn channel(&self) -> u8 {
282 $ch
283 }
284 }
285
286 impl<'d> crate::adc::AdcChannel<crate::peripherals::$adc>
287 for OpAmpInternalOutput<'d, crate::peripherals::$inst>
288 {
289 }
290 };
291 );
292 };
293}
294
295#[cfg(opamp_g4)]
296foreach_peripheral!(
297 (opamp, OPAMP1) => {
298 impl_opamp_internal_output!(OPAMP1, ADC1, 13);
299 };
300 (opamp, OPAMP2) => {
301 impl_opamp_internal_output!(OPAMP2, ADC2, 16);
302 };
303 (opamp, OPAMP3) => {
304 impl_opamp_internal_output!(OPAMP3, ADC2, 18);
305 impl_opamp_internal_output!(OPAMP3, ADC3, 13);
307 };
308 (opamp, OPAMP4) => {
310 impl_opamp_internal_output!(OPAMP4, ADC5, 5);
311 };
312 (opamp, OPAMP5) => {
314 impl_opamp_internal_output!(OPAMP5, ADC5, 3);
315 };
316 (opamp, OPAMP6) => {
318 impl_opamp_internal_output!(OPAMP6, ADC4, 17);
320 impl_opamp_internal_output!(OPAMP6, ADC3, 17);
322 };
323);
324
325foreach_peripheral! {
326 (opamp, $inst:ident) => {
327 impl SealedInstance for crate::peripherals::$inst {
328 fn regs() -> crate::pac::opamp::Opamp {
329 crate::pac::$inst
330 }
331 }
332
333 impl Instance for crate::peripherals::$inst {
334 }
335 };
336}
337
338#[allow(unused_macros)]
339macro_rules! impl_opamp_vp_pin {
340 ($inst:ident, $pin:ident, $ch:expr) => {
341 impl crate::opamp::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {}
342 impl crate::opamp::SealedNonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {
343 fn channel(&self) -> u8 {
344 $ch
345 }
346 }
347 };
348}
349
350#[allow(unused_macros)]
351macro_rules! impl_opamp_vout_pin {
352 ($inst:ident, $pin:ident) => {
353 impl crate::opamp::OutputPin<peripherals::$inst> for crate::peripherals::$pin {}
354 impl crate::opamp::SealedOutputPin<peripherals::$inst> for crate::peripherals::$pin {}
355 };
356}