aboutsummaryrefslogtreecommitdiff
path: root/embassy-nxp/src
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-nxp/src')
-rw-r--r--embassy-nxp/src/gpio.rs361
-rw-r--r--embassy-nxp/src/lib.rs95
-rw-r--r--embassy-nxp/src/pac_utils.rs323
-rw-r--r--embassy-nxp/src/pint.rs440
4 files changed, 1219 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);
diff --git a/embassy-nxp/src/lib.rs b/embassy-nxp/src/lib.rs
new file mode 100644
index 000000000..80fdecb2e
--- /dev/null
+++ b/embassy-nxp/src/lib.rs
@@ -0,0 +1,95 @@
1#![no_std]
2
3pub mod gpio;
4mod pac_utils;
5pub mod pint;
6
7pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
8pub use lpc55_pac as pac;
9
10/// Initialize the `embassy-nxp` HAL with the provided configuration.
11///
12/// This returns the peripheral singletons that can be used for creating drivers.
13///
14/// This should only be called once and at startup, otherwise it panics.
15pub fn init(_config: config::Config) -> Peripherals {
16 gpio::init();
17 pint::init();
18
19 crate::Peripherals::take()
20}
21
22embassy_hal_internal::peripherals! {
23 // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other
24 // peripheral types (e.g. I2C).
25 PIO0_0,
26 PIO0_1,
27 PIO0_2,
28 PIO0_3,
29 PIO0_4,
30 PIO0_5,
31 PIO0_6,
32 PIO0_7,
33 PIO0_8,
34 PIO0_9,
35 PIO0_10,
36 PIO0_11,
37 PIO0_12,
38 PIO0_13,
39 PIO0_14,
40 PIO0_15,
41 PIO0_16,
42 PIO0_17,
43 PIO0_18,
44 PIO0_19,
45 PIO0_20,
46 PIO0_21,
47 PIO0_22,
48 PIO0_23,
49 PIO0_24,
50 PIO0_25,
51 PIO0_26,
52 PIO0_27,
53 PIO0_28,
54 PIO0_29,
55 PIO0_30,
56 PIO0_31,
57 PIO1_0,
58 PIO1_1,
59 PIO1_2,
60 PIO1_3,
61 PIO1_4,
62 PIO1_5,
63 PIO1_6,
64 PIO1_7,
65 PIO1_8,
66 PIO1_9,
67 PIO1_10,
68 PIO1_11,
69 PIO1_12,
70 PIO1_13,
71 PIO1_14,
72 PIO1_15,
73 PIO1_16,
74 PIO1_17,
75 PIO1_18,
76 PIO1_19,
77 PIO1_20,
78 PIO1_21,
79 PIO1_22,
80 PIO1_23,
81 PIO1_24,
82 PIO1_25,
83 PIO1_26,
84 PIO1_27,
85 PIO1_28,
86 PIO1_29,
87 PIO1_30,
88 PIO1_31,
89}
90
91/// HAL configuration for the NXP board.
92pub mod config {
93 #[derive(Default)]
94 pub struct Config {}
95}
diff --git a/embassy-nxp/src/pac_utils.rs b/embassy-nxp/src/pac_utils.rs
new file mode 100644
index 000000000..86a807f6c
--- /dev/null
+++ b/embassy-nxp/src/pac_utils.rs
@@ -0,0 +1,323 @@
1/// Get the GPIO register block. This is used to configure all GPIO pins.
2///
3/// # Safety
4/// Due to the type system of peripherals, access to the settings of a single pin is possible only
5/// by a single thread at a time. Read/Write operations on a single registers are NOT atomic. You
6/// must ensure that the GPIO registers are not accessed concurrently by multiple threads.
7pub(crate) fn gpio_reg() -> &'static lpc55_pac::gpio::RegisterBlock {
8 unsafe { &*lpc55_pac::GPIO::ptr() }
9}
10
11/// Get the IOCON register block.
12///
13/// # Safety
14/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
15/// registers are not accessed concurrently by multiple threads.
16pub(crate) fn iocon_reg() -> &'static lpc55_pac::iocon::RegisterBlock {
17 unsafe { &*lpc55_pac::IOCON::ptr() }
18}
19
20/// Get the INPUTMUX register block.
21///
22/// # Safety
23/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
24/// registers are not accessed concurrently by multiple threads.
25pub(crate) fn inputmux_reg() -> &'static lpc55_pac::inputmux::RegisterBlock {
26 unsafe { &*lpc55_pac::INPUTMUX::ptr() }
27}
28
29/// Get the SYSCON register block.
30///
31/// # Safety
32/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
33/// registers are not accessed concurrently by multiple threads.
34pub(crate) fn syscon_reg() -> &'static lpc55_pac::syscon::RegisterBlock {
35 unsafe { &*lpc55_pac::SYSCON::ptr() }
36}
37
38/// Get the PINT register block.
39///
40/// # Safety
41/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
42/// registers are not accessed concurrently by multiple threads.
43pub(crate) fn pint_reg() -> &'static lpc55_pac::pint::RegisterBlock {
44 unsafe { &*lpc55_pac::PINT::ptr() }
45}
46
47/// Match the pin bank and number of a pin to the corresponding IOCON register.
48///
49/// # Example
50/// ```
51/// use embassy_nxp::gpio::Bank;
52/// use embassy_nxp::pac_utils::{iocon_reg, match_iocon};
53///
54/// // Make pin PIO1_6 digital and set it to pull-down mode.
55/// match_iocon!(register, iocon_reg(), Bank::Bank1, 6, {
56/// register.modify(|_, w| w.mode().pull_down().digimode().digital());
57/// });
58/// ```
59macro_rules! match_iocon {
60 ($register:ident, $iocon_register:expr, $pin_bank:expr, $pin_number:expr, $action:expr) => {
61 match ($pin_bank, $pin_number) {
62 (Bank::Bank0, 0) => {
63 let $register = &($iocon_register).pio0_0;
64 $action;
65 }
66 (Bank::Bank0, 1) => {
67 let $register = &($iocon_register).pio0_1;
68 $action;
69 }
70 (Bank::Bank0, 2) => {
71 let $register = &($iocon_register).pio0_2;
72 $action;
73 }
74 (Bank::Bank0, 3) => {
75 let $register = &($iocon_register).pio0_3;
76 $action;
77 }
78 (Bank::Bank0, 4) => {
79 let $register = &($iocon_register).pio0_4;
80 $action;
81 }
82 (Bank::Bank0, 5) => {
83 let $register = &($iocon_register).pio0_5;
84 $action;
85 }
86 (Bank::Bank0, 6) => {
87 let $register = &($iocon_register).pio0_6;
88 $action;
89 }
90 (Bank::Bank0, 7) => {
91 let $register = &($iocon_register).pio0_7;
92 $action;
93 }
94 (Bank::Bank0, 8) => {
95 let $register = &($iocon_register).pio0_8;
96 $action;
97 }
98 (Bank::Bank0, 9) => {
99 let $register = &($iocon_register).pio0_9;
100 $action;
101 }
102 (Bank::Bank0, 10) => {
103 let $register = &($iocon_register).pio0_10;
104 $action;
105 }
106 (Bank::Bank0, 11) => {
107 let $register = &($iocon_register).pio0_11;
108 $action;
109 }
110 (Bank::Bank0, 12) => {
111 let $register = &($iocon_register).pio0_12;
112 $action;
113 }
114 (Bank::Bank0, 13) => {
115 let $register = &($iocon_register).pio0_13;
116 $action;
117 }
118 (Bank::Bank0, 14) => {
119 let $register = &($iocon_register).pio0_14;
120 $action;
121 }
122 (Bank::Bank0, 15) => {
123 let $register = &($iocon_register).pio0_15;
124 $action;
125 }
126 (Bank::Bank0, 16) => {
127 let $register = &($iocon_register).pio0_16;
128 $action;
129 }
130 (Bank::Bank0, 17) => {
131 let $register = &($iocon_register).pio0_17;
132 $action;
133 }
134 (Bank::Bank0, 18) => {
135 let $register = &($iocon_register).pio0_18;
136 $action;
137 }
138 (Bank::Bank0, 19) => {
139 let $register = &($iocon_register).pio0_19;
140 $action;
141 }
142 (Bank::Bank0, 20) => {
143 let $register = &($iocon_register).pio0_20;
144 $action;
145 }
146 (Bank::Bank0, 21) => {
147 let $register = &($iocon_register).pio0_21;
148 $action;
149 }
150 (Bank::Bank0, 22) => {
151 let $register = &($iocon_register).pio0_22;
152 $action;
153 }
154 (Bank::Bank0, 23) => {
155 let $register = &($iocon_register).pio0_23;
156 $action;
157 }
158 (Bank::Bank0, 24) => {
159 let $register = &($iocon_register).pio0_24;
160 $action;
161 }
162 (Bank::Bank0, 25) => {
163 let $register = &($iocon_register).pio0_25;
164 $action;
165 }
166 (Bank::Bank0, 26) => {
167 let $register = &($iocon_register).pio0_26;
168 $action;
169 }
170 (Bank::Bank0, 27) => {
171 let $register = &($iocon_register).pio0_27;
172 $action;
173 }
174 (Bank::Bank0, 28) => {
175 let $register = &($iocon_register).pio0_28;
176 $action;
177 }
178 (Bank::Bank0, 29) => {
179 let $register = &($iocon_register).pio0_29;
180 $action;
181 }
182 (Bank::Bank0, 30) => {
183 let $register = &($iocon_register).pio0_30;
184 $action;
185 }
186 (Bank::Bank0, 31) => {
187 let $register = &($iocon_register).pio0_31;
188 $action;
189 }
190 (Bank::Bank1, 0) => {
191 let $register = &($iocon_register).pio1_0;
192 $action;
193 }
194 (Bank::Bank1, 1) => {
195 let $register = &($iocon_register).pio1_1;
196 $action;
197 }
198 (Bank::Bank1, 2) => {
199 let $register = &($iocon_register).pio1_2;
200 $action;
201 }
202 (Bank::Bank1, 3) => {
203 let $register = &($iocon_register).pio1_3;
204 $action;
205 }
206 (Bank::Bank1, 4) => {
207 let $register = &($iocon_register).pio1_4;
208 $action;
209 }
210 (Bank::Bank1, 5) => {
211 let $register = &($iocon_register).pio1_5;
212 $action;
213 }
214 (Bank::Bank1, 6) => {
215 let $register = &($iocon_register).pio1_6;
216 $action;
217 }
218 (Bank::Bank1, 7) => {
219 let $register = &($iocon_register).pio1_7;
220 $action;
221 }
222 (Bank::Bank1, 8) => {
223 let $register = &($iocon_register).pio1_8;
224 $action;
225 }
226 (Bank::Bank1, 9) => {
227 let $register = &($iocon_register).pio1_9;
228 $action;
229 }
230 (Bank::Bank1, 10) => {
231 let $register = &($iocon_register).pio1_10;
232 $action;
233 }
234 (Bank::Bank1, 11) => {
235 let $register = &($iocon_register).pio1_11;
236 $action;
237 }
238 (Bank::Bank1, 12) => {
239 let $register = &($iocon_register).pio1_12;
240 $action;
241 }
242 (Bank::Bank1, 13) => {
243 let $register = &($iocon_register).pio1_13;
244 $action;
245 }
246 (Bank::Bank1, 14) => {
247 let $register = &($iocon_register).pio1_14;
248 $action;
249 }
250 (Bank::Bank1, 15) => {
251 let $register = &($iocon_register).pio1_15;
252 $action;
253 }
254 (Bank::Bank1, 16) => {
255 let $register = &($iocon_register).pio1_16;
256 $action;
257 }
258 (Bank::Bank1, 17) => {
259 let $register = &($iocon_register).pio1_17;
260 $action;
261 }
262 (Bank::Bank1, 18) => {
263 let $register = &($iocon_register).pio1_18;
264 $action;
265 }
266 (Bank::Bank1, 19) => {
267 let $register = &($iocon_register).pio1_19;
268 $action;
269 }
270 (Bank::Bank1, 20) => {
271 let $register = &($iocon_register).pio1_20;
272 $action;
273 }
274 (Bank::Bank1, 21) => {
275 let $register = &($iocon_register).pio1_21;
276 $action;
277 }
278 (Bank::Bank1, 22) => {
279 let $register = &($iocon_register).pio1_22;
280 $action;
281 }
282 (Bank::Bank1, 23) => {
283 let $register = &($iocon_register).pio1_23;
284 $action;
285 }
286 (Bank::Bank1, 24) => {
287 let $register = &($iocon_register).pio1_24;
288 $action;
289 }
290 (Bank::Bank1, 25) => {
291 let $register = &($iocon_register).pio1_25;
292 $action;
293 }
294 (Bank::Bank1, 26) => {
295 let $register = &($iocon_register).pio1_26;
296 $action;
297 }
298 (Bank::Bank1, 27) => {
299 let $register = &($iocon_register).pio1_27;
300 $action;
301 }
302 (Bank::Bank1, 28) => {
303 let $register = &($iocon_register).pio1_28;
304 $action;
305 }
306 (Bank::Bank1, 29) => {
307 let $register = &($iocon_register).pio1_29;
308 $action;
309 }
310 (Bank::Bank1, 30) => {
311 let $register = &($iocon_register).pio1_30;
312 $action;
313 }
314 (Bank::Bank1, 31) => {
315 let $register = &($iocon_register).pio1_31;
316 $action;
317 }
318 _ => unreachable!(),
319 }
320 };
321}
322
323pub(crate) use match_iocon;
diff --git a/embassy-nxp/src/pint.rs b/embassy-nxp/src/pint.rs
new file mode 100644
index 000000000..3313f91a6
--- /dev/null
+++ b/embassy-nxp/src/pint.rs
@@ -0,0 +1,440 @@
1//! Pin Interrupt module.
2use core::cell::RefCell;
3use core::future::Future;
4use core::pin::Pin as FuturePin;
5use core::task::{Context, Poll};
6
7use critical_section::Mutex;
8use embassy_hal_internal::{Peripheral, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker;
10
11use crate::gpio::{self, AnyPin, Level, SealedPin};
12use crate::pac::interrupt;
13use crate::pac_utils::*;
14
15struct PinInterrupt {
16 assigned: bool,
17 waker: AtomicWaker,
18 /// If true, the interrupt was triggered due to this PinInterrupt. This is used to determine if
19 /// an [InputFuture] should return Poll::Ready.
20 at_fault: bool,
21}
22
23impl PinInterrupt {
24 pub fn interrupt_active(&self) -> bool {
25 self.assigned
26 }
27
28 /// Mark the interrupt as assigned to a pin.
29 pub fn enable(&mut self) {
30 self.assigned = true;
31 self.at_fault = false;
32 }
33
34 /// Mark the interrupt as available.
35 pub fn disable(&mut self) {
36 self.assigned = false;
37 self.at_fault = false;
38 }
39
40 /// Returns true if the interrupt was triggered due to this PinInterrupt.
41 ///
42 /// If this function returns true, it will also reset the at_fault flag.
43 pub fn at_fault(&mut self) -> bool {
44 let val = self.at_fault;
45 self.at_fault = false;
46 val
47 }
48
49 /// Set the at_fault flag to true.
50 pub fn fault(&mut self) {
51 self.at_fault = true;
52 }
53}
54
55const NEW_PIN_INTERRUPT: PinInterrupt = PinInterrupt {
56 assigned: false,
57 waker: AtomicWaker::new(),
58 at_fault: false,
59};
60const INTERUPT_COUNT: usize = 8;
61static PIN_INTERRUPTS: Mutex<RefCell<[PinInterrupt; INTERUPT_COUNT]>> =
62 Mutex::new(RefCell::new([NEW_PIN_INTERRUPT; INTERUPT_COUNT]));
63
64fn next_available_interrupt() -> Option<usize> {
65 critical_section::with(|cs| {
66 for (i, pin_interrupt) in PIN_INTERRUPTS.borrow(cs).borrow().iter().enumerate() {
67 if !pin_interrupt.interrupt_active() {
68 return Some(i);
69 }
70 }
71
72 None
73 })
74}
75
76#[derive(Clone, Copy, PartialEq, Eq)]
77enum Edge {
78 Rising,
79 Falling,
80 Both,
81}
82
83#[derive(Clone, Copy, PartialEq, Eq)]
84enum InterruptOn {
85 Level(Level),
86 Edge(Edge),
87}
88
89pub(crate) fn init() {
90 syscon_reg().ahbclkctrl0.modify(|_, w| w.pint().enable());
91
92 // Enable interrupts
93 unsafe {
94 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT0);
95 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT1);
96 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT2);
97 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT3);
98 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT4);
99 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT5);
100 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT6);
101 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT7);
102 };
103}
104
105#[must_use = "futures do nothing unless you `.await` or poll them"]
106struct InputFuture<'d> {
107 #[allow(dead_code)]
108 pin: PeripheralRef<'d, AnyPin>,
109 interrupt_number: usize,
110}
111
112impl<'d> InputFuture<'d> {
113 /// Create a new input future. Returns None if all interrupts are in use.
114 fn new(pin: impl Peripheral<P = impl gpio::Pin> + 'd, interrupt_on: InterruptOn) -> Option<Self> {
115 let pin = pin.into_ref().map_into();
116 let interrupt_number = next_available_interrupt()?;
117
118 // Clear interrupt, just in case
119 pint_reg()
120 .rise
121 .write(|w| unsafe { w.rdet().bits(1 << interrupt_number) });
122 pint_reg()
123 .fall
124 .write(|w| unsafe { w.fdet().bits(1 << interrupt_number) });
125
126 // Enable input multiplexing on pin interrupt register 0 for pin (32*bank + pin_number)
127 inputmux_reg().pintsel[interrupt_number]
128 .write(|w| unsafe { w.intpin().bits(32 * pin.pin_bank() as u8 + pin.pin_number()) });
129
130 match interrupt_on {
131 InterruptOn::Level(level) => {
132 // Set pin interrupt register to edge sensitive or level sensitive
133 // 0 = edge sensitive, 1 = level sensitive
134 pint_reg()
135 .isel
136 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << interrupt_number)) });
137
138 // Enable level interrupt.
139 //
140 // Note: Level sensitive interrupts are enabled by the same register as rising edge
141 // is activated.
142
143 // 0 = no-op, 1 = enable
144 pint_reg()
145 .sienr
146 .write(|w| unsafe { w.setenrl().bits(1 << interrupt_number) });
147
148 // Set active level
149 match level {
150 Level::Low => {
151 // 0 = no-op, 1 = select LOW
152 pint_reg()
153 .cienf
154 .write(|w| unsafe { w.cenaf().bits(1 << interrupt_number) });
155 }
156 Level::High => {
157 // 0 = no-op, 1 = select HIGH
158 pint_reg()
159 .sienf
160 .write(|w| unsafe { w.setenaf().bits(1 << interrupt_number) });
161 }
162 }
163 }
164 InterruptOn::Edge(edge) => {
165 // Set pin interrupt register to edge sensitive or level sensitive
166 // 0 = edge sensitive, 1 = level sensitive
167 pint_reg()
168 .isel
169 .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << interrupt_number)) });
170
171 // Enable rising/falling edge detection
172 match edge {
173 Edge::Rising => {
174 // 0 = no-op, 1 = enable rising edge
175 pint_reg()
176 .sienr
177 .write(|w| unsafe { w.setenrl().bits(1 << interrupt_number) });
178 // 0 = no-op, 1 = disable falling edge
179 pint_reg()
180 .cienf
181 .write(|w| unsafe { w.cenaf().bits(1 << interrupt_number) });
182 }
183 Edge::Falling => {
184 // 0 = no-op, 1 = enable falling edge
185 pint_reg()
186 .sienf
187 .write(|w| unsafe { w.setenaf().bits(1 << interrupt_number) });
188 // 0 = no-op, 1 = disable rising edge
189 pint_reg()
190 .cienr
191 .write(|w| unsafe { w.cenrl().bits(1 << interrupt_number) });
192 }
193 Edge::Both => {
194 // 0 = no-op, 1 = enable
195 pint_reg()
196 .sienr
197 .write(|w| unsafe { w.setenrl().bits(1 << interrupt_number) });
198 pint_reg()
199 .sienf
200 .write(|w| unsafe { w.setenaf().bits(1 << interrupt_number) });
201 }
202 }
203 }
204 }
205
206 critical_section::with(|cs| {
207 let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut();
208 let pin_interrupt = &mut pin_interrupts[interrupt_number];
209
210 pin_interrupt.enable();
211 });
212
213 Some(Self { pin, interrupt_number })
214 }
215
216 /// Returns true if the interrupt was triggered for this pin.
217 fn interrupt_triggered(&self) -> bool {
218 let interrupt_number = self.interrupt_number;
219
220 // Initially, we determine if the interrupt was triggered by this InputFuture by checking
221 // the flags of the interrupt_number. However, by the time we get to this point, the
222 // interrupt may have been triggered again, so we needed to clear the cpu flags immediately.
223 // As a solution, we mark which [PinInterrupt] is responsible for the interrupt ("at fault")
224 critical_section::with(|cs| {
225 let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut();
226 let pin_interrupt = &mut pin_interrupts[interrupt_number];
227
228 pin_interrupt.at_fault()
229 })
230 }
231}
232
233impl<'d> Drop for InputFuture<'d> {
234 fn drop(&mut self) {
235 let interrupt_number = self.interrupt_number;
236
237 // Disable pin interrupt
238 // 0 = no-op, 1 = disable
239 pint_reg()
240 .cienr
241 .write(|w| unsafe { w.cenrl().bits(1 << interrupt_number) });
242 pint_reg()
243 .cienf
244 .write(|w| unsafe { w.cenaf().bits(1 << interrupt_number) });
245
246 critical_section::with(|cs| {
247 let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut();
248 let pin_interrupt = &mut pin_interrupts[interrupt_number];
249
250 pin_interrupt.disable();
251 });
252 }
253}
254
255impl<'d> Future for InputFuture<'d> {
256 type Output = ();
257
258 fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
259 let interrupt_number = self.interrupt_number;
260
261 critical_section::with(|cs| {
262 let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut();
263 let pin_interrupt = &mut pin_interrupts[interrupt_number];
264
265 pin_interrupt.waker.register(cx.waker());
266 });
267
268 if self.interrupt_triggered() {
269 Poll::Ready(())
270 } else {
271 Poll::Pending
272 }
273 }
274}
275
276fn handle_interrupt(interrupt_number: usize) {
277 pint_reg()
278 .rise
279 .write(|w| unsafe { w.rdet().bits(1 << interrupt_number) });
280 pint_reg()
281 .fall
282 .write(|w| unsafe { w.fdet().bits(1 << interrupt_number) });
283
284 critical_section::with(|cs| {
285 let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut();
286 let pin_interrupt = &mut pin_interrupts[interrupt_number];
287
288 pin_interrupt.fault();
289 pin_interrupt.waker.wake();
290 });
291}
292
293#[allow(non_snake_case)]
294#[interrupt]
295fn PIN_INT0() {
296 handle_interrupt(0);
297}
298
299#[allow(non_snake_case)]
300#[interrupt]
301fn PIN_INT1() {
302 handle_interrupt(1);
303}
304
305#[allow(non_snake_case)]
306#[interrupt]
307fn PIN_INT2() {
308 handle_interrupt(2);
309}
310
311#[allow(non_snake_case)]
312#[interrupt]
313fn PIN_INT3() {
314 handle_interrupt(3);
315}
316
317#[allow(non_snake_case)]
318#[interrupt]
319fn PIN_INT4() {
320 handle_interrupt(4);
321}
322
323#[allow(non_snake_case)]
324#[interrupt]
325fn PIN_INT5() {
326 handle_interrupt(5);
327}
328
329#[allow(non_snake_case)]
330#[interrupt]
331fn PIN_INT6() {
332 handle_interrupt(6);
333}
334
335#[allow(non_snake_case)]
336#[interrupt]
337fn PIN_INT7() {
338 handle_interrupt(7);
339}
340
341impl gpio::Flex<'_> {
342 /// Wait for a falling or rising edge on the pin. You can have at most 8 pins waiting. If you
343 /// try to wait for more than 8 pins, this function will return `None`.
344 pub async fn wait_for_any_edge(&mut self) -> Option<()> {
345 InputFuture::new(&mut self.pin, InterruptOn::Edge(Edge::Both))?.await;
346 Some(())
347 }
348
349 /// Wait for a falling edge on the pin. You can have at most 8 pins waiting. If you try to wait
350 /// for more than 8 pins, this function will return `None`.
351 pub async fn wait_for_falling_edge(&mut self) -> Option<()> {
352 InputFuture::new(&mut self.pin, InterruptOn::Edge(Edge::Falling))?.await;
353 Some(())
354 }
355
356 /// Wait for a rising edge on the pin. You can have at most 8 pins waiting. If you try to wait
357 /// for more than 8 pins, this function will return `None`.
358 pub async fn wait_for_rising_edge(&mut self) -> Option<()> {
359 InputFuture::new(&mut self.pin, InterruptOn::Edge(Edge::Rising))?.await;
360 Some(())
361 }
362
363 /// Wait for a low level on the pin. You can have at most 8 pins waiting. If you try to wait for
364 /// more than 8 pins, this function will return `None`.
365 pub async fn wait_for_low(&mut self) -> Option<()> {
366 InputFuture::new(&mut self.pin, InterruptOn::Level(Level::Low))?.await;
367 Some(())
368 }
369
370 /// Wait for a high level on the pin. You can have at most 8 pins waiting. If you try to wait for
371 /// more than 8 pins, this function will return `None`.
372 pub async fn wait_for_high(&mut self) -> Option<()> {
373 InputFuture::new(&mut self.pin, InterruptOn::Level(Level::High))?.await;
374 Some(())
375 }
376}
377
378impl gpio::Input<'_> {
379 /// Wait for a falling or rising edge on the pin. You can have at most 8 pins waiting. If you
380 /// try to wait for more than 8 pins, this function will return `None`.
381 pub async fn wait_for_any_edge(&mut self) -> Option<()> {
382 self.pin.wait_for_any_edge().await
383 }
384
385 /// Wait for a falling edge on the pin. You can have at most 8 pins waiting. If you try to wait
386 /// for more than 8 pins, this function will return `None`.
387 pub async fn wait_for_falling_edge(&mut self) -> Option<()> {
388 self.pin.wait_for_falling_edge().await
389 }
390
391 /// Wait for a rising edge on the pin. You can have at most 8 pins waiting. If you try to wait
392 /// for more than 8 pins, this function will return `None`.
393 pub async fn wait_for_rising_edge(&mut self) -> Option<()> {
394 self.pin.wait_for_rising_edge().await
395 }
396
397 /// Wait for a low level on the pin. You can have at most 8 pins waiting. If you try to wait for
398 /// more than 8 pins, this function will return `None`.
399 pub async fn wait_for_low(&mut self) -> Option<()> {
400 self.pin.wait_for_low().await
401 }
402
403 /// Wait for a high level on the pin. You can have at most 8 pins waiting. If you try to wait for
404 /// more than 8 pins, this function will return `None`.
405 pub async fn wait_for_high(&mut self) -> Option<()> {
406 self.pin.wait_for_high().await
407 }
408}
409
410impl gpio::Output<'_> {
411 /// Wait for a falling or rising edge on the pin. You can have at most 8 pins waiting. If you
412 /// try to wait for more than 8 pins, this function will return `None`.
413 pub async fn wait_for_any_edge(&mut self) -> Option<()> {
414 self.pin.wait_for_any_edge().await
415 }
416
417 /// Wait for a falling edge on the pin. You can have at most 8 pins waiting. If you try to wait
418 /// for more than 8 pins, this function will return `None`.
419 pub async fn wait_for_falling_edge(&mut self) -> Option<()> {
420 self.pin.wait_for_falling_edge().await
421 }
422
423 /// Wait for a rising edge on the pin. You can have at most 8 pins waiting. If you try to wait
424 /// for more than 8 pins, this function will return `None`.
425 pub async fn wait_for_rising_edge(&mut self) -> Option<()> {
426 self.pin.wait_for_rising_edge().await
427 }
428
429 /// Wait for a low level on the pin. You can have at most 8 pins waiting. If you try to wait for
430 /// more than 8 pins, this function will return `None`.
431 pub async fn wait_for_low(&mut self) -> Option<()> {
432 self.pin.wait_for_low().await
433 }
434
435 /// Wait for a high level on the pin. You can have at most 8 pins waiting. If you try to wait for
436 /// more than 8 pins, this function will return `None`.
437 pub async fn wait_for_high(&mut self) -> Option<()> {
438 self.pin.wait_for_high().await
439 }
440}