da14531_hal/
gpio.rs

1use core::marker::PhantomData;
2
3use void::Void;
4
5use crate::{
6    hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, PinState},
7    pac::{gpio, GPIO as P0},
8};
9
10/// Disconnected pin in input mode (type state, reset value).
11pub struct Disconnected;
12
13/// Input mode (type state).
14pub struct Input<MODE> {
15    _mode: PhantomData<MODE>,
16}
17
18/// Floating input (type state).
19pub struct Floating;
20/// Pulled down input (type state).
21pub struct PullDown;
22/// Pulled up input (type state).
23pub struct PullUp;
24
25/// Output mode (type state).
26pub struct Output;
27
28/// Alternate function mode (type state)
29pub struct AlternateFunction<const PID: u8, const PUPD: u8>;
30
31macro_rules! alternate_functions {
32    (
33            $($AF:ident: ($pid:literal, $pupd:literal)),+
34    ) => {
35        $(
36            paste::paste! {
37                pub type [<Af $AF>] = AlternateFunction<$pid, $pupd>;
38            }
39        )+
40    };
41}
42
43alternate_functions! {
44    Uart1Rx:    ( 1, 0b01),
45    Uart1Tx:    ( 2, 0b01),
46    Uart2Rx:    ( 3, 0b01),
47    Uart2Tx:    ( 4, 0b01),
48    SysClk:     ( 5, 0b01),
49    LpClk:      ( 6, 0b01),
50    I2cScl:     ( 9, 0b00),
51    I2cSda:     (10, 0b00),
52    Pwm5:       (11, 0b11),
53    Pwm6:       (12, 0b11),
54    Pwm7:       (13, 0b11),
55    Adc:        (15, 0b01),
56    Pwm0:       (16, 0b11),
57    Pwm1:       (17, 0b11),
58    BleDiag:    (18, 0b01),
59    Uart1Ctsn:  (19, 0b01),
60    Uart1Rtsn:  (20, 0b01),
61    Pwm2:       (23, 0b11),
62    Pwm3:       (24, 0b11),
63    Pwm4:       (25, 0b11),
64    SpiDi:      (26, 0b01),
65    SpiDo:      (27, 0b01),
66    SpiClk:     (28, 0b01),
67    SpiCsn0:    (29, 0b01),
68    SpiCsn1:    (30, 0b01)
69}
70
71// ===============================================================
72// Implement Generic Pins for this port, which allows you to use
73// other peripherals without having to be completely rust-generic
74// across all of the possible pins
75// ===============================================================
76/// Generic $PX pin
77pub struct Pin<MODE> {
78    pin: u8,
79    _mode: PhantomData<MODE>,
80}
81
82impl<MODE> Pin<MODE> {
83    fn new(pin: u8) -> Self {
84        Self {
85            pin,
86            _mode: PhantomData,
87        }
88    }
89
90    #[inline]
91    pub fn pin(&self) -> u8 {
92        self.pin
93    }
94
95    fn block(&self) -> &gpio::RegisterBlock {
96        unsafe { &*P0::ptr() }
97    }
98
99    // ToDo: Port this section!
100    pub(crate) fn pin_mode(&self) -> &gpio::P0_MODE_REG {
101        &self.block().p0_mode_reg[self.pin as usize]
102    }
103
104    /// Convert the pin to be a floating input
105    pub fn into_floating_input(self) -> Pin<Input<Floating>> {
106        self.pin_mode().write(|w| {
107            unsafe {
108                w.pupd().bits(0b00);
109                w.pid().bits(0);
110            }
111            w
112        });
113
114        Pin {
115            _mode: PhantomData,
116            pin: self.pin,
117        }
118    }
119    pub fn into_pullup_input(self) -> Pin<Input<PullUp>> {
120        self.pin_mode().write(|w| {
121            unsafe {
122                w.pupd().bits(0b01);
123                w.pid().bits(0);
124            }
125            w
126        });
127
128        Pin {
129            _mode: PhantomData,
130            pin: self.pin,
131        }
132    }
133
134    pub fn into_pulldown_input(self) -> Pin<Input<PullDown>> {
135        self.pin_mode().write(|w| {
136            unsafe {
137                w.pupd().bits(0b10);
138                w.pid().bits(0);
139            }
140            w
141        });
142
143        Pin {
144            _mode: PhantomData,
145            pin: self.pin,
146        }
147    }
148
149    /// Convert the pin to be a push-pull output with normal drive.
150    pub fn into_output(self, initial_output: PinState) -> Pin<Output> {
151        let mut pin = Pin {
152            _mode: PhantomData,
153            pin: self.pin,
154        };
155
156        match initial_output {
157            PinState::Low => pin.set_low().unwrap(),
158            PinState::High => pin.set_high().unwrap(),
159        }
160
161        self.pin_mode().write(|w| {
162            unsafe {
163                w.pupd().bits(0b11);
164                w.pid().bits(0);
165            }
166            w
167        });
168
169        pin
170    }
171
172    pub fn into_alternate<const PID: u8, const PUPD: u8>(
173        self,
174    ) -> Pin<AlternateFunction<PID, PUPD>> {
175        self.pin_mode().write(|w| {
176            unsafe {
177                w.pupd().bits(PUPD);
178                w.pid().bits(PID);
179            }
180            w
181        });
182
183        Pin {
184            _mode: PhantomData,
185            pin: self.pin,
186        }
187    }
188
189    /// Disconnects the pin.
190    ///
191    /// In disconnected mode the pin cannot be used as input or output.
192    /// It is primarily useful to reduce power usage.
193    pub fn into_disconnected(self) -> Pin<Disconnected> {
194        // Reset value is disconnected.
195        self.pin_mode().reset();
196
197        Pin {
198            _mode: PhantomData,
199            pin: self.pin,
200        }
201    }
202}
203
204impl<MODE> InputPin for Pin<Input<MODE>> {
205    type Error = Void;
206
207    fn is_high(&self) -> Result<bool, Self::Error> {
208        self.is_low().map(|v| !v)
209    }
210
211    fn is_low(&self) -> Result<bool, Self::Error> {
212        Ok(self.block().p0_data_reg.read().bits() & (1 << self.pin()) == 0)
213    }
214}
215
216impl OutputPin for Pin<Output> {
217    type Error = Void;
218
219    /// Set the output as high.
220    fn set_high(&mut self) -> Result<(), Self::Error> {
221        unsafe {
222            self.block()
223                .p0_set_data_reg
224                .write(|w| w.bits(1u16 << self.pin()));
225        }
226        Ok(())
227    }
228
229    /// Set the output as low.
230    fn set_low(&mut self) -> Result<(), Self::Error> {
231        unsafe {
232            self.block()
233                .p0_reset_data_reg
234                .write(|w| w.bits(1u16 << self.pin()));
235        }
236        Ok(())
237    }
238}
239
240impl StatefulOutputPin for Pin<Output> {
241    /// Is the output pin set as high?
242    fn is_set_high(&self) -> Result<bool, Self::Error> {
243        self.is_set_low().map(|v| !v)
244    }
245
246    /// Is the output pin set as low?
247    fn is_set_low(&self) -> Result<bool, Self::Error> {
248        // NOTE(unsafe) atomic read with no side effects - TODO(AJM) verify?
249        // TODO - I wish I could do something like `.pins$i()`...
250        Ok(self.block().p0_data_reg.read().bits() & (1 << self.pin()) == 0)
251    }
252}
253
254macro_rules! gpio {
255    (
256        $PX:ident, $pxsvd:ident, $px:ident, [
257            $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty),)+
258        ]
259    ) => {
260        /// GPIO
261        pub mod $px {
262            use super::{
263                Pin,
264
265                Floating,
266                Disconnected,
267                Input,
268                PinState,
269                Output,
270                PullDown,
271                PullUp,
272                AlternateFunction,
273
274                PhantomData,
275                $PX
276            };
277
278            use crate::hal::digital::v2::{OutputPin, StatefulOutputPin, InputPin};
279            use void::Void;
280
281
282            // ===============================================================
283            // This chunk allows you to obtain an da14531 gpio from the
284            // upstream gpio definitions by defining a trait
285            // ===============================================================
286            /// GPIO parts
287            pub struct Parts {
288                $(
289                    /// Pin
290                    pub $pxi: $PXi<$MODE>,
291                )+
292            }
293
294            impl Parts {
295                pub fn new(_gpio: $PX) -> Self {
296                    Self {
297                        $(
298                            $pxi: $PXi {
299                                _mode: PhantomData,
300                            },
301                        )+
302                    }
303                }
304            }
305
306            // ===============================================================
307            // Implement each of the typed pins usable through the da14531-hal
308            // defined interface
309            // ===============================================================
310            $(
311                pub struct $PXi<MODE> {
312                    _mode: PhantomData<MODE>,
313                }
314
315
316                impl<MODE> $PXi<MODE> {
317                    /// Convert the pin to be a floating input
318                    pub fn into_floating_input(self) -> $PXi<Input<Floating>> {
319                        unsafe { &(*$PX::ptr()).p0_mode_reg[$i] }.write(|w| {
320                            unsafe {
321                                w.pupd().bits(0b00);
322                                w.pid().bits(0);
323                            }
324                            w
325                        });
326
327                        $PXi {
328                            _mode: PhantomData,
329                        }
330                    }
331                    pub fn into_pulldown_input(self) -> $PXi<Input<PullDown>> {
332                        unsafe { &(*$PX::ptr()).p0_mode_reg[$i] }.write(|w| {
333                            unsafe {
334                                w.pupd().bits(0b01);
335                                w.pid().bits(0);
336                            }
337                            w
338                        });
339
340                        $PXi {
341                            _mode: PhantomData,
342                        }
343                    }
344                    pub fn into_pullup_input(self) -> $PXi<Input<PullUp>> {
345                        unsafe { &(*$PX::ptr()).p0_mode_reg[$i] }.write(|w| {
346                            unsafe {
347                                w.pupd().bits(0b10);
348                                w.pid().bits(0);
349                            }
350                            w
351                        });
352
353                        $PXi {
354                            _mode: PhantomData,
355                        }
356                    }
357
358                    /// Convert the pin to bepin a push-pull output with normal drive
359                    pub fn into_output(self, initial_output: PinState)
360                        -> $PXi<Output>
361                    {
362                        let mut pin = $PXi {
363                            _mode: PhantomData,
364                        };
365
366                        match initial_output {
367                            PinState::Low  => pin.set_low().unwrap(),
368                            PinState::High => pin.set_high().unwrap(),
369                        }
370
371                        unsafe { &(*$PX::ptr()).p0_mode_reg[$i] }.write(|w| {
372                            unsafe {
373                                w.pupd().bits(0b11);
374                                w.pid().bits(0);
375                            }
376                            w
377                        });
378
379                        pin
380                    }
381
382                    pub fn into_alternate<const PID: u8, const PUPD: u8>(self) -> $PXi<AlternateFunction<PID, PUPD>> {
383                        let pin = $PXi {
384                            _mode: PhantomData,
385                        };
386
387                        unsafe { &(*$PX::ptr()).p0_mode_reg[$i] }.write(|w| {
388                            unsafe {
389                                w.pupd().bits(PUPD);
390                                w.pid().bits(PID);
391                            }
392                            w
393                        });
394
395                        pin
396                    }
397
398
399                    /// Disconnects the pin.
400                    ///
401                    /// In disconnected mode the pin cannot be used as input or output.
402                    /// It is primarily useful to reduce power usage.
403                    pub fn into_disconnected(self) -> $PXi<Disconnected> {
404                        // Reset value is disconnected.
405                        unsafe { &(*$PX::ptr()).p0_mode_reg[$i] }.reset();
406
407                        $PXi {
408                            _mode: PhantomData,
409                        }
410                    }
411
412                    /// Degrade to a generic pin struct, which can be used with peripherals
413                    pub fn degrade(self) -> Pin<MODE> {
414                        Pin::new($i)
415                    }
416                }
417
418                impl<MODE> InputPin for $PXi<Input<MODE>> {
419                    type Error = Void;
420
421                    fn is_high(&self) -> Result<bool, Self::Error> {
422                        self.is_low().map(|v| !v)
423                    }
424
425                    fn is_low(&self) -> Result<bool, Self::Error> {
426                        Ok(unsafe { ((*$PX::ptr()).p0_data_reg.read().bits() & (1 << $i)) == 0 })
427                    }
428                }
429
430                impl<MODE> From<$PXi<MODE>> for Pin<MODE> {
431                    fn from(value: $PXi<MODE>) -> Self {
432                        value.degrade()
433                    }
434                }
435
436                impl OutputPin for $PXi<Output> {
437                    type Error = Void;
438
439                    /// Set the output as high
440                    fn set_high(&mut self) -> Result<(), Self::Error> {
441                        unsafe { (*$PX::ptr()).p0_set_data_reg.write(|w| w.bits(1u16 << $i)); }
442                        Ok(())
443                    }
444
445                    /// Set the output as low
446                    fn set_low(&mut self) -> Result<(), Self::Error> {
447                        unsafe { (*$PX::ptr()).p0_reset_data_reg.write(|w| w.bits(1u16 << $i)); }
448                        Ok(())
449                    }
450                }
451
452                impl StatefulOutputPin for $PXi<Output> {
453                    /// Is the output pin set as high?
454                    fn is_set_high(&self) -> Result<bool, Self::Error> {
455                        self.is_set_low().map(|v| !v)
456                    }
457
458                    /// Is the output pin set as low?
459                    fn is_set_low(&self) -> Result<bool, Self::Error> {
460                        // NOTE(unsafe) atomic read with no side effects - TODO(AJM) verify?
461                        // TODO - I wish I could do something like `.pins$i()`...
462                        Ok(unsafe { ((*$PX::ptr()).p0_data_reg.read().bits() & (1 << $i)) == 0 })
463                    }
464                }
465            )+
466        }
467    }
468}
469
470// ===========================================================================
471// Definition of all the items used by the macros above.
472// ===========================================================================
473gpio!(P0, p0, p0, [
474    P0_00: (p0_00,  0, Disconnected),
475    P0_01: (p0_01,  1, Disconnected),
476    P0_02: (p0_02,  2, Disconnected),
477    P0_03: (p0_03,  3, Disconnected),
478    P0_04: (p0_04,  4, Disconnected),
479    P0_05: (p0_05,  5, Disconnected),
480    P0_06: (p0_06,  6, Disconnected),
481    P0_07: (p0_07,  7, Disconnected),
482    P0_08: (p0_08,  8, Disconnected),
483    P0_09: (p0_09,  9, Disconnected),
484    P0_10: (p0_10, 10, Disconnected),
485    P0_11: (p0_11, 11, Disconnected),
486]);