diff options
| author | George Cosma <[email protected]> | 2024-06-05 13:54:00 +0300 |
|---|---|---|
| committer | George Cosma <[email protected]> | 2024-10-07 09:34:10 +0300 |
| commit | e7e245eeb77974bf1f374f24cbf5c0bc41f745f1 (patch) | |
| tree | c04b67ec1b80ac4fdbfe2276c89520dcd40f1a8f /embassy-nxp | |
| parent | a23f56b3ddc84a7e87e4b8750df26b91a2cb9637 (diff) | |
feat: embassy-lpc55 hal with gpio and pint driver
Diffstat (limited to 'embassy-nxp')
| -rw-r--r-- | embassy-nxp/Cargo.toml | 17 | ||||
| -rw-r--r-- | embassy-nxp/src/gpio.rs | 361 | ||||
| -rw-r--r-- | embassy-nxp/src/lib.rs | 95 | ||||
| -rw-r--r-- | embassy-nxp/src/pac_utils.rs | 323 | ||||
| -rw-r--r-- | embassy-nxp/src/pint.rs | 440 |
5 files changed, 1236 insertions, 0 deletions
diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml new file mode 100644 index 000000000..df329be66 --- /dev/null +++ b/embassy-nxp/Cargo.toml | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | [package] | ||
| 2 | name = "embassy-nxp" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | |||
| 6 | [dependencies] | ||
| 7 | cortex-m = "0.7.7" | ||
| 8 | cortex-m-rt = "0.7.0" | ||
| 9 | critical-section = "1.1.2" | ||
| 10 | embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } | ||
| 11 | embassy-sync = { version = "0.6.0", path = "../embassy-sync" } | ||
| 12 | lpc55-pac = "0.5.0" | ||
| 13 | defmt = "0.3.8" | ||
| 14 | |||
| 15 | [features] | ||
| 16 | default = ["rt"] | ||
| 17 | rt = ["lpc55-pac/rt"] \ No newline at end of file | ||
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 @@ | |||
| 1 | use embassy_hal_internal::impl_peripheral; | ||
| 2 | |||
| 3 | use crate::pac_utils::*; | ||
| 4 | use crate::{peripherals, Peripheral, PeripheralRef}; | ||
| 5 | |||
| 6 | pub(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)] | ||
| 15 | pub 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)] | ||
| 24 | pub 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)] | ||
| 35 | pub enum Bank { | ||
| 36 | Bank0 = 0, | ||
| 37 | Bank1 = 1, | ||
| 38 | } | ||
| 39 | |||
| 40 | /// GPIO output driver. Internally, this is a specialized [Flex] pin. | ||
| 41 | pub struct Output<'d> { | ||
| 42 | pub(crate) pin: Flex<'d>, | ||
| 43 | } | ||
| 44 | |||
| 45 | impl<'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. | ||
| 86 | pub struct Input<'d> { | ||
| 87 | pub(crate) pin: Flex<'d>, | ||
| 88 | } | ||
| 89 | |||
| 90 | impl<'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). | ||
| 126 | pub struct Flex<'d> { | ||
| 127 | pub(crate) pin: PeripheralRef<'d, AnyPin>, | ||
| 128 | } | ||
| 129 | |||
| 130 | impl<'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. | ||
| 212 | pub(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)] | ||
| 221 | pub 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. | ||
| 244 | pub struct AnyPin { | ||
| 245 | pin_bank: Bank, | ||
| 246 | pin_number: u8, | ||
| 247 | } | ||
| 248 | |||
| 249 | impl 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 | |||
| 260 | impl_peripheral!(AnyPin); | ||
| 261 | |||
| 262 | impl Pin for AnyPin {} | ||
| 263 | impl 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 | |||
| 275 | macro_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 | |||
| 298 | impl_pin!(PIO0_0, Bank::Bank0, 0); | ||
| 299 | impl_pin!(PIO0_1, Bank::Bank0, 1); | ||
| 300 | impl_pin!(PIO0_2, Bank::Bank0, 2); | ||
| 301 | impl_pin!(PIO0_3, Bank::Bank0, 3); | ||
| 302 | impl_pin!(PIO0_4, Bank::Bank0, 4); | ||
| 303 | impl_pin!(PIO0_5, Bank::Bank0, 5); | ||
| 304 | impl_pin!(PIO0_6, Bank::Bank0, 6); | ||
| 305 | impl_pin!(PIO0_7, Bank::Bank0, 7); | ||
| 306 | impl_pin!(PIO0_8, Bank::Bank0, 8); | ||
| 307 | impl_pin!(PIO0_9, Bank::Bank0, 9); | ||
| 308 | impl_pin!(PIO0_10, Bank::Bank0, 10); | ||
| 309 | impl_pin!(PIO0_11, Bank::Bank0, 11); | ||
| 310 | impl_pin!(PIO0_12, Bank::Bank0, 12); | ||
| 311 | impl_pin!(PIO0_13, Bank::Bank0, 13); | ||
| 312 | impl_pin!(PIO0_14, Bank::Bank0, 14); | ||
| 313 | impl_pin!(PIO0_15, Bank::Bank0, 15); | ||
| 314 | impl_pin!(PIO0_16, Bank::Bank0, 16); | ||
| 315 | impl_pin!(PIO0_17, Bank::Bank0, 17); | ||
| 316 | impl_pin!(PIO0_18, Bank::Bank0, 18); | ||
| 317 | impl_pin!(PIO0_19, Bank::Bank0, 19); | ||
| 318 | impl_pin!(PIO0_20, Bank::Bank0, 20); | ||
| 319 | impl_pin!(PIO0_21, Bank::Bank0, 21); | ||
| 320 | impl_pin!(PIO0_22, Bank::Bank0, 22); | ||
| 321 | impl_pin!(PIO0_23, Bank::Bank0, 23); | ||
| 322 | impl_pin!(PIO0_24, Bank::Bank0, 24); | ||
| 323 | impl_pin!(PIO0_25, Bank::Bank0, 25); | ||
| 324 | impl_pin!(PIO0_26, Bank::Bank0, 26); | ||
| 325 | impl_pin!(PIO0_27, Bank::Bank0, 27); | ||
| 326 | impl_pin!(PIO0_28, Bank::Bank0, 28); | ||
| 327 | impl_pin!(PIO0_29, Bank::Bank0, 29); | ||
| 328 | impl_pin!(PIO0_30, Bank::Bank0, 30); | ||
| 329 | impl_pin!(PIO0_31, Bank::Bank0, 31); | ||
| 330 | impl_pin!(PIO1_0, Bank::Bank1, 0); | ||
| 331 | impl_pin!(PIO1_1, Bank::Bank1, 1); | ||
| 332 | impl_pin!(PIO1_2, Bank::Bank1, 2); | ||
| 333 | impl_pin!(PIO1_3, Bank::Bank1, 3); | ||
| 334 | impl_pin!(PIO1_4, Bank::Bank1, 4); | ||
| 335 | impl_pin!(PIO1_5, Bank::Bank1, 5); | ||
| 336 | impl_pin!(PIO1_6, Bank::Bank1, 6); | ||
| 337 | impl_pin!(PIO1_7, Bank::Bank1, 7); | ||
| 338 | impl_pin!(PIO1_8, Bank::Bank1, 8); | ||
| 339 | impl_pin!(PIO1_9, Bank::Bank1, 9); | ||
| 340 | impl_pin!(PIO1_10, Bank::Bank1, 10); | ||
| 341 | impl_pin!(PIO1_11, Bank::Bank1, 11); | ||
| 342 | impl_pin!(PIO1_12, Bank::Bank1, 12); | ||
| 343 | impl_pin!(PIO1_13, Bank::Bank1, 13); | ||
| 344 | impl_pin!(PIO1_14, Bank::Bank1, 14); | ||
| 345 | impl_pin!(PIO1_15, Bank::Bank1, 15); | ||
| 346 | impl_pin!(PIO1_16, Bank::Bank1, 16); | ||
| 347 | impl_pin!(PIO1_17, Bank::Bank1, 17); | ||
| 348 | impl_pin!(PIO1_18, Bank::Bank1, 18); | ||
| 349 | impl_pin!(PIO1_19, Bank::Bank1, 19); | ||
| 350 | impl_pin!(PIO1_20, Bank::Bank1, 20); | ||
| 351 | impl_pin!(PIO1_21, Bank::Bank1, 21); | ||
| 352 | impl_pin!(PIO1_22, Bank::Bank1, 22); | ||
| 353 | impl_pin!(PIO1_23, Bank::Bank1, 23); | ||
| 354 | impl_pin!(PIO1_24, Bank::Bank1, 24); | ||
| 355 | impl_pin!(PIO1_25, Bank::Bank1, 25); | ||
| 356 | impl_pin!(PIO1_26, Bank::Bank1, 26); | ||
| 357 | impl_pin!(PIO1_27, Bank::Bank1, 27); | ||
| 358 | impl_pin!(PIO1_28, Bank::Bank1, 28); | ||
| 359 | impl_pin!(PIO1_29, Bank::Bank1, 29); | ||
| 360 | impl_pin!(PIO1_30, Bank::Bank1, 30); | ||
| 361 | impl_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 | |||
| 3 | pub mod gpio; | ||
| 4 | mod pac_utils; | ||
| 5 | pub mod pint; | ||
| 6 | |||
| 7 | pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | ||
| 8 | pub 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. | ||
| 15 | pub fn init(_config: config::Config) -> Peripherals { | ||
| 16 | gpio::init(); | ||
| 17 | pint::init(); | ||
| 18 | |||
| 19 | crate::Peripherals::take() | ||
| 20 | } | ||
| 21 | |||
| 22 | embassy_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. | ||
| 92 | pub 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. | ||
| 7 | pub(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. | ||
| 16 | pub(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. | ||
| 25 | pub(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. | ||
| 34 | pub(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. | ||
| 43 | pub(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 | /// ``` | ||
| 59 | macro_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 | |||
| 323 | pub(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. | ||
| 2 | use core::cell::RefCell; | ||
| 3 | use core::future::Future; | ||
| 4 | use core::pin::Pin as FuturePin; | ||
| 5 | use core::task::{Context, Poll}; | ||
| 6 | |||
| 7 | use critical_section::Mutex; | ||
| 8 | use embassy_hal_internal::{Peripheral, PeripheralRef}; | ||
| 9 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 10 | |||
| 11 | use crate::gpio::{self, AnyPin, Level, SealedPin}; | ||
| 12 | use crate::pac::interrupt; | ||
| 13 | use crate::pac_utils::*; | ||
| 14 | |||
| 15 | struct 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 | |||
| 23 | impl 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 | |||
| 55 | const NEW_PIN_INTERRUPT: PinInterrupt = PinInterrupt { | ||
| 56 | assigned: false, | ||
| 57 | waker: AtomicWaker::new(), | ||
| 58 | at_fault: false, | ||
| 59 | }; | ||
| 60 | const INTERUPT_COUNT: usize = 8; | ||
| 61 | static PIN_INTERRUPTS: Mutex<RefCell<[PinInterrupt; INTERUPT_COUNT]>> = | ||
| 62 | Mutex::new(RefCell::new([NEW_PIN_INTERRUPT; INTERUPT_COUNT])); | ||
| 63 | |||
| 64 | fn 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)] | ||
| 77 | enum Edge { | ||
| 78 | Rising, | ||
| 79 | Falling, | ||
| 80 | Both, | ||
| 81 | } | ||
| 82 | |||
| 83 | #[derive(Clone, Copy, PartialEq, Eq)] | ||
| 84 | enum InterruptOn { | ||
| 85 | Level(Level), | ||
| 86 | Edge(Edge), | ||
| 87 | } | ||
| 88 | |||
| 89 | pub(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"] | ||
| 106 | struct InputFuture<'d> { | ||
| 107 | #[allow(dead_code)] | ||
| 108 | pin: PeripheralRef<'d, AnyPin>, | ||
| 109 | interrupt_number: usize, | ||
| 110 | } | ||
| 111 | |||
| 112 | impl<'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 | |||
| 233 | impl<'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 | |||
| 255 | impl<'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 | |||
| 276 | fn 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] | ||
| 295 | fn PIN_INT0() { | ||
| 296 | handle_interrupt(0); | ||
| 297 | } | ||
| 298 | |||
| 299 | #[allow(non_snake_case)] | ||
| 300 | #[interrupt] | ||
| 301 | fn PIN_INT1() { | ||
| 302 | handle_interrupt(1); | ||
| 303 | } | ||
| 304 | |||
| 305 | #[allow(non_snake_case)] | ||
| 306 | #[interrupt] | ||
| 307 | fn PIN_INT2() { | ||
| 308 | handle_interrupt(2); | ||
| 309 | } | ||
| 310 | |||
| 311 | #[allow(non_snake_case)] | ||
| 312 | #[interrupt] | ||
| 313 | fn PIN_INT3() { | ||
| 314 | handle_interrupt(3); | ||
| 315 | } | ||
| 316 | |||
| 317 | #[allow(non_snake_case)] | ||
| 318 | #[interrupt] | ||
| 319 | fn PIN_INT4() { | ||
| 320 | handle_interrupt(4); | ||
| 321 | } | ||
| 322 | |||
| 323 | #[allow(non_snake_case)] | ||
| 324 | #[interrupt] | ||
| 325 | fn PIN_INT5() { | ||
| 326 | handle_interrupt(5); | ||
| 327 | } | ||
| 328 | |||
| 329 | #[allow(non_snake_case)] | ||
| 330 | #[interrupt] | ||
| 331 | fn PIN_INT6() { | ||
| 332 | handle_interrupt(6); | ||
| 333 | } | ||
| 334 | |||
| 335 | #[allow(non_snake_case)] | ||
| 336 | #[interrupt] | ||
| 337 | fn PIN_INT7() { | ||
| 338 | handle_interrupt(7); | ||
| 339 | } | ||
| 340 | |||
| 341 | impl 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 | |||
| 378 | impl 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 | |||
| 410 | impl 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 | } | ||
