embedded_c_sdk_bind_hal/gpio/
pin.rs

1//! General-purpose Input/Output (GPIO)
2
3use crate::ll_api::{ll_cmd::*, GpioInitParam};
4use core::convert::Infallible;
5use embassy_hal_internal::{Peri, PeripheralType};
6
7/// GPIO flexible pin.
8///
9/// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain
10/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
11/// mode.
12pub struct Flex<'d> {
13    pub(crate) pin: Peri<'d, AnyPin>,
14}
15
16impl<'d> Flex<'d> {
17    /// Wrap the pin in a `Flex`.
18    ///
19    /// The pin remains disconnected. The initial output level is unspecified, but can be changed
20    /// before the pin is put into output mode.
21    ///
22    #[inline]
23    pub fn new(pin: Peri<'d, impl Pin>) -> Self {
24        // Pin will be in disconnected state.
25        Self { pin: pin.into() }
26    }
27
28    /// Put the pin into input mode.
29    ///
30    /// The internal weak pull-up and pull-down resistors will be enabled according to `pull`.
31    #[inline(never)]
32    pub fn set_as_input(&mut self, pull: Pull) {
33        let port = self.pin._port();
34        let pin = self.pin._pin();
35        let flag = pull.to_pupdr();
36
37        ll_invoke_inner!(INVOKE_ID_GPIO_INIT, port, pin, flag);
38    }
39
40    /// Put the pin into push-pull output mode.
41    ///
42    /// The pin level will be whatever was set before (or low by default). If you want it to begin
43    /// at a specific level, call `set_high`/`set_low` on the pin first.
44    ///
45    /// The internal weak pull-up and pull-down resistors will be disabled.
46    #[inline(never)]
47    pub fn set_as_output(&mut self) {
48        let port = self.pin._port();
49        let pin = self.pin._pin();
50        let flag = GpioInitParam::OutPP.param();
51
52        ll_invoke_inner!(INVOKE_ID_GPIO_INIT, port, pin, flag);
53    }
54
55    /// Put the pin into open-drain output mode.
56    #[inline(never)]
57    pub fn set_as_open_drain(&mut self) {
58        let port = self.pin._port();
59        let pin = self.pin._pin();
60        let flag = GpioInitParam::OutOD.param();
61
62        ll_invoke_inner!(INVOKE_ID_GPIO_INIT, port, pin, flag);
63    }
64
65    /// Put the pin into alternate function mode.
66    pub fn set_as_alternate(&mut self, mode: AltMode) {
67        let port = self.pin._port();
68        let pin = self.pin._pin();
69        let flag = mode.to_flag();
70
71        ll_invoke_inner!(INVOKE_ID_GPIO_INIT, port, pin, flag);
72    }
73
74    /// Put the pin into analog mode.
75    pub fn set_as_analog(&mut self) {
76        let port = self.pin._port();
77        let pin = self.pin._pin();
78        let flag = GpioInitParam::Analog.param();
79
80        ll_invoke_inner!(INVOKE_ID_GPIO_INIT, port, pin, flag);
81    }
82
83    /// Get whether the pin input level is high.
84    #[inline]
85    pub fn is_high(&self) -> bool {
86        let port = self.pin._port();
87        let pin = self.pin._pin();
88
89        ll_invoke_inner!(INVOKE_ID_GPIO_GET_INPUT, port, pin) > 0
90    }
91
92    /// Get whether the pin input level is low.
93    #[inline]
94    pub fn is_low(&self) -> bool {
95        let port = self.pin._port();
96        let pin = self.pin._pin();
97
98        ll_invoke_inner!(INVOKE_ID_GPIO_GET_INPUT, port, pin) == 0
99    }
100
101    /// Get the current pin input level.
102    #[inline]
103    pub fn get_level(&self) -> Level {
104        self.is_high().into()
105    }
106
107    /// Get whether the output level is set to high.
108    #[inline]
109    pub fn is_set_high(&self) -> bool {
110        !self.is_set_low()
111    }
112
113    /// Get whether the output level is set to low.
114    #[inline]
115    pub fn is_set_low(&self) -> bool {
116        let port = self.pin._port();
117        let pin = self.pin._pin();
118
119        ll_invoke_inner!(INVOKE_ID_GPIO_GET_OUTPUT, port, pin) == 0
120    }
121
122    /// Get the current output level.
123    #[inline]
124    pub fn get_output_level(&self) -> Level {
125        self.is_set_high().into()
126    }
127
128    /// Set the output as high.
129    #[inline]
130    pub fn set_high(&mut self) {
131        self.pin.set_high();
132    }
133
134    /// Set the output as low.
135    #[inline]
136    pub fn set_low(&mut self) {
137        self.pin.set_low();
138    }
139
140    /// Set the output level.
141    #[inline]
142    pub fn set_level(&mut self, level: Level) {
143        match level {
144            Level::Low => self.pin.set_low(),
145            Level::High => self.pin.set_high(),
146        }
147    }
148
149    /// Toggle the output level.
150    #[inline]
151    pub fn toggle(&mut self) {
152        if self.is_set_low() {
153            self.set_high()
154        } else {
155            self.set_low()
156        }
157    }
158}
159
160impl<'d> Drop for Flex<'d> {
161    #[inline]
162    fn drop(&mut self) {
163        //Do nothing, hold status
164    }
165}
166
167/// Pull setting for an input.
168#[derive(Debug, Eq, PartialEq, Copy, Clone)]
169pub enum Pull {
170    /// No pull
171    None,
172    /// Pull up
173    Up,
174    /// Pull down
175    Down,
176}
177
178impl Pull {
179    const fn to_pupdr(self) -> u32 {
180        match self {
181            Pull::None => GpioInitParam::InFloating.param(),
182            Pull::Up => GpioInitParam::InPU.param(),
183            Pull::Down => GpioInitParam::InPD.param(),
184        }
185    }
186}
187
188/// GPIO input driver.
189pub struct Input<'d> {
190    pub(crate) pin: Flex<'d>,
191}
192
193impl<'d> Input<'d> {
194    /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
195    #[inline]
196    pub fn new(pin: Peri<'d, impl Pin>, pull: Pull) -> Self {
197        let mut pin = Flex::new(pin);
198        pin.set_as_input(pull);
199        Self { pin }
200    }
201
202    /// Get whether the pin input level is high.
203    #[inline]
204    pub fn is_high(&self) -> bool {
205        self.pin.is_high()
206    }
207
208    /// Get whether the pin input level is low.
209    #[inline]
210    pub fn is_low(&self) -> bool {
211        self.pin.is_low()
212    }
213
214    /// Get the current pin input level.
215    #[inline]
216    pub fn get_level(&self) -> Level {
217        self.pin.get_level()
218    }
219}
220
221/// Digital input or output level.
222#[derive(Debug, Eq, PartialEq, Copy, Clone)]
223pub enum Level {
224    /// Low
225    Low,
226    /// High
227    High,
228}
229
230impl From<bool> for Level {
231    fn from(val: bool) -> Self {
232        match val {
233            true => Self::High,
234            false => Self::Low,
235        }
236    }
237}
238
239impl From<Level> for bool {
240    fn from(level: Level) -> bool {
241        match level {
242            Level::Low => false,
243            Level::High => true,
244        }
245    }
246}
247
248/// GPIO output driver.
249///
250/// Note that pins will **return to their floating state** when `Output` is dropped.
251/// If pins should retain their state indefinitely, either keep ownership of the
252/// `Output`, or pass it to [`core::mem::forget`].
253pub struct Output<'d> {
254    pub(crate) pin: Flex<'d>,
255}
256
257impl<'d> Output<'d> {
258    /// Create GPIO output driver for a [Pin] with the provided [Level] and [Speed] configuration.
259    #[inline]
260    pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level) -> Self {
261        let mut pin = Flex::new(pin);
262        match initial_output {
263            Level::High => pin.set_high(),
264            Level::Low => pin.set_low(),
265        }
266        pin.set_as_output();
267        Self { pin }
268    }
269
270    /// Set the output as high.
271    #[inline]
272    pub fn set_high(&mut self) {
273        self.pin.set_high();
274    }
275
276    /// Set the output as low.
277    #[inline]
278    pub fn set_low(&mut self) {
279        self.pin.set_low();
280    }
281
282    /// Set the output level.
283    #[inline]
284    pub fn set_level(&mut self, level: Level) {
285        self.pin.set_level(level)
286    }
287
288    /// Is the output pin set as high?
289    #[inline]
290    pub fn is_set_high(&self) -> bool {
291        self.pin.is_set_high()
292    }
293
294    /// Is the output pin set as low?
295    #[inline]
296    pub fn is_set_low(&self) -> bool {
297        self.pin.is_set_low()
298    }
299
300    /// What level output is set to
301    #[inline]
302    pub fn get_output_level(&self) -> Level {
303        self.pin.get_output_level()
304    }
305
306    /// Toggle pin output
307    #[inline]
308    pub fn toggle(&mut self) {
309        self.pin.toggle();
310    }
311}
312
313/// GPIO output open-drain driver.
314///
315/// Note that pins will **return to their floating state** when `OutputOpenDrain` is dropped.
316/// If pins should retain their state indefinitely, either keep ownership of the
317/// `OutputOpenDrain`, or pass it to [`core::mem::forget`].
318pub struct OutputOpenDrain<'d> {
319    pub(crate) pin: Flex<'d>,
320}
321
322impl<'d> OutputOpenDrain<'d> {
323    /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed].
324    #[inline]
325    pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level) -> Self {
326        let mut pin = Flex::new(pin);
327        match initial_output {
328            Level::High => pin.set_high(),
329            Level::Low => pin.set_low(),
330        }
331        pin.set_as_open_drain();
332        Self { pin }
333    }
334
335    /// Get whether the pin input level is high.
336    #[inline]
337    pub fn is_high(&self) -> bool {
338        !self.pin.is_low()
339    }
340
341    /// Get whether the pin input level is low.
342    #[inline]
343    pub fn is_low(&self) -> bool {
344        self.pin.is_low()
345    }
346
347    /// Get the current pin input level.
348    #[inline]
349    pub fn get_level(&self) -> Level {
350        self.pin.get_level()
351    }
352
353    /// Set the output as high.
354    #[inline]
355    pub fn set_high(&mut self) {
356        self.pin.set_high();
357    }
358
359    /// Set the output as low.
360    #[inline]
361    pub fn set_low(&mut self) {
362        self.pin.set_low();
363    }
364
365    /// Set the output level.
366    #[inline]
367    pub fn set_level(&mut self, level: Level) {
368        self.pin.set_level(level);
369    }
370
371    /// Get whether the output level is set to high.
372    #[inline]
373    pub fn is_set_high(&self) -> bool {
374        self.pin.is_set_high()
375    }
376
377    /// Get whether the output level is set to low.
378    #[inline]
379    pub fn is_set_low(&self) -> bool {
380        self.pin.is_set_low()
381    }
382
383    /// Get the current output level.
384    #[inline]
385    pub fn get_output_level(&self) -> Level {
386        self.pin.get_output_level()
387    }
388
389    /// Toggle pin output
390    #[inline]
391    pub fn toggle(&mut self) {
392        self.pin.toggle()
393    }
394}
395
396pub enum AltMode {
397    AFIN,
398    AFOD,
399    AFPP,
400    AF(u8),
401}
402
403impl AltMode {
404    fn to_flag(&self) -> u32 {
405        match self {
406            AltMode::AFIN => GpioInitParam::AFIN.param(),
407            AltMode::AFOD => GpioInitParam::AFOD.param(),
408            AltMode::AFPP => GpioInitParam::AFPP.param(),
409            AltMode::AF(idx) => GpioInitParam::AF(*idx).param(),
410        }
411    }
412}
413
414/// GPIO alternate driver.
415pub struct Alternate<'d> {
416    pub(crate) _pin: Flex<'d>,
417}
418
419impl<'d> Alternate<'d> {
420    /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
421    #[inline]
422    pub fn new(pin: Peri<'d, impl Pin>, mode: AltMode) -> Self {
423        let mut pin = Flex::new(pin);
424        pin.set_as_alternate(mode);
425        Self { _pin: pin }
426    }
427}
428
429/// GPIO analog driver.
430pub struct Analog<'d> {
431    pub(crate) _pin: Flex<'d>,
432}
433
434impl<'d> Analog<'d> {
435    /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
436    #[inline]
437    pub fn new(pin: Peri<'d, impl Pin>) -> Self {
438        let mut pin = Flex::new(pin);
439        pin.set_as_analog();
440        Self { _pin: pin }
441    }
442}
443
444pub(crate) trait SealedPin {
445    fn pin_port(&self) -> u8;
446
447    #[inline]
448    fn _pin(&self) -> u8 {
449        self.pin_port() % 16
450    }
451
452    #[inline]
453    fn _port(&self) -> u8 {
454        self.pin_port() / 16
455    }
456
457    // #[inline]
458    // fn block(&self) -> gpio::Gpio {
459    //     crate::chip::gpio_block(self._port() as _)
460    // }
461
462    /// Set the output as high.
463    #[inline]
464    fn set_high(&self) {
465        let port = self._port();
466        let pin = self._pin();
467
468        ll_invoke_inner!(INVOKE_ID_GPIO_SET, port, pin, 1);
469    }
470
471    /// Set the output as low.
472    #[inline]
473    fn set_low(&self) {
474        let port = self._port();
475        let pin = self._pin();
476
477        ll_invoke_inner!(INVOKE_ID_GPIO_SET, port, pin, 0);
478    }
479}
480
481/// GPIO pin trait.
482#[allow(private_bounds)]
483pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static {
484    /// Number of the pin within the port (0..31)
485    #[inline]
486    fn pin(&self) -> u8 {
487        self._pin()
488    }
489
490    /// Port of the pin
491    #[inline]
492    fn port(&self) -> u8 {
493        self._port()
494    }
495}
496
497/// Type-erased GPIO pin
498pub struct AnyPin {
499    pin_port: u8,
500}
501
502impl AnyPin {
503    /// Unsafely create an `AnyPin` from a pin+port number.
504    ///
505    /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc...
506    #[inline]
507    pub unsafe fn steal(pin_port: u8) -> Peri<'static, Self> {
508        Peri::new_unchecked(Self { pin_port })
509    }
510
511    #[inline]
512    fn _port(&self) -> u8 {
513        self.pin_port / 16
514    }
515}
516
517impl Copy for AnyPin {}
518
519impl Clone for AnyPin {
520    fn clone(&self) -> Self {
521        *self
522    }
523}
524impl PeripheralType for AnyPin {}
525
526impl Pin for AnyPin {}
527
528impl SealedPin for AnyPin {
529    #[inline]
530    fn pin_port(&self) -> u8 {
531        self.pin_port
532    }
533}
534
535crate::foreach_pin!(
536    ($pin_name:ident, $port_num:expr, $pin_num:expr) => {
537        impl Pin for $crate::peripherals::$pin_name {
538        }
539
540        impl SealedPin for $crate::peripherals::$pin_name {
541            #[inline]
542            fn pin_port(&self) -> u8 {
543                $port_num * 16 + $pin_num
544            }
545        }
546
547        impl From<$crate::peripherals::$pin_name> for AnyPin {
548            fn from(val: $crate::peripherals::$pin_name) -> Self {
549                Self {
550                    pin_port: val.pin_port(),
551                }
552            }
553        }
554    };
555);
556
557impl<'d> embedded_hal::digital::ErrorType for Input<'d> {
558    type Error = Infallible;
559}
560
561impl<'d> embedded_hal::digital::InputPin for Input<'d> {
562    #[inline]
563    fn is_high(&mut self) -> Result<bool, Self::Error> {
564        Ok(Input::is_high(self))
565    }
566
567    #[inline]
568    fn is_low(&mut self) -> Result<bool, Self::Error> {
569        Ok(Input::is_low(self))
570    }
571}
572
573impl<'d> embedded_hal::digital::ErrorType for Output<'d> {
574    type Error = Infallible;
575}
576
577impl<'d> embedded_hal::digital::OutputPin for Output<'d> {
578    #[inline]
579    fn set_high(&mut self) -> Result<(), Self::Error> {
580        Output::set_high(self);
581        Ok(())
582    }
583
584    #[inline]
585    fn set_low(&mut self) -> Result<(), Self::Error> {
586        Output::set_low(self);
587        Ok(())
588    }
589}
590
591impl<'d> embedded_hal::digital::StatefulOutputPin for Output<'d> {
592    #[inline]
593    fn is_set_high(&mut self) -> Result<bool, Self::Error> {
594        Ok(Output::is_set_high(self))
595    }
596
597    /// Is the output pin set as low?
598    #[inline]
599    fn is_set_low(&mut self) -> Result<bool, Self::Error> {
600        Ok(Output::is_set_low(self))
601    }
602}
603
604impl<'d> embedded_hal::digital::ErrorType for OutputOpenDrain<'d> {
605    type Error = Infallible;
606}
607
608impl<'d> embedded_hal::digital::InputPin for OutputOpenDrain<'d> {
609    #[inline]
610    fn is_high(&mut self) -> Result<bool, Self::Error> {
611        Ok(OutputOpenDrain::is_high(self))
612    }
613
614    #[inline]
615    fn is_low(&mut self) -> Result<bool, Self::Error> {
616        Ok(OutputOpenDrain::is_low(self))
617    }
618}
619
620impl<'d> embedded_hal::digital::OutputPin for OutputOpenDrain<'d> {
621    #[inline]
622    fn set_high(&mut self) -> Result<(), Self::Error> {
623        OutputOpenDrain::set_high(self);
624        Ok(())
625    }
626
627    #[inline]
628    fn set_low(&mut self) -> Result<(), Self::Error> {
629        OutputOpenDrain::set_low(self);
630        Ok(())
631    }
632}
633
634impl<'d> embedded_hal::digital::StatefulOutputPin for OutputOpenDrain<'d> {
635    #[inline]
636    fn is_set_high(&mut self) -> Result<bool, Self::Error> {
637        Ok(OutputOpenDrain::is_set_high(self))
638    }
639
640    /// Is the output pin set as low?
641    #[inline]
642    fn is_set_low(&mut self) -> Result<bool, Self::Error> {
643        Ok(OutputOpenDrain::is_set_low(self))
644    }
645}
646
647impl<'d> embedded_hal::digital::InputPin for Flex<'d> {
648    #[inline]
649    fn is_high(&mut self) -> Result<bool, Self::Error> {
650        Ok(Flex::is_high(self))
651    }
652
653    #[inline]
654    fn is_low(&mut self) -> Result<bool, Self::Error> {
655        Ok(Flex::is_low(self))
656    }
657}
658
659impl<'d> embedded_hal::digital::OutputPin for Flex<'d> {
660    #[inline]
661    fn set_high(&mut self) -> Result<(), Self::Error> {
662        Flex::set_high(self);
663        Ok(())
664    }
665
666    #[inline]
667    fn set_low(&mut self) -> Result<(), Self::Error> {
668        Flex::set_low(self);
669        Ok(())
670    }
671}
672
673impl<'d> embedded_hal::digital::ErrorType for Flex<'d> {
674    type Error = Infallible;
675}
676
677impl<'d> embedded_hal::digital::StatefulOutputPin for Flex<'d> {
678    #[inline]
679    fn is_set_high(&mut self) -> Result<bool, Self::Error> {
680        Ok(Flex::is_set_high(self))
681    }
682
683    /// Is the output pin set as low?
684    #[inline]
685    fn is_set_low(&mut self) -> Result<bool, Self::Error> {
686        Ok(Flex::is_set_low(self))
687    }
688}