stm32f7xx_hal/gpio/
erased.rs

1use super::*;
2
3pub type EPin<MODE> = ErasedPin<MODE>;
4
5/// Fully erased pin
6///
7/// `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section).
8pub struct ErasedPin<MODE> {
9    // Bits 0-3: Pin, Bits 4-7: Port
10    pin_port: u8,
11    _mode: PhantomData<MODE>,
12}
13
14impl<MODE> fmt::Debug for ErasedPin<MODE> {
15    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
16        formatter.write_fmt(format_args!(
17            "P({}{})<{}>",
18            self.port_id(),
19            self.pin_id(),
20            crate::stripped_type_name::<MODE>()
21        ))
22    }
23}
24
25impl<MODE> PinExt for ErasedPin<MODE> {
26    type Mode = MODE;
27
28    #[inline(always)]
29    fn pin_id(&self) -> u8 {
30        self.pin_port & 0x0f
31    }
32    #[inline(always)]
33    fn port_id(&self) -> u8 {
34        self.pin_port >> 4
35    }
36}
37
38impl<MODE> ErasedPin<MODE> {
39    pub(crate) fn new(port: u8, pin: u8) -> Self {
40        Self {
41            pin_port: port << 4 | pin,
42            _mode: PhantomData,
43        }
44    }
45
46    #[inline]
47    fn block(&self) -> &crate::pac::gpioa::RegisterBlock {
48        // This function uses pointer arithmetic instead of branching to be more efficient
49
50        // The logic relies on the following assumptions:
51        // - GPIOA register is available on all chips
52        // - all gpio register blocks have the same layout
53        // - consecutive gpio register blocks have the same offset between them, namely 0x0400
54        // - ErasedPin::new was called with a valid port
55
56        // FIXME could be calculated after const_raw_ptr_to_usize_cast stabilization #51910
57        const GPIO_REGISTER_OFFSET: usize = 0x0400;
58
59        let offset = GPIO_REGISTER_OFFSET * self.port_id() as usize;
60        let block_ptr =
61            (crate::pac::GPIOA::ptr() as usize + offset) as *const crate::pac::gpioa::RegisterBlock;
62
63        unsafe { &*block_ptr }
64    }
65}
66
67impl<MODE> ErasedPin<Output<MODE>> {
68    #[inline(always)]
69    pub fn set_high(&mut self) {
70        // NOTE(unsafe) atomic write to a stateless register
71        unsafe { self.block().bsrr.write(|w| w.bits(1 << self.pin_id())) };
72    }
73
74    #[inline(always)]
75    pub fn set_low(&mut self) {
76        // NOTE(unsafe) atomic write to a stateless register
77        unsafe {
78            self.block()
79                .bsrr
80                .write(|w| w.bits(1 << (self.pin_id() + 16)))
81        };
82    }
83
84    #[inline(always)]
85    pub fn get_state(&self) -> PinState {
86        if self.is_set_low() {
87            PinState::Low
88        } else {
89            PinState::High
90        }
91    }
92
93    #[inline(always)]
94    pub fn set_state(&mut self, state: PinState) {
95        match state {
96            PinState::Low => self.set_low(),
97            PinState::High => self.set_high(),
98        }
99    }
100
101    #[inline(always)]
102    pub fn is_set_high(&self) -> bool {
103        !self.is_set_low()
104    }
105
106    #[inline(always)]
107    pub fn is_set_low(&self) -> bool {
108        self.block().odr.read().bits() & (1 << self.pin_id()) == 0
109    }
110
111    #[inline(always)]
112    pub fn toggle(&mut self) {
113        if self.is_set_low() {
114            self.set_high()
115        } else {
116            self.set_low()
117        }
118    }
119}
120
121impl ErasedPin<Output<OpenDrain>> {
122    #[inline(always)]
123    pub fn is_high(&self) -> bool {
124        !self.is_low()
125    }
126
127    #[inline(always)]
128    pub fn is_low(&self) -> bool {
129        self.block().idr.read().bits() & (1 << self.pin_id()) == 0
130    }
131}
132
133impl<MODE> ErasedPin<Input<MODE>> {
134    #[inline(always)]
135    pub fn is_high(&self) -> bool {
136        !self.is_low()
137    }
138
139    #[inline(always)]
140    pub fn is_low(&self) -> bool {
141        self.block().idr.read().bits() & (1 << self.pin_id()) == 0
142    }
143}