aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-07-16 16:11:37 +0000
committerGitHub <[email protected]>2022-07-16 16:11:37 +0000
commit4dc800710d2269d5baebd62ae5a62205570db365 (patch)
treeb04e87b586ec1fa2a08d9d3963302583791a78e1
parent9d388d357aefcb87677a70716e727bc91933191a (diff)
parent8979959dd15be496e74a1a670a468d4d5168f0c8 (diff)
Merge #853
853: Add embedded_hal_async support for embassy-rp r=Dirbaio a=danbev This commit adds support for embedded-hal-async to the Embassy Raspberry PI crate. Co-authored-by: Daniel Bevenius <[email protected]>
-rw-r--r--embassy-rp/Cargo.toml1
-rw-r--r--embassy-rp/src/gpio.rs302
-rw-r--r--examples/rp/src/bin/gpio_async.rs38
-rw-r--r--tests/rp/Cargo.toml1
-rw-r--r--tests/rp/src/bin/gpio_async.rs148
5 files changed, 489 insertions, 1 deletions
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 95ae76cd2..ffb4c9148 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -38,6 +38,7 @@ log = { version = "0.4.14", optional = true }
38cortex-m-rt = ">=0.6.15,<0.8" 38cortex-m-rt = ">=0.6.15,<0.8"
39cortex-m = "0.7.3" 39cortex-m = "0.7.3"
40critical-section = "0.2.5" 40critical-section = "0.2.5"
41futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
41 42
42rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="9ad7223a48a065e612bc7dc7be5bf5bd0b41cfc4", features = ["rt"] } 43rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="9ad7223a48a065e612bc7dc7be5bf5bd0b41cfc4", features = ["rt"] }
43#rp2040-pac2 = { path = "../../rp/rp2040-pac2", features = ["rt"] } 44#rp2040-pac2 = { path = "../../rp/rp2040-pac2", features = ["rt"] }
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index c6dbb3d48..ef15a5eff 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -1,11 +1,20 @@
1use core::convert::Infallible; 1use core::convert::Infallible;
2use core::future::Future;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
4use core::pin::Pin as FuturePin;
5use core::task::{Context, Poll};
3 6
7use embassy::waitqueue::AtomicWaker;
8use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
4use embassy_hal_common::{unborrow, unsafe_impl_unborrow}; 9use embassy_hal_common::{unborrow, unsafe_impl_unborrow};
5 10
6use crate::pac::common::{Reg, RW}; 11use crate::pac::common::{Reg, RW};
7use crate::pac::SIO; 12use crate::pac::SIO;
8use crate::{pac, peripherals, Unborrow}; 13use crate::{interrupt, pac, peripherals, Unborrow};
14
15const PIN_COUNT: usize = 30;
16const NEW_AW: AtomicWaker = AtomicWaker::new();
17static INTERRUPT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AW; PIN_COUNT];
9 18
10/// Represents a digital input or output level. 19/// Represents a digital input or output level.
11#[derive(Debug, Eq, PartialEq)] 20#[derive(Debug, Eq, PartialEq)]
@@ -75,6 +84,204 @@ impl<'d, T: Pin> Input<'d, T> {
75 pub fn get_level(&self) -> Level { 84 pub fn get_level(&self) -> Level {
76 self.pin.get_level() 85 self.pin.get_level()
77 } 86 }
87
88 pub async fn wait_for_high<'a>(&mut self) {
89 self.pin.wait_for_high().await;
90 }
91
92 pub async fn wait_for_low<'a>(&mut self) {
93 self.pin.wait_for_low().await;
94 }
95
96 pub async fn wait_for_rising_edge<'a>(&mut self) {
97 self.pin.wait_for_rising_edge().await;
98 }
99
100 pub async fn wait_for_falling_edge<'a>(&mut self) {
101 self.pin.wait_for_falling_edge().await;
102 }
103
104 pub async fn wait_for_any_edge<'a>(&mut self) {
105 self.pin.wait_for_any_edge().await;
106 }
107}
108
109/// Interrupt trigger levels.
110#[derive(Debug, Eq, PartialEq, Copy, Clone)]
111#[cfg_attr(feature = "defmt", derive(defmt::Format))]
112pub enum InterruptTrigger {
113 LevelLow,
114 LevelHigh,
115 EdgeLow,
116 EdgeHigh,
117 AnyEdge,
118}
119
120impl InterruptTrigger {
121 fn from_u32(value: u32) -> Option<InterruptTrigger> {
122 match value {
123 1 => Some(InterruptTrigger::LevelLow),
124 2 => Some(InterruptTrigger::LevelHigh),
125 3 => Some(InterruptTrigger::EdgeLow),
126 4 => Some(InterruptTrigger::EdgeHigh),
127 _ => None,
128 }
129 }
130}
131
132#[interrupt]
133unsafe fn IO_IRQ_BANK0() {
134 let cpu = SIO.cpuid().read() as usize;
135 // There are two sets of interrupt registers, one for cpu0 and one for cpu1
136 // and here we are selecting the set that belongs to the currently executing
137 // cpu.
138 let proc_intx: pac::io::Int = pac::IO_BANK0.int_proc(cpu);
139 for pin in 0..PIN_COUNT {
140 // There are 4 raw interrupt status registers, PROCx_INTS0, PROCx_INTS1,
141 // PROCx_INTS2, and PROCx_INTS3, and we are selecting the one that the
142 // current pin belongs to.
143 let intsx = proc_intx.ints(pin / 8);
144 // The status register is divided into groups of four, one group for
145 // each pin. Each group consists of four trigger levels LEVEL_LOW,
146 // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin.
147 let pin_group = (pin % 8) as usize;
148 let event = (intsx.read().0 >> pin_group * 4) & 0xf as u32;
149
150 if let Some(trigger) = InterruptTrigger::from_u32(event) {
151 proc_intx.inte(pin / 8).write(|w| match trigger {
152 InterruptTrigger::AnyEdge => {
153 w.set_edge_high(pin_group, false);
154 w.set_edge_low(pin_group, false);
155 }
156 InterruptTrigger::LevelHigh => {
157 debug!("IO_IRQ_BANK0 pin {} LevelHigh triggered\n", pin);
158 w.set_level_high(pin_group, false);
159 }
160 InterruptTrigger::LevelLow => {
161 w.set_level_low(pin_group, false);
162 }
163 InterruptTrigger::EdgeHigh => {
164 w.set_edge_high(pin_group, false);
165 }
166 InterruptTrigger::EdgeLow => {
167 w.set_edge_low(pin_group, false);
168 }
169 });
170 INTERRUPT_WAKERS[pin as usize].wake();
171 }
172 }
173}
174
175struct InputFuture<'a, T: Pin> {
176 pin: &'a mut T,
177 level: InterruptTrigger,
178 phantom: PhantomData<&'a mut AnyPin>,
179}
180
181impl<'d, T: Pin> InputFuture<'d, T> {
182 pub fn new(pin: &'d mut T, level: InterruptTrigger) -> Self {
183 unsafe {
184 let irq = interrupt::IO_IRQ_BANK0::steal();
185 irq.disable();
186 irq.set_priority(interrupt::Priority::P6);
187
188 // Each INTR register is divided into 8 groups, one group for each
189 // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW,
190 // and EGDE_HIGH.
191 let pin_group = (pin.pin() % 8) as usize;
192 pin.int_proc().inte((pin.pin() / 8) as usize).write(|w| match level {
193 InterruptTrigger::LevelHigh => {
194 debug!("InputFuture::new enable LevelHigh for pin {} \n", pin.pin());
195 w.set_level_high(pin_group, true);
196 }
197 InterruptTrigger::LevelLow => {
198 w.set_level_low(pin_group, true);
199 }
200 InterruptTrigger::EdgeHigh => {
201 w.set_edge_high(pin_group, true);
202 }
203 InterruptTrigger::EdgeLow => {
204 w.set_edge_low(pin_group, true);
205 }
206 InterruptTrigger::AnyEdge => {
207 // noop
208 }
209 });
210
211 irq.enable();
212 }
213
214 Self {
215 pin,
216 level,
217 phantom: PhantomData,
218 }
219 }
220}
221
222impl<'d, T: Pin> Future for InputFuture<'d, T> {
223 type Output = ();
224
225 fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
226 // We need to register/re-register the waker for each poll because any
227 // calls to wake will deregister the waker.
228 INTERRUPT_WAKERS[self.pin.pin() as usize].register(cx.waker());
229
230 // self.int_proc() will get the register offset for the current cpu,
231 // then we want to access the interrupt enable register for our
232 // pin (there are 4 of these PROC0_INTE0, PROC0_INTE1, PROC0_INTE2, and
233 // PROC0_INTE3 per cpu).
234 let inte: pac::io::regs::Int = unsafe { self.pin.int_proc().inte((self.pin.pin() / 8) as usize).read() };
235 // The register is divided into groups of four, one group for
236 // each pin. Each group consists of four trigger levels LEVEL_LOW,
237 // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin.
238 let pin_group = (self.pin.pin() % 8) as usize;
239
240 // This should check the the level of the interrupt trigger level of
241 // the pin and if it has been disabled that means it was done by the
242 // interrupt service routine, so we then know that the event/trigger
243 // happened and Poll::Ready will be returned.
244 debug!("{:?} for pin {}\n", self.level, self.pin.pin());
245 match self.level {
246 InterruptTrigger::AnyEdge => {
247 if !inte.edge_high(pin_group) && !inte.edge_low(pin_group) {
248 #[rustfmt::skip]
249 debug!("{:?} for pin {} was cleared, return Poll::Ready\n", self.level, self.pin.pin());
250 return Poll::Ready(());
251 }
252 }
253 InterruptTrigger::LevelHigh => {
254 if !inte.level_high(pin_group) {
255 #[rustfmt::skip]
256 debug!("{:?} for pin {} was cleared, return Poll::Ready\n", self.level, self.pin.pin());
257 return Poll::Ready(());
258 }
259 }
260 InterruptTrigger::LevelLow => {
261 if !inte.level_low(pin_group) {
262 #[rustfmt::skip]
263 debug!("{:?} for pin {} was cleared, return Poll::Ready\n", self.level, self.pin.pin());
264 return Poll::Ready(());
265 }
266 }
267 InterruptTrigger::EdgeHigh => {
268 if !inte.edge_high(pin_group) {
269 #[rustfmt::skip]
270 debug!("{:?} for pin {} was cleared, return Poll::Ready\n", self.level, self.pin.pin());
271 return Poll::Ready(());
272 }
273 }
274 InterruptTrigger::EdgeLow => {
275 if !inte.edge_low(pin_group) {
276 #[rustfmt::skip]
277 debug!("{:?} for pin {} was cleared, return Poll::Ready\n", self.level, self.pin.pin());
278 return Poll::Ready(());
279 }
280 }
281 }
282 debug!("InputFuture::poll return Poll::Pending\n");
283 Poll::Pending
284 }
78} 285}
79 286
80pub struct Output<'d, T: Pin> { 287pub struct Output<'d, T: Pin> {
@@ -340,6 +547,32 @@ impl<'d, T: Pin> Flex<'d, T> {
340 pub fn toggle(&mut self) { 547 pub fn toggle(&mut self) {
341 unsafe { self.pin.sio_out().value_xor().write_value(self.bit()) } 548 unsafe { self.pin.sio_out().value_xor().write_value(self.bit()) }
342 } 549 }
550
551 pub async fn wait_for_high<'a>(&mut self) {
552 InputFuture::new(&mut self.pin, InterruptTrigger::LevelHigh).await;
553 }
554
555 pub async fn wait_for_low<'a>(&mut self) {
556 InputFuture::new(&mut self.pin, InterruptTrigger::LevelLow).await;
557 }
558
559 pub async fn wait_for_rising_edge<'a>(&mut self) {
560 self.wait_for_low().await;
561 self.wait_for_high().await;
562 }
563
564 pub async fn wait_for_falling_edge<'a>(&mut self) {
565 self.wait_for_high().await;
566 self.wait_for_low().await;
567 }
568
569 pub async fn wait_for_any_edge<'a>(&mut self) {
570 if self.is_high() {
571 self.wait_for_low().await;
572 } else {
573 self.wait_for_high().await;
574 }
575 }
343} 576}
344 577
345impl<'d, T: Pin> Drop for Flex<'d, T> { 578impl<'d, T: Pin> Drop for Flex<'d, T> {
@@ -401,6 +634,15 @@ pub(crate) mod sealed {
401 fn sio_in(&self) -> Reg<u32, RW> { 634 fn sio_in(&self) -> Reg<u32, RW> {
402 SIO.gpio_in(self.bank() as _) 635 SIO.gpio_in(self.bank() as _)
403 } 636 }
637
638 fn int_proc(&self) -> pac::io::Int {
639 let io_block = match self.bank() {
640 Bank::Bank0 => crate::pac::IO_BANK0,
641 Bank::Qspi => crate::pac::IO_QSPI,
642 };
643 let proc = unsafe { SIO.cpuid().read() };
644 io_block.int_proc(proc as _)
645 }
404 } 646 }
405} 647}
406 648
@@ -478,6 +720,8 @@ impl_pin!(PIN_QSPI_SD3, Bank::Qspi, 5);
478// ==================== 720// ====================
479 721
480mod eh02 { 722mod eh02 {
723 use futures::FutureExt;
724
481 use super::*; 725 use super::*;
482 726
483 impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> { 727 impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> {
@@ -595,6 +839,62 @@ mod eh02 {
595 Ok(self.toggle()) 839 Ok(self.toggle())
596 } 840 }
597 } 841 }
842
843 use core::convert::Infallible;
844
845 impl<'d, T: Pin> embedded_hal_async::digital::Wait for Flex<'d, T> {
846 type WaitForHighFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
847 fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> {
848 self.wait_for_high().map(Ok)
849 }
850
851 type WaitForLowFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
852 fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> {
853 self.wait_for_low().map(Ok)
854 }
855
856 type WaitForRisingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
857 fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> {
858 self.wait_for_rising_edge().map(Ok)
859 }
860
861 type WaitForFallingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
862 fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> {
863 self.wait_for_falling_edge().map(Ok)
864 }
865
866 type WaitForAnyEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
867 fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> {
868 self.wait_for_any_edge().map(Ok)
869 }
870 }
871
872 impl<'d, T: Pin> embedded_hal_async::digital::Wait for Input<'d, T> {
873 type WaitForHighFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
874 fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> {
875 self.wait_for_high().map(Ok)
876 }
877
878 type WaitForLowFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
879 fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> {
880 self.wait_for_low().map(Ok)
881 }
882
883 type WaitForRisingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
884 fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> {
885 self.wait_for_rising_edge().map(Ok)
886 }
887
888 type WaitForFallingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
889 fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> {
890 self.wait_for_falling_edge().map(Ok)
891 }
892
893 type WaitForAnyEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
894 fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> {
895 self.wait_for_any_edge().map(Ok)
896 }
897 }
598} 898}
599 899
600#[cfg(feature = "unstable-traits")] 900#[cfg(feature = "unstable-traits")]
diff --git a/examples/rp/src/bin/gpio_async.rs b/examples/rp/src/bin/gpio_async.rs
new file mode 100644
index 000000000..e0f2aa961
--- /dev/null
+++ b/examples/rp/src/bin/gpio_async.rs
@@ -0,0 +1,38 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy::executor::Spawner;
7use embassy::time::{Duration, Timer};
8use embassy_rp::{gpio, Peripherals};
9use gpio::{Input, Level, Output, Pull};
10use {defmt_rtt as _, panic_probe as _};
11
12/// This example shows how async gpio can be used with a RP2040.
13///
14/// It requires an external signal to be manually triggered on PIN 16. For
15/// example, this could be accomplished using an external power source with a
16/// button so that it is possible to toggle the signal from low to high.
17///
18/// This example will begin with turning on the LED on the board and wait for a
19/// high signal on PIN 16. Once the high event/signal occurs the program will
20/// continue and turn off the LED, and then wait for 2 seconds before completing
21/// the loop and starting over again.
22#[embassy::main]
23async fn main(_spawner: Spawner, p: Peripherals) {
24 let mut led = Output::new(p.PIN_25, Level::Low);
25 let mut async_input = Input::new(p.PIN_16, Pull::None);
26
27 loop {
28 info!("wait_for_high. Turn on LED");
29 led.set_high();
30
31 async_input.wait_for_high().await;
32
33 info!("done wait_for_high. Turn off LED");
34 led.set_low();
35
36 Timer::after(Duration::from_secs(2)).await;
37 }
38}
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index b3067fffd..fe791d0d7 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -16,6 +16,7 @@ embedded-hal = "0.2.6"
16embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" } 16embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" }
17embedded-hal-async = { version = "0.1.0-alpha.1" } 17embedded-hal-async = { version = "0.1.0-alpha.1" }
18panic-probe = { version = "0.3.0", features = ["print-defmt"] } 18panic-probe = { version = "0.3.0", features = ["print-defmt"] }
19futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
19 20
20[profile.dev] 21[profile.dev]
21debug = 2 22debug = 2
diff --git a/tests/rp/src/bin/gpio_async.rs b/tests/rp/src/bin/gpio_async.rs
new file mode 100644
index 000000000..46df4105c
--- /dev/null
+++ b/tests/rp/src/bin/gpio_async.rs
@@ -0,0 +1,148 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{assert, *};
6use embassy::executor::Spawner;
7use embassy::time::{Duration, Instant, Timer};
8use embassy_rp::gpio::{Input, Level, Output, Pull};
9use embassy_rp::Peripherals;
10use futures::future::join;
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy::main]
14async fn main(_spawner: Spawner, p: Peripherals) {
15 info!("embassy-rp gpio_async test");
16
17 // On the CI device the following pins are connected with each other.
18 let (mut output_pin, mut input_pin) = (p.PIN_0, p.PIN_1);
19
20 {
21 info!("test wait_for_high");
22 let mut output = Output::new(&mut output_pin, Level::Low);
23 let mut input = Input::new(&mut input_pin, Pull::None);
24
25 assert!(input.is_low(), "input was expected to be low");
26
27 let set_high_future = async {
28 // Allow time for wait_for_high_future to await wait_for_high().
29 Timer::after(Duration::from_millis(10)).await;
30 output.set_high();
31 };
32 let wait_for_high_future = async {
33 let start = Instant::now();
34 input.wait_for_high().await;
35 assert_duration(start);
36 };
37 join(set_high_future, wait_for_high_future).await;
38 info!("test wait_for_high: OK\n");
39 }
40
41 {
42 info!("test wait_for_low");
43 let mut output = Output::new(&mut output_pin, Level::High);
44 let mut input = Input::new(&mut input_pin, Pull::None);
45
46 assert!(input.is_high(), "input was expected to be high");
47
48 let set_low_future = async {
49 Timer::after(Duration::from_millis(10)).await;
50 output.set_low();
51 };
52 let wait_for_low_future = async {
53 let start = Instant::now();
54 input.wait_for_low().await;
55 assert_duration(start);
56 };
57 join(set_low_future, wait_for_low_future).await;
58 info!("test wait_for_low: OK\n");
59 }
60
61 {
62 info!("test wait_for_rising_edge");
63 let mut output = Output::new(&mut output_pin, Level::Low);
64 let mut input = Input::new(&mut input_pin, Pull::None);
65
66 assert!(input.is_low(), "input was expected to be low");
67
68 let set_high_future = async {
69 Timer::after(Duration::from_millis(10)).await;
70 output.set_high();
71 };
72 let wait_for_rising_edge_future = async {
73 let start = Instant::now();
74 input.wait_for_rising_edge().await;
75 assert_duration(start);
76 };
77 join(set_high_future, wait_for_rising_edge_future).await;
78 info!("test wait_for_rising_edge: OK\n");
79 }
80
81 {
82 info!("test wait_for_falling_edge");
83 let mut output = Output::new(&mut output_pin, Level::High);
84 let mut input = Input::new(&mut input_pin, Pull::None);
85
86 assert!(input.is_high(), "input was expected to be high");
87
88 let set_low_future = async {
89 Timer::after(Duration::from_millis(10)).await;
90 output.set_low();
91 };
92 let wait_for_falling_edge_future = async {
93 let start = Instant::now();
94 input.wait_for_falling_edge().await;
95 assert_duration(start);
96 };
97 join(set_low_future, wait_for_falling_edge_future).await;
98 info!("test wait_for_falling_edge: OK\n");
99 }
100
101 {
102 info!("test wait_for_any_edge (falling)");
103 let mut output = Output::new(&mut output_pin, Level::High);
104 let mut input = Input::new(&mut input_pin, Pull::None);
105
106 assert!(input.is_high(), "input was expected to be high");
107
108 let set_low_future = async {
109 Timer::after(Duration::from_millis(10)).await;
110 output.set_low();
111 };
112 let wait_for_any_edge_future = async {
113 let start = Instant::now();
114 input.wait_for_any_edge().await;
115 assert_duration(start);
116 };
117 join(set_low_future, wait_for_any_edge_future).await;
118 info!("test wait_for_any_edge (falling): OK\n");
119 }
120
121 {
122 info!("test wait_for_any_edge (rising)");
123 let mut output = Output::new(&mut output_pin, Level::Low);
124 let mut input = Input::new(&mut input_pin, Pull::None);
125
126 assert!(input.is_low(), "input was expected to be low");
127
128 let set_high_future = async {
129 Timer::after(Duration::from_millis(10)).await;
130 output.set_high();
131 };
132 let wait_for_any_edge_future = async {
133 let start = Instant::now();
134 input.wait_for_any_edge().await;
135 assert_duration(start);
136 };
137 join(set_high_future, wait_for_any_edge_future).await;
138 info!("test wait_for_any_edge (rising): OK\n");
139 }
140
141 info!("Test OK");
142 cortex_m::asm::bkpt();
143
144 fn assert_duration(start: Instant) {
145 let dur = Instant::now() - start;
146 assert!(dur >= Duration::from_millis(10) && dur < Duration::from_millis(11));
147 }
148}