1use core::marker::PhantomData;
4
5use crate::analog::dac;
6use crate::exti::{Event as ExtiEvent, ExtiExt};
7use crate::gpio::*;
8use crate::rcc::{Clocks, Rcc};
9use crate::stm32::comp::{COMP1_CSR, COMP2_CSR};
10use crate::stm32::{COMP, EXTI};
11
12pub struct Enabled;
14
15pub struct Disabled;
17
18pub trait ED {}
19impl ED for Enabled {}
20impl ED for Disabled {}
21
22pub struct COMP1 {
23 _rb: PhantomData<()>,
24}
25
26impl COMP1 {
27 pub fn csr(&self) -> &COMP1_CSR {
28 &unsafe { &*COMP::ptr() }.comp1_csr
31 }
32}
33
34pub struct COMP2 {
35 _rb: PhantomData<()>,
36}
37
38impl COMP2 {
39 pub fn csr(&self) -> &COMP2_CSR {
40 &unsafe { &*COMP::ptr() }.comp2_csr
43 }
44}
45
46#[derive(Copy, Clone, Eq, PartialEq)]
50pub struct Config {
51 power_mode: PowerMode,
52 hysteresis: Hysteresis,
53 inverted: bool,
54 output_xor: bool,
55}
56
57impl Default for Config {
58 fn default() -> Self {
59 Self {
60 hysteresis: Hysteresis::None,
61 inverted: false,
62 power_mode: PowerMode::HighSpeed,
63 output_xor: false,
64 }
65 }
66}
67
68impl Config {
69 pub fn hysteresis(mut self, hysteresis: Hysteresis) -> Self {
70 self.hysteresis = hysteresis;
71 self
72 }
73
74 pub fn output_inverted(mut self) -> Self {
75 self.inverted = true;
76 self
77 }
78
79 pub fn output_polarity(mut self, inverted: bool) -> Self {
80 self.inverted = inverted;
81 self
82 }
83
84 pub fn power_mode(mut self, power_mode: PowerMode) -> Self {
85 self.power_mode = power_mode;
86 self
87 }
88
89 pub fn output_xor(mut self) -> Self {
92 self.output_xor = true;
93 self
94 }
95}
96
97#[derive(Copy, Clone, Eq, PartialEq)]
98pub enum Hysteresis {
99 None = 0b00,
100 Low = 0b01,
101 Medium = 0b10,
102 High = 0b11,
103}
104
105#[derive(Copy, Clone, Eq, PartialEq)]
106pub enum PowerMode {
107 HighSpeed = 0b00,
108 MediumSpeed = 0b01,
109}
110
111pub trait PositiveInput<C> {
113 fn setup(&self, comp: &C);
114}
115
116pub trait NegativeInput<C> {
118 fn setup(&self, comp: &C);
119}
120
121#[derive(Copy, Clone, Eq, PartialEq)]
123pub struct Open;
124
125#[derive(Copy, Clone, Eq, PartialEq)]
128pub struct Comp1InP;
129
130#[derive(Copy, Clone, Eq, PartialEq)]
133pub struct Comp2InP;
134
135macro_rules! window_input_pin {
136 ($COMP:ident, $pin:ty) => {
137 impl PositiveInput<$COMP> for $pin {
138 fn setup(&self, comp: &$COMP) {
139 comp.csr().modify(|_, w| w.winmode().set_bit())
140 }
141 }
142 };
143}
144
145window_input_pin!(COMP1, Comp2InP);
146window_input_pin!(COMP2, Comp1InP);
147
148macro_rules! positive_input_pin {
149 ($COMP:ident, $pin:ty, $bits:expr) => {
150 impl PositiveInput<$COMP> for $pin {
151 fn setup(&self, comp: &$COMP) {
152 comp.csr().modify(|_, w| unsafe { w.inpsel().bits($bits) })
153 }
154 }
155 };
156}
157
158positive_input_pin!(COMP1, PC5<Analog>, 0b00);
159positive_input_pin!(COMP1, PB2<Analog>, 0b01);
160positive_input_pin!(COMP1, PA1<Analog>, 0b10);
161positive_input_pin!(COMP1, Open, 0b11);
162
163positive_input_pin!(COMP2, PB4<Analog>, 0b00);
164positive_input_pin!(COMP2, PB6<Analog>, 0b01);
165positive_input_pin!(COMP2, PA3<Analog>, 0b10);
166positive_input_pin!(COMP2, Open, 0b11);
167
168macro_rules! negative_input_pin {
169 ($COMP:ident, $pin:ty, $bits:expr) => {
170 impl NegativeInput<$COMP> for $pin {
171 fn setup(&self, comp: &$COMP) {
172 comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) })
173 }
174 }
175 };
176}
177
178negative_input_pin!(COMP1, PB1<Analog>, 0b0110);
179negative_input_pin!(COMP1, PC4<Analog>, 0b0111);
180negative_input_pin!(COMP1, PA0<Analog>, 0b1000);
181
182negative_input_pin!(COMP2, PB3<Analog>, 0b0110);
183negative_input_pin!(COMP2, PB7<Analog>, 0b0111);
184negative_input_pin!(COMP2, PA2<Analog>, 0b1000);
185
186#[derive(Copy, Clone, Eq, PartialEq)]
187pub enum RefintInput {
188 VRefintM14 = 0b0000,
190 VRefintM12 = 0b0001,
192 VRefintM34 = 0b0010,
194 VRefint = 0b0011,
196}
197
198macro_rules! refint_input {
199 ($COMP:ident) => {
200 impl NegativeInput<$COMP> for RefintInput {
201 fn setup(&self, comp: &$COMP) {
202 comp.csr()
203 .modify(|_, w| unsafe { w.inmsel().bits(*self as u8) })
204 }
205 }
206 };
207}
208
209refint_input!(COMP1);
210refint_input!(COMP2);
211
212macro_rules! dac_input {
213 ($COMP:ident, $channel:ty, $bits:expr) => {
214 impl<ED> NegativeInput<$COMP> for &$channel {
215 fn setup(&self, comp: &$COMP) {
216 comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) })
217 }
218 }
219 };
220}
221
222#[cfg(any(feature = "stm32g071", feature = "stm32g081"))]
223dac_input!(COMP1, dac::Channel1<ED>, 0b0100);
224#[cfg(any(feature = "stm32g071", feature = "stm32g081"))]
225dac_input!(COMP1, dac::Channel2<ED>, 0b0101);
226
227#[cfg(any(feature = "stm32g071", feature = "stm32g081"))]
228dac_input!(COMP2, dac::Channel1<ED>, 0b0100);
229#[cfg(any(feature = "stm32g071", feature = "stm32g081"))]
230dac_input!(COMP2, dac::Channel2<ED>, 0b0101);
231
232pub struct Comparator<C, ED> {
233 regs: C,
234 _enabled: PhantomData<ED>,
235}
236
237pub trait ComparatorExt<COMP> {
238 fn comparator<P: PositiveInput<COMP>, N: NegativeInput<COMP>>(
240 self,
241 positive_input: P,
242 negative_input: N,
243 config: Config,
244 clocks: &Clocks,
245 ) -> Comparator<COMP, Disabled>;
246}
247
248macro_rules! impl_comparator {
249 ($COMP:ty, $comp:ident, $Event:expr) => {
250 impl ComparatorExt<$COMP> for $COMP {
251 fn comparator<P: PositiveInput<$COMP>, N: NegativeInput<$COMP>>(
252 self,
253 positive_input: P,
254 negative_input: N,
255 config: Config,
256 clocks: &Clocks,
257 ) -> Comparator<$COMP, Disabled> {
258 positive_input.setup(&self);
259 negative_input.setup(&self);
260 let voltage_scaler_delay = clocks.sys_clk.raw() / (1_000_000 / 200); cortex_m::asm::delay(voltage_scaler_delay);
263 self.csr().modify(|_, w| unsafe {
264 w.hyst()
265 .bits(config.hysteresis as u8)
266 .polarity()
267 .bit(config.inverted)
268 .pwrmode()
269 .bits(config.power_mode as u8)
270 .winout()
271 .bit(config.output_xor)
272 });
273
274 Comparator {
275 regs: self,
276 _enabled: PhantomData,
277 }
278 }
279 }
280
281 impl Comparator<$COMP, Disabled> {
282 pub fn $comp<P: PositiveInput<$COMP>, N: NegativeInput<$COMP>>(
284 comp: $COMP,
285 positive_input: P,
286 negative_input: N,
287 config: Config,
288 clocks: &Clocks,
289 ) -> Self {
290 comp.comparator(positive_input, negative_input, config, clocks)
291 }
292
293 pub fn enable(self) -> Comparator<$COMP, Enabled> {
295 self.regs.csr().modify(|_, w| w.en().set_bit());
296 Comparator {
297 regs: self.regs,
298 _enabled: PhantomData,
299 }
300 }
301
302 pub fn listen(&self, edge: SignalEdge, exti: &EXTI) {
304 exti.listen($Event, edge);
305 }
306 }
307
308 impl Comparator<$COMP, Enabled> {
309 pub fn output(&self) -> bool {
311 self.regs.csr().read().value().bit_is_set()
312 }
313
314 pub fn disable(self) -> Comparator<$COMP, Disabled> {
316 self.regs.csr().modify(|_, w| w.en().clear_bit());
317 Comparator {
318 regs: self.regs,
319 _enabled: PhantomData,
320 }
321 }
322 }
323
324 impl<ED> Comparator<$COMP, ED> {
325 pub fn unlisten(&self, exti: &EXTI) {
327 exti.unlisten($Event);
328 }
329
330 pub fn is_pending(&self, edge: SignalEdge, exti: &EXTI) -> bool {
332 exti.is_pending($Event, edge)
333 }
334
335 pub fn unpend(&self, exti: &EXTI) {
337 exti.unpend($Event);
338 }
339
340 pub fn output_pin<P: OutputPin<$COMP>>(&self, pin: P) {
344 pin.setup();
345 }
346 }
347 };
348}
349
350impl_comparator!(COMP1, comp1, ExtiEvent::COMP1);
351impl_comparator!(COMP2, comp2, ExtiEvent::COMP2);
352
353pub struct WindowComparator<U, L, ED> {
356 pub upper: Comparator<U, ED>,
357 pub lower: Comparator<L, ED>,
358}
359
360pub trait WindowComparatorExt<UC, LC> {
361 fn window_comparator<I: PositiveInput<UC>, L: NegativeInput<LC>, U: NegativeInput<UC>>(
365 self,
366 input: I,
367 lower_threshold: L,
368 upper_threshold: U,
369 config: Config,
370 clocks: &Clocks,
371 ) -> WindowComparator<UC, LC, Disabled>;
372}
373
374macro_rules! impl_window_comparator {
375 ($UPPER:ident, $LOWER:ident, $LOTHR:expr) => {
376 impl WindowComparatorExt<$UPPER, $LOWER> for ($UPPER, $LOWER) {
377 fn window_comparator<
378 I: PositiveInput<$UPPER>,
379 L: NegativeInput<$LOWER>,
380 U: NegativeInput<$UPPER>,
381 >(
382 self,
383 input: I,
384 lower_threshold: L,
385 upper_threshold: U,
386 config: Config,
387 clocks: &Clocks,
388 ) -> WindowComparator<$UPPER, $LOWER, Disabled> {
389 let (upper, lower) = self;
390
391 let mut configu = config.clone();
392 configu.output_xor = true;
393 let upper = upper.comparator(input, upper_threshold, configu, clocks);
394
395 let mut configl = config;
396 configl.output_xor = false;
397 let lower = lower.comparator($LOTHR, lower_threshold, configl, clocks);
398
399 WindowComparator { upper, lower }
400 }
401 }
402
403 impl WindowComparator<$UPPER, $LOWER, Disabled> {
404 pub fn enable(self) -> WindowComparator<$UPPER, $LOWER, Enabled> {
406 WindowComparator {
407 upper: self.upper.enable(),
408 lower: self.lower.enable(),
409 }
410 }
411
412 pub fn listen(&self, edge: SignalEdge, exti: &mut EXTI) {
414 self.upper.listen(edge, exti)
415 }
416 }
417
418 impl WindowComparator<$UPPER, $LOWER, Enabled> {
419 pub fn disable(self) -> WindowComparator<$UPPER, $LOWER, Disabled> {
421 WindowComparator {
422 upper: self.upper.disable(),
423 lower: self.lower.disable(),
424 }
425 }
426
427 pub fn output(&self) -> bool {
429 self.upper.output()
430 }
431
432 pub fn above_lower(&self) -> bool {
434 self.lower.output()
435 }
436 }
437
438 impl<ED> WindowComparator<$UPPER, $LOWER, ED> {
439 pub fn output_pin<P: OutputPin<$UPPER>>(&self, pin: P) {
443 self.upper.output_pin(pin)
444 }
445
446 pub fn unlisten(&self, exti: &mut EXTI) {
448 self.upper.unlisten(exti)
449 }
450
451 pub fn is_pending(&self, edge: SignalEdge, exti: &EXTI) -> bool {
453 self.upper.is_pending(edge, exti)
454 }
455
456 pub fn unpend(&self, exti: &EXTI) {
458 self.upper.unpend(exti)
459 }
460 }
461 };
462}
463
464impl_window_comparator!(COMP1, COMP2, Comp1InP);
465impl_window_comparator!(COMP2, COMP1, Comp2InP);
466
467pub fn window_comparator12<
468 I: PositiveInput<COMP1>,
469 L: NegativeInput<COMP2>,
470 U: NegativeInput<COMP1>,
471>(
472 comp: COMP,
473 input: I,
474 lower_threshold: L,
475 upper_threshold: U,
476 config: Config,
477 rcc: &mut Rcc,
478) -> WindowComparator<COMP1, COMP2, Disabled> {
479 let (comp1, comp2) = comp.split(rcc);
480 (comp1, comp2).window_comparator(input, lower_threshold, upper_threshold, config, &rcc.clocks)
481}
482
483pub fn window_comparator21<
484 I: PositiveInput<COMP2>,
485 L: NegativeInput<COMP1>,
486 U: NegativeInput<COMP2>,
487>(
488 comp: COMP,
489 input: I,
490 lower_threshold: L,
491 upper_threshold: U,
492 config: Config,
493 rcc: &mut Rcc,
494) -> WindowComparator<COMP2, COMP1, Disabled> {
495 let (comp1, comp2) = comp.split(rcc);
496 (comp2, comp1).window_comparator(input, lower_threshold, upper_threshold, config, &rcc.clocks)
497}
498
499pub fn split(_comp: COMP, rcc: &mut Rcc) -> (COMP1, COMP2) {
501 rcc.rb.apbenr2.modify(|_, w| w.syscfgen().set_bit());
503
504 rcc.rb.apbrstr2.modify(|_, w| w.syscfgrst().set_bit());
506 rcc.rb.apbrstr2.modify(|_, w| w.syscfgrst().clear_bit());
507
508 (COMP1 { _rb: PhantomData }, COMP2 { _rb: PhantomData })
509}
510
511pub trait ComparatorSplit {
512 fn split(self, rcc: &mut Rcc) -> (COMP1, COMP2);
514}
515
516impl ComparatorSplit for COMP {
517 fn split(self, rcc: &mut Rcc) -> (COMP1, COMP2) {
518 split(self, rcc)
519 }
520}
521
522pub trait OutputPin<COMP> {
523 fn setup(&self);
524 fn release(self) -> Self;
525}
526
527macro_rules! output_pin_push_pull {
528 ($COMP:ident, $pin:ty) => {
529 impl OutputPin<$COMP> for $pin {
530 fn setup(&self) {
531 self.set_alt_mode(AltFunction::AF7)
532 }
533
534 fn release(self) -> Self {
535 self.into_push_pull_output()
536 }
537 }
538 };
539}
540
541macro_rules! output_pin_open_drain {
542 ($COMP:ident, $pin:ty) => {
543 impl OutputPin<$COMP> for $pin {
544 fn setup(&self) {
545 self.set_alt_mode(AltFunction::AF7)
546 }
547
548 fn release(self) -> Self {
549 self.into_open_drain_output()
550 }
551 }
552 };
553}
554
555output_pin_push_pull!(COMP1, PA0<Output<PushPull>>);
556output_pin_open_drain!(COMP1, PA0<Output<OpenDrain>>);
557output_pin_push_pull!(COMP1, PA6<Output<PushPull>>);
558output_pin_open_drain!(COMP1, PA6<Output<OpenDrain>>);
559output_pin_push_pull!(COMP1, PA11<Output<PushPull>>);
560output_pin_open_drain!(COMP1, PA11<Output<OpenDrain>>);
561output_pin_push_pull!(COMP1, PB0<Output<PushPull>>);
562output_pin_open_drain!(COMP1, PB0<Output<OpenDrain>>);
563output_pin_push_pull!(COMP1, PB10<Output<PushPull>>);
564output_pin_open_drain!(COMP1, PB10<Output<OpenDrain>>);
565
566output_pin_push_pull!(COMP2, PA2<Output<PushPull>>);
567output_pin_open_drain!(COMP2, PA2<Output<OpenDrain>>);
568output_pin_push_pull!(COMP2, PA7<Output<PushPull>>);
569output_pin_open_drain!(COMP2, PA7<Output<OpenDrain>>);
570output_pin_push_pull!(COMP2, PA12<Output<PushPull>>);
571output_pin_open_drain!(COMP2, PA12<Output<OpenDrain>>);
572output_pin_push_pull!(COMP2, PB5<Output<PushPull>>);
573output_pin_open_drain!(COMP2, PB5<Output<OpenDrain>>);
574output_pin_push_pull!(COMP2, PB11<Output<PushPull>>);
575output_pin_open_drain!(COMP2, PB11<Output<OpenDrain>>);