diff options
| author | Dario Nieuwenhuis <[email protected]> | 2020-11-08 18:59:31 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2020-11-08 18:59:31 +0100 |
| commit | fc0fe842ee0c9a39b23a0b82847580bd596b6e82 (patch) | |
| tree | f12e68892e8cd55804f7c5a5518bc46e2c71a54d | |
| parent | a2735a716c72ec9098297a4ef3120a8e12b5e61d (diff) | |
Add support for GPIOTE Port event.
| -rw-r--r-- | embassy-nrf/src/gpiote.rs | 226 |
1 files changed, 219 insertions, 7 deletions
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index ffea98f2e..1980e8746 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | use anyfmt::*; | 1 | use anyfmt::{panic, *}; |
| 2 | use core::cell::Cell; | 2 | use core::cell::Cell; |
| 3 | use core::ptr; | 3 | use core::ptr; |
| 4 | use embassy::util::Signal; | 4 | use embassy::util::Signal; |
| @@ -7,19 +7,32 @@ use crate::hal::gpio::{Input, Level, Output, Pin, Port}; | |||
| 7 | use crate::interrupt; | 7 | use crate::interrupt; |
| 8 | use crate::pac::generic::Reg; | 8 | use crate::pac::generic::Reg; |
| 9 | use crate::pac::gpiote::_TASKS_OUT; | 9 | use crate::pac::gpiote::_TASKS_OUT; |
| 10 | use crate::pac::GPIOTE; | 10 | use crate::pac::{p0 as gpio, GPIOTE, P0, P1}; |
| 11 | 11 | ||
| 12 | #[cfg(not(feature = "51"))] | 12 | #[cfg(not(feature = "51"))] |
| 13 | use crate::pac::gpiote::{_TASKS_CLR, _TASKS_SET}; | 13 | use crate::pac::gpiote::{_TASKS_CLR, _TASKS_SET}; |
| 14 | 14 | ||
| 15 | pub const CHANNEL_COUNT: usize = 8; | ||
| 16 | |||
| 17 | #[cfg(any(feature = "52833", feature = "52840"))] | ||
| 18 | pub const PIN_COUNT: usize = 48; | ||
| 19 | #[cfg(not(any(feature = "52833", feature = "52840")))] | ||
| 20 | pub const PIN_COUNT: usize = 32; | ||
| 21 | |||
| 15 | pub struct Gpiote { | 22 | pub struct Gpiote { |
| 16 | inner: GPIOTE, | 23 | inner: GPIOTE, |
| 17 | free_channels: Cell<u8>, // 0 = used, 1 = free. 8 bits for 8 channelself. | 24 | free_channels: Cell<u8>, // 0 = used, 1 = free. 8 bits for 8 channelself. |
| 18 | signals: [Signal<()>; 8], | 25 | channel_signals: [Signal<()>; CHANNEL_COUNT], |
| 26 | port_signals: [Signal<()>; PIN_COUNT], | ||
| 19 | } | 27 | } |
| 20 | 28 | ||
| 21 | static mut INSTANCE: *const Gpiote = ptr::null_mut(); | 29 | static mut INSTANCE: *const Gpiote = ptr::null_mut(); |
| 22 | 30 | ||
| 31 | pub enum PortInputPolarity { | ||
| 32 | High, | ||
| 33 | Low, | ||
| 34 | } | ||
| 35 | |||
| 23 | pub enum InputChannelPolarity { | 36 | pub enum InputChannelPolarity { |
| 24 | None, | 37 | None, |
| 25 | HiToLo, | 38 | HiToLo, |
| @@ -42,13 +55,115 @@ pub enum NewChannelError { | |||
| 42 | 55 | ||
| 43 | impl Gpiote { | 56 | impl Gpiote { |
| 44 | pub fn new(gpiote: GPIOTE) -> Self { | 57 | pub fn new(gpiote: GPIOTE) -> Self { |
| 58 | #[cfg(any(feature = "52833", feature = "52840"))] | ||
| 59 | let ports = unsafe { &[&*P0::ptr(), &*P1::ptr()] }; | ||
| 60 | #[cfg(not(any(feature = "52833", feature = "52840")))] | ||
| 61 | let ports = unsafe { &[&*P0::ptr()] }; | ||
| 62 | |||
| 63 | for &p in ports { | ||
| 64 | // Enable latched detection | ||
| 65 | p.detectmode.write(|w| w.detectmode().ldetect()); | ||
| 66 | // Clear latch | ||
| 67 | p.latch.write(|w| unsafe { w.bits(0xFFFFFFFF) }) | ||
| 68 | } | ||
| 69 | |||
| 70 | // Enable interrupts | ||
| 71 | gpiote.events_port.write(|w| w); | ||
| 72 | gpiote.intenset.write(|w| w.port().set()); | ||
| 45 | interrupt::unpend(interrupt::GPIOTE); | 73 | interrupt::unpend(interrupt::GPIOTE); |
| 46 | interrupt::enable(interrupt::GPIOTE); | 74 | interrupt::enable(interrupt::GPIOTE); |
| 47 | 75 | ||
| 48 | Self { | 76 | Self { |
| 49 | inner: gpiote, | 77 | inner: gpiote, |
| 50 | free_channels: Cell::new(0xFF), // all 8 channels free | 78 | free_channels: Cell::new(0xFF), // all 8 channels free |
| 51 | signals: [ | 79 | channel_signals: [ |
| 80 | Signal::new(), | ||
| 81 | Signal::new(), | ||
| 82 | Signal::new(), | ||
| 83 | Signal::new(), | ||
| 84 | Signal::new(), | ||
| 85 | Signal::new(), | ||
| 86 | Signal::new(), | ||
| 87 | Signal::new(), | ||
| 88 | ], | ||
| 89 | // This is just horrible | ||
| 90 | #[cfg(any(feature = "52833", feature = "52840"))] | ||
| 91 | port_signals: [ | ||
| 92 | Signal::new(), | ||
| 93 | Signal::new(), | ||
| 94 | Signal::new(), | ||
| 95 | Signal::new(), | ||
| 96 | Signal::new(), | ||
| 97 | Signal::new(), | ||
| 98 | Signal::new(), | ||
| 99 | Signal::new(), | ||
| 100 | Signal::new(), | ||
| 101 | Signal::new(), | ||
| 102 | Signal::new(), | ||
| 103 | Signal::new(), | ||
| 104 | Signal::new(), | ||
| 105 | Signal::new(), | ||
| 106 | Signal::new(), | ||
| 107 | Signal::new(), | ||
| 108 | Signal::new(), | ||
| 109 | Signal::new(), | ||
| 110 | Signal::new(), | ||
| 111 | Signal::new(), | ||
| 112 | Signal::new(), | ||
| 113 | Signal::new(), | ||
| 114 | Signal::new(), | ||
| 115 | Signal::new(), | ||
| 116 | Signal::new(), | ||
| 117 | Signal::new(), | ||
| 118 | Signal::new(), | ||
| 119 | Signal::new(), | ||
| 120 | Signal::new(), | ||
| 121 | Signal::new(), | ||
| 122 | Signal::new(), | ||
| 123 | Signal::new(), | ||
| 124 | Signal::new(), | ||
| 125 | Signal::new(), | ||
| 126 | Signal::new(), | ||
| 127 | Signal::new(), | ||
| 128 | Signal::new(), | ||
| 129 | Signal::new(), | ||
| 130 | Signal::new(), | ||
| 131 | Signal::new(), | ||
| 132 | Signal::new(), | ||
| 133 | Signal::new(), | ||
| 134 | Signal::new(), | ||
| 135 | Signal::new(), | ||
| 136 | Signal::new(), | ||
| 137 | Signal::new(), | ||
| 138 | Signal::new(), | ||
| 139 | Signal::new(), | ||
| 140 | ], | ||
| 141 | #[cfg(not(any(feature = "52833", feature = "52840")))] | ||
| 142 | port_signals: [ | ||
| 143 | Signal::new(), | ||
| 144 | Signal::new(), | ||
| 145 | Signal::new(), | ||
| 146 | Signal::new(), | ||
| 147 | Signal::new(), | ||
| 148 | Signal::new(), | ||
| 149 | Signal::new(), | ||
| 150 | Signal::new(), | ||
| 151 | Signal::new(), | ||
| 152 | Signal::new(), | ||
| 153 | Signal::new(), | ||
| 154 | Signal::new(), | ||
| 155 | Signal::new(), | ||
| 156 | Signal::new(), | ||
| 157 | Signal::new(), | ||
| 158 | Signal::new(), | ||
| 159 | Signal::new(), | ||
| 160 | Signal::new(), | ||
| 161 | Signal::new(), | ||
| 162 | Signal::new(), | ||
| 163 | Signal::new(), | ||
| 164 | Signal::new(), | ||
| 165 | Signal::new(), | ||
| 166 | Signal::new(), | ||
| 52 | Signal::new(), | 167 | Signal::new(), |
| 53 | Signal::new(), | 168 | Signal::new(), |
| 54 | Signal::new(), | 169 | Signal::new(), |
| @@ -84,6 +199,13 @@ impl Gpiote { | |||
| 84 | }) | 199 | }) |
| 85 | } | 200 | } |
| 86 | 201 | ||
| 202 | pub fn new_port_input<'a, T>(&'a self, pin: Pin<Input<T>>) -> PortInput<'a, T> { | ||
| 203 | interrupt::free(|_| { | ||
| 204 | unsafe { INSTANCE = self }; | ||
| 205 | PortInput { gpiote: self, pin } | ||
| 206 | }) | ||
| 207 | } | ||
| 208 | |||
| 87 | pub fn new_input_channel<'a, T>( | 209 | pub fn new_input_channel<'a, T>( |
| 88 | &'a self, | 210 | &'a self, |
| 89 | pin: Pin<Input<T>>, | 211 | pin: Pin<Input<T>>, |
| @@ -161,6 +283,56 @@ impl Gpiote { | |||
| 161 | } | 283 | } |
| 162 | } | 284 | } |
| 163 | 285 | ||
| 286 | pub struct PortInput<'a, T> { | ||
| 287 | gpiote: &'a Gpiote, | ||
| 288 | pin: Pin<Input<T>>, | ||
| 289 | } | ||
| 290 | |||
| 291 | impl<'a, T> Drop for PortInput<'a, T> { | ||
| 292 | fn drop(&mut self) { | ||
| 293 | pin_conf(&self.pin).modify(|_, w| w.sense().disabled()); | ||
| 294 | self.gpiote.port_signals[pin_num(&self.pin)].reset(); | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | impl<'a, T> PortInput<'a, T> { | ||
| 299 | pub async fn wait(&self, polarity: PortInputPolarity) { | ||
| 300 | pin_conf(&self.pin).modify(|_, w| match polarity { | ||
| 301 | PortInputPolarity::Low => w.sense().low(), | ||
| 302 | PortInputPolarity::High => w.sense().high(), | ||
| 303 | }); | ||
| 304 | self.gpiote.port_signals[pin_num(&self.pin)].wait().await; | ||
| 305 | } | ||
| 306 | |||
| 307 | pub fn pin(&self) -> &Pin<Input<T>> { | ||
| 308 | &self.pin | ||
| 309 | } | ||
| 310 | } | ||
| 311 | |||
| 312 | fn pin_num<T>(pin: &Pin<T>) -> usize { | ||
| 313 | let port = match pin.port() { | ||
| 314 | Port::Port0 => 0, | ||
| 315 | #[cfg(any(feature = "52833", feature = "52840"))] | ||
| 316 | Port::Port1 => 32, | ||
| 317 | }; | ||
| 318 | |||
| 319 | port + pin.pin() as usize | ||
| 320 | } | ||
| 321 | |||
| 322 | fn pin_block<T>(pin: &Pin<T>) -> &gpio::RegisterBlock { | ||
| 323 | let ptr = match pin.port() { | ||
| 324 | Port::Port0 => P0::ptr(), | ||
| 325 | #[cfg(any(feature = "52833", feature = "52840"))] | ||
| 326 | Port::Port1 => P1::ptr(), | ||
| 327 | }; | ||
| 328 | |||
| 329 | unsafe { &*ptr } | ||
| 330 | } | ||
| 331 | |||
| 332 | fn pin_conf<T>(pin: &Pin<T>) -> &gpio::PIN_CNF { | ||
| 333 | &pin_block(pin).pin_cnf[pin.pin() as usize] | ||
| 334 | } | ||
| 335 | |||
| 164 | pub struct InputChannel<'a, T> { | 336 | pub struct InputChannel<'a, T> { |
| 165 | gpiote: &'a Gpiote, | 337 | gpiote: &'a Gpiote, |
| 166 | pin: Pin<Input<T>>, | 338 | pin: Pin<Input<T>>, |
| @@ -174,8 +346,10 @@ impl<'a, T> Drop for InputChannel<'a, T> { | |||
| 174 | } | 346 | } |
| 175 | 347 | ||
| 176 | impl<'a, T> InputChannel<'a, T> { | 348 | impl<'a, T> InputChannel<'a, T> { |
| 177 | pub async fn wait(&self) -> () { | 349 | pub async fn wait(&self) { |
| 178 | self.gpiote.signals[self.index as usize].wait().await; | 350 | self.gpiote.channel_signals[self.index as usize] |
| 351 | .wait() | ||
| 352 | .await; | ||
| 179 | } | 353 | } |
| 180 | 354 | ||
| 181 | pub fn pin(&self) -> &Pin<Input<T>> { | 355 | pub fn pin(&self) -> &Pin<Input<T>> { |
| @@ -235,7 +409,45 @@ unsafe fn GPIOTE() { | |||
| 235 | for i in 0..8 { | 409 | for i in 0..8 { |
| 236 | if s.inner.events_in[i].read().bits() != 0 { | 410 | if s.inner.events_in[i].read().bits() != 0 { |
| 237 | s.inner.events_in[i].write(|w| w); | 411 | s.inner.events_in[i].write(|w| w); |
| 238 | s.signals[i].signal(()); | 412 | s.channel_signals[i].signal(()); |
| 413 | } | ||
| 414 | } | ||
| 415 | |||
| 416 | if s.inner.events_port.read().bits() != 0 { | ||
| 417 | s.inner.events_port.write(|w| w); | ||
| 418 | |||
| 419 | #[cfg(any(feature = "52833", feature = "52840"))] | ||
| 420 | let ports = &[&*P0::ptr(), &*P1::ptr()]; | ||
| 421 | #[cfg(not(any(feature = "52833", feature = "52840")))] | ||
| 422 | let ports = &[&*P0::ptr()]; | ||
| 423 | |||
| 424 | let mut work = true; | ||
| 425 | while work { | ||
| 426 | work = false; | ||
| 427 | for (port, &p) in ports.iter().enumerate() { | ||
| 428 | for pin in BitIter(p.latch.read().bits()) { | ||
| 429 | work = true; | ||
| 430 | p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled()); | ||
| 431 | p.latch.write(|w| w.bits(1 << pin)); | ||
| 432 | s.port_signals[port * 32 + pin as usize].signal(()); | ||
| 433 | } | ||
| 434 | } | ||
| 435 | } | ||
| 436 | } | ||
| 437 | } | ||
| 438 | |||
| 439 | struct BitIter(u32); | ||
| 440 | |||
| 441 | impl Iterator for BitIter { | ||
| 442 | type Item = u32; | ||
| 443 | |||
| 444 | fn next(&mut self) -> Option<Self::Item> { | ||
| 445 | match self.0.trailing_zeros() { | ||
| 446 | 32 => None, | ||
| 447 | b => { | ||
| 448 | self.0 &= !(1 << b); | ||
| 449 | Some(b) | ||
| 450 | } | ||
| 239 | } | 451 | } |
| 240 | } | 452 | } |
| 241 | } | 453 | } |
