diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-03-22 02:10:15 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2021-03-29 00:58:58 +0200 |
| commit | e7e34cb8c21517eb9e23dab8df719580eaa1bc3a (patch) | |
| tree | e58aa18e4d8c45ca03cec56468f96e7d4b588749 | |
| parent | df42c384923579c449a13511b0fdb8de3b2a4773 (diff) | |
nrf/gpio: add OptionalPin
| -rw-r--r-- | embassy-nrf/src/gpio.rs | 104 |
1 files changed, 103 insertions, 1 deletions
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index dd334c633..d48ad3d0e 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | use core::convert::Infallible; | 1 | use core::convert::Infallible; |
| 2 | use core::hint::unreachable_unchecked; | 2 | use core::hint::unreachable_unchecked; |
| 3 | 3 | ||
| 4 | use embassy::util::PeripheralBorrow; | ||
| 4 | use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; | 5 | use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; |
| 5 | use gpio::pin_cnf::DRIVE_A; | 6 | use gpio::pin_cnf::DRIVE_A; |
| 6 | 7 | ||
| @@ -205,6 +206,7 @@ pub(crate) mod sealed { | |||
| 205 | } | 206 | } |
| 206 | } | 207 | } |
| 207 | 208 | ||
| 209 | #[inline] | ||
| 208 | fn block(&self) -> &gpio::RegisterBlock { | 210 | fn block(&self) -> &gpio::RegisterBlock { |
| 209 | unsafe { | 211 | unsafe { |
| 210 | match self.pin_port() / 32 { | 212 | match self.pin_port() / 32 { |
| @@ -216,11 +218,13 @@ pub(crate) mod sealed { | |||
| 216 | } | 218 | } |
| 217 | } | 219 | } |
| 218 | 220 | ||
| 221 | #[inline] | ||
| 219 | fn conf(&self) -> &gpio::PIN_CNF { | 222 | fn conf(&self) -> &gpio::PIN_CNF { |
| 220 | &self.block().pin_cnf[self._pin() as usize] | 223 | &self.block().pin_cnf[self._pin() as usize] |
| 221 | } | 224 | } |
| 222 | 225 | ||
| 223 | /// Set the output as high. | 226 | /// Set the output as high. |
| 227 | #[inline] | ||
| 224 | fn set_high(&self) { | 228 | fn set_high(&self) { |
| 225 | unsafe { | 229 | unsafe { |
| 226 | self.block().outset.write(|w| w.bits(1u32 << self._pin())); | 230 | self.block().outset.write(|w| w.bits(1u32 << self._pin())); |
| @@ -228,12 +232,15 @@ pub(crate) mod sealed { | |||
| 228 | } | 232 | } |
| 229 | 233 | ||
| 230 | /// Set the output as low. | 234 | /// Set the output as low. |
| 235 | #[inline] | ||
| 231 | fn set_low(&self) { | 236 | fn set_low(&self) { |
| 232 | unsafe { | 237 | unsafe { |
| 233 | self.block().outclr.write(|w| w.bits(1u32 << self._pin())); | 238 | self.block().outclr.write(|w| w.bits(1u32 << self._pin())); |
| 234 | } | 239 | } |
| 235 | } | 240 | } |
| 236 | } | 241 | } |
| 242 | |||
| 243 | pub trait OptionalPin {} | ||
| 237 | } | 244 | } |
| 238 | 245 | ||
| 239 | pub trait Pin: sealed::Pin + Sized { | 246 | pub trait Pin: sealed::Pin + Sized { |
| @@ -247,7 +254,7 @@ pub trait Pin: sealed::Pin + Sized { | |||
| 247 | #[inline] | 254 | #[inline] |
| 248 | fn port(&self) -> Port { | 255 | fn port(&self) -> Port { |
| 249 | match self.pin_port() / 32 { | 256 | match self.pin_port() / 32 { |
| 250 | 1 => Port::Port0, | 257 | 0 => Port::Port0, |
| 251 | #[cfg(any(feature = "52833", feature = "52840"))] | 258 | #[cfg(any(feature = "52833", feature = "52840"))] |
| 252 | 1 => Port::Port1, | 259 | 1 => Port::Port1, |
| 253 | _ => unsafe { unreachable_unchecked() }, | 260 | _ => unsafe { unreachable_unchecked() }, |
| @@ -260,6 +267,7 @@ pub trait Pin: sealed::Pin + Sized { | |||
| 260 | } | 267 | } |
| 261 | 268 | ||
| 262 | /// Convert from concrete pin type PX_XX to type erased `AnyPin`. | 269 | /// Convert from concrete pin type PX_XX to type erased `AnyPin`. |
| 270 | #[inline] | ||
| 263 | fn degrade(self) -> AnyPin { | 271 | fn degrade(self) -> AnyPin { |
| 264 | AnyPin { | 272 | AnyPin { |
| 265 | pin_port: self.pin_port(), | 273 | pin_port: self.pin_port(), |
| @@ -273,6 +281,7 @@ pub struct AnyPin { | |||
| 273 | } | 281 | } |
| 274 | 282 | ||
| 275 | impl AnyPin { | 283 | impl AnyPin { |
| 284 | #[inline] | ||
| 276 | pub unsafe fn steal(pin_port: u8) -> Self { | 285 | pub unsafe fn steal(pin_port: u8) -> Self { |
| 277 | Self { pin_port } | 286 | Self { pin_port } |
| 278 | } | 287 | } |
| @@ -280,15 +289,108 @@ impl AnyPin { | |||
| 280 | 289 | ||
| 281 | impl Pin for AnyPin {} | 290 | impl Pin for AnyPin {} |
| 282 | impl sealed::Pin for AnyPin { | 291 | impl sealed::Pin for AnyPin { |
| 292 | #[inline] | ||
| 283 | fn pin_port(&self) -> u8 { | 293 | fn pin_port(&self) -> u8 { |
| 284 | self.pin_port | 294 | self.pin_port |
| 285 | } | 295 | } |
| 286 | } | 296 | } |
| 287 | 297 | ||
| 298 | impl PeripheralBorrow for AnyPin { | ||
| 299 | type Target = AnyPin; | ||
| 300 | #[inline] | ||
| 301 | unsafe fn unborrow(self) -> Self::Target { | ||
| 302 | self | ||
| 303 | } | ||
| 304 | } | ||
| 305 | |||
| 306 | impl<'a> PeripheralBorrow for &'a mut AnyPin { | ||
| 307 | type Target = AnyPin; | ||
| 308 | #[inline] | ||
| 309 | unsafe fn unborrow(self) -> Self::Target { | ||
| 310 | AnyPin { | ||
| 311 | pin_port: self.pin_port, | ||
| 312 | } | ||
| 313 | } | ||
| 314 | } | ||
| 315 | |||
| 316 | // ==================== | ||
| 317 | |||
| 318 | pub trait OptionalPin: sealed::OptionalPin + Sized { | ||
| 319 | type Pin: Pin; | ||
| 320 | fn pin(&self) -> Option<&Self::Pin>; | ||
| 321 | fn pin_mut(&mut self) -> Option<&mut Self::Pin>; | ||
| 322 | |||
| 323 | #[inline] | ||
| 324 | fn psel_bits(&self) -> u32 { | ||
| 325 | self.pin().map_or(1u32 << 31, |pin| Pin::psel_bits(pin)) | ||
| 326 | } | ||
| 327 | |||
| 328 | /// Convert from concrete pin type PX_XX to type erased `Option<AnyPin>`. | ||
| 329 | #[inline] | ||
| 330 | fn degrade_optional(mut self) -> Option<AnyPin> { | ||
| 331 | self.pin_mut() | ||
| 332 | .map(|pin| unsafe { core::ptr::read(pin) }.degrade()) | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | impl<T: Pin> sealed::OptionalPin for T {} | ||
| 337 | impl<T: Pin> OptionalPin for T { | ||
| 338 | type Pin = T; | ||
| 339 | |||
| 340 | #[inline] | ||
| 341 | fn pin(&self) -> Option<&T> { | ||
| 342 | Some(self) | ||
| 343 | } | ||
| 344 | |||
| 345 | #[inline] | ||
| 346 | fn pin_mut(&mut self) -> Option<&mut T> { | ||
| 347 | Some(self) | ||
| 348 | } | ||
| 349 | } | ||
| 350 | |||
| 351 | // Uninhabited enum, so it's actually impossible to create a DummyPin value. | ||
| 352 | #[doc(hidden)] | ||
| 353 | pub enum DummyPin {} | ||
| 354 | impl Pin for DummyPin {} | ||
| 355 | impl sealed::Pin for DummyPin { | ||
| 356 | #[inline] | ||
| 357 | fn pin_port(&self) -> u8 { | ||
| 358 | unreachable!() | ||
| 359 | } | ||
| 360 | } | ||
| 361 | |||
| 362 | #[derive(Clone, Copy, Debug)] | ||
| 363 | pub struct NoPin; | ||
| 364 | impl sealed::OptionalPin for NoPin {} | ||
| 365 | impl OptionalPin for NoPin { | ||
| 366 | type Pin = DummyPin; | ||
| 367 | |||
| 368 | #[inline] | ||
| 369 | fn pin(&self) -> Option<&DummyPin> { | ||
| 370 | None | ||
| 371 | } | ||
| 372 | |||
| 373 | #[inline] | ||
| 374 | fn pin_mut(&mut self) -> Option<&mut DummyPin> { | ||
| 375 | None | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | impl PeripheralBorrow for NoPin { | ||
| 380 | type Target = NoPin; | ||
| 381 | #[inline] | ||
| 382 | unsafe fn unborrow(self) -> Self::Target { | ||
| 383 | self | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 | // ==================== | ||
| 388 | |||
| 288 | macro_rules! make_impl { | 389 | macro_rules! make_impl { |
| 289 | ($type:ident, $port_num:expr, $pin_num:expr) => { | 390 | ($type:ident, $port_num:expr, $pin_num:expr) => { |
| 290 | impl Pin for peripherals::$type {} | 391 | impl Pin for peripherals::$type {} |
| 291 | impl sealed::Pin for peripherals::$type { | 392 | impl sealed::Pin for peripherals::$type { |
| 393 | #[inline] | ||
| 292 | fn pin_port(&self) -> u8 { | 394 | fn pin_port(&self) -> u8 { |
| 293 | $port_num * 32 + $pin_num | 395 | $port_num * 32 + $pin_num |
| 294 | } | 396 | } |
