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.rs361
1 files changed, 361 insertions, 0 deletions
diff --git a/embassy-nxp/src/gpio.rs b/embassy-nxp/src/gpio.rs
new file mode 100644
index 000000000..d5d04ee69
--- /dev/null
+++ b/embassy-nxp/src/gpio.rs
@@ -0,0 +1,361 @@
1use embassy_hal_internal::impl_peripheral;
2
3use crate::pac_utils::*;
4use crate::{peripherals, Peripheral, PeripheralRef};
5
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: impl Peripheral<P = impl Pin> + 'd, 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: impl Peripheral<P = impl Pin> + 'd, 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: PeripheralRef<'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: impl Peripheral<P = impl Pin> + 'd) -> Self {
136 Self {
137 pin: pin.into_ref().map_into(),
138 }
139 }
140
141 /// Get the bank of this pin. See also [Bank].
142 ///
143 /// # Example
144 ///
145 /// ```
146 /// use embassy_nxp::gpio::{Bank, Flex};
147 ///
148 /// let p = embassy_nxp::init(Default::default());
149 /// let pin = Flex::new(p.PIO1_15);
150 ///
151 /// assert_eq!(pin.pin_bank(), Bank::Bank1);
152 /// ```
153 pub fn pin_bank(&self) -> Bank {
154 self.pin.pin_bank()
155 }
156
157 /// Get the number of this pin within its bank. See also [Bank].
158 ///
159 /// # Example
160 ///
161 /// ```
162 /// use embassy_nxp::gpio::Flex;
163 ///
164 /// let p = embassy_nxp::init(Default::default());
165 /// let pin = Flex::new(p.PIO1_15);
166 ///
167 /// assert_eq!(pin.pin_number(), 15 as u8);
168 /// ```
169 pub fn pin_number(&self) -> u8 {
170 self.pin.pin_number()
171 }
172
173 /// Get the bit mask for this pin. Useful for setting or clearing bits in a register. Note:
174 /// PIOx_0 is bit 0, PIOx_1 is bit 1, etc.
175 ///
176 /// # Example
177 ///
178 /// ```
179 /// use embassy_nxp::gpio::Flex;
180 ///
181 /// let p = embassy_nxp::init(Default::default());
182 /// let pin = Flex::new(p.PIO1_3);
183 ///
184 /// assert_eq!(pin.bit(), 0b0000_1000);
185 /// ```
186 pub fn bit(&self) -> u32 {
187 1 << self.pin.pin_number()
188 }
189
190 /// Set the pin to digital mode. This is required for using a pin as a GPIO pin. The default
191 /// setting for pins is (usually) non-digital.
192 fn set_as_digital(&mut self) {
193 match_iocon!(register, iocon_reg(), self.pin_bank(), self.pin_number(), {
194 register.modify(|_, w| w.digimode().digital());
195 });
196 }
197
198 /// Set the pin in output mode. This implies setting the pin to digital mode, which this
199 /// function handles itself.
200 pub fn set_as_output(&mut self) {
201 self.set_as_digital();
202 gpio_reg().dirset[self.pin.pin_bank() as usize].write(|w| unsafe { w.dirsetp().bits(self.bit()) })
203 }
204
205 pub fn set_as_input(&mut self) {
206 self.set_as_digital();
207 gpio_reg().dirclr[self.pin.pin_bank() as usize].write(|w| unsafe { w.dirclrp().bits(self.bit()) })
208 }
209}
210
211/// Sealed trait for pins. This trait is sealed and cannot be implemented outside of this crate.
212pub(crate) trait SealedPin: Sized {
213 fn pin_bank(&self) -> Bank;
214 fn pin_number(&self) -> u8;
215}
216
217/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an
218/// [AnyPin]. By default, this trait is sealed and cannot be implemented outside of the
219/// `embassy-nxp` crate due to the [SealedPin] trait.
220#[allow(private_bounds)]
221pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + SealedPin + Sized + 'static {
222 /// Degrade to a generic pin struct
223 fn degrade(self) -> AnyPin {
224 AnyPin {
225 pin_bank: self.pin_bank(),
226 pin_number: self.pin_number(),
227 }
228 }
229
230 /// Returns the pin number within a bank
231 #[inline]
232 fn pin(&self) -> u8 {
233 self.pin_number()
234 }
235
236 /// Returns the bank of this pin
237 #[inline]
238 fn bank(&self) -> Bank {
239 self.pin_bank()
240 }
241}
242
243/// Type-erased GPIO pin.
244pub struct AnyPin {
245 pin_bank: Bank,
246 pin_number: u8,
247}
248
249impl AnyPin {
250 /// Unsafely create a new type-erased pin.
251 ///
252 /// # Safety
253 ///
254 /// You must ensure that you’re only using one instance of this type at a time.
255 pub unsafe fn steal(pin_bank: Bank, pin_number: u8) -> Self {
256 Self { pin_bank, pin_number }
257 }
258}
259
260impl_peripheral!(AnyPin);
261
262impl Pin for AnyPin {}
263impl SealedPin for AnyPin {
264 #[inline]
265 fn pin_bank(&self) -> Bank {
266 self.pin_bank
267 }
268
269 #[inline]
270 fn pin_number(&self) -> u8 {
271 self.pin_number
272 }
273}
274
275macro_rules! impl_pin {
276 ($name:ident, $bank:expr, $pin_num:expr) => {
277 impl Pin for peripherals::$name {}
278 impl SealedPin for peripherals::$name {
279 #[inline]
280 fn pin_bank(&self) -> Bank {
281 $bank
282 }
283
284 #[inline]
285 fn pin_number(&self) -> u8 {
286 $pin_num
287 }
288 }
289
290 impl From<peripherals::$name> for crate::gpio::AnyPin {
291 fn from(val: peripherals::$name) -> Self {
292 crate::gpio::Pin::degrade(val)
293 }
294 }
295 };
296}
297
298impl_pin!(PIO0_0, Bank::Bank0, 0);
299impl_pin!(PIO0_1, Bank::Bank0, 1);
300impl_pin!(PIO0_2, Bank::Bank0, 2);
301impl_pin!(PIO0_3, Bank::Bank0, 3);
302impl_pin!(PIO0_4, Bank::Bank0, 4);
303impl_pin!(PIO0_5, Bank::Bank0, 5);
304impl_pin!(PIO0_6, Bank::Bank0, 6);
305impl_pin!(PIO0_7, Bank::Bank0, 7);
306impl_pin!(PIO0_8, Bank::Bank0, 8);
307impl_pin!(PIO0_9, Bank::Bank0, 9);
308impl_pin!(PIO0_10, Bank::Bank0, 10);
309impl_pin!(PIO0_11, Bank::Bank0, 11);
310impl_pin!(PIO0_12, Bank::Bank0, 12);
311impl_pin!(PIO0_13, Bank::Bank0, 13);
312impl_pin!(PIO0_14, Bank::Bank0, 14);
313impl_pin!(PIO0_15, Bank::Bank0, 15);
314impl_pin!(PIO0_16, Bank::Bank0, 16);
315impl_pin!(PIO0_17, Bank::Bank0, 17);
316impl_pin!(PIO0_18, Bank::Bank0, 18);
317impl_pin!(PIO0_19, Bank::Bank0, 19);
318impl_pin!(PIO0_20, Bank::Bank0, 20);
319impl_pin!(PIO0_21, Bank::Bank0, 21);
320impl_pin!(PIO0_22, Bank::Bank0, 22);
321impl_pin!(PIO0_23, Bank::Bank0, 23);
322impl_pin!(PIO0_24, Bank::Bank0, 24);
323impl_pin!(PIO0_25, Bank::Bank0, 25);
324impl_pin!(PIO0_26, Bank::Bank0, 26);
325impl_pin!(PIO0_27, Bank::Bank0, 27);
326impl_pin!(PIO0_28, Bank::Bank0, 28);
327impl_pin!(PIO0_29, Bank::Bank0, 29);
328impl_pin!(PIO0_30, Bank::Bank0, 30);
329impl_pin!(PIO0_31, Bank::Bank0, 31);
330impl_pin!(PIO1_0, Bank::Bank1, 0);
331impl_pin!(PIO1_1, Bank::Bank1, 1);
332impl_pin!(PIO1_2, Bank::Bank1, 2);
333impl_pin!(PIO1_3, Bank::Bank1, 3);
334impl_pin!(PIO1_4, Bank::Bank1, 4);
335impl_pin!(PIO1_5, Bank::Bank1, 5);
336impl_pin!(PIO1_6, Bank::Bank1, 6);
337impl_pin!(PIO1_7, Bank::Bank1, 7);
338impl_pin!(PIO1_8, Bank::Bank1, 8);
339impl_pin!(PIO1_9, Bank::Bank1, 9);
340impl_pin!(PIO1_10, Bank::Bank1, 10);
341impl_pin!(PIO1_11, Bank::Bank1, 11);
342impl_pin!(PIO1_12, Bank::Bank1, 12);
343impl_pin!(PIO1_13, Bank::Bank1, 13);
344impl_pin!(PIO1_14, Bank::Bank1, 14);
345impl_pin!(PIO1_15, Bank::Bank1, 15);
346impl_pin!(PIO1_16, Bank::Bank1, 16);
347impl_pin!(PIO1_17, Bank::Bank1, 17);
348impl_pin!(PIO1_18, Bank::Bank1, 18);
349impl_pin!(PIO1_19, Bank::Bank1, 19);
350impl_pin!(PIO1_20, Bank::Bank1, 20);
351impl_pin!(PIO1_21, Bank::Bank1, 21);
352impl_pin!(PIO1_22, Bank::Bank1, 22);
353impl_pin!(PIO1_23, Bank::Bank1, 23);
354impl_pin!(PIO1_24, Bank::Bank1, 24);
355impl_pin!(PIO1_25, Bank::Bank1, 25);
356impl_pin!(PIO1_26, Bank::Bank1, 26);
357impl_pin!(PIO1_27, Bank::Bank1, 27);
358impl_pin!(PIO1_28, Bank::Bank1, 28);
359impl_pin!(PIO1_29, Bank::Bank1, 29);
360impl_pin!(PIO1_30, Bank::Bank1, 30);
361impl_pin!(PIO1_31, Bank::Bank1, 31);