aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf/src/gpio.rs
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-12-19 23:25:02 +0100
committerDario Nieuwenhuis <[email protected]>2021-12-20 00:55:18 +0100
commit22bc1e4ae17fbc76442d4ee1375cf3a86e0b4757 (patch)
treef40189ea47351acc04ad0a616c316cf59ac02ebd /embassy-nrf/src/gpio.rs
parentfcb43caa36bcf2fb62ddd1c334c46bd6bc876a9e (diff)
nrf/gpio: add infallible inherent methods, remove some duplication.
This implements Input and Output using FlexPin, to avoid some code duplication.
Diffstat (limited to 'embassy-nrf/src/gpio.rs')
-rw-r--r--embassy-nrf/src/gpio.rs340
1 files changed, 108 insertions, 232 deletions
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs
index cb06f0971..ddc84cf5d 100644
--- a/embassy-nrf/src/gpio.rs
+++ b/embassy-nrf/src/gpio.rs
@@ -1,7 +1,6 @@
1#![macro_use] 1#![macro_use]
2 2
3use core::convert::Infallible; 3use core::convert::Infallible;
4use core::future::Future;
5use core::hint::unreachable_unchecked; 4use core::hint::unreachable_unchecked;
6use core::marker::PhantomData; 5use core::marker::PhantomData;
7 6
@@ -38,26 +37,23 @@ pub enum Pull {
38 37
39/// GPIO input driver. 38/// GPIO input driver.
40pub struct Input<'d, T: Pin> { 39pub struct Input<'d, T: Pin> {
41 pub(crate) pin: T, 40 pub(crate) pin: FlexPin<'d, T>,
42 phantom: PhantomData<&'d mut T>,
43} 41}
44 42
45impl<'d, T: Pin> Input<'d, T> { 43impl<'d, T: Pin> Input<'d, T> {
46 pub fn new(pin: impl Unborrow<Target = T> + 'd, pull: Pull) -> Self { 44 pub fn new(pin: impl Unborrow<Target = T> + 'd, pull: Pull) -> Self {
47 unborrow!(pin); 45 let mut pin = FlexPin::new(pin);
46 pin.set_as_input(pull);
48 47
49 init_input(&pin, pull); 48 Self { pin }
49 }
50 50
51 Self { 51 fn is_high(&self) -> bool {
52 pin, 52 self.pin.is_high()
53 phantom: PhantomData,
54 }
55 } 53 }
56}
57 54
58impl<'d, T: Pin> Drop for Input<'d, T> { 55 fn is_low(&self) -> bool {
59 fn drop(&mut self) { 56 self.pin.is_low()
60 self.pin.conf().reset();
61 } 57 }
62} 58}
63 59
@@ -65,65 +61,11 @@ impl<'d, T: Pin> InputPin for Input<'d, T> {
65 type Error = Infallible; 61 type Error = Infallible;
66 62
67 fn is_high(&self) -> Result<bool, Self::Error> { 63 fn is_high(&self) -> Result<bool, Self::Error> {
68 self.is_low().map(|v| !v) 64 Ok(self.is_high())
69 } 65 }
70 66
71 fn is_low(&self) -> Result<bool, Self::Error> { 67 fn is_low(&self) -> Result<bool, Self::Error> {
72 Ok(self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0) 68 Ok(self.is_low())
73 }
74}
75
76#[cfg(feature = "gpiote")]
77impl<'d, T: Pin> embassy::traits::gpio::WaitForHigh for Input<'d, T> {
78 type Future<'a>
79 where
80 Self: 'a,
81 = impl Future<Output = ()> + Unpin + 'a;
82
83 fn wait_for_high<'a>(&'a mut self) -> Self::Future<'a> {
84 self.pin.conf().modify(|_, w| w.sense().high());
85
86 crate::gpiote::PortInputFuture {
87 pin_port: self.pin.pin_port(),
88 phantom: PhantomData,
89 }
90 }
91}
92
93#[cfg(feature = "gpiote")]
94impl<'d, T: Pin> embassy::traits::gpio::WaitForLow for Input<'d, T> {
95 type Future<'a>
96 where
97 Self: 'a,
98 = impl Future<Output = ()> + Unpin + 'a;
99
100 fn wait_for_low<'a>(&'a mut self) -> Self::Future<'a> {
101 self.pin.conf().modify(|_, w| w.sense().low());
102
103 crate::gpiote::PortInputFuture {
104 pin_port: self.pin.pin_port(),
105 phantom: PhantomData,
106 }
107 }
108}
109
110#[cfg(feature = "gpiote")]
111impl<'d, T: Pin> embassy::traits::gpio::WaitForAnyEdge for Input<'d, T> {
112 type Future<'a>
113 where
114 Self: 'a,
115 = impl Future<Output = ()> + Unpin + 'a;
116
117 fn wait_for_any_edge<'a>(&'a mut self) -> Self::Future<'a> {
118 if self.is_high().ok().unwrap() {
119 self.pin.conf().modify(|_, w| w.sense().low());
120 } else {
121 self.pin.conf().modify(|_, w| w.sense().high());
122 }
123 crate::gpiote::PortInputFuture {
124 pin_port: self.pin.pin_port(),
125 phantom: PhantomData,
126 }
127 } 69 }
128} 70}
129 71
@@ -160,8 +102,7 @@ pub enum OutputDrive {
160 102
161/// GPIO output driver. 103/// GPIO output driver.
162pub struct Output<'d, T: Pin> { 104pub struct Output<'d, T: Pin> {
163 pub(crate) pin: T, 105 pub(crate) pin: FlexPin<'d, T>,
164 phantom: PhantomData<&'d mut T>,
165} 106}
166 107
167impl<'d, T: Pin> Output<'d, T> { 108impl<'d, T: Pin> Output<'d, T> {
@@ -170,63 +111,56 @@ impl<'d, T: Pin> Output<'d, T> {
170 initial_output: Level, 111 initial_output: Level,
171 drive: OutputDrive, 112 drive: OutputDrive,
172 ) -> Self { 113 ) -> Self {
173 unborrow!(pin); 114 let mut pin = FlexPin::new(pin);
174
175 match initial_output { 115 match initial_output {
176 Level::High => pin.set_high(), 116 Level::High => pin.set_high(),
177 Level::Low => pin.set_low(), 117 Level::Low => pin.set_low(),
178 } 118 }
119 pin.set_as_output(drive);
179 120
180 init_output(&pin, drive); 121 Self { pin }
122 }
181 123
182 Self { 124 /// Set the output as high.
183 pin, 125 pub fn set_high(&mut self) {
184 phantom: PhantomData, 126 self.pin.set_high()
185 }
186 } 127 }
187}
188 128
189impl<'d, T: Pin> Drop for Output<'d, T> { 129 /// Set the output as low.
190 fn drop(&mut self) { 130 pub fn set_low(&mut self) {
191 self.pin.conf().reset(); 131 self.pin.set_low()
132 }
133
134 /// Is the output pin set as high?
135 pub fn is_set_high(&self) -> bool {
136 self.pin.is_set_high()
137 }
138
139 /// Is the output pin set as low?
140 pub fn is_set_low(&self) -> bool {
141 self.pin.is_set_low()
192 } 142 }
193} 143}
194 144
195impl<'d, T: Pin> OutputPin for Output<'d, T> { 145impl<'d, T: Pin> OutputPin for Output<'d, T> {
196 type Error = Infallible; 146 type Error = Infallible;
197 147
198 /// Set the output as high.
199 fn set_high(&mut self) -> Result<(), Self::Error> { 148 fn set_high(&mut self) -> Result<(), Self::Error> {
200 unsafe { 149 Ok(self.set_high())
201 self.pin
202 .block()
203 .outset
204 .write(|w| w.bits(1u32 << self.pin.pin()));
205 }
206 Ok(())
207 } 150 }
208 151
209 /// Set the output as low.
210 fn set_low(&mut self) -> Result<(), Self::Error> { 152 fn set_low(&mut self) -> Result<(), Self::Error> {
211 unsafe { 153 Ok(self.set_low())
212 self.pin
213 .block()
214 .outclr
215 .write(|w| w.bits(1u32 << self.pin.pin()));
216 }
217 Ok(())
218 } 154 }
219} 155}
220 156
221impl<'d, T: Pin> StatefulOutputPin for Output<'d, T> { 157impl<'d, T: Pin> StatefulOutputPin for Output<'d, T> {
222 /// Is the output pin set as high?
223 fn is_set_high(&self) -> Result<bool, Self::Error> { 158 fn is_set_high(&self) -> Result<bool, Self::Error> {
224 self.is_set_low().map(|v| !v) 159 Ok(self.is_set_high())
225 } 160 }
226 161
227 /// Is the output pin set as low?
228 fn is_set_low(&self) -> Result<bool, Self::Error> { 162 fn is_set_low(&self) -> Result<bool, Self::Error> {
229 Ok(self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0) 163 Ok(self.is_set_low())
230 } 164 }
231} 165}
232 166
@@ -256,7 +190,24 @@ impl<'d, T: Pin> FlexPin<'d, T> {
256 190
257 /// Put the pin into input mode. 191 /// Put the pin into input mode.
258 pub fn set_as_input(&mut self, pull: Pull) { 192 pub fn set_as_input(&mut self, pull: Pull) {
259 init_input(&self.pin, pull); 193 self.pin.conf().write(|w| {
194 w.dir().input();
195 w.input().connect();
196 match pull {
197 Pull::None => {
198 w.pull().disabled();
199 }
200 Pull::Up => {
201 w.pull().pullup();
202 }
203 Pull::Down => {
204 w.pull().pulldown();
205 }
206 }
207 w.drive().s0s1();
208 w.sense().disabled();
209 w
210 });
260 } 211 }
261 212
262 /// Put the pin into output mode. 213 /// Put the pin into output mode.
@@ -264,13 +215,59 @@ impl<'d, T: Pin> FlexPin<'d, T> {
264 /// The pin level will be whatever was set before (or low by default). If you want it to begin 215 /// The pin level will be whatever was set before (or low by default). If you want it to begin
265 /// at a specific level, call `set_high`/`set_low` on the pin first. 216 /// at a specific level, call `set_high`/`set_low` on the pin first.
266 pub fn set_as_output(&mut self, drive: OutputDrive) { 217 pub fn set_as_output(&mut self, drive: OutputDrive) {
267 init_output(&self.pin, drive); 218 let drive = match drive {
219 OutputDrive::Standard => DRIVE_A::S0S1,
220 OutputDrive::HighDrive0Standard1 => DRIVE_A::H0S1,
221 OutputDrive::Standard0HighDrive1 => DRIVE_A::S0H1,
222 OutputDrive::HighDrive => DRIVE_A::H0H1,
223 OutputDrive::Disconnect0Standard1 => DRIVE_A::D0S1,
224 OutputDrive::Disconnect0HighDrive1 => DRIVE_A::D0H1,
225 OutputDrive::Standard0Disconnect1 => DRIVE_A::S0D1,
226 OutputDrive::HighDrive0Disconnect1 => DRIVE_A::H0D1,
227 };
228
229 self.pin.conf().write(|w| {
230 w.dir().output();
231 w.input().disconnect();
232 w.pull().disabled();
233 w.drive().variant(drive);
234 w.sense().disabled();
235 w
236 });
268 } 237 }
269 238
270 /// Put the pin into disconnected mode. 239 /// Put the pin into disconnected mode.
271 pub fn set_as_disconnected(&mut self) { 240 pub fn set_as_disconnected(&mut self) {
272 self.pin.conf().reset(); 241 self.pin.conf().reset();
273 } 242 }
243
244 pub fn is_high(&self) -> bool {
245 !self.is_low()
246 }
247
248 pub fn is_low(&self) -> bool {
249 self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0
250 }
251
252 /// Set the output as high.
253 pub fn set_high(&mut self) {
254 self.pin.set_high()
255 }
256
257 /// Set the output as low.
258 pub fn set_low(&mut self) {
259 self.pin.set_low()
260 }
261
262 /// Is the output pin set as high?
263 pub fn is_set_high(&self) -> bool {
264 !self.is_set_low()
265 }
266
267 /// Is the output pin set as low?
268 pub fn is_set_low(&self) -> bool {
269 self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0
270 }
274} 271}
275 272
276impl<'d, T: Pin> Drop for FlexPin<'d, T> { 273impl<'d, T: Pin> Drop for FlexPin<'d, T> {
@@ -286,103 +283,33 @@ impl<'d, T: Pin> InputPin for FlexPin<'d, T> {
286 type Error = Infallible; 283 type Error = Infallible;
287 284
288 fn is_high(&self) -> Result<bool, Self::Error> { 285 fn is_high(&self) -> Result<bool, Self::Error> {
289 self.is_low().map(|v| !v) 286 Ok(self.is_high())
290 } 287 }
291 288
292 fn is_low(&self) -> Result<bool, Self::Error> { 289 fn is_low(&self) -> Result<bool, Self::Error> {
293 Ok(self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0) 290 Ok(self.is_low())
294 } 291 }
295} 292}
296 293
297impl<'d, T: Pin> OutputPin for FlexPin<'d, T> { 294impl<'d, T: Pin> OutputPin for FlexPin<'d, T> {
298 type Error = Infallible; 295 type Error = Infallible;
299 296
300 /// Set the output as high.
301 fn set_high(&mut self) -> Result<(), Self::Error> { 297 fn set_high(&mut self) -> Result<(), Self::Error> {
302 unsafe { 298 Ok(self.set_high())
303 self.pin
304 .block()
305 .outset
306 .write(|w| w.bits(1u32 << self.pin.pin()));
307 }
308 Ok(())
309 } 299 }
310 300
311 /// Set the output as low.
312 fn set_low(&mut self) -> Result<(), Self::Error> { 301 fn set_low(&mut self) -> Result<(), Self::Error> {
313 unsafe { 302 Ok(self.set_low())
314 self.pin
315 .block()
316 .outclr
317 .write(|w| w.bits(1u32 << self.pin.pin()));
318 }
319 Ok(())
320 } 303 }
321} 304}
322 305
323impl<'d, T: Pin> StatefulOutputPin for FlexPin<'d, T> { 306impl<'d, T: Pin> StatefulOutputPin for FlexPin<'d, T> {
324 /// Is the output pin set as high?
325 fn is_set_high(&self) -> Result<bool, Self::Error> { 307 fn is_set_high(&self) -> Result<bool, Self::Error> {
326 self.is_set_low().map(|v| !v) 308 Ok(self.is_set_high())
327 } 309 }
328 310
329 /// Is the output pin set as low?
330 fn is_set_low(&self) -> Result<bool, Self::Error> { 311 fn is_set_low(&self) -> Result<bool, Self::Error> {
331 Ok(self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0) 312 Ok(self.is_set_low())
332 }
333}
334
335#[cfg(feature = "gpiote")]
336impl<'d, T: Pin> embassy::traits::gpio::WaitForHigh for FlexPin<'d, T> {
337 type Future<'a>
338 where
339 Self: 'a,
340 = impl Future<Output = ()> + Unpin + 'a;
341
342 fn wait_for_high<'a>(&'a mut self) -> Self::Future<'a> {
343 self.pin.conf().modify(|_, w| w.sense().high());
344
345 crate::gpiote::PortInputFuture {
346 pin_port: self.pin.pin_port(),
347 phantom: PhantomData,
348 }
349 }
350}
351
352#[cfg(feature = "gpiote")]
353impl<'d, T: Pin> embassy::traits::gpio::WaitForLow for FlexPin<'d, T> {
354 type Future<'a>
355 where
356 Self: 'a,
357 = impl Future<Output = ()> + Unpin + 'a;
358
359 fn wait_for_low<'a>(&'a mut self) -> Self::Future<'a> {
360 self.pin.conf().modify(|_, w| w.sense().low());
361
362 crate::gpiote::PortInputFuture {
363 pin_port: self.pin.pin_port(),
364 phantom: PhantomData,
365 }
366 }
367}
368
369#[cfg(feature = "gpiote")]
370impl<'d, T: Pin> embassy::traits::gpio::WaitForAnyEdge for FlexPin<'d, T> {
371 type Future<'a>
372 where
373 Self: 'a,
374 = impl Future<Output = ()> + Unpin + 'a;
375
376 fn wait_for_any_edge<'a>(&'a mut self) -> Self::Future<'a> {
377 if self.is_high().ok().unwrap() {
378 self.pin.conf().modify(|_, w| w.sense().low());
379 } else {
380 self.pin.conf().modify(|_, w| w.sense().high());
381 }
382 crate::gpiote::PortInputFuture {
383 pin_port: self.pin.pin_port(),
384 phantom: PhantomData,
385 }
386 } 313 }
387} 314}
388 315
@@ -493,55 +420,6 @@ impl sealed::Pin for AnyPin {
493 } 420 }
494} 421}
495 422
496// =====================
497
498/// Set up a pin for input
499#[inline]
500fn init_input<T: Pin>(pin: &T, pull: Pull) {
501 pin.conf().write(|w| {
502 w.dir().input();
503 w.input().connect();
504 match pull {
505 Pull::None => {
506 w.pull().disabled();
507 }
508 Pull::Up => {
509 w.pull().pullup();
510 }
511 Pull::Down => {
512 w.pull().pulldown();
513 }
514 }
515 w.drive().s0s1();
516 w.sense().disabled();
517 w
518 });
519}
520
521/// Set up a pin for output
522#[inline]
523fn init_output<T: Pin>(pin: &T, drive: OutputDrive) {
524 let drive = match drive {
525 OutputDrive::Standard => DRIVE_A::S0S1,
526 OutputDrive::HighDrive0Standard1 => DRIVE_A::H0S1,
527 OutputDrive::Standard0HighDrive1 => DRIVE_A::S0H1,
528 OutputDrive::HighDrive => DRIVE_A::H0H1,
529 OutputDrive::Disconnect0Standard1 => DRIVE_A::D0S1,
530 OutputDrive::Disconnect0HighDrive1 => DRIVE_A::D0H1,
531 OutputDrive::Standard0Disconnect1 => DRIVE_A::S0D1,
532 OutputDrive::HighDrive0Disconnect1 => DRIVE_A::H0D1,
533 };
534
535 pin.conf().write(|w| {
536 w.dir().output();
537 w.input().disconnect();
538 w.pull().disabled();
539 w.drive().variant(drive);
540 w.sense().disabled();
541 w
542 });
543}
544
545// ==================== 423// ====================
546 424
547pub trait OptionalPin: Unborrow<Target = Self> + sealed::OptionalPin + Sized { 425pub trait OptionalPin: Unborrow<Target = Self> + sealed::OptionalPin + Sized {
@@ -601,9 +479,7 @@ pub(crate) fn deconfigure_pin(psel_bits: u32) {
601 if psel_bits & 0x8000_0000 != 0 { 479 if psel_bits & 0x8000_0000 != 0 {
602 return; 480 return;
603 } 481 }
604 unsafe { 482 unsafe { AnyPin::steal(psel_bits as _).conf().reset() }
605 AnyPin::steal(psel_bits as _).conf().reset();
606 }
607} 483}
608 484
609// ==================== 485// ====================