stm32f030_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
14pub struct AF0;
15pub struct AF1;
16pub struct AF2;
17pub struct AF3;
18pub struct AF4;
19pub struct AF5;
20pub struct AF6;
21pub struct AF7;
22
23pub struct Alternate<MODE> {
24    _mode: PhantomData<MODE>,
25}
26
27/// Input mode (type state)
28pub struct Input<MODE> {
29    _mode: PhantomData<MODE>,
30}
31
32/// Floating input (type state)
33pub struct Floating;
34
35/// Pulled down input (type state)
36pub struct PullDown;
37
38/// Pulled up input (type state)
39pub struct PullUp;
40
41/// Open drain input or output (type state)
42pub struct OpenDrain;
43
44/// Output mode (type state)
45pub struct Output<MODE> {
46    _mode: PhantomData<MODE>,
47}
48
49/// Push pull output (type state)
50pub struct PushPull;
51
52use hal::digital::{InputPin, OutputPin, StatefulOutputPin};
53use stm32;
54
55/// Fully erased pin
56// We can just pretend it's gpioa. It's modified using the bits and it can only be constructed out of already existing pins
57pub struct Pin<MODE> {
58    i: u8,
59    port: *const stm32::gpioa::RegisterBlock,
60    _mode: PhantomData<MODE>,
61}
62
63impl<MODE> StatefulOutputPin for Pin<Output<MODE>> {
64    fn is_set_high(&self) -> bool {
65        !self.is_set_low()
66    }
67
68    fn is_set_low(&self) -> bool {
69        // NOTE(unsafe) atomic read with no side effects
70        unsafe { (*self.port).odr.read().bits() & (1 << self.i) == 0 }
71    }
72}
73
74impl<MODE> OutputPin for Pin<Output<MODE>> {
75    fn set_high(&mut self) {
76        // NOTE(unsafe) atomic write to a stateless register
77        unsafe { (*self.port).bsrr.write(|w| w.bits(1 << self.i)) }
78    }
79
80    fn set_low(&mut self) {
81        // NOTE(unsafe) atomic write to a stateless register
82        unsafe { (*self.port).bsrr.write(|w| w.bits(1 << (self.i + 16))) }
83    }
84}
85
86impl InputPin for Pin<Output<OpenDrain>> {
87    fn is_high(&self) -> bool {
88        !self.is_low()
89    }
90
91    fn is_low(&self) -> bool {
92        // NOTE(unsafe) atomic read with no side effects
93        unsafe { (*self.port).idr.read().bits() & (1 << self.i) == 0 }
94    }
95}
96
97impl<MODE> InputPin for Pin<Input<MODE>> {
98    fn is_high(&self) -> bool {
99        !self.is_low()
100    }
101
102    fn is_low(&self) -> bool {
103        // NOTE(unsafe) atomic read with no side effects
104        unsafe { (*self.port).idr.read().bits() & (1 << self.i) == 0 }
105    }
106}
107
108macro_rules! gpio {
109    ($GPIOX:ident, $gpiox:ident, $iopxenr:ident, $PXx:ident, [
110        $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty),)+
111    ]) => {
112        /// GPIO
113        pub mod $gpiox {
114            use core::marker::PhantomData;
115
116            use hal::digital::{InputPin, OutputPin, StatefulOutputPin};
117            use stm32::$GPIOX;
118
119            use stm32::RCC;
120            use super::{
121                Alternate, Floating, GpioExt, Input, OpenDrain, Output,
122                PullDown, PullUp, PushPull, AF0, AF1, AF2, AF3, AF4, AF5, AF6, AF7, Pin
123            };
124
125            /// GPIO parts
126            pub struct Parts {
127                $(
128                    /// Pin
129                    pub $pxi: $PXi<$MODE>,
130                )+
131            }
132
133            impl GpioExt for $GPIOX {
134                type Parts = Parts;
135
136                fn split(self) -> Parts {
137                    // NOTE(unsafe) This executes only during initialisation
138                    let rcc = unsafe { &(*RCC::ptr()) };
139                    rcc.ahbenr.modify(|_, w| w.$iopxenr().set_bit());
140
141                    Parts {
142                        $(
143                            $pxi: $PXi { _mode: PhantomData },
144                        )+
145                    }
146                }
147            }
148
149            /// Partially erased pin
150            pub struct $PXx<MODE> {
151                i: u8,
152                _mode: PhantomData<MODE>,
153            }
154
155            impl<MODE> StatefulOutputPin for $PXx<Output<MODE>> {
156                fn is_set_high(&self) -> bool {
157                    !self.is_set_low()
158                }
159
160                fn is_set_low(&self) -> bool {
161                    // NOTE(unsafe) atomic read with no side effects
162                    unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << self.i) == 0 }
163                }
164            }
165
166            impl<MODE> OutputPin for $PXx<Output<MODE>> {
167                fn set_high(&mut self) {
168                    // NOTE(unsafe) atomic write to a stateless register
169                    unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << self.i)) }
170                }
171
172                fn set_low(&mut self) {
173                    // NOTE(unsafe) atomic write to a stateless register
174                    unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (self.i + 16))) }
175                }
176            }
177
178            impl InputPin for $PXx<Output<OpenDrain>> {
179                fn is_high(&self) -> bool {
180                    !self.is_low()
181                }
182
183                fn is_low(&self) -> bool {
184                    // NOTE(unsafe) atomic read with no side effects
185                    unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }
186                }
187            }
188
189            impl<MODE> InputPin for $PXx<Input<MODE>> {
190                fn is_high(&self) -> bool {
191                    !self.is_low()
192                }
193
194                fn is_low(&self) -> bool {
195                    // NOTE(unsafe) atomic read with no side effects
196                    unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }
197                }
198            }
199
200            fn _set_alternate_mode (index:usize, mode: u32)
201            {
202                let offset = 2 * index;
203                let offset2 = 4 * index;
204                unsafe {
205                    if offset2 < 32 {
206                        &(*$GPIOX::ptr()).afrl.modify(|r, w| {
207                            w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset2))
208                        });
209                    } else
210                    {
211                        let offset2 = offset2 - 32;
212                        &(*$GPIOX::ptr()).afrh.modify(|r, w| {
213                            w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset2))
214                        });
215                    }
216                    &(*$GPIOX::ptr()).moder.modify(|r, w| {
217                        w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset))
218                    });
219                }
220            }
221
222            impl<MODE> $PXx<Input<MODE>> {
223                /// Erases the port from the type
224                ///
225                /// This is useful when you want to collect the pins into an array where you
226                /// need all the elements to have the same type
227                pub fn downgrade(self) -> Pin<Input<MODE>> {
228                    use stm32::gpioa;
229                    use core::intrinsics::transmute;
230                    Pin {
231                        i: self.i,
232                        port: unsafe{ transmute::<_, *const gpioa::RegisterBlock>($GPIOX::ptr())},
233                        _mode: self._mode,
234                    }
235                }
236            }
237
238            impl<MODE> $PXx<Output<MODE>> {
239                /// Erases the port from the type
240                ///
241                /// This is useful when you want to collect the pins into an array where you
242                /// need all the elements to have the same type
243                pub fn downgrade(self) -> Pin<Output<MODE>> {
244                    use stm32::gpioa;
245                    use core::intrinsics::transmute;
246                    Pin {
247                        i: self.i,
248                        port: unsafe{ transmute::<_, *const gpioa::RegisterBlock>($GPIOX::ptr())},
249                        _mode: self._mode,
250                    }
251                }
252            }
253
254            $(
255                /// Pin
256                pub struct $PXi<MODE> {
257                    _mode: PhantomData<MODE>,
258                }
259
260                impl<MODE> $PXi<MODE> {
261                    /// Configures the pin to operate in AF0 mode
262                    pub fn into_alternate_af0(
263                        self,
264                    ) -> $PXi<Alternate<AF0>> {
265                        _set_alternate_mode($i, 0);
266                        $PXi { _mode: PhantomData }
267                    }
268
269                    /// Configures the pin to operate in AF1 mode
270                    pub fn into_alternate_af1(
271                        self,
272                    ) -> $PXi<Alternate<AF1>> {
273                        _set_alternate_mode($i, 1);
274                        $PXi { _mode: PhantomData }
275                    }
276
277                    /// Configures the pin to operate in AF2 mode
278                    pub fn into_alternate_af2(
279                        self,
280                    ) -> $PXi<Alternate<AF2>> {
281                        _set_alternate_mode($i, 2);
282                        $PXi { _mode: PhantomData }
283                    }
284
285                    /// Configures the pin to operate in AF3 mode
286                    pub fn into_alternate_af3(
287                        self,
288                    ) -> $PXi<Alternate<AF3>> {
289                        _set_alternate_mode($i, 3);
290                        $PXi { _mode: PhantomData }
291                    }
292
293                    /// Configures the pin to operate in AF4 mode
294                    pub fn into_alternate_af4(
295                        self,
296                    ) -> $PXi<Alternate<AF4>> {
297                        _set_alternate_mode($i, 4);
298                        $PXi { _mode: PhantomData }
299                    }
300
301                    /// Configures the pin to operate in AF5 mode
302                    pub fn into_alternate_af5(
303                        self,
304                    ) -> $PXi<Alternate<AF5>> {
305                        _set_alternate_mode($i, 5);
306                        $PXi { _mode: PhantomData }
307                    }
308
309                    /// Configures the pin to operate in AF6 mode
310                    pub fn into_alternate_af6(
311                        self,
312                    ) -> $PXi<Alternate<AF6>> {
313                        _set_alternate_mode($i, 6);
314                        $PXi { _mode: PhantomData }
315                    }
316
317                    /// Configures the pin to operate in AF7 mode
318                    pub fn into_alternate_af7(
319                        self,
320                    ) -> $PXi<Alternate<AF7>> {
321                        _set_alternate_mode($i, 7);
322                        $PXi { _mode: PhantomData }
323                    }
324
325                    /// Configures the pin to operate as a floating input pin
326                    pub fn into_floating_input(
327                        self,
328                    ) -> $PXi<Input<Floating>> {
329                        let offset = 2 * $i;
330                        unsafe {
331                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
332                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
333                            });
334                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
335                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
336                            });
337                        }
338                        $PXi { _mode: PhantomData }
339                    }
340
341                    /// Configures the pin to operate as a pulled down input pin
342                    pub fn into_pull_down_input(
343                        self,
344                    ) -> $PXi<Input<PullDown>> {
345                        let offset = 2 * $i;
346                        unsafe {
347                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
348                                w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset))
349                            });
350                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
351                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
352                            });
353                        }
354                        $PXi { _mode: PhantomData }
355                    }
356
357                    /// Configures the pin to operate as a pulled up input pin
358                    pub fn into_pull_up_input(
359                        self,
360                    ) -> $PXi<Input<PullUp>> {
361                        let offset = 2 * $i;
362                        unsafe {
363                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
364                                w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
365                            });
366                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
367                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
368                            });
369                        }
370                        $PXi { _mode: PhantomData }
371                    }
372
373                    /// Configures the pin to operate as an open drain output pin
374                    pub fn into_open_drain_output(
375                        self,
376                    ) -> $PXi<Output<OpenDrain>> {
377                        let offset = 2 * $i;
378                        unsafe {
379                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
380                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
381                            });
382                            &(*$GPIOX::ptr()).otyper.modify(|r, w| {
383                                w.bits(r.bits() | (0b1 << $i))
384                            });
385                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
386                                w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
387                            });
388                        }
389                        $PXi { _mode: PhantomData }
390                    }
391
392                    /// Configures the pin to operate as an push pull output pin
393                    pub fn into_push_pull_output(
394                        self,
395                    ) -> $PXi<Output<PushPull>> {
396                        let offset = 2 * $i;
397
398                        unsafe {
399                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
400                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
401                            });
402                            &(*$GPIOX::ptr()).otyper.modify(|r, w| {
403                                w.bits(r.bits() & !(0b1 << $i))
404                            });
405                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
406                                w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
407                            });
408                        }
409                        $PXi { _mode: PhantomData }
410                    }
411
412                    /// Configures the pin to operate as an push pull output pin with quick fall
413                    /// and rise times
414                    pub fn into_push_pull_output_hs(
415                        self,
416                    ) -> $PXi<Output<PushPull>> {
417                        let offset = 2 * $i;
418
419                        unsafe {
420                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
421                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
422                            });
423                            &(*$GPIOX::ptr()).otyper.modify(|r, w| {
424                                w.bits(r.bits() & !(0b1 << $i))
425                            });
426                            &(*$GPIOX::ptr()).ospeedr.modify(|r, w| {
427                                w.bits(r.bits() & !(0b1 << $i))
428                            });
429                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
430                                w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
431                            });
432                        }
433
434                        $PXi { _mode: PhantomData }
435                    }
436                }
437
438                impl $PXi<Output<OpenDrain>> {
439                    /// Enables / disables the internal pull up
440                    pub fn internal_pull_up(&mut self, on: bool) {
441                        let offset = 2 * $i;
442                        let value = if on { 0b01 } else { 0b00 };
443                        unsafe {
444                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
445                                w.bits((r.bits() & !(0b11 << offset)) | (value << offset))
446                            })};
447                    }
448                }
449
450                impl InputPin for $PXi<Output<OpenDrain>> {
451                    fn is_high(&self) -> bool {
452                        !self.is_low()
453                    }
454
455                    fn is_low(&self) -> bool {
456                        // NOTE(unsafe) atomic read with no side effects
457                        unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 }
458                    }
459                }
460
461                impl<MODE> $PXi<Alternate<MODE>> {
462                    /// Enables / disables the internal pull up
463                    pub fn internal_pull_up(&mut self, on: bool) {
464                        let offset = 2 * $i;
465                        let value = if on { 0b01 } else { 0b00 };
466                        unsafe {
467                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
468                                w.bits((r.bits() & !(0b11 << offset)) | (value << offset))
469                            })};
470                    }
471                }
472
473                impl<MODE> $PXi<Alternate<MODE>> {
474                    /// Turns pin alternate configuration pin into open drain
475                    pub fn set_open_drain(self) -> Self {
476                        let offset = $i;
477                        unsafe {
478                            &(*$GPIOX::ptr()).otyper.modify(|r, w| {
479                                w.bits(r.bits() | (1 << offset))
480                            })};
481
482                        self
483                    }
484                }
485
486                impl<MODE> $PXi<Output<MODE>> {
487                    /// Erases the pin number from the type
488                    ///
489                    /// This is useful when you want to collect the pins into an array where you
490                    /// need all the elements to have the same type
491                    pub fn downgrade(self) -> $PXx<Output<MODE>> {
492                        $PXx {
493                            i: $i,
494                            _mode: self._mode,
495                        }
496                    }
497                }
498
499                impl<MODE> StatefulOutputPin for $PXi<Output<MODE>> {
500                    fn is_set_high(&self) -> bool {
501                        !self.is_set_low()
502                    }
503
504                    fn is_set_low(&self) -> bool {
505                        // NOTE(unsafe) atomic read with no side effects
506                        unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << $i) == 0 }
507                    }
508                }
509
510                impl<MODE> OutputPin for $PXi<Output<MODE>> {
511                    fn set_high(&mut self) {
512                        // NOTE(unsafe) atomic write to a stateless register
513                        unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }
514                    }
515
516                    fn set_low(&mut self) {
517                        // NOTE(unsafe) atomic write to a stateless register
518                        unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << ($i + 16))) }
519                    }
520                }
521
522                impl<MODE> $PXi<Input<MODE>> {
523                    /// Erases the pin number from the type
524                    ///
525                    /// This is useful when you want to collect the pins into an array where you
526                    /// need all the elements to have the same type
527                    pub fn downgrade(self) -> $PXx<Input<MODE>> {
528                        $PXx {
529                            i: $i,
530                            _mode: self._mode,
531                        }
532                    }
533                }
534
535                impl<MODE> InputPin for $PXi<Input<MODE>> {
536                    fn is_high(&self) -> bool {
537                        !self.is_low()
538                    }
539
540                    fn is_low(&self) -> bool {
541                        // NOTE(unsafe) atomic read with no side effects
542                        unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 }
543                    }
544                }
545            )+
546            /// Get the pin number
547            impl<TYPE> $PXx<TYPE> {
548                pub fn get_id (&self) -> u8
549                {
550                    self.i
551                }
552            }
553        }
554    }
555}
556
557// TSSOP20
558#[cfg(any(feature = "stm32f030f4"))]
559gpio!(GPIOA, gpioa, iopaen, PA, [
560    PA0: (pa0, 0, Input<Floating>),
561    PA1: (pa1, 1, Input<Floating>),
562    PA2: (pa2, 2, Input<Floating>),
563    PA3: (pa3, 3, Input<Floating>),
564    PA4: (pa4, 4, Input<Floating>),
565    PA5: (pa5, 5, Input<Floating>),
566    PA6: (pa6, 6, Input<Floating>),
567    PA7: (pa7, 7, Input<Floating>),
568    PA9: (pa9, 9, Input<Floating>),
569    PA10: (pa10, 10, Input<Floating>),
570    PA13: (pa13, 13, Input<Floating>),
571    PA14: (pa14, 14, Input<Floating>),
572]);
573
574// LQFP32 & LQFP48 & LQFP64
575#[cfg(any(
576    feature = "stm32f030k6",
577    feature = "stm32f030c6",
578    feature = "stm32f030c8",
579    feature = "stm32f030cc",
580    feature = "stm32f030r8",
581    feature = "stm32f030rc"
582))]
583gpio!(GPIOA, gpioa, iopaen, PA, [
584    PA0: (pa0, 0, Input<Floating>),
585    PA1: (pa1, 1, Input<Floating>),
586    PA2: (pa2, 2, Input<Floating>),
587    PA3: (pa3, 3, Input<Floating>),
588    PA4: (pa4, 4, Input<Floating>),
589    PA5: (pa5, 5, Input<Floating>),
590    PA6: (pa6, 6, Input<Floating>),
591    PA7: (pa7, 7, Input<Floating>),
592    PA8: (pa8, 8, Input<Floating>),
593    PA9: (pa9, 9, Input<Floating>),
594    PA10: (pa10, 10, Input<Floating>),
595    PA11: (pa11, 11, Input<Floating>),
596    PA12: (pa12, 12, Input<Floating>),
597    PA13: (pa13, 13, Input<Floating>),
598    PA14: (pa14, 14, Input<Floating>),
599    PA15: (pa15, 15, Input<Floating>),
600]);
601
602// TSSOP20
603#[cfg(any(feature = "stm32f030x4"))]
604gpio!(GPIOB, gpiob, iopben, PB, [
605    PB1: (pb1, 1, Input<Floating>),
606]);
607
608// LQFP32
609#[cfg(any(feature = "stm32f030k6"))]
610gpio!(GPIOB, gpiob, iopben, PB, [
611    PB0: (pb0, 0, Input<Floating>),
612    PB1: (pb1, 1, Input<Floating>),
613    PB3: (pb3, 3, Input<Floating>),
614    PB4: (pb4, 4, Input<Floating>),
615    PB5: (pb5, 5, Input<Floating>),
616    PB6: (pb6, 6, Input<Floating>),
617    PB7: (pb7, 7, Input<Floating>),
618]);
619
620// LQFP48 & LQFP64
621#[cfg(any(
622    feature = "stm32f030c6",
623    feature = "stm32f030c8",
624    feature = "stm32f030cc",
625    feature = "stm32f030r8",
626    feature = "stm32f030rc"
627))]
628gpio!(GPIOB, gpiob, iopben, PB, [
629    PB0: (pb0, 0, Input<Floating>),
630    PB1: (pb1, 1, Input<Floating>),
631    PB2: (pb2, 2, Input<Floating>),
632    PB3: (pb3, 3, Input<Floating>),
633    PB4: (pb4, 4, Input<Floating>),
634    PB5: (pb5, 5, Input<Floating>),
635    PB6: (pb6, 6, Input<Floating>),
636    PB7: (pb7, 7, Input<Floating>),
637    PB8: (pb8, 8, Input<Floating>),
638    PB9: (pb9, 9, Input<Floating>),
639    PB10: (pb10, 10, Input<Floating>),
640    PB11: (pb11, 11, Input<Floating>),
641    PB12: (pb12, 12, Input<Floating>),
642    PB13: (pb13, 13, Input<Floating>),
643    PB14: (pb14, 14, Input<Floating>),
644    PB15: (pb15, 15, Input<Floating>),
645]);
646
647// LQFP48
648#[cfg(any(
649    feature = "stm32f030c6",
650    feature = "stm32f030c8",
651    feature = "stm32f030cc",
652))]
653gpio!(GPIOC, gpioc, iopcen, PC, [
654    PC13: (pb13, 13, Input<Floating>),
655    PC14: (pb14, 14, Input<Floating>),
656    PC15: (pb15, 15, Input<Floating>),
657]);
658
659// LQFP64
660#[cfg(any(feature = "stm32f030r8", feature = "stm32f030rc"))]
661gpio!(GPIOC, gpioc, iopcen, PC, [
662    PC0: (pb0, 0, Input<Floating>),
663    PC1: (pb1, 1, Input<Floating>),
664    PC2: (pb2, 2, Input<Floating>),
665    PC3: (pb3, 3, Input<Floating>),
666    PC4: (pb4, 4, Input<Floating>),
667    PC5: (pb5, 5, Input<Floating>),
668    PC6: (pb6, 6, Input<Floating>),
669    PC7: (pb7, 7, Input<Floating>),
670    PC8: (pb8, 8, Input<Floating>),
671    PC9: (pb9, 9, Input<Floating>),
672    PC10: (pb10, 10, Input<Floating>),
673    PC11: (pb11, 11, Input<Floating>),
674    PC12: (pb12, 12, Input<Floating>),
675    PC13: (pb13, 13, Input<Floating>),
676    PC14: (pb14, 14, Input<Floating>),
677    PC15: (pb15, 15, Input<Floating>),
678]);
679
680// TODO Check if the bit is implemented
681// In the device crate the iopden bit is missing, so it won't compile
682// // LQFP64
683// #[cfg(any(feature = "stm32f030r8", feature = "stm32f030rc"))]
684// gpio!(GPIOD, gpiod, iopden, PD, [
685//     PD2: (pd2, 2, Input<Floating>),
686// ]);
687
688// TSSOP20 & LQFP32
689#[cfg(any(
690    feature = "stm32f030f4",
691    feature = "stm32f030k6",
692    feature = "stm32f030cc",
693    feature = "stm32f030rc"
694))]
695gpio!(GPIOF, gpiof, iopfen, PF, [
696    PF0: (pf0, 0, Input<Floating>),
697    PF1: (pf1, 1, Input<Floating>),
698]);
699
700// LQFP48
701#[cfg(any(feature = "stm32f030c6", feature = "stm32f030c8",))]
702gpio!(GPIOF, gpiof, iopfen, PF, [
703    PF0: (pf0, 0, Input<Floating>),
704    PF1: (pf1, 1, Input<Floating>),
705    // STM32F030x4/6/8
706    PF6: (pf5, 5, Input<Floating>),
707    PF7: (pf5, 5, Input<Floating>),
708]);
709
710// LQFP64
711// LQFP64
712#[cfg(feature = "stm32f030r8")]
713gpio!(GPIOF, gpiof, iopfen, PF, [
714    PF0: (pf0, 0, Input<Floating>),
715    PF1: (pf1, 1, Input<Floating>),
716    // STM32F030x4/6/8
717    PF4: (pf4, 4, Input<Floating>),
718    PF5: (pf5, 5, Input<Floating>),
719    PF6: (pf5, 5, Input<Floating>),
720    PF7: (pf5, 5, Input<Floating>),
721]);