alt_stm32f30x_hal/
gpio.rs

1//! General Purpose Input / Output
2
3// TODO the pins here currently correspond to the LQFP-100 package. There
4// should be Cargo features that let you select different microcontroller
5// packages
6
7use crate::rcc::AHB;
8use bobbin_bits::*;
9use core::intrinsics::transmute;
10use core::marker::PhantomData;
11#[allow(deprecated)]
12use hal::digital::{v2, InputPin, OutputPin, StatefulOutputPin};
13
14/// Marker trait for any pin
15pub trait GPIOPin {
16    /// Returns GPIO group
17    fn group(&self) -> Group;
18    /// Returns pin index within group
19    fn index(&self) -> u8;
20}
21
22/// Trait for pin mode
23pub trait PinMode {
24    /// Convert type state into actual bits
25    fn pin_mode() -> U2;
26}
27
28/// Input
29pub struct Input;
30impl PinMode for Input {
31    /// bits
32    fn pin_mode() -> U2 {
33        U2::B00
34    }
35}
36
37/// Output
38pub struct Output<OT: OutputType, OS: OutputSpeed> {
39    _output_mode: PhantomData<OT>,
40    _output_speed: PhantomData<OS>,
41}
42impl<OT: OutputType, OS: OutputSpeed> PinMode for Output<OT, OS> {
43    fn pin_mode() -> U2 {
44        U2::B01
45    }
46}
47
48/// Alternating function
49pub struct AltFn<AN: AltFnNum, OT: OutputType, OS: OutputSpeed> {
50    _afnum: PhantomData<AN>,
51    _output_mode: PhantomData<OT>,
52    _output_speed: PhantomData<OS>,
53}
54impl<AN: AltFnNum, OT: OutputType, OS: OutputSpeed> PinMode
55    for AltFn<AN, OT, OS>
56{
57    fn pin_mode() -> U2 {
58        U2::B10
59    }
60}
61
62/// Analog
63pub struct Analog;
64impl PinMode for Analog {
65    fn pin_mode() -> U2 {
66        U2::B11
67    }
68}
69
70/// Pull (pin resistor state)
71pub trait PullType {
72    /// pull
73    fn pull_type(&self) -> U2;
74}
75
76/// No pull; floating
77pub struct PullNone;
78impl PullType for PullNone {
79    fn pull_type(&self) -> U2 {
80        U2::B00
81    }
82}
83
84/// Pull up
85pub struct PullUp;
86impl PullType for PullUp {
87    fn pull_type(&self) -> U2 {
88        U2::B01
89    }
90}
91
92/// Pull down
93pub struct PullDown;
94impl PullType for PullDown {
95    fn pull_type(&self) -> U2 {
96        U2::B10
97    }
98}
99
100/// Reserved
101pub struct PullReserved;
102impl PullType for PullReserved {
103    fn pull_type(&self) -> U2 {
104        U2::B11
105    }
106}
107
108/// Configures output speed
109pub trait OutputSpeed {
110    /// Converts type state to actual bits
111    fn output_speed(&self) -> U2;
112}
113
114/// Low speed
115pub struct LowSpeed;
116impl OutputSpeed for LowSpeed {
117    fn output_speed(&self) -> U2 {
118        U2::B00
119    }
120}
121
122/// Medium  speed
123pub struct MediumSpeed;
124impl OutputSpeed for MediumSpeed {
125    fn output_speed(&self) -> U2 {
126        U2::B01
127    }
128}
129
130/// Fast speed
131pub struct FastSpeed;
132impl OutputSpeed for FastSpeed {
133    fn output_speed(&self) -> U2 {
134        U2::B10
135    }
136}
137
138/// High speed
139pub struct HighSpeed;
140impl OutputSpeed for HighSpeed {
141    fn output_speed(&self) -> U2 {
142        U2::B11
143    }
144}
145
146/// Output type
147pub trait OutputType {
148    /// converts type state to actual type
149    fn output_type(&self) -> U1;
150}
151
152/// Push pull
153pub struct PushPull;
154impl OutputType for PushPull {
155    fn output_type(&self) -> U1 {
156        U1::B0
157    }
158}
159
160/// Open drain
161pub struct OpenDrain;
162impl OutputType for OpenDrain {
163    fn output_type(&self) -> U1 {
164        U1::B1
165    }
166}
167
168/// AltFn number
169pub trait AltFnNum {
170    /// converts type state
171    fn alt_fn_num(&self) -> U4;
172}
173
174macro_rules! gen_af {
175    ([$(($af:ident, $bit:ident)) , +]) => {
176        $(
177            /// $af
178            pub struct $af;
179            impl AltFnNum for $af {
180                fn alt_fn_num(&self) -> U4 {
181                    U4::$bit
182                }
183            }
184        )+
185    }
186}
187
188gen_af!([(AF0, B0000),
189         (AF1, B0001),
190         (AF2, B0010),
191         (AF3, B0011),
192         (AF4, B0100),
193         (AF5, B0101),
194         (AF6, B0110),
195         (AF7, B0111),
196         (AF8, B1000),
197         (AF9, B1001),
198         (AF10, B1010),
199         (AF11, B1011),
200         (AF12, B1100),
201         (AF13, B1101),
202         (AF14, B1110),
203         (AF15, B1111)]);
204
205/// Extension trait to split a GPIO peripheral in independent pins and registers
206pub trait GpioExt {
207    /// The to split the GPIO into
208    type Ports;
209
210    /// Splits the GPIO block into independent pins and registers
211    fn split(self, ahb: &mut AHB) -> Self::Ports;
212}
213
214macro_rules! gpio {
215    ($GPIOX:ident, $Gpiox:ident, $gpiox:ident, $iopxenr:ident, $iopxrst:ident, $group: ident, $PXx:ident, [
216        $($PXi:ident: ($pxi:ident, $i:expr, $AFR:ident),)+
217    ]) => {
218        use crate::pac::$GPIOX;
219        /// GPIO ports
220        pub struct $Gpiox {
221            $(
222                /// Pin $PXi
223                pub $pxi: $PXi<PullNone, Input>,
224            )+
225        }
226
227        impl GpioExt for $GPIOX {
228            type Ports = $Gpiox;
229
230            fn split(self, ahb: &mut AHB) -> Self::Ports {
231                ahb.enr().modify(|_, w| w.$iopxenr().enabled());
232                ahb.rstr().modify(|_, w| w.$iopxrst().set_bit());
233                ahb.rstr().modify(|_, w| w.$iopxrst().clear_bit());
234
235                $Gpiox {
236                    $(
237                        $pxi: $PXi {
238                            _pullup_state: PhantomData,
239                            _pin_mode: PhantomData
240                        },
241                    )+
242                }
243            }
244        }
245
246        impl $Gpiox {
247            // helper functions
248
249            fn set_pin_mode<PM: PinMode>(index: u32) {
250                let offset = 2 * index;
251                let mode_bits:u32 = PM::pin_mode().into();
252                let moder = unsafe { &(*$GPIOX::ptr()).moder };
253                // set io mode
254                moder.modify(|r, w| unsafe {
255                    w.bits((r.bits()
256                            & !(0b11 << offset))
257                           | (mode_bits << offset))
258                });
259            }
260
261            fn set_output_speed<OS: OutputSpeed>(index: u32, os: OS) {
262                let offset = 2 * index;
263                let ospeedr = unsafe { &(*$GPIOX::ptr()).ospeedr };
264                let speed_bits:u32 = os.output_speed().into();
265                ospeedr.modify(|r, w| unsafe {
266                    w.bits((r.bits()
267                            & !(0b11 << offset))
268                           | (speed_bits << offset))
269                });
270            }
271
272            fn set_output_type<OT: OutputType>(index: u32, ot: OT) {
273                let otyper = unsafe { &(*$GPIOX::ptr()).otyper };
274                let type_bits:u32 = ot.output_type().into();
275                otyper.modify(|r, w| unsafe {
276                    w.bits(r.bits() | (type_bits << index))
277                });
278            }
279
280        }
281
282
283        /// Partially erased pin
284        pub struct $PXx<PT: PullType, PM: PinMode> {
285            i: u8,
286            _pullup_state: PhantomData<PT>,
287            _pin_mode: PhantomData<PM>
288        }
289
290        #[allow(deprecated)]
291        impl<PT: PullType, OT: OutputType, OS: OutputSpeed>
292            OutputPin for $PXx<PT, Output<OT, OS>> {
293                fn set_high(&mut self) {
294                    // NOTE(unsafe) atomic write to a stateless register
295                    unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << self.i)) }
296                }
297
298                fn set_low(&mut self) {
299                    // NOTE(unsafe) atomic write to a stateless register
300                    unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + self.i))) }
301                }
302            }
303
304        #[allow(deprecated)]
305        impl<PT: PullType,
306        AN: AltFnNum,
307        OT: OutputType,
308        OS: OutputSpeed> OutputPin for $PXx<PT, AltFn<AN, OT, OS>> {
309            fn set_high(&mut self) {
310                // NOTE(unsafe) atomic write to a stateless register
311                unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << self.i)) }
312            }
313
314            fn set_low(&mut self) {
315                // NOTE(unsafe) atomic write to a stateless register
316                unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + self.i))) }
317            }
318        }
319
320        #[allow(deprecated)]
321        impl<PT: PullType> InputPin for $PXx<PT, Input> {
322            fn is_high(&self) -> bool {
323                !self.is_low()
324            }
325
326            fn is_low(&self) -> bool {
327                // NOTE(unsafe) atomic read with no side effects
328                unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }
329            }
330        }
331
332        $(
333            /// Pin
334            pub struct $PXi<PT: PullType, PM: PinMode> {
335                _pullup_state: PhantomData<PT>,
336                _pin_mode: PhantomData<PM>
337            }
338
339            impl <PT: PullType, PM: PinMode> GPIOPin for $PXi<PT, PM> {
340                fn group(&self) -> Group {
341                    Group::$group
342                }
343
344                fn index(&self) -> u8 {
345                    $i
346                }
347            }
348
349            impl<PT: PullType, PM: PinMode> $PXi<PT, PM> {
350                /// Erases the pin number from the type
351                ///
352                /// This is useful when you want to collect the pins into an array where you
353                /// need all the elements to have the same type
354                pub fn downgrade(self) -> $PXx<PT, PM> {
355                    $PXx {
356                        i: $i,
357                        _pullup_state: PhantomData,
358                        _pin_mode: PhantomData
359                    }
360                }
361
362                /// Sets pull type: Floaing, PullUp, PullDown
363                pub fn pull_type<NPT: PullType>(self, pt: NPT)
364                                                -> $PXi<NPT, PM>
365                {
366                    let shift = 0 + ($i << 1);
367                    let pupdr = unsafe { &(*$GPIOX::ptr()).pupdr };
368                    let pd_bits:u32 = pt.pull_type().into();
369                    pupdr.modify(|r, w| unsafe {
370                        w.bits((r.bits() & !(0b11 << shift))
371                               | (pd_bits << shift))
372                    });
373
374                    unsafe { transmute(self) }
375                }
376
377                // XXX: it maybe makes sense to disallow this
378                //      when Pin is input already;
379                //      need to think about that
380                /// Sets io_mode to input
381                pub fn input(self) -> $PXi<PT, Input> {
382                    $Gpiox::set_pin_mode::<Input>($i);
383                    unsafe { transmute(self) }
384                }
385
386                /// Sets io_mode to analog
387                pub fn analog(self) -> $PXi<PT, Analog> {
388                    $Gpiox::set_pin_mode::<Analog>($i);
389                    unsafe { transmute(self) }
390                }
391
392                /// Set io_mode to output
393                pub fn output(self) -> $PXi<PT, Output<PushPull, LowSpeed>> {
394                    let result: $PXi<PT, Output<PushPull, LowSpeed>> =
395                        unsafe { transmute(self) };
396                    // ensure output type and speed are set
397                    let result2 = result
398                        .output_type(PushPull)
399                        .output_speed(LowSpeed);
400                    $Gpiox::set_pin_mode::<Output<PushPull, LowSpeed>>($i);
401                    result2
402                }
403
404                /// Set io_mode to altfn and set alternating function
405                pub fn alternating<AFN: AltFnNum>(self, af: AFN) -> $PXi<PT, AltFn<AFN, PushPull, LowSpeed>> {
406                    let result: $PXi<PT, AltFn<AFN, PushPull, LowSpeed>> =
407                        unsafe { transmute(self) };
408                    // ensure output type, speed, and afnum are set
409                    let result2 = result
410                        .alt_fn(af)
411                        .output_type(PushPull)
412                        .output_speed(LowSpeed);
413                    $Gpiox::set_pin_mode::<AltFn<AFN, PushPull, LowSpeed>>($i);
414                    result2
415                }
416            }
417
418            impl<PT: PullType, OT: OutputType, OS: OutputSpeed> $PXi<PT, Output<OT, OS>> {
419                /// Set output type
420                pub fn output_type<NOT: OutputType>(self, ot: NOT) -> $PXi<PT, Output<NOT, OS>> {
421                    $Gpiox::set_output_type($i, ot);
422                    unsafe { transmute(self) }
423                }
424
425                /// Set output type to PushPull
426                pub fn push_pull(self) -> $PXi<PT, Output<PushPull, OS>> {
427                    self.output_type(PushPull)
428                }
429
430                /// Set output type to OpenDrain
431                pub fn open_drain(self) -> $PXi<PT, Output<OpenDrain, OS>> {
432                    self.output_type(OpenDrain)
433                }
434
435                /// Set output speed
436                pub fn output_speed<NOS: OutputSpeed>(self, os: NOS) -> $PXi<PT, Output<OT, NOS>> {
437                    $Gpiox::set_output_speed($i, os);
438                    unsafe { transmute(self) }
439                }
440            }
441
442            impl<PT: PullType, AFN: AltFnNum, OT: OutputType, OS: OutputSpeed> $PXi<PT, AltFn<AFN, OT, OS>> {
443                /// Set output type
444                pub fn output_type<NOT: OutputType>(self, ot: NOT) -> $PXi<PT, AltFn<AFN, NOT, OS>> {
445                    $Gpiox::set_output_type($i, ot);
446                    unsafe { transmute(self) }
447                }
448
449                /// Set output speed
450                pub fn output_speed<NOS: OutputSpeed>(self, os: NOS) -> $PXi<PT, AltFn<AFN, OT, NOS>> {
451                    $Gpiox::set_output_speed($i, os);
452                    unsafe { transmute(self) }
453                }
454
455                /// Set altfn
456                pub fn alt_fn<NAFN: AltFnNum>(self, af: NAFN) -> $PXi<PT, AltFn<NAFN, OT, OS>> {
457                    let index = $i & (8 - 1);
458                    let shift: usize = 0 + (index << 2);
459                    let af_bits: u32 = af.alt_fn_num().into();
460                    let afr = unsafe { &(*$GPIOX::ptr()).$AFR };
461                    afr.modify(|r, w| unsafe {
462                        w.bits((r.bits() & !(0b1111 << shift))
463                               | (af_bits << shift))
464                    });
465
466                    unsafe { transmute(self) }
467                }
468            }
469
470            #[allow(deprecated)]
471            impl<PT: PullType, OT:OutputType, OS:OutputSpeed> OutputPin
472                for $PXi<PT, Output<OT, OS>> {
473                    fn set_high(&mut self) {
474                        // NOTE(unsafe) atomic write to a stateless register
475                        unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }
476                    }
477
478                    fn set_low(&mut self) {
479                        // NOTE(unsafe) atomic write to a stateless register
480                        unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + $i))) }
481                    }
482                }
483
484            #[allow(deprecated)]
485            impl<PT: PullType, AN: AltFnNum, OT:OutputType, OS:OutputSpeed> OutputPin
486                for $PXi<PT, AltFn<AN, OT, OS>> {
487                    fn set_high(&mut self) {
488                        // NOTE(unsafe) atomic write to a stateless register
489                        unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }
490                    }
491
492                    fn set_low(&mut self) {
493                        // NOTE(unsafe) atomic write to a stateless register
494                        unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + $i))) }
495                    }
496                }
497
498            #[allow(deprecated)]
499            impl<PT: PullType, OT:OutputType, OS:OutputSpeed> StatefulOutputPin
500                for $PXi<PT, Output<OT, OS>> {
501                    fn is_set_high(&self) -> bool {
502                        !self.is_set_low()
503                    }
504
505                    fn is_set_low(&self) -> bool {
506                        // NOTE(unsafe) atomic read with no side effects
507                        unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << $i) == 0 }
508                    }
509                }
510
511            impl<PT: PullType, OT:OutputType, OS:OutputSpeed> v2::toggleable::Default
512                for $PXi<PT, Output<OT, OS>> {}
513
514            #[allow(deprecated)]
515            impl<PT: PullType> InputPin for $PXi<PT, Input> {
516                fn is_high(&self) -> bool {
517                    !self.is_low()
518                }
519
520                fn is_low(&self) -> bool {
521                    // NOTE(unsafe) atomic read with no side effects
522                    unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 }
523                }
524            }
525
526        )+
527
528    }
529}
530
531/// GPIO pin group [A-F]
532pub enum Group {
533    /// GPIOA
534    A,
535    /// GPIOB
536    B,
537    /// GPIOC
538    C,
539    /// GPIOD
540    D,
541    /// GPIOE
542    E,
543    /// GPIOF
544    F,
545    /// GPIOG
546    G,
547}
548
549gpio!(GPIOA, Gpioa, gpioa, iopaen, ioparst, A, PAx, [
550    PA0: (pa0, 0, afrl),
551    PA1: (pa1, 1, afrl),
552    PA2: (pa2, 2, afrl),
553    PA3: (pa3, 3, afrl),
554    PA4: (pa4, 4, afrl),
555    PA5: (pa5, 5, afrl),
556    PA6: (pa6, 6, afrl),
557    PA7: (pa7, 7, afrl),
558    PA8: (pa8, 8, afrh),
559    PA9: (pa9, 9, afrh),
560    PA10: (pa10, 10, afrh),
561    PA11: (pa11, 11, afrh),
562    PA12: (pa12, 12, afrh),
563    PA13: (pa13, 13, afrh),
564    PA14: (pa14, 14, afrh),
565    PA15: (pa15, 15, afrh),
566]);
567
568gpio!(GPIOB, Gpiob, gpiob, iopben, iopbrst, B, PBx, [
569    PB0: (pb0, 0, afrl),
570    PB1: (pb1, 1, afrl),
571    PB2: (pb2, 2, afrl),
572    PB3: (pb3, 3, afrl),
573    PB4: (pb4, 4, afrl),
574    PB5: (pb5, 5, afrl),
575    PB6: (pb6, 6, afrl),
576    PB7: (pb7, 7, afrl),
577    PB8: (pb8, 8, afrh),
578    PB9: (pb9, 9, afrh),
579    PB10: (pb10, 10, afrh),
580    PB11: (pb11, 11, afrh),
581    PB12: (pb12, 12, afrh),
582    PB13: (pb13, 13, afrh),
583    PB14: (pb14, 14, afrh),
584    PB15: (pb15, 15, afrh),
585]);
586
587gpio!(GPIOC, Gpioc, gpioc, iopcen, iopcrst, C, PCx, [
588    PC0: (pc0, 0, afrl),
589    PC1: (pc1, 1, afrl),
590    PC2: (pc2, 2, afrl),
591    PC3: (pc3, 3, afrl),
592    PC4: (pc4, 4, afrl),
593    PC5: (pc5, 5, afrl),
594    PC6: (pc6, 6, afrl),
595    PC7: (pc7, 7, afrl),
596    PC8: (pc8, 8, afrh),
597    PC9: (pc9, 9, afrh),
598    PC10: (pc10, 10, afrh),
599    PC11: (pc11, 11, afrh),
600    PC12: (pc12, 12, afrh),
601    PC13: (pc13, 13, afrh),
602    PC14: (pc14, 14, afrh),
603    PC15: (pc15, 15, afrh),
604]);
605
606gpio!(GPIOD, Gpiod, gpiod, iopden, iopdrst, D, PDx, [
607    PD0: (pd0, 0, afrl),
608    PD1: (pd1, 1, afrl),
609    PD2: (pd2, 2, afrl),
610    PD3: (pd3, 3, afrl),
611    PD4: (pd4, 4, afrl),
612    PD5: (pd5, 5, afrl),
613    PD6: (pd6, 6, afrl),
614    PD7: (pd7, 7, afrl),
615    PD8: (pd8, 8, afrh),
616    PD9: (pd9, 9, afrh),
617    PD10: (pd10, 10, afrh),
618    PD11: (pd11, 11, afrh),
619    PD12: (pd12, 12, afrh),
620    PD13: (pd13, 13, afrh),
621    PD14: (pd14, 14, afrh),
622    PD15: (pd15, 15, afrh),
623]);
624
625gpio!(GPIOE, Gpioe, gpioe, iopeen, ioperst, E, PEx, [
626    PE0: (pe0, 0, afrl),
627    PE1: (pe1, 1, afrl),
628    PE2: (pe2, 2, afrl),
629    PE3: (pe3, 3, afrl),
630    PE4: (pe4, 4, afrl),
631    PE5: (pe5, 5, afrl),
632    PE6: (pe6, 6, afrl),
633    PE7: (pe7, 7, afrl),
634    PE8: (pe8, 8, afrh),
635    PE9: (pe9, 9, afrh),
636    PE10: (pe10, 10, afrh),
637    PE11: (pe11, 11, afrh),
638    PE12: (pe12, 12, afrh),
639    PE13: (pe13, 13, afrh),
640    PE14: (pe14, 14, afrh),
641    PE15: (pe15, 15, afrh),
642]);
643
644gpio!(GPIOF, Gpiof, gpiof, iopfen, iopfrst, F, PFx, [
645    PF0: (pf0, 0, afrl),
646    PF1: (pf1, 1, afrl),
647    PF2: (pf2, 2, afrl),
648    PF4: (pf3, 4, afrl),
649    PF6: (pf6, 6, afrl),
650    PF9: (pf9, 9, afrh),
651    PF10: (pf10, 10, afrh),
652]);