aboutsummaryrefslogtreecommitdiff
path: root/embassy-nxp/src/gpio.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-nxp/src/gpio.rs')
-rw-r--r--embassy-nxp/src/gpio.rs357
1 files changed, 4 insertions, 353 deletions
diff --git a/embassy-nxp/src/gpio.rs b/embassy-nxp/src/gpio.rs
index c7c78ce61..809903d97 100644
--- a/embassy-nxp/src/gpio.rs
+++ b/embassy-nxp/src/gpio.rs
@@ -1,354 +1,5 @@
1use embassy_hal_internal::{impl_peripheral, PeripheralType}; 1//! General purpose input/output (GPIO) driver.
2 2
3use crate::pac_utils::*; 3#[cfg_attr(feature = "lpc55", path = "./gpio/lpc55.rs")]
4use crate::{peripherals, Peri}; 4mod inner;
5 5pub use inner::*;
6pub(crate) fn init() {
7 // Enable clocks for GPIO, PINT, and IOCON
8 syscon_reg()
9 .ahbclkctrl0
10 .modify(|_, w| w.gpio0().enable().gpio1().enable().mux().enable().iocon().enable());
11}
12
13/// The GPIO pin level for pins set on "Digital" mode.
14#[derive(Debug, Eq, PartialEq, Clone, Copy)]
15pub enum Level {
16 /// Logical low. Corresponds to 0V.
17 Low,
18 /// Logical high. Corresponds to VDD.
19 High,
20}
21
22/// Pull setting for a GPIO input set on "Digital" mode.
23#[derive(Debug, Clone, Copy, Eq, PartialEq)]
24pub enum Pull {
25 /// No pull.
26 None,
27 /// Internal pull-up resistor.
28 Up,
29 /// Internal pull-down resistor.
30 Down,
31}
32
33/// The LPC55 boards have two GPIO banks, each with 32 pins. This enum represents the two banks.
34#[derive(Debug, Eq, PartialEq, Clone, Copy)]
35pub enum Bank {
36 Bank0 = 0,
37 Bank1 = 1,
38}
39
40/// GPIO output driver. Internally, this is a specialized [Flex] pin.
41pub struct Output<'d> {
42 pub(crate) pin: Flex<'d>,
43}
44
45impl<'d> Output<'d> {
46 /// Create GPIO output driver for a [Pin] with the provided [initial output](Level).
47 #[inline]
48 pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level) -> Self {
49 let mut pin = Flex::new(pin);
50 pin.set_as_output();
51 let mut result = Self { pin };
52
53 match initial_output {
54 Level::High => result.set_high(),
55 Level::Low => result.set_low(),
56 };
57
58 result
59 }
60
61 pub fn set_high(&mut self) {
62 gpio_reg().set[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) })
63 }
64
65 pub fn set_low(&mut self) {
66 gpio_reg().clr[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) })
67 }
68
69 pub fn toggle(&mut self) {
70 gpio_reg().not[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) })
71 }
72
73 /// Get the current output level of the pin. Note that the value returned by this function is
74 /// the voltage level reported by the pin, not the value set by the output driver.
75 pub fn level(&self) -> Level {
76 let bits = gpio_reg().pin[self.pin.pin_bank() as usize].read().bits();
77 if bits & self.pin.bit() != 0 {
78 Level::High
79 } else {
80 Level::Low
81 }
82 }
83}
84
85/// GPIO input driver. Internally, this is a specialized [Flex] pin.
86pub struct Input<'d> {
87 pub(crate) pin: Flex<'d>,
88}
89
90impl<'d> Input<'d> {
91 /// Create GPIO output driver for a [Pin] with the provided [Pull].
92 #[inline]
93 pub fn new(pin: Peri<'d, impl Pin>, pull: Pull) -> Self {
94 let mut pin = Flex::new(pin);
95 pin.set_as_input();
96 let mut result = Self { pin };
97 result.set_pull(pull);
98
99 result
100 }
101
102 /// Set the pull configuration for the pin. To disable the pull, use [Pull::None].
103 pub fn set_pull(&mut self, pull: Pull) {
104 match_iocon!(register, iocon_reg(), self.pin.pin_bank(), self.pin.pin_number(), {
105 register.modify(|_, w| match pull {
106 Pull::None => w.mode().inactive(),
107 Pull::Up => w.mode().pull_up(),
108 Pull::Down => w.mode().pull_down(),
109 });
110 });
111 }
112
113 /// Get the current input level of the pin.
114 pub fn read(&self) -> Level {
115 let bits = gpio_reg().pin[self.pin.pin_bank() as usize].read().bits();
116 if bits & self.pin.bit() != 0 {
117 Level::High
118 } else {
119 Level::Low
120 }
121 }
122}
123
124/// A flexible GPIO (digital mode) pin whose mode is not yet determined. Under the hood, this is a
125/// reference to a type-erased pin called ["AnyPin"](AnyPin).
126pub struct Flex<'d> {
127 pub(crate) pin: Peri<'d, AnyPin>,
128}
129
130impl<'d> Flex<'d> {
131 /// Wrap the pin in a `Flex`.
132 ///
133 /// Note: you cannot assume that the pin will be in Digital mode after this call.
134 #[inline]
135 pub fn new(pin: Peri<'d, impl Pin>) -> Self {
136 Self { pin: pin.into() }
137 }
138
139 /// Get the bank of this pin. See also [Bank].
140 ///
141 /// # Example
142 ///
143 /// ```
144 /// use embassy_nxp::gpio::{Bank, Flex};
145 ///
146 /// let p = embassy_nxp::init(Default::default());
147 /// let pin = Flex::new(p.PIO1_15);
148 ///
149 /// assert_eq!(pin.pin_bank(), Bank::Bank1);
150 /// ```
151 pub fn pin_bank(&self) -> Bank {
152 self.pin.pin_bank()
153 }
154
155 /// Get the number of this pin within its bank. See also [Bank].
156 ///
157 /// # Example
158 ///
159 /// ```
160 /// use embassy_nxp::gpio::Flex;
161 ///
162 /// let p = embassy_nxp::init(Default::default());
163 /// let pin = Flex::new(p.PIO1_15);
164 ///
165 /// assert_eq!(pin.pin_number(), 15 as u8);
166 /// ```
167 pub fn pin_number(&self) -> u8 {
168 self.pin.pin_number()
169 }
170
171 /// Get the bit mask for this pin. Useful for setting or clearing bits in a register. Note:
172 /// PIOx_0 is bit 0, PIOx_1 is bit 1, etc.
173 ///
174 /// # Example
175 ///
176 /// ```
177 /// use embassy_nxp::gpio::Flex;
178 ///
179 /// let p = embassy_nxp::init(Default::default());
180 /// let pin = Flex::new(p.PIO1_3);
181 ///
182 /// assert_eq!(pin.bit(), 0b0000_1000);
183 /// ```
184 pub fn bit(&self) -> u32 {
185 1 << self.pin.pin_number()
186 }
187
188 /// Set the pin to digital mode. This is required for using a pin as a GPIO pin. The default
189 /// setting for pins is (usually) non-digital.
190 fn set_as_digital(&mut self) {
191 match_iocon!(register, iocon_reg(), self.pin_bank(), self.pin_number(), {
192 register.modify(|_, w| w.digimode().digital());
193 });
194 }
195
196 /// Set the pin in output mode. This implies setting the pin to digital mode, which this
197 /// function handles itself.
198 pub fn set_as_output(&mut self) {
199 self.set_as_digital();
200 gpio_reg().dirset[self.pin.pin_bank() as usize].write(|w| unsafe { w.dirsetp().bits(self.bit()) })
201 }
202
203 pub fn set_as_input(&mut self) {
204 self.set_as_digital();
205 gpio_reg().dirclr[self.pin.pin_bank() as usize].write(|w| unsafe { w.dirclrp().bits(self.bit()) })
206 }
207}
208
209/// Sealed trait for pins. This trait is sealed and cannot be implemented outside of this crate.
210pub(crate) trait SealedPin: Sized {
211 fn pin_bank(&self) -> Bank;
212 fn pin_number(&self) -> u8;
213}
214
215/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an
216/// [AnyPin]. By default, this trait is sealed and cannot be implemented outside of the
217/// `embassy-nxp` crate due to the [SealedPin] trait.
218#[allow(private_bounds)]
219pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static {
220 /// Returns the pin number within a bank
221 #[inline]
222 fn pin(&self) -> u8 {
223 self.pin_number()
224 }
225
226 /// Returns the bank of this pin
227 #[inline]
228 fn bank(&self) -> Bank {
229 self.pin_bank()
230 }
231}
232
233/// Type-erased GPIO pin.
234pub struct AnyPin {
235 pin_bank: Bank,
236 pin_number: u8,
237}
238
239impl AnyPin {
240 /// Unsafely create a new type-erased pin.
241 ///
242 /// # Safety
243 ///
244 /// You must ensure that you’re only using one instance of this type at a time.
245 pub unsafe fn steal(pin_bank: Bank, pin_number: u8) -> Peri<'static, Self> {
246 Peri::new_unchecked(Self { pin_bank, pin_number })
247 }
248}
249
250impl_peripheral!(AnyPin);
251
252impl Pin for AnyPin {}
253impl SealedPin for AnyPin {
254 #[inline]
255 fn pin_bank(&self) -> Bank {
256 self.pin_bank
257 }
258
259 #[inline]
260 fn pin_number(&self) -> u8 {
261 self.pin_number
262 }
263}
264
265macro_rules! impl_pin {
266 ($name:ident, $bank:expr, $pin_num:expr) => {
267 impl Pin for peripherals::$name {}
268 impl SealedPin for peripherals::$name {
269 #[inline]
270 fn pin_bank(&self) -> Bank {
271 $bank
272 }
273
274 #[inline]
275 fn pin_number(&self) -> u8 {
276 $pin_num
277 }
278 }
279
280 impl From<peripherals::$name> for crate::gpio::AnyPin {
281 fn from(val: peripherals::$name) -> Self {
282 Self {
283 pin_bank: val.pin_bank(),
284 pin_number: val.pin_number(),
285 }
286 }
287 }
288 };
289}
290
291impl_pin!(PIO0_0, Bank::Bank0, 0);
292impl_pin!(PIO0_1, Bank::Bank0, 1);
293impl_pin!(PIO0_2, Bank::Bank0, 2);
294impl_pin!(PIO0_3, Bank::Bank0, 3);
295impl_pin!(PIO0_4, Bank::Bank0, 4);
296impl_pin!(PIO0_5, Bank::Bank0, 5);
297impl_pin!(PIO0_6, Bank::Bank0, 6);
298impl_pin!(PIO0_7, Bank::Bank0, 7);
299impl_pin!(PIO0_8, Bank::Bank0, 8);
300impl_pin!(PIO0_9, Bank::Bank0, 9);
301impl_pin!(PIO0_10, Bank::Bank0, 10);
302impl_pin!(PIO0_11, Bank::Bank0, 11);
303impl_pin!(PIO0_12, Bank::Bank0, 12);
304impl_pin!(PIO0_13, Bank::Bank0, 13);
305impl_pin!(PIO0_14, Bank::Bank0, 14);
306impl_pin!(PIO0_15, Bank::Bank0, 15);
307impl_pin!(PIO0_16, Bank::Bank0, 16);
308impl_pin!(PIO0_17, Bank::Bank0, 17);
309impl_pin!(PIO0_18, Bank::Bank0, 18);
310impl_pin!(PIO0_19, Bank::Bank0, 19);
311impl_pin!(PIO0_20, Bank::Bank0, 20);
312impl_pin!(PIO0_21, Bank::Bank0, 21);
313impl_pin!(PIO0_22, Bank::Bank0, 22);
314impl_pin!(PIO0_23, Bank::Bank0, 23);
315impl_pin!(PIO0_24, Bank::Bank0, 24);
316impl_pin!(PIO0_25, Bank::Bank0, 25);
317impl_pin!(PIO0_26, Bank::Bank0, 26);
318impl_pin!(PIO0_27, Bank::Bank0, 27);
319impl_pin!(PIO0_28, Bank::Bank0, 28);
320impl_pin!(PIO0_29, Bank::Bank0, 29);
321impl_pin!(PIO0_30, Bank::Bank0, 30);
322impl_pin!(PIO0_31, Bank::Bank0, 31);
323impl_pin!(PIO1_0, Bank::Bank1, 0);
324impl_pin!(PIO1_1, Bank::Bank1, 1);
325impl_pin!(PIO1_2, Bank::Bank1, 2);
326impl_pin!(PIO1_3, Bank::Bank1, 3);
327impl_pin!(PIO1_4, Bank::Bank1, 4);
328impl_pin!(PIO1_5, Bank::Bank1, 5);
329impl_pin!(PIO1_6, Bank::Bank1, 6);
330impl_pin!(PIO1_7, Bank::Bank1, 7);
331impl_pin!(PIO1_8, Bank::Bank1, 8);
332impl_pin!(PIO1_9, Bank::Bank1, 9);
333impl_pin!(PIO1_10, Bank::Bank1, 10);
334impl_pin!(PIO1_11, Bank::Bank1, 11);
335impl_pin!(PIO1_12, Bank::Bank1, 12);
336impl_pin!(PIO1_13, Bank::Bank1, 13);
337impl_pin!(PIO1_14, Bank::Bank1, 14);
338impl_pin!(PIO1_15, Bank::Bank1, 15);
339impl_pin!(PIO1_16, Bank::Bank1, 16);
340impl_pin!(PIO1_17, Bank::Bank1, 17);
341impl_pin!(PIO1_18, Bank::Bank1, 18);
342impl_pin!(PIO1_19, Bank::Bank1, 19);
343impl_pin!(PIO1_20, Bank::Bank1, 20);
344impl_pin!(PIO1_21, Bank::Bank1, 21);
345impl_pin!(PIO1_22, Bank::Bank1, 22);
346impl_pin!(PIO1_23, Bank::Bank1, 23);
347impl_pin!(PIO1_24, Bank::Bank1, 24);
348impl_pin!(PIO1_25, Bank::Bank1, 25);
349impl_pin!(PIO1_26, Bank::Bank1, 26);
350impl_pin!(PIO1_27, Bank::Bank1, 27);
351impl_pin!(PIO1_28, Bank::Bank1, 28);
352impl_pin!(PIO1_29, Bank::Bank1, 29);
353impl_pin!(PIO1_30, Bank::Bank1, 30);
354impl_pin!(PIO1_31, Bank::Bank1, 31);