stm32l1xx_hal/
gpio.rs

1//! General Purpose Input / Output
2
3use core::marker::PhantomData;
4
5/// Extension trait to split a GPIO peripheral in independent pins and registers
6pub trait GpioExt {
7    /// The parts to split the GPIO into
8    type Parts;
9
10    /// Splits the GPIO block into independent pins and registers
11    fn split(self) -> Self::Parts;
12}
13
14/// Input mode (type state)
15pub struct Input<MODE> {
16    _mode: PhantomData<MODE>,
17}
18
19/// Floating input (type state)
20pub struct Floating;
21
22/// Pulled down input (type state)
23pub struct PullDown;
24
25/// Pulled up input (type state)
26pub struct PullUp;
27
28/// Open drain input or output (type state)
29pub struct OpenDrain;
30
31/// Analog mode (type state)
32pub struct Analog;
33
34/// Output mode (type state)
35pub struct Output<MODE> {
36    _mode: PhantomData<MODE>,
37}
38
39/// Push pull output (type state)
40pub struct PushPull;
41
42/// GPIO Pin speed selection
43pub enum Speed {
44    Low = 0,
45    Medium = 1,
46    High = 2,
47    VeryHigh = 3,
48}
49
50#[allow(dead_code)]
51pub(crate) enum AltMode {
52    SYSTEM = 0,
53    TIM2 = 1,
54    TIM3_5 = 2,
55    TIM9_11 = 3,
56    I2C = 4,
57    SPI1_2 = 5,
58    SPI3 = 6,
59    USART1_3 = 7,
60    UART4_5 = 8,
61    USB = 10,
62    LCD = 11,
63    FSMC = 12,
64    RI = 14,
65    EVENTOUT = 15,
66}
67
68macro_rules! gpio {
69    ($GPIOX:ident, $gpiox:ident, $iopxenr:ident, $PXx:ident, [
70        $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty),)+
71    ]) => {
72        /// GPIO
73        pub mod $gpiox {
74            use core::marker::PhantomData;
75            use core::convert::Infallible;
76
77            use hal::digital::v2::{toggleable, InputPin, OutputPin, StatefulOutputPin};
78            use crate::stm32::$GPIOX;
79            use crate::stm32::RCC;
80            use super::{
81                Floating, GpioExt, Input, OpenDrain, Output, Speed,
82                PullDown, PullUp, PushPull, AltMode, Analog
83            };
84
85            /// GPIO parts
86            pub struct Parts {
87                $(
88                    /// Pin
89                    pub $pxi: $PXi<$MODE>,
90                )+
91            }
92
93            impl GpioExt for $GPIOX {
94                type Parts = Parts;
95
96                fn split(self) -> Parts {
97                    // NOTE(unsafe) This executes only during initialisation
98                    let rcc = unsafe { &(*RCC::ptr()) };
99                    rcc.ahbenr.modify(|_, w| w.$iopxenr().set_bit());
100
101                    Parts {
102                        $(
103                            $pxi: $PXi { _mode: PhantomData },
104                        )+
105                    }
106                }
107            }
108
109            /// Partially erased pin
110            pub struct $PXx<MODE> {
111                i: u8,
112                _mode: PhantomData<MODE>,
113            }
114
115            impl<MODE> OutputPin for $PXx<Output<MODE>> {
116                type Error = Infallible;
117
118                fn set_high(&mut self) -> Result<(), Self::Error> {
119                    // NOTE(unsafe) atomic write to a stateless register
120                    Ok(unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << self.i)) })
121                }
122
123                fn set_low(&mut self) -> Result<(), Self::Error> {
124                    // NOTE(unsafe) atomic write to a stateless register
125                    Ok(unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (self.i + 16))) })
126                }
127            }
128
129            impl<MODE> StatefulOutputPin for $PXx<Output<MODE>> {
130                fn is_set_high(&self) -> Result<bool, Self::Error> {
131                    self.is_set_low().map(|v| !v)
132                }
133
134                fn is_set_low(&self) -> Result<bool, Self::Error> {
135                    // NOTE(unsafe) atomic read with no side effects
136                    Ok(unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << self.i) == 0 })
137                }
138            }
139
140            impl<MODE> toggleable::Default for $PXx<Output<MODE>> {}
141
142            impl<MODE> InputPin for $PXx<Output<MODE>> {
143                type Error = Infallible;
144
145                fn is_high(&self) -> Result<bool, Self::Error> {
146                    self.is_low().map(|v| !v)
147                }
148
149                fn is_low(&self) -> Result<bool, Self::Error> {
150                    // NOTE(unsafe) atomic read with no side effects
151                    Ok(unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 })
152                }
153            }
154
155            impl<MODE> InputPin for $PXx<Input<MODE>> {
156                type Error = Infallible;
157
158                fn is_high(&self) -> Result<bool, Self::Error> {
159                    self.is_low().map(|v| !v)
160                }
161
162                fn is_low(&self) -> Result<bool, Self::Error> {
163                    // NOTE(unsafe) atomic read with no side effects
164                    Ok(unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 })
165                }
166            }
167
168            $(
169                /// Pin
170                pub struct $PXi<MODE> {
171                    _mode: PhantomData<MODE>,
172                }
173
174                impl<MODE> $PXi<MODE> {
175                    /// Configures the pin to operate as a floating input pin
176                    pub fn into_floating_input(
177                        self,
178                    ) -> $PXi<Input<Floating>> {
179                        let offset = 2 * $i;
180                        unsafe {
181                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
182                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
183                            });
184                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
185                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
186                            })
187                        };
188                        $PXi { _mode: PhantomData }
189                    }
190
191                    /// Configures the pin to operate as a pulled down input pin
192                    pub fn into_pull_down_input(
193                        self,
194                        ) -> $PXi<Input<PullDown>> {
195                        let offset = 2 * $i;
196                        unsafe {
197                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
198                                w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset))
199                            });
200                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
201                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
202                            })
203                        };
204                        $PXi { _mode: PhantomData }
205                    }
206
207                    /// Configures the pin to operate as a pulled up input pin
208                    pub fn into_pull_up_input(
209                        self,
210                    ) -> $PXi<Input<PullUp>> {
211                        let offset = 2 * $i;
212                        unsafe {
213                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
214                                w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
215                            });
216                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
217                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
218                            })
219                        };
220                        $PXi { _mode: PhantomData }
221                    }
222
223                    /// Configures the pin to operate as an analog pin
224                    pub fn into_analog(
225                        self,
226                    ) -> $PXi<Analog> {
227                        let offset = 2 * $i;
228                        unsafe {
229                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
230                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
231                            });
232                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
233                                w.bits((r.bits() & !(0b11 << offset)) | (0b11 << offset))
234                            });
235                        }
236                        $PXi { _mode: PhantomData }
237                    }
238
239                    /// Configures the pin to operate as an open drain output pin
240                    pub fn into_open_drain_output(
241                        self,
242                    ) -> $PXi<Output<OpenDrain>> {
243                        let offset = 2 * $i;
244                        unsafe {
245                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
246                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
247                            });
248                            &(*$GPIOX::ptr()).otyper.modify(|r, w| {
249                                w.bits(r.bits() | (0b1 << $i))
250                            });
251                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
252                                w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
253                            })
254                        };
255                        $PXi { _mode: PhantomData }
256                    }
257
258                    /// Configures the pin to operate as an push pull output pin
259                    pub fn into_push_pull_output(
260                        self,
261                    ) -> $PXi<Output<PushPull>> {
262                        let offset = 2 * $i;
263                        unsafe {
264                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
265                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
266                            });
267                            &(*$GPIOX::ptr()).otyper.modify(|r, w| {
268                                w.bits(r.bits() & !(0b1 << $i))
269                            });
270                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
271                                w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
272                            })
273                        };
274                        $PXi { _mode: PhantomData }
275                    }
276
277                    /// Set pin speed
278                    pub fn set_speed(self, speed: Speed) -> Self {
279                        let offset = 2 * $i;
280                        unsafe {
281                            &(*$GPIOX::ptr()).ospeedr.modify(|r, w| {
282                                w.bits((r.bits() & !(0b11 << offset)) | ((speed as u32) << offset))
283                            })
284                        };
285                        self
286                    }
287
288                    #[allow(dead_code)]
289                    pub(crate) fn set_alt_mode(&self, mode: AltMode) {
290                        let mode = mode as u32;
291                        let offset = 2 * $i;
292                        let offset2 = 4 * $i;
293                        unsafe {
294                            if offset2 < 32 {
295                                &(*$GPIOX::ptr()).afrl.modify(|r, w| {
296                                    w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset2))
297                                });
298                            } else {
299                                let offset2 = offset2 - 32;
300                                &(*$GPIOX::ptr()).afrh.modify(|r, w| {
301                                    w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset2))
302                                });
303                            }
304                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
305                                w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset))
306                            });
307                        }
308                    }
309                }
310
311                impl<MODE> $PXi<Output<MODE>> {
312                    /// Erases the pin number from the type
313                    ///
314                    /// This is useful when you want to collect the pins into an array where you
315                    /// need all the elements to have the same type
316                    pub fn downgrade(self) -> $PXx<Output<MODE>> {
317                        $PXx {
318                            i: $i,
319                            _mode: self._mode,
320                        }
321                    }
322                }
323
324                impl<MODE> OutputPin for $PXi<Output<MODE>> {
325                    type Error = Infallible;
326
327                    fn set_high(&mut self) -> Result<(), Self::Error> {
328                        // NOTE(unsafe) atomic write to a stateless register
329                        Ok(unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) })
330                    }
331
332                    fn set_low(&mut self) -> Result<(), Self::Error> {
333                        // NOTE(unsafe) atomic write to a stateless register
334                        Ok(unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << ($i + 16))) })
335                    }
336                }
337
338                impl<MODE> StatefulOutputPin for $PXi<Output<MODE>> {
339                    fn is_set_high(&self) -> Result<bool, Self::Error> {
340                        self.is_set_low().map(|v| !v)
341                    }
342
343                    fn is_set_low(&self) -> Result<bool, Self::Error> {
344                        // NOTE(unsafe) atomic read with no side effects
345                        Ok(unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << $i) == 0 })
346                    }
347                }
348
349                impl<MODE> toggleable::Default for $PXi<Output<MODE>> {}
350
351                impl<MODE> InputPin for $PXi<Output<MODE>> {
352                    type Error = Infallible;
353
354                    fn is_high(&self) -> Result<bool, Self::Error> {
355                        self.is_low().map(|v| !v)
356                    }
357
358                    fn is_low(&self) -> Result<bool, Self::Error> {
359                        // NOTE(unsafe) atomic read with no side effects
360                        Ok(unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 })
361                    }
362                }
363
364                impl<MODE> $PXi<Input<MODE>> {
365                    /// Erases the pin number from the type
366                    ///
367                    /// This is useful when you want to collect the pins into an array where you
368                    /// need all the elements to have the same type
369                    pub fn downgrade(self) -> $PXx<Input<MODE>> {
370                        $PXx {
371                            i: $i,
372                            _mode: self._mode,
373                        }
374                    }
375                }
376
377                impl<MODE> InputPin for $PXi<Input<MODE>> {
378                    type Error = Infallible;
379
380                    fn is_high(&self) -> Result<bool, Self::Error> {
381                        self.is_low().map(|v| !v)
382                    }
383
384                    fn is_low(&self) -> Result<bool, Self::Error> {
385                        // NOTE(unsafe) atomic read with no side effects
386                        Ok(unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 })
387                    }
388                }
389            )+
390
391                impl<TYPE> $PXx<TYPE> {
392                    pub fn get_id (&self) -> u8
393                    {
394                        self.i
395                    }
396                }
397        }
398    }
399}
400
401gpio!(GPIOA, gpioa, gpiopaen, PA, [
402    PA0: (pa0, 0, Input<Floating>),
403    PA1: (pa1, 1, Input<Floating>),
404    PA2: (pa2, 2, Input<Floating>),
405    PA3: (pa3, 3, Input<Floating>),
406    PA4: (pa4, 4, Input<Floating>),
407    PA5: (pa5, 5, Input<Floating>),
408    PA6: (pa6, 6, Input<Floating>),
409    PA7: (pa7, 7, Input<Floating>),
410    PA8: (pa8, 8, Input<Floating>),
411    PA9: (pa9, 9, Input<Floating>),
412    PA10: (pa10, 10, Input<Floating>),
413    PA11: (pa11, 11, Input<Floating>),
414    PA12: (pa12, 12, Input<Floating>),
415    PA13: (pa13, 13, Input<Floating>),
416    PA14: (pa14, 14, Input<Floating>),
417    PA15: (pa15, 15, Input<Floating>),
418]);
419
420gpio!(GPIOB, gpiob, gpiopben, PB, [
421    PB0: (pb0, 0, Input<Floating>),
422    PB1: (pb1, 1, Input<Floating>),
423    PB2: (pb2, 2, Input<Floating>),
424    PB3: (pb3, 3, Input<Floating>),
425    PB4: (pb4, 4, Input<Floating>),
426    PB5: (pb5, 5, Input<Floating>),
427    PB6: (pb6, 6, Input<Floating>),
428    PB7: (pb7, 7, Input<Floating>),
429    PB8: (pb8, 8, Input<Floating>),
430    PB9: (pb9, 9, Input<Floating>),
431    PB10: (pb10, 10, Input<Floating>),
432    PB11: (pb11, 11, Input<Floating>),
433    PB12: (pb12, 12, Input<Floating>),
434    PB13: (pb13, 13, Input<Floating>),
435    PB14: (pb14, 14, Input<Floating>),
436    PB15: (pb15, 15, Input<Floating>),
437]);
438
439gpio!(GPIOC, gpioc, gpiopcen, PC, [
440    PC0: (pc0, 0, Input<Floating>),
441    PC1: (pc1, 1, Input<Floating>),
442    PC2: (pc2, 2, Input<Floating>),
443    PC3: (pc3, 3, Input<Floating>),
444    PC4: (pc4, 4, Input<Floating>),
445    PC5: (pc5, 5, Input<Floating>),
446    PC6: (pc6, 6, Input<Floating>),
447    PC7: (pc7, 7, Input<Floating>),
448    PC8: (pc8, 8, Input<Floating>),
449    PC9: (pc9, 9, Input<Floating>),
450    PC10: (pc10, 10, Input<Floating>),
451    PC11: (pc11, 11, Input<Floating>),
452    PC12: (pc12, 12, Input<Floating>),
453    PC13: (pc13, 13, Input<Floating>),
454    PC14: (pc14, 14, Input<Floating>),
455    PC15: (pc15, 15, Input<Floating>),
456]);
457
458gpio!(GPIOD, gpiod, gpiopden, PD, [
459    PD0: (pd0, 0, Input<Floating>),
460    PD1: (pd1, 1, Input<Floating>),
461    PD2: (pd2, 2, Input<Floating>),
462    PD3: (pd3, 3, Input<Floating>),
463    PD4: (pd4, 4, Input<Floating>),
464    PD5: (pd5, 5, Input<Floating>),
465    PD6: (pd6, 6, Input<Floating>),
466    PD7: (pd7, 7, Input<Floating>),
467    PD8: (pd8, 8, Input<Floating>),
468    PD9: (pd9, 9, Input<Floating>),
469    PD10: (pd10, 10, Input<Floating>),
470    PD11: (pd11, 11, Input<Floating>),
471    PD12: (pd12, 12, Input<Floating>),
472    PD13: (pd13, 13, Input<Floating>),
473    PD14: (pd14, 14, Input<Floating>),
474    PD15: (pd15, 15, Input<Floating>),
475]);
476
477#[cfg(any(feature = "stm32l151", feature = "stm32l152", feature = "stm32l162"))]
478gpio!(GPIOE, gpioe, gpiopeen, PE, [
479    PE0: (pe0, 0, Input<Floating>),
480    PE1: (pe1, 1, Input<Floating>),
481    PE2: (pe2, 2, Input<Floating>),
482    PE3: (pe3, 3, Input<Floating>),
483    PE4: (pe4, 4, Input<Floating>),
484    PE5: (pe5, 5, Input<Floating>),
485    PE6: (pe6, 6, Input<Floating>),
486    PE7: (pe7, 7, Input<Floating>),
487    PE8: (pe8, 8, Input<Floating>),
488    PE9: (pe9, 9, Input<Floating>),
489    PE10: (pe10, 10, Input<Floating>),
490    PE11: (pe11, 11, Input<Floating>),
491    PE12: (pe12, 12, Input<Floating>),
492    PE13: (pe13, 13, Input<Floating>),
493    PE14: (pe14, 14, Input<Floating>),
494    PE15: (pe15, 15, Input<Floating>),
495]);
496
497#[cfg(any(feature = "stm32l151", feature = "stm32l152", feature = "stm32l162"))]
498gpio!(GPIOF, gpiof, gpiopfen, PF, [
499    PF0: (pf0, 0, Input<Floating>),
500    PF1: (pf1, 1, Input<Floating>),
501    PF2: (pf2, 2, Input<Floating>),
502    PF3: (pf3, 3, Input<Floating>),
503    PF4: (pf4, 4, Input<Floating>),
504    PF5: (pf5, 5, Input<Floating>),
505    PF6: (pf6, 6, Input<Floating>),
506    PF7: (pf7, 7, Input<Floating>),
507    PF8: (pf8, 8, Input<Floating>),
508    PF9: (pf9, 9, Input<Floating>),
509    PF10: (pf10, 10, Input<Floating>),
510    PF11: (pf11, 11, Input<Floating>),
511    PF12: (pf12, 12, Input<Floating>),
512    PF13: (pf13, 13, Input<Floating>),
513    PF14: (pf14, 14, Input<Floating>),
514    PF15: (pf15, 15, Input<Floating>),
515]);
516
517#[cfg(any(feature = "stm32l151", feature = "stm32l152", feature = "stm32l162"))]
518gpio!(GPIOG, gpiog, gpiopgen, PG, [
519    PG0: (pg0, 0, Input<Floating>),
520    PG1: (pg1, 1, Input<Floating>),
521    PG2: (pg2, 2, Input<Floating>),
522    PG3: (pg3, 3, Input<Floating>),
523    PG4: (pg4, 4, Input<Floating>),
524    PG5: (pg5, 5, Input<Floating>),
525    PG6: (pg6, 6, Input<Floating>),
526    PG7: (pg7, 7, Input<Floating>),
527    PG8: (pg8, 8, Input<Floating>),
528    PG9: (pg9, 9, Input<Floating>),
529    PG10: (pg10, 10, Input<Floating>),
530    PG11: (pg11, 11, Input<Floating>),
531    PG12: (pg12, 12, Input<Floating>),
532    PG13: (pg13, 13, Input<Floating>),
533    PG14: (pg14, 14, Input<Floating>),
534    PG15: (pg15, 15, Input<Floating>),
535]);
536
537#[cfg(any(feature = "stm32l151", feature = "stm32l152", feature = "stm32l162"))]
538gpio!(GPIOH, gpioh, gpiophen, PH, [
539    PH0: (ph0, 0, Input<Floating>),
540    PH1: (ph1, 1, Input<Floating>),
541    PH2: (ph2, 2, Input<Floating>),
542    PH3: (ph3, 3, Input<Floating>),
543    PH4: (ph4, 4, Input<Floating>),
544    PH5: (ph5, 5, Input<Floating>),
545    PH6: (ph6, 6, Input<Floating>),
546    PH7: (ph7, 7, Input<Floating>),
547    PH8: (ph8, 8, Input<Floating>),
548    PH9: (ph9, 9, Input<Floating>),
549    PH10: (ph10, 10, Input<Floating>),
550    PH11: (ph11, 11, Input<Floating>),
551    PH12: (ph12, 12, Input<Floating>),
552    PH13: (ph13, 13, Input<Floating>),
553    PH14: (ph14, 14, Input<Floating>),
554    PH15: (ph15, 15, Input<Floating>),
555]);