stm32_hal2/
comp.rs

1//! Comparator
2//!
3//! TODO:
4//! - Window Mode Configuration (COMP1 and COMP2 have different configs)
5//! - Blanking Source Configuration (COMP1 and COMP2 have different configs)
6//! - More Inputs For Inverting Input (STM32L41xxx/42xxx/43xxx/44xxx/45xxx/46xxx)
7//! - Moving Peripheral into Struct (pac needs to change)
8//! - Add Configuration Defaults
9//! - Interrupts?
10
11use core::marker::PhantomData;
12
13use cfg_if::cfg_if;
14use paste::paste;
15
16use crate::pac;
17#[cfg(any(feature = "g473"))]
18use crate::pac::comp::{C1CSR, C2CSR, C3CSR, C4CSR, C5CSR, C6CSR, C7CSR};
19#[cfg(any(feature = "l4x6"))]
20use crate::pac::comp::{COMP1_CSR, COMP2_CSR};
21#[cfg(any(feature = "h747cm4", feature = "h747cm7"))]
22use crate::pac::comp1::{CFGR1, CFGR2};
23
24// Config enums
25/// Comparator power mode
26#[cfg(any(feature = "l4"))]
27pub enum PowerMode {
28    /// High speed/full power (Lowest propagation delay).
29    HighSpeed = 0x00000000,
30    /// Medium speed/medium power (Medium propagation delay).
31    MediumSpeed = 0x00000004,
32    /// Low speed/ultra-low power (Highest propagation delay).
33    LowSpeed = 0x0000000c,
34}
35
36/// Comparator input plus (Non-inverting Input)
37#[cfg(any(feature = "g473", feature = "h7"))]
38#[derive(Clone, Copy)]
39#[repr(u8)]
40// STM32G4 reference manual section 24.3.2 table 196
41pub enum NonInvertingInput {
42    Io1 = 0b0,
43    Io2 = 0b1,
44}
45
46#[cfg(any(feature = "l4"))]
47pub enum NonInvertingInput {
48    /// From the first GPIO pin connected to the comparator.
49    ///
50    /// The GPIO pin used depends on the MCU and comparator used.
51    Io1 = 0x00000000,
52    /// From the second GPIO pin connected to the comparator.
53    ///
54    /// The GPIO pin used depends on the MCU and comparator used.
55    Io2 = 0x00000080,
56    // PA1/PA3 for STM32L41xxx/42xxx/43xxx/44xxx/45xxx/46xxx
57    // TODO: Include stm32l471
58    #[cfg(any(feature = "stm32l4x1", feature = "stm32l4x2", feature = "stm32l4x3",))]
59    /// From the third GPIO pin connected to the comparator.
60    ///
61    /// The GPIO pin used depends on the MCU and comparator used.
62    Io3 = 0x00000100,
63}
64
65/// Comparator input minus (Inverted Input)
66#[cfg(any(feature = "g473", feature = "h7", feature = "l4"))]
67#[derive(Clone, Copy)]
68#[repr(u8)]
69// STM32G4 reference manual section 24.3.2 table 197
70pub enum InvertingInput {
71    OneQuarterVref = 0b000,
72    OneHalfVref = 0b001,
73    ThreeQuarterVref = 0b010,
74    Vref = 0b011,
75    Dac1 = 0b100,
76    Dac2 = 0b101,
77    Io1 = 0b110,
78    Io2 = 0b111,
79}
80
81/// Comparator hysterisis
82#[cfg(any(feature = "g473"))]
83#[derive(Clone, Copy)]
84pub enum Hysterisis {
85    None = 0b000,
86    TenMilliVolt = 0b001,
87    TwentyMilliVolt = 0b010,
88    ThirtyMilliVolt = 0b011,
89    FourtyMilliVolt = 0b100,
90    FiftyMilliVolt = 0b101,
91    SixtyMilliVolt = 0b110,
92    SeventyMilliVolt = 0b111,
93}
94
95#[cfg(any(feature = "l4", feature = "h7"))]
96pub enum Hysterisis {
97    /// No Hysterisis.
98    NoHysterisis = 0b00,
99    /// Low Hysterisis.
100    LowHysteresis = 0b01,
101    /// Medium Hysterisis.
102    MediumHysteresis = 0b10,
103    /// High Hysterisis.
104    HighHysteresis = 0b11,
105}
106
107/// Comparator output polarity
108///
109/// When [OutputPolarity::NotInverted] is used.
110/// The comparator output will be high (1) when [NonInvertingInput] has higher
111/// voltage than [InvertingInput]. The comparator output will be low (0) when
112/// [NonInvertingInput] has lower voltage than [InvertingInput].
113///
114/// When [OutputPolarity::Inverted] is used.
115/// The comparator output will be high (1) when [NonInvertingInput] has lower
116/// voltage than [InvertingInput]. The comparator output will be low (0) when
117/// [NonInvertingInput] has higher voltage than [InvertingInput].
118
119#[cfg(any(feature = "g473", feature = "h7"))]
120#[derive(Clone, Copy)]
121pub enum OutputPolarity {
122    NotInverted = 0b0,
123    Inverted = 0b1,
124}
125
126#[cfg(any(feature = "l4"))]
127pub enum OutputPolarity {
128    /// Comparator output will not be inverted.
129    NotInverted = 0x00000000,
130    /// Comparator output will be inverted.
131    Inverted = 0x00008000,
132}
133
134/// Comparator blanking source
135pub enum BlankingSource {
136    /// No Blanking.
137    None = 0x00000000,
138    /// TIM1 OC5 as the blanking source.
139    Timloc5 = 0x400000,
140}
141
142/// Comparator devices avaiable.
143#[cfg(any(feature = "g473"))]
144pub enum CompDevice {
145    One,
146    Two,
147    Three,
148    Four,
149    Five,
150    Six,
151    Seven,
152}
153
154// Structs
155/// Initial configuration data for the comparator peripheral.
156
157#[cfg(any(feature = "g473"))]
158#[derive(Clone, Copy)]
159pub struct CompConfig {
160    pub inpsel: NonInvertingInput,
161    pub inmsel: InvertingInput,
162    pub hyst: Hysterisis,
163    pub polarity: OutputPolarity,
164}
165
166#[cfg(any(feature = "l4"))]
167pub struct CompConfig {
168    /// Comparator power mode.
169    pub pwrmode: PowerMode,
170    /// Comparator non-inverting input.
171    pub inpsel: NonInvertingInput,
172    /// Comparator inverting input.
173    pub inmsel: InvertingInput,
174    /// Comparator hysterisis.
175    pub hyst: Hysterisis,
176    /// Comparator output polarity.
177    pub polarity: OutputPolarity,
178    // Comparator blanking source.
179    // pub blanking: BlankingSource,
180}
181
182/// Represents an Analog Comparator peripheral.
183pub struct Comp<T> {
184    phantom: PhantomData<T>,
185    /// The lock status of the comparator.
186    is_locked: bool,
187}
188
189// Macro to implement a comparator using generics
190// This will create `new_compX` methods to instantiate a new comparator
191// and provide a csr() method to access the register scoped to this comparator
192macro_rules! make_comp {
193    ($csr_type:ident, $csr_reg:ident, $comp:ident) => {
194        impl Comp<$csr_type> {
195            paste! {
196                pub fn [<new_ $comp>]() -> Self {
197                    unsafe {
198                        Self {
199                            phantom: PhantomData,
200                            is_locked: false
201                        }
202                    }
203                }
204            }
205
206            // Get a reference to the CSR from the COMP RegisterBlock for this comparator
207            pub fn csr(&self) -> &$csr_type {
208                #[cfg(any(feature = "g473", feature = "l4"))]
209                unsafe {
210                    &(*pac::COMP::ptr()).$csr_reg
211                }
212                #[cfg(any(feature = "h747cm4", feature = "h747cm7"))]
213                unsafe {
214                    &(*pac::COMP1::ptr()).$csr_reg
215                }
216            }
217
218            pub fn enable(&self) {
219                self.csr().modify(|_, w| w.en().set_bit());
220            }
221
222            pub fn disable(&self) {
223                self.csr().modify(|_, w| w.en().clear_bit());
224            }
225
226            // Sets the inverting input in the CSR
227            pub fn set_inverting_input(&self, input: InvertingInput) {
228                cfg_if! {
229                    if #[cfg(feature = "l4")] {
230                        unsafe { self.csr().modify(|_,w| w.inmsel().bits(input as u8)) };
231                    } else {
232                        self.csr().modify(|_,w| w.inmsel().variant(input as u8));
233                    }
234                }
235            }
236
237            pub fn set_non_inverting_input(&self, input: NonInvertingInput) {
238                cfg_if! {
239                    if #[cfg(feature = "l4")] {
240                        self.csr().modify(|_,w| w.inpsel().bit(input as u8 != 0));
241                    } else {
242                        self.csr().modify(|_,w| w.inpsel().variant(input as u8 != 0));
243                    }
244                }
245            }
246
247            pub fn set_polarity(&self, polarity: OutputPolarity) {
248                cfg_if! {
249                    if #[cfg(feature = "l4")] {
250                        self.csr().modify(|_,w| w.polarity().bit((polarity as u8) != 0));
251                    } else {
252                        #[cfg(feature = "g4")]
253                        self.csr().modify(|_,w| w.pol().variant((polarity as u8) != 0));
254
255                        #[cfg(feature = "h7")]
256                        self.csr().modify(|_,w| w.polarity().variant((polarity as u8) != 0));
257                    }
258                }
259            }
260
261            pub fn set_hysterisis(&self, hyst: Hysterisis) {
262                cfg_if! {
263                    if #[cfg(feature = "l4")] {
264                        self.csr().modify(|_,w| w.hyst().bits((hyst as u8)));
265                    } else {
266                        self.csr().modify(|_,w| w.hyst().variant((hyst as u8)));
267                    }
268                }
269            }
270
271            pub fn set_blanking_source(&self, source: u8) {
272                #[cfg(feature = "g473")]
273                self.csr().modify(|_, w| w.blanksel().variant(source));
274
275                #[cfg(feature = "h7")]
276                self.csr().modify(|_, w| w.blanking().variant(source));
277            }
278
279            /// Locks the comparator.
280            ///
281            /// This locks the comparator registers making it only read-only.
282            ///
283            /// **Note:** The lock also applies to the lock bit itself. Therefore,
284            /// the comparator register/configuration **cannot** be changed until
285            /// a hardware reset.
286            pub fn lock(&mut self) {
287                self.is_locked = true;
288                self.csr().modify(|_, w| w.lock().set_bit());
289            }
290
291            /// Gets the output level of the comparator
292            ///
293            /// The output level depends on the configuration of the comparator.
294            /// If the [polarity](CompConfig::polarity) is [NotInverted](OutputPolarity::NotInverted)
295            /// - It will output high (1) if the non-inverting input is higher than
296            /// the output of inverting input.
297            /// - It will output low (0) if the non-inverting input is lower than
298            /// the output of the inverting input.
299            ///
300            /// The oposite will be out inverted if [polarity](CompConfig::polarity) is
301            /// [Inverted](OutputPolarity::NotInverted).
302            pub fn get_output_level(&self) -> bool {
303                cfg_if! {
304                    if #[cfg(any(feature = "g4", feature = "l4"))] {
305                        self.csr().read().value().bit()
306                    }
307                    else if #[cfg(feature = "h7")] {
308                        // On the H7, the comparator output is in a separate status register
309                        let status = unsafe { &(*pac::COMP1::ptr()).sr.read() };
310
311                        // Check which channel this impl is for
312                        match "$csr_reg" {
313                            "c1csr" => {
314                                status.c1val().bit_is_set()
315                            }
316
317                            "c2csr" => {
318                                status.c2val().bit_is_set()
319                            }
320
321                            _ => todo!(),
322                        }
323                    }
324                }
325            }
326        }
327    };
328}
329
330cfg_if! {
331    if #[cfg(any(feature = "g4"))] {
332        make_comp!(C1CSR, c1csr, comp1);
333        make_comp!(C2CSR, c2csr, comp2);
334        make_comp!(C3CSR, c3csr, comp3);
335        make_comp!(C4CSR, c4csr, comp4);
336        make_comp!(C5CSR, c5csr, comp5);
337        make_comp!(C6CSR, c6csr, comp6);
338        make_comp!(C7CSR, c7csr, comp7);
339    } else if #[cfg(any(feature = "l4x6"))] {
340        make_comp!(COMP1_CSR, comp1_csr, comp1);
341        make_comp!(COMP2_CSR, comp2_csr, comp2);
342    } else if #[cfg(any(feature = "h747cm4", feature = "h747cm7"))] {
343        make_comp!(CFGR1, cfgr1, comp1);
344        make_comp!(CFGR2, cfgr2, comp2);
345    }
346}