stm32l4xx_hal/gpio/
convert.rs

1use super::*;
2
3/// Const assert hack
4struct Assert<const L: u8, const R: u8>;
5
6impl<const L: u8, const R: u8> Assert<L, R> {
7    pub const LESS: u8 = R - L - 1;
8}
9
10impl<MODE, HL, const P: char, const N: u8> Pin<MODE, HL, P, N> {
11    fn set_alternate<const A: u8>(&mut self) {
12        #[allow(path_statements, clippy::no_effect)]
13        {
14            Assert::<A, 16>::LESS;
15        }
16        let offset = 2 * { N };
17        unsafe {
18            if N < 8 {
19                let offset2 = 4 * { N };
20                (*Gpio::<P>::ptr()).afrl.modify(|r, w| {
21                    w.bits((r.bits() & !(0b1111 << offset2)) | ((A as u32) << offset2))
22                });
23            } else {
24                let offset2 = 4 * { N - 8 };
25                (*Gpio::<P>::ptr()).afrh.modify(|r, w| {
26                    w.bits((r.bits() & !(0b1111 << offset2)) | ((A as u32) << offset2))
27                });
28            }
29            (*Gpio::<P>::ptr())
30                .moder
31                .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset)));
32        }
33    }
34    /// Configures the pin to operate alternate mode
35    pub fn into_alternate<const A: u8>(
36        mut self,
37        _moder: &mut MODER<P>,
38        _otyper: &mut OTYPER<P>,
39        _afr: &mut Afr<HL, P>,
40    ) -> Pin<Alternate<PushPull, A>, HL, P, N> {
41        self.set_alternate::<A>();
42        Pin::new()
43    }
44
45    /// Configures the pin to operate alternate mode (alias for `into_alternate`)
46    pub fn into_alternate_push_pull<const A: u8>(
47        self,
48        moder: &mut MODER<P>,
49        otyper: &mut OTYPER<P>,
50        afr: &mut Afr<HL, P>,
51    ) -> Pin<Alternate<PushPull, A>, HL, P, N> {
52        self.into_alternate::<A>(moder, otyper, afr)
53    }
54
55    /// Configures the pin to operate in alternate open drain mode
56    #[allow(path_statements)]
57    pub fn into_alternate_open_drain<const A: u8>(
58        self,
59        moder: &mut MODER<P>,
60        otyper: &mut OTYPER<P>,
61        afr: &mut Afr<HL, P>,
62    ) -> Pin<Alternate<OpenDrain, A>, HL, P, N> {
63        self.into_alternate::<A>(moder, otyper, afr)
64            .set_open_drain()
65    }
66
67    /// Configures the pin to operate as a floating input pin
68    pub fn into_floating_input(
69        mut self,
70        _moder: &mut MODER<P>,
71        _pupdr: &mut PUPDR<P>,
72    ) -> Pin<Input<Floating>, HL, P, N> {
73        self.mode::<Input<Floating>>();
74        Pin::new()
75    }
76
77    /// Configures the pin to operate as a pulled down input pin
78    pub fn into_pull_down_input(
79        mut self,
80        _moder: &mut MODER<P>,
81        _pupdr: &mut PUPDR<P>,
82    ) -> Pin<Input<PullDown>, HL, P, N> {
83        self.mode::<Input<PullDown>>();
84        Pin::new()
85    }
86
87    /// Configures the pin to operate as a pulled up input pin
88    pub fn into_pull_up_input(
89        mut self,
90        _moder: &mut MODER<P>,
91        _pupdr: &mut PUPDR<P>,
92    ) -> Pin<Input<PullUp>, HL, P, N> {
93        self.mode::<Input<PullUp>>();
94        Pin::new()
95    }
96
97    /// Configures the pin to operate as an open drain output pin
98    /// Initial state will be low.
99    pub fn into_open_drain_output(
100        mut self,
101        _moder: &mut MODER<P>,
102        _otyper: &mut OTYPER<P>,
103    ) -> Pin<Output<OpenDrain>, HL, P, N> {
104        self.mode::<Output<OpenDrain>>();
105        Pin::new()
106    }
107
108    /// Configures the pin to operate as an open-drain output pin.
109    /// `initial_state` specifies whether the pin should be initially high or low.
110    pub fn into_open_drain_output_in_state(
111        mut self,
112        _moder: &mut MODER<P>,
113        _otyper: &mut OTYPER<P>,
114        initial_state: PinState,
115    ) -> Pin<Output<OpenDrain>, HL, P, N> {
116        self._set_state(initial_state);
117        self.mode::<Output<OpenDrain>>();
118        Pin::new()
119    }
120
121    /// Configures the pin to operate as an push pull output pin
122    /// Initial state will be low.
123    pub fn into_push_pull_output(
124        mut self,
125        _moder: &mut MODER<P>,
126        _otyper: &mut OTYPER<P>,
127    ) -> Pin<Output<PushPull>, HL, P, N> {
128        self._set_low();
129        self.mode::<Output<PushPull>>();
130        Pin::new()
131    }
132
133    /// Configures the pin to operate as an push-pull output pin.
134    /// `initial_state` specifies whether the pin should be initially high or low.
135    pub fn into_push_pull_output_in_state(
136        mut self,
137        _moder: &mut MODER<P>,
138        _otyper: &mut OTYPER<P>,
139        initial_state: PinState,
140    ) -> Pin<Output<PushPull>, HL, P, N> {
141        self._set_state(initial_state);
142        self.mode::<Output<PushPull>>();
143        Pin::new()
144    }
145
146    /// Configures the pin to operate as an analog input pin
147    pub fn into_analog(
148        mut self,
149        _moder: &mut MODER<P>,
150        _pupdr: &mut PUPDR<P>,
151    ) -> Pin<Analog, HL, P, N> {
152        self.mode::<Analog>();
153        Pin::new()
154    }
155
156    /// Puts `self` into mode `M`.
157    ///
158    /// This violates the type state constraints from `MODE`, so callers must
159    /// ensure they use this properly.
160    #[inline(always)]
161    fn mode<M: PinMode>(&mut self) {
162        let offset = 2 * N;
163        unsafe {
164            (*Gpio::<P>::ptr())
165                .pupdr
166                .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | (M::PUPDR << offset)));
167
168            if let Some(otyper) = M::OTYPER {
169                (*Gpio::<P>::ptr())
170                    .otyper
171                    .modify(|r, w| w.bits(r.bits() & !(0b1 << N) | (otyper << N)));
172            }
173
174            (*Gpio::<P>::ptr())
175                .moder
176                .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | (M::MODER << offset)));
177        }
178    }
179}
180
181impl<MODE, HL, const P: char, const N: u8> Pin<MODE, HL, P, N>
182where
183    MODE: PinMode,
184{
185    fn with_mode<M, F, R>(&mut self, f: F) -> R
186    where
187        M: PinMode,
188        F: FnOnce(&mut Pin<M, HL, P, N>) -> R,
189    {
190        self.mode::<M>();
191
192        // This will reset the pin back to the original mode when dropped.
193        // (so either when `with_mode` returns or when `f` unwinds)
194        let _resetti = ResetMode { pin: self };
195
196        let mut witness = Pin::new();
197
198        f(&mut witness)
199    }
200
201    /// Temporarily configures this pin as a floating input.
202    ///
203    /// The closure `f` is called with the reconfigured pin. After it returns,
204    /// the pin will be configured back.
205    pub fn with_floating_input<R>(
206        &mut self,
207        f: impl FnOnce(&mut Pin<Input<Floating>, HL, P, N>) -> R,
208    ) -> R {
209        self.with_mode(f)
210    }
211
212    /// Temporarily configures this pin as a pulled-down input.
213    ///
214    /// The closure `f` is called with the reconfigured pin. After it returns,
215    /// the pin will be configured back.
216    pub fn with_pull_down_input<R>(
217        &mut self,
218        f: impl FnOnce(&mut Pin<Input<PullDown>, HL, P, N>) -> R,
219    ) -> R {
220        self.with_mode(f)
221    }
222
223    /// Temporarily configures this pin as a pulled-up input.
224    ///
225    /// The closure `f` is called with the reconfigured pin. After it returns,
226    /// the pin will be configured back.
227    pub fn with_pull_up_input<R>(
228        &mut self,
229        f: impl FnOnce(&mut Pin<Input<PullUp>, HL, P, N>) -> R,
230    ) -> R {
231        self.with_mode(f)
232    }
233
234    /// Temporarily configures this pin as an analog pin.
235    ///
236    /// The closure `f` is called with the reconfigured pin. After it returns,
237    /// the pin will be configured back.
238    pub fn with_analog<R>(&mut self, f: impl FnOnce(&mut Pin<Analog, HL, P, N>) -> R) -> R {
239        self.with_mode(f)
240    }
241
242    /// Temporarily configures this pin as an open drain output.
243    ///
244    /// The closure `f` is called with the reconfigured pin. After it returns,
245    /// the pin will be configured back.
246    /// The value of the pin after conversion is undefined. If you
247    /// want to control it, use `with_open_drain_output_in_state`
248    pub fn with_open_drain_output<R>(
249        &mut self,
250        f: impl FnOnce(&mut Pin<Output<OpenDrain>, HL, P, N>) -> R,
251    ) -> R {
252        self.with_mode(f)
253    }
254
255    /// Temporarily configures this pin as an open drain output .
256    ///
257    /// The closure `f` is called with the reconfigured pin. After it returns,
258    /// the pin will be configured back.
259    /// Note that the new state is set slightly before conversion
260    /// happens. This can cause a short output glitch if switching
261    /// between output modes
262    pub fn with_open_drain_output_in_state<R>(
263        &mut self,
264        state: PinState,
265        f: impl FnOnce(&mut Pin<Output<OpenDrain>, HL, P, N>) -> R,
266    ) -> R {
267        self._set_state(state);
268        self.with_mode(f)
269    }
270
271    /// Temporarily configures this pin as a push-pull output.
272    ///
273    /// The closure `f` is called with the reconfigured pin. After it returns,
274    /// the pin will be configured back.
275    /// The value of the pin after conversion is undefined. If you
276    /// want to control it, use `with_push_pull_output_in_state`
277    pub fn with_push_pull_output<R>(
278        &mut self,
279        f: impl FnOnce(&mut Pin<Output<PushPull>, HL, P, N>) -> R,
280    ) -> R {
281        self.with_mode(f)
282    }
283
284    /// Temporarily configures this pin as a push-pull output.
285    ///
286    /// The closure `f` is called with the reconfigured pin. After it returns,
287    /// the pin will be configured back.
288    /// Note that the new state is set slightly before conversion
289    /// happens. This can cause a short output glitch if switching
290    /// between output modes
291    pub fn with_push_pull_output_in_state<R>(
292        &mut self,
293        state: PinState,
294        f: impl FnOnce(&mut Pin<Output<PushPull>, HL, P, N>) -> R,
295    ) -> R {
296        self._set_state(state);
297        self.with_mode(f)
298    }
299}
300
301struct ResetMode<'a, ORIG: PinMode, HL, const P: char, const N: u8> {
302    pin: &'a mut Pin<ORIG, HL, P, N>,
303}
304
305impl<'a, ORIG: PinMode, HL, const P: char, const N: u8> Drop for ResetMode<'a, ORIG, HL, P, N> {
306    fn drop(&mut self) {
307        self.pin.mode::<ORIG>();
308    }
309}
310
311/// Marker trait for valid pin modes (type state).
312///
313/// It can not be implemented by outside types.
314pub trait PinMode: crate::Sealed {
315    // These constants are used to implement the pin configuration code.
316    // They are not part of public API.
317
318    #[doc(hidden)]
319    const PUPDR: u32;
320    #[doc(hidden)]
321    const MODER: u32;
322    #[doc(hidden)]
323    const OTYPER: Option<u32> = None;
324}
325
326impl crate::Sealed for Input<Floating> {}
327impl PinMode for Input<Floating> {
328    const PUPDR: u32 = 0b00;
329    const MODER: u32 = 0b00;
330}
331
332impl crate::Sealed for Input<PullDown> {}
333impl PinMode for Input<PullDown> {
334    const PUPDR: u32 = 0b10;
335    const MODER: u32 = 0b00;
336}
337
338impl crate::Sealed for Input<PullUp> {}
339impl PinMode for Input<PullUp> {
340    const PUPDR: u32 = 0b01;
341    const MODER: u32 = 0b00;
342}
343
344impl crate::Sealed for Analog {}
345impl PinMode for Analog {
346    const PUPDR: u32 = 0b00;
347    const MODER: u32 = 0b11;
348}
349
350impl crate::Sealed for Output<OpenDrain> {}
351impl PinMode for Output<OpenDrain> {
352    const PUPDR: u32 = 0b00;
353    const MODER: u32 = 0b01;
354    const OTYPER: Option<u32> = Some(0b1);
355}
356
357impl crate::Sealed for Output<PushPull> {}
358impl PinMode for Output<PushPull> {
359    const PUPDR: u32 = 0b00;
360    const MODER: u32 = 0b01;
361    const OTYPER: Option<u32> = Some(0b0);
362}