aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2021-03-27 21:24:21 -0500
committerxoviat <[email protected]>2021-03-27 21:24:21 -0500
commit3242990690927e7a1c07774078f1d6a55dced5be (patch)
treeb14960ab0a2a25bf666bd7e634134da1b1346296
parentd4f35c17290ac1c76690cc057c52072054e1485f (diff)
parent19b959b0f8690d7eead40df699c48a37345639b3 (diff)
Merge branch 'master' of https://github.com/akiles/embassy into st-usb
-rw-r--r--.github/workflows/rust.yml3
-rw-r--r--.vscode/settings.json1
-rw-r--r--README.md3
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/src/can.rs (renamed from embassy-stm32f4/src/can.rs)19
-rw-r--r--embassy-stm32/src/exti.rs (renamed from embassy-stm32f4/src/exti.rs)366
-rw-r--r--embassy-stm32/src/interrupt.rs2
-rw-r--r--embassy-stm32/src/lib.rs23
-rw-r--r--embassy-stm32/src/rtc.rs (renamed from embassy-stm32f4/src/rtc.rs)0
-rw-r--r--embassy-stm32f4-examples/src/bin/exti.rs3
-rw-r--r--embassy-stm32f4/Cargo.toml1
-rw-r--r--embassy-stm32f4/src/lib.rs7
-rw-r--r--embassy-stm32f4/src/serial.rs102
-rw-r--r--embassy-stm32l0/src/exti.rs268
-rw-r--r--embassy-stm32l0/src/lib.rs4
-rw-r--r--embassy-traits/src/delay.rs3
-rw-r--r--embassy-traits/src/uart.rs9
-rw-r--r--embassy/src/executor/timer.rs73
-rw-r--r--embassy/src/time/duration.rs13
-rw-r--r--embassy/src/time/instant.rs15
-rw-r--r--embassy/src/time/mod.rs9
-rw-r--r--embassy/src/util/drop_bomb.rs7
-rw-r--r--embassy/src/util/forever.rs24
-rw-r--r--embassy/src/util/mod.rs1
-rw-r--r--embassy/src/util/signal.rs25
25 files changed, 637 insertions, 348 deletions
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 9b3d3b29e..19499632d 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -54,6 +54,9 @@ jobs:
54 features: stm32f405 54 features: stm32f405
55 - package: embassy-stm32f4 55 - package: embassy-stm32f4
56 target: thumbv7em-none-eabi 56 target: thumbv7em-none-eabi
57 features: stm32f446
58 - package: embassy-stm32f4
59 target: thumbv7em-none-eabi
57 features: stm32f405,defmt 60 features: stm32f405,defmt
58 - package: embassy-stm32l0 61 - package: embassy-stm32l0
59 target: thumbv6m-none-eabi 62 target: thumbv6m-none-eabi
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 8a292c0be..58ef9d8af 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,6 +1,7 @@
1{ 1{
2 "rust-analyzer.assist.importMergeBehavior": "last", 2 "rust-analyzer.assist.importMergeBehavior": "last",
3 "editor.formatOnSave": true, 3 "editor.formatOnSave": true,
4 "rust.target": "thumbv7em-none-eabihf",
4 "rust-analyzer.cargo.allFeatures": false, 5 "rust-analyzer.cargo.allFeatures": false,
5 "rust-analyzer.checkOnSave.allFeatures": false, 6 "rust-analyzer.checkOnSave.allFeatures": false,
6 "rust-analyzer.checkOnSave.allTargets": false, 7 "rust-analyzer.checkOnSave.allTargets": false,
diff --git a/README.md b/README.md
index 29c4a2215..03732306e 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
1# Embassy 1# Embassy
2 2
3Embassy is a project to make async/await a first-class option for embedded development. 3Embassy is a project to make async/await a first-class option for embedded development. For more information and instructions to
4get started, click [here](https://github.com/embassy-rs/embassy/wiki).
4 5
5## Traits and types 6## Traits and types
6 7
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 136bd7fc7..66221ed59 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -43,5 +43,7 @@ cortex-m-rt = "0.6.13"
43cortex-m = "0.7.1" 43cortex-m = "0.7.1"
44embedded-hal = { version = "0.2.4" } 44embedded-hal = { version = "0.2.4" }
45embedded-dma = { version = "0.1.2" } 45embedded-dma = { version = "0.1.2" }
46bxcan = "0.5.0"
47nb = "*"
46stm32f4xx-hal = { version = "0.8.3", features = ["rt", "can"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git", optional = true } 48stm32f4xx-hal = { version = "0.8.3", features = ["rt", "can"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git", optional = true }
47stm32l0xx-hal = { version = "0.7.0", features = ["rt"], git = "https://github.com/stm32-rs/stm32l0xx-hal.git", optional = true } \ No newline at end of file 49stm32l0xx-hal = { version = "0.7.0", features = ["rt"], optional = true } \ No newline at end of file
diff --git a/embassy-stm32f4/src/can.rs b/embassy-stm32/src/can.rs
index 526d002c0..f97e900ea 100644
--- a/embassy-stm32f4/src/can.rs
+++ b/embassy-stm32/src/can.rs
@@ -95,6 +95,25 @@ macro_rules! can {
95 } 95 }
96} 96}
97 97
98#[cfg(any(
99 feature = "stm32f401",
100 feature = "stm32f405",
101 feature = "stm32f407",
102 feature = "stm32f410",
103 feature = "stm32f411",
104 feature = "stm32f412",
105 feature = "stm32f413",
106 feature = "stm32f415",
107 feature = "stm32f417",
108 feature = "stm32f423",
109 feature = "stm32f427",
110 feature = "stm32f429",
111 feature = "stm32f437",
112 feature = "stm32f439",
113 feature = "stm32f446",
114 feature = "stm32f469",
115 feature = "stm32f479",
116))]
98can! { 117can! {
99 CAN1 => (CAN1_TX, CAN1_RX0), 118 CAN1 => (CAN1_TX, CAN1_RX0),
100 CAN2 => (CAN2_TX, CAN2_RX0), 119 CAN2 => (CAN2_TX, CAN2_RX0),
diff --git a/embassy-stm32f4/src/exti.rs b/embassy-stm32/src/exti.rs
index 154ca45c1..8d70defe6 100644
--- a/embassy-stm32f4/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -3,35 +3,57 @@ use core::mem;
3use core::pin::Pin; 3use core::pin::Pin;
4use cortex_m; 4use cortex_m;
5 5
6use embassy::traits::gpio::{WaitForFallingEdge, WaitForRisingEdge};
7use embassy::util::InterruptFuture;
8
9use crate::hal::gpio; 6use crate::hal::gpio;
10use crate::hal::gpio::Edge; 7
8#[cfg(any(
9 feature = "stm32f401",
10 feature = "stm32f405",
11 feature = "stm32f407",
12 feature = "stm32f410",
13 feature = "stm32f411",
14 feature = "stm32f412",
15 feature = "stm32f413",
16 feature = "stm32f415",
17 feature = "stm32f417",
18 feature = "stm32f423",
19 feature = "stm32f427",
20 feature = "stm32f429",
21 feature = "stm32f437",
22 feature = "stm32f439",
23 feature = "stm32f446",
24 feature = "stm32f469",
25 feature = "stm32f479",
26))]
11use crate::hal::syscfg::SysCfg; 27use crate::hal::syscfg::SysCfg;
12use crate::pac::EXTI; 28
29#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
30use crate::hal::syscfg::SYSCFG as SysCfg;
31
32use embassy::traits::gpio::{
33 WaitForAnyEdge, WaitForFallingEdge, WaitForHigh, WaitForLow, WaitForRisingEdge,
34};
35use embassy::util::InterruptFuture;
36
13use embedded_hal::digital::v2 as digital; 37use embedded_hal::digital::v2 as digital;
14 38
15use crate::interrupt; 39use crate::interrupt;
16 40
17pub struct ExtiPin<T: gpio::ExtiPin + WithInterrupt> { 41pub struct ExtiPin<T: Instance> {
18 pin: T, 42 pin: T,
19 interrupt: T::Interrupt, 43 interrupt: T::Interrupt,
20} 44}
21 45
22impl<T: gpio::ExtiPin + WithInterrupt> ExtiPin<T> { 46impl<T: Instance> ExtiPin<T> {
23 pub fn new(mut pin: T, interrupt: T::Interrupt) -> Self { 47 pub fn new(mut pin: T, interrupt: T::Interrupt, syscfg: &mut SysCfg) -> Self {
24 let mut syscfg: SysCfg = unsafe { mem::transmute(()) };
25
26 cortex_m::interrupt::free(|_| { 48 cortex_m::interrupt::free(|_| {
27 pin.make_interrupt_source(&mut syscfg); 49 pin.make_source(syscfg);
28 }); 50 });
29 51
30 Self { pin, interrupt } 52 Self { pin, interrupt }
31 } 53 }
32} 54}
33 55
34impl<T: gpio::ExtiPin + WithInterrupt + digital::OutputPin> digital::OutputPin for ExtiPin<T> { 56impl<T: Instance + digital::OutputPin> digital::OutputPin for ExtiPin<T> {
35 type Error = T::Error; 57 type Error = T::Error;
36 58
37 fn set_low(&mut self) -> Result<(), Self::Error> { 59 fn set_low(&mut self) -> Result<(), Self::Error> {
@@ -43,9 +65,7 @@ impl<T: gpio::ExtiPin + WithInterrupt + digital::OutputPin> digital::OutputPin f
43 } 65 }
44} 66}
45 67
46impl<T: gpio::ExtiPin + WithInterrupt + digital::StatefulOutputPin> digital::StatefulOutputPin 68impl<T: Instance + digital::StatefulOutputPin> digital::StatefulOutputPin for ExtiPin<T> {
47 for ExtiPin<T>
48{
49 fn is_set_low(&self) -> Result<bool, Self::Error> { 69 fn is_set_low(&self) -> Result<bool, Self::Error> {
50 self.pin.is_set_low() 70 self.pin.is_set_low()
51 } 71 }
@@ -55,9 +75,7 @@ impl<T: gpio::ExtiPin + WithInterrupt + digital::StatefulOutputPin> digital::Sta
55 } 75 }
56} 76}
57 77
58impl<T: gpio::ExtiPin + WithInterrupt + digital::ToggleableOutputPin> digital::ToggleableOutputPin 78impl<T: Instance + digital::ToggleableOutputPin> digital::ToggleableOutputPin for ExtiPin<T> {
59 for ExtiPin<T>
60{
61 type Error = T::Error; 79 type Error = T::Error;
62 80
63 fn toggle(&mut self) -> Result<(), Self::Error> { 81 fn toggle(&mut self) -> Result<(), Self::Error> {
@@ -65,7 +83,7 @@ impl<T: gpio::ExtiPin + WithInterrupt + digital::ToggleableOutputPin> digital::T
65 } 83 }
66} 84}
67 85
68impl<T: gpio::ExtiPin + WithInterrupt + digital::InputPin> digital::InputPin for ExtiPin<T> { 86impl<T: Instance + digital::InputPin> digital::InputPin for ExtiPin<T> {
69 type Error = T::Error; 87 type Error = T::Error;
70 88
71 fn is_high(&self) -> Result<bool, Self::Error> { 89 fn is_high(&self) -> Result<bool, Self::Error> {
@@ -77,71 +95,129 @@ impl<T: gpio::ExtiPin + WithInterrupt + digital::InputPin> digital::InputPin for
77 } 95 }
78} 96}
79 97
80/* 98impl<T: Instance + digital::InputPin + 'static> ExtiPin<T> {
81 Irq Handler Description 99 fn wait_for_state<'a>(self: Pin<&'a mut Self>, state: bool) -> impl Future<Output = ()> + 'a {
82 EXTI0_IRQn EXTI0_IRQHandler Handler for pins connected to line 0
83 EXTI1_IRQn EXTI1_IRQHandler Handler for pins connected to line 1
84 EXTI2_IRQn EXTI2_IRQHandler Handler for pins connected to line 2
85 EXTI3_IRQn EXTI3_IRQHandler Handler for pins connected to line 3
86 EXTI4_IRQn EXTI4_IRQHandler Handler for pins connected to line 4
87 EXTI9_5_IRQn EXTI9_5_IRQHandler Handler for pins connected to line 5 to 9
88 EXTI15_10_IRQn EXTI15_10_IRQHandler Handler for pins connected to line 10 to 15
89*/
90
91impl<T: gpio::ExtiPin + WithInterrupt + 'static> WaitForRisingEdge for ExtiPin<T> {
92 type Future<'a> = impl Future<Output = ()> + 'a;
93
94 fn wait_for_rising_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
95 let s = unsafe { self.get_unchecked_mut() }; 100 let s = unsafe { self.get_unchecked_mut() };
96 101
97 s.pin.clear_interrupt_pending_bit(); 102 s.pin.clear_pending_bit();
98 async move { 103 async move {
99 let fut = InterruptFuture::new(&mut s.interrupt); 104 let fut = InterruptFuture::new(&mut s.interrupt);
100 let pin = &mut s.pin; 105 let pin = &mut s.pin;
101 cortex_m::interrupt::free(|_| { 106 cortex_m::interrupt::free(|_| {
102 let mut exti: EXTI = unsafe { mem::transmute(()) }; 107 pin.trigger_edge(if state {
103 108 EdgeOption::Rising
104 pin.trigger_on_edge(&mut exti, Edge::RISING); 109 } else {
105 pin.enable_interrupt(&mut exti); 110 EdgeOption::Falling
111 });
106 }); 112 });
113
114 if (state && s.pin.is_high().unwrap_or(false))
115 || (!state && s.pin.is_low().unwrap_or(false))
116 {
117 return;
118 }
119
107 fut.await; 120 fut.await;
108 121
109 s.pin.clear_interrupt_pending_bit(); 122 s.pin.clear_pending_bit();
110 } 123 }
111 } 124 }
112} 125}
113 126
114impl<T: gpio::ExtiPin + WithInterrupt + 'static> WaitForFallingEdge for ExtiPin<T> { 127impl<T: Instance + 'static> ExtiPin<T> {
115 type Future<'a> = impl Future<Output = ()> + 'a; 128 fn wait_for_edge<'a>(
116 129 self: Pin<&'a mut Self>,
117 fn wait_for_falling_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> { 130 state: EdgeOption,
131 ) -> impl Future<Output = ()> + 'a {
118 let s = unsafe { self.get_unchecked_mut() }; 132 let s = unsafe { self.get_unchecked_mut() };
119 133
120 s.pin.clear_interrupt_pending_bit(); 134 s.pin.clear_pending_bit();
121 async move { 135 async move {
122 let fut = InterruptFuture::new(&mut s.interrupt); 136 let fut = InterruptFuture::new(&mut s.interrupt);
123 let pin = &mut s.pin; 137 let pin = &mut s.pin;
124 cortex_m::interrupt::free(|_| { 138 cortex_m::interrupt::free(|_| {
125 let mut exti: EXTI = unsafe { mem::transmute(()) }; 139 pin.trigger_edge(state);
126
127 pin.trigger_on_edge(&mut exti, Edge::FALLING);
128 pin.enable_interrupt(&mut exti);
129 }); 140 });
141
130 fut.await; 142 fut.await;
131 143
132 s.pin.clear_interrupt_pending_bit(); 144 s.pin.clear_pending_bit();
133 } 145 }
134 } 146 }
135} 147}
136 148
149impl<T: Instance + digital::InputPin + 'static> WaitForHigh for ExtiPin<T> {
150 type Future<'a> = impl Future<Output = ()> + 'a;
151
152 fn wait_for_high<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
153 self.wait_for_state(true)
154 }
155}
156
157impl<T: Instance + digital::InputPin + 'static> WaitForLow for ExtiPin<T> {
158 type Future<'a> = impl Future<Output = ()> + 'a;
159
160 fn wait_for_low<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
161 self.wait_for_state(false)
162 }
163}
164
165/*
166 Irq Handler Description
167 EXTI0_IRQn EXTI0_IRQHandler Handler for pins connected to line 0
168 EXTI1_IRQn EXTI1_IRQHandler Handler for pins connected to line 1
169 EXTI2_IRQn EXTI2_IRQHandler Handler for pins connected to line 2
170 EXTI3_IRQn EXTI3_IRQHandler Handler for pins connected to line 3
171 EXTI4_IRQn EXTI4_IRQHandler Handler for pins connected to line 4
172 EXTI9_5_IRQn EXTI9_5_IRQHandler Handler for pins connected to line 5 to 9
173 EXTI15_10_IRQn EXTI15_10_IRQHandler Handler for pins connected to line 10 to 15
174*/
175
176impl<T: Instance + 'static> WaitForRisingEdge for ExtiPin<T> {
177 type Future<'a> = impl Future<Output = ()> + 'a;
178
179 fn wait_for_rising_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
180 self.wait_for_edge(EdgeOption::Rising)
181 }
182}
183
184impl<T: Instance + 'static> WaitForFallingEdge for ExtiPin<T> {
185 type Future<'a> = impl Future<Output = ()> + 'a;
186
187 fn wait_for_falling_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
188 self.wait_for_edge(EdgeOption::Falling)
189 }
190}
191
192impl<T: Instance + 'static> WaitForAnyEdge for ExtiPin<T> {
193 type Future<'a> = impl Future<Output = ()> + 'a;
194
195 fn wait_for_any_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
196 self.wait_for_edge(EdgeOption::RisingFalling)
197 }
198}
199
137mod private { 200mod private {
138 pub trait Sealed {} 201 pub trait Sealed {}
139} 202}
140 203
204#[derive(Copy, Clone)]
205pub enum EdgeOption {
206 Rising,
207 Falling,
208 RisingFalling,
209}
210
141pub trait WithInterrupt: private::Sealed { 211pub trait WithInterrupt: private::Sealed {
142 type Interrupt: interrupt::Interrupt; 212 type Interrupt: interrupt::Interrupt;
143} 213}
144 214
215pub trait Instance: WithInterrupt {
216 fn make_source(&mut self, syscfg: &mut SysCfg);
217 fn clear_pending_bit(&mut self);
218 fn trigger_edge(&mut self, edge: EdgeOption);
219}
220
145macro_rules! exti { 221macro_rules! exti {
146 ($set:ident, [ 222 ($set:ident, [
147 $($INT:ident => $pin:ident,)+ 223 $($INT:ident => $pin:ident,)+
@@ -151,8 +227,88 @@ macro_rules! exti {
151 impl<T> WithInterrupt for gpio::$set::$pin<T> { 227 impl<T> WithInterrupt for gpio::$set::$pin<T> {
152 type Interrupt = interrupt::$INT; 228 type Interrupt = interrupt::$INT;
153 } 229 }
154 )+
155 230
231 #[cfg(any(
232 feature = "stm32f401",
233 feature = "stm32f405",
234 feature = "stm32f407",
235 feature = "stm32f410",
236 feature = "stm32f411",
237 feature = "stm32f412",
238 feature = "stm32f413",
239 feature = "stm32f415",
240 feature = "stm32f417",
241 feature = "stm32f423",
242 feature = "stm32f427",
243 feature = "stm32f429",
244 feature = "stm32f437",
245 feature = "stm32f439",
246 feature = "stm32f446",
247 feature = "stm32f469",
248 feature = "stm32f479",
249 ))]
250 impl<T> Instance for gpio::$set::$pin<gpio::Input<T>> {
251 fn make_source(&mut self, syscfg: &mut SysCfg) {
252 use crate::hal::gpio::ExtiPin;
253 self.make_interrupt_source(syscfg);
254 }
255
256 fn clear_pending_bit(&mut self) {
257 use crate::hal::{gpio::Edge, gpio::ExtiPin, syscfg::SysCfg};
258
259 self.clear_interrupt_pending_bit();
260 }
261
262 fn trigger_edge(&mut self, edge: EdgeOption) {
263 use crate::hal::{gpio::Edge, gpio::ExtiPin, syscfg::SysCfg};
264 use crate::pac::EXTI;
265 let mut exti: EXTI = unsafe { mem::transmute(()) };
266 let edge = match edge {
267 EdgeOption::Falling => Edge::FALLING,
268 EdgeOption::Rising => Edge::RISING,
269 EdgeOption::RisingFalling => Edge::RISING_FALLING,
270 };
271 self.trigger_on_edge(&mut exti, edge);
272 self.enable_interrupt(&mut exti);
273 }
274 }
275
276 #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
277 impl<T> Instance for gpio::$set::$pin<T> {
278 fn make_source(&mut self, syscfg: &mut SysCfg) {}
279
280 fn clear_pending_bit(&mut self) {
281 use crate::hal::{
282 exti::{Exti, ExtiLine, GpioLine, TriggerEdge},
283 syscfg::SYSCFG,
284 };
285
286 Exti::unpend(GpioLine::from_raw_line(self.pin_number()).unwrap());
287 }
288
289 fn trigger_edge(&mut self, edge: EdgeOption) {
290 use crate::hal::{
291 exti::{Exti, ExtiLine, GpioLine, TriggerEdge},
292 syscfg::SYSCFG,
293 };
294
295 use crate::pac::EXTI;
296
297 let edge = match edge {
298 EdgeOption::Falling => TriggerEdge::Falling,
299 EdgeOption::Rising => TriggerEdge::Rising,
300 EdgeOption::RisingFalling => TriggerEdge::Both,
301 };
302
303 let exti: EXTI = unsafe { mem::transmute(()) };
304 let mut exti = Exti::new(exti);
305 let port = self.port();
306 let mut syscfg: SYSCFG = unsafe { mem::transmute(()) };
307 let line = GpioLine::from_raw_line(self.pin_number()).unwrap();
308 exti.listen_gpio(&mut syscfg, port, line, edge);
309 }
310 }
311 )+
156 }; 312 };
157} 313}
158 314
@@ -533,3 +689,111 @@ exti!(gpiok, [
533 EXTI9_5 => PK6, 689 EXTI9_5 => PK6,
534 EXTI9_5 => PK7, 690 EXTI9_5 => PK7,
535]); 691]);
692
693#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
694exti!(gpioa, [
695 EXTI0_1 => PA0,
696 EXTI0_1 => PA1,
697 EXTI2_3 => PA2,
698 EXTI2_3 => PA3,
699 EXTI4_15 => PA4,
700 EXTI4_15 => PA5,
701 EXTI4_15 => PA6,
702 EXTI4_15 => PA7,
703 EXTI4_15 => PA8,
704 EXTI4_15 => PA9,
705 EXTI4_15 => PA10,
706 EXTI4_15 => PA11,
707 EXTI4_15 => PA12,
708 EXTI4_15 => PA13,
709 EXTI4_15 => PA14,
710 EXTI4_15 => PA15,
711]);
712
713#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
714exti!(gpiob, [
715 EXTI0_1 => PB0,
716 EXTI0_1 => PB1,
717 EXTI2_3 => PB2,
718 EXTI2_3 => PB3,
719 EXTI4_15 => PB4,
720 EXTI4_15 => PB5,
721 EXTI4_15 => PB6,
722 EXTI4_15 => PB7,
723 EXTI4_15 => PB8,
724 EXTI4_15 => PB9,
725 EXTI4_15 => PB10,
726 EXTI4_15 => PB11,
727 EXTI4_15 => PB12,
728 EXTI4_15 => PB13,
729 EXTI4_15 => PB14,
730 EXTI4_15 => PB15,
731]);
732
733#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
734exti!(gpioc, [
735 EXTI0_1 => PC0,
736 EXTI0_1 => PC1,
737 EXTI2_3 => PC2,
738 EXTI2_3 => PC3,
739 EXTI4_15 => PC4,
740 EXTI4_15 => PC5,
741 EXTI4_15 => PC6,
742 EXTI4_15 => PC7,
743 EXTI4_15 => PC8,
744 EXTI4_15 => PC9,
745 EXTI4_15 => PC10,
746 EXTI4_15 => PC11,
747 EXTI4_15 => PC12,
748 EXTI4_15 => PC13,
749 EXTI4_15 => PC14,
750 EXTI4_15 => PC15,
751]);
752
753#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
754exti!(gpiod, [
755 EXTI0_1 => PD0,
756 EXTI0_1 => PD1,
757 EXTI2_3 => PD2,
758 EXTI2_3 => PD3,
759 EXTI4_15 => PD4,
760 EXTI4_15 => PD5,
761 EXTI4_15 => PD6,
762 EXTI4_15 => PD7,
763 EXTI4_15 => PD8,
764 EXTI4_15 => PD9,
765 EXTI4_15 => PD10,
766 EXTI4_15 => PD11,
767 EXTI4_15 => PD12,
768 EXTI4_15 => PD13,
769 EXTI4_15 => PD14,
770 EXTI4_15 => PD15,
771]);
772
773#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
774exti!(gpioe, [
775 EXTI0_1 => PE0,
776 EXTI0_1 => PE1,
777 EXTI2_3 => PE2,
778 EXTI2_3 => PE3,
779 EXTI4_15 => PE4,
780 EXTI4_15 => PE5,
781 EXTI4_15 => PE6,
782 EXTI4_15 => PE7,
783 EXTI4_15 => PE8,
784 EXTI4_15 => PE9,
785 EXTI4_15 => PE10,
786 EXTI4_15 => PE11,
787 EXTI4_15 => PE12,
788 EXTI4_15 => PE13,
789 EXTI4_15 => PE14,
790 EXTI4_15 => PE15,
791]);
792
793#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
794exti!(gpioh, [
795 EXTI0_1 => PH0,
796 EXTI0_1 => PH1,
797 EXTI4_15 => PH9,
798 EXTI4_15 => PH10,
799]);
diff --git a/embassy-stm32/src/interrupt.rs b/embassy-stm32/src/interrupt.rs
index 5ad7ef8ef..262bc3d98 100644
--- a/embassy-stm32/src/interrupt.rs
+++ b/embassy-stm32/src/interrupt.rs
@@ -889,7 +889,7 @@ mod irqs {
889 declare!(TIM8_CC); 889 declare!(TIM8_CC);
890 declare!(DMA1_STREAM7); 890 declare!(DMA1_STREAM7);
891 declare!(FMC); 891 declare!(FMC);
892 declare!(SDIO); 892 // declare!(SDIO);
893 declare!(TIM5); 893 declare!(TIM5);
894 declare!(SPI3); 894 declare!(SPI3);
895 declare!(UART4); 895 declare!(UART4);
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index d15d4130e..d098d6995 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -32,12 +32,33 @@ pub use {stm32l0xx_hal as hal, stm32l0xx_hal::pac};
32 32
33pub mod fmt; 33pub mod fmt;
34 34
35pub mod exti;
35pub mod interrupt; 36pub mod interrupt;
36 37
37#[cfg(any( 38#[cfg(any(
38 feature = "stm32f401", 39 feature = "stm32f401",
39 feature = "stm32f405", 40 feature = "stm32f405",
40 feature = "stm32f407", 41 feature = "stm32f407",
42 feature = "stm32f412",
43 feature = "stm32f413",
44 feature = "stm32f415",
45 feature = "stm32f417",
46 feature = "stm32f423",
47 feature = "stm32f427",
48 feature = "stm32f429",
49 feature = "stm32f437",
50 feature = "stm32f439",
51 feature = "stm32f446",
52 feature = "stm32f469",
53 feature = "stm32f479",
54))]
55pub mod can;
56
57#[cfg(any(
58 feature = "stm32f401",
59 feature = "stm32f405",
60 feature = "stm32f407",
61 feature = "stm32f410",
41 feature = "stm32f411", 62 feature = "stm32f411",
42 feature = "stm32f412", 63 feature = "stm32f412",
43 feature = "stm32f413", 64 feature = "stm32f413",
@@ -52,4 +73,6 @@ pub mod interrupt;
52 feature = "stm32f469", 73 feature = "stm32f469",
53 feature = "stm32f479", 74 feature = "stm32f479",
54))] 75))]
76pub mod rtc;
77
55unsafe impl embassy_extras::usb::USBInterrupt for interrupt::OTG_FS {} 78unsafe impl embassy_extras::usb::USBInterrupt for interrupt::OTG_FS {}
diff --git a/embassy-stm32f4/src/rtc.rs b/embassy-stm32/src/rtc.rs
index 824a47072..824a47072 100644
--- a/embassy-stm32f4/src/rtc.rs
+++ b/embassy-stm32/src/rtc.rs
diff --git a/embassy-stm32f4-examples/src/bin/exti.rs b/embassy-stm32f4-examples/src/bin/exti.rs
index 2201189eb..9b2535b1c 100644
--- a/embassy-stm32f4-examples/src/bin/exti.rs
+++ b/embassy-stm32f4-examples/src/bin/exti.rs
@@ -24,8 +24,9 @@ async fn run(dp: stm32::Peripherals, _cp: cortex_m::Peripherals) {
24 let gpioa = dp.GPIOA.split(); 24 let gpioa = dp.GPIOA.split();
25 25
26 let button = gpioa.pa0.into_pull_up_input(); 26 let button = gpioa.pa0.into_pull_up_input();
27 let mut syscfg = dp.SYSCFG.constrain();
27 28
28 let pin = ExtiPin::new(button, interrupt::take!(EXTI0)); 29 let pin = ExtiPin::new(button, interrupt::take!(EXTI0), &mut syscfg);
29 pin_mut!(pin); 30 pin_mut!(pin);
30 31
31 info!("Starting loop"); 32 info!("Starting loop");
diff --git a/embassy-stm32f4/Cargo.toml b/embassy-stm32f4/Cargo.toml
index 5375261c2..8e9b14f03 100644
--- a/embassy-stm32f4/Cargo.toml
+++ b/embassy-stm32f4/Cargo.toml
@@ -37,6 +37,7 @@ defmt = { version = "0.2.0", optional = true }
37log = { version = "0.4.11", optional = true } 37log = { version = "0.4.11", optional = true }
38cortex-m-rt = "0.6.13" 38cortex-m-rt = "0.6.13"
39cortex-m = "0.7.1" 39cortex-m = "0.7.1"
40futures = { version = "0.3.5", default-features = false, features = ["async-await"] }
40embedded-hal = { version = "0.2.4" } 41embedded-hal = { version = "0.2.4" }
41embedded-dma = { version = "0.1.2" } 42embedded-dma = { version = "0.1.2" }
42stm32f4xx-hal = { version = "0.8.3", features = ["rt", "can"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"} 43stm32f4xx-hal = { version = "0.8.3", features = ["rt", "can"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"}
diff --git a/embassy-stm32f4/src/lib.rs b/embassy-stm32f4/src/lib.rs
index 0d490525c..eb6f04f88 100644
--- a/embassy-stm32f4/src/lib.rs
+++ b/embassy-stm32f4/src/lib.rs
@@ -307,12 +307,11 @@ compile_error!(
307 "Multile chip features activated. You must activate exactly one of the following features: " 307 "Multile chip features activated. You must activate exactly one of the following features: "
308); 308);
309 309
310pub use embassy_stm32::{fmt, hal, interrupt, pac}; 310pub use embassy_stm32::{exti, fmt, hal, interrupt, pac, rtc};
311 311
312#[cfg(not(any(feature = "stm32f401", feature = "stm32f410", feature = "stm32f411",)))] 312#[cfg(not(any(feature = "stm32f401", feature = "stm32f410", feature = "stm32f411",)))]
313pub mod can; 313pub use embassy_stm32::can;
314pub mod exti; 314
315#[cfg(not(feature = "stm32f410"))] 315#[cfg(not(feature = "stm32f410"))]
316pub mod qei; 316pub mod qei;
317pub mod rtc;
318pub mod serial; 317pub mod serial;
diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs
index 87d0caaaf..c8dc0598a 100644
--- a/embassy-stm32f4/src/serial.rs
+++ b/embassy-stm32f4/src/serial.rs
@@ -7,8 +7,10 @@
7use core::future::Future; 7use core::future::Future;
8use core::marker::PhantomData; 8use core::marker::PhantomData;
9 9
10use futures::{select_biased, FutureExt};
11
10use embassy::interrupt::Interrupt; 12use embassy::interrupt::Interrupt;
11use embassy::traits::uart::{Error, Uart}; 13use embassy::traits::uart::{Error, IdleUart, Uart};
12use embassy::util::InterruptFuture; 14use embassy::util::InterruptFuture;
13 15
14use crate::hal::{ 16use crate::hal::{
@@ -19,7 +21,7 @@ use crate::hal::{
19 rcc::Clocks, 21 rcc::Clocks,
20 serial, 22 serial,
21 serial::config::{Config as SerialConfig, DmaConfig as SerialDmaConfig}, 23 serial::config::{Config as SerialConfig, DmaConfig as SerialDmaConfig},
22 serial::{Event as SerialEvent, Pins, Serial as HalSerial}, 24 serial::{Event as SerialEvent, Pins},
23}; 25};
24use crate::interrupt; 26use crate::interrupt;
25use crate::pac; 27use crate::pac;
@@ -29,14 +31,14 @@ pub struct Serial<
29 USART: PeriAddress<MemSize = u8> + WithInterrupt, 31 USART: PeriAddress<MemSize = u8> + WithInterrupt,
30 TSTREAM: Stream + WithInterrupt, 32 TSTREAM: Stream + WithInterrupt,
31 RSTREAM: Stream + WithInterrupt, 33 RSTREAM: Stream + WithInterrupt,
32 CHANNEL: dma::traits::Channel, 34 CHANNEL: Channel,
33> { 35> {
34 tx_stream: Option<TSTREAM>, 36 tx_stream: Option<TSTREAM>,
35 rx_stream: Option<RSTREAM>, 37 rx_stream: Option<RSTREAM>,
36 usart: Option<USART>, 38 usart: Option<USART>,
37 tx_int: TSTREAM::Interrupt, 39 tx_int: TSTREAM::Interrupt,
38 rx_int: RSTREAM::Interrupt, 40 rx_int: RSTREAM::Interrupt,
39 _usart_int: USART::Interrupt, 41 usart_int: USART::Interrupt,
40 channel: PhantomData<CHANNEL>, 42 channel: PhantomData<CHANNEL>,
41} 43}
42 44
@@ -68,12 +70,10 @@ where
68 PINS: Pins<USART>, 70 PINS: Pins<USART>,
69 { 71 {
70 config.dma = SerialDmaConfig::TxRx; 72 config.dma = SerialDmaConfig::TxRx;
71 let mut serial = HalSerial::new(usart, pins, config, clocks).unwrap();
72 73
73 serial.listen(SerialEvent::Idle); 74 let (usart, _) = serial::Serial::new(usart, pins, config, clocks)
74 // serial.listen(SerialEvent::Txe); 75 .unwrap()
75 76 .release();
76 let (usart, _) = serial.release();
77 77
78 let (tx_stream, rx_stream) = streams; 78 let (tx_stream, rx_stream) = streams;
79 79
@@ -83,8 +83,8 @@ where
83 usart: Some(usart), 83 usart: Some(usart),
84 tx_int: tx_int, 84 tx_int: tx_int,
85 rx_int: rx_int, 85 rx_int: rx_int,
86 _usart_int: usart_int, 86 usart_int: usart_int,
87 channel: core::marker::PhantomData, 87 channel: PhantomData,
88 } 88 }
89 } 89 }
90} 90}
@@ -127,10 +127,10 @@ where
127 let fut = InterruptFuture::new(&mut self.tx_int); 127 let fut = InterruptFuture::new(&mut self.tx_int);
128 128
129 tx_transfer.start(|_usart| {}); 129 tx_transfer.start(|_usart| {});
130
131 fut.await; 130 fut.await;
132 131
133 let (tx_stream, usart, _buf, _) = tx_transfer.free(); 132 let (tx_stream, usart, _buf, _) = tx_transfer.free();
133
134 self.tx_stream.replace(tx_stream); 134 self.tx_stream.replace(tx_stream);
135 self.usart.replace(usart); 135 self.usart.replace(usart);
136 136
@@ -163,7 +163,6 @@ where
163 ); 163 );
164 164
165 let fut = InterruptFuture::new(&mut self.rx_int); 165 let fut = InterruptFuture::new(&mut self.rx_int);
166
167 rx_transfer.start(|_usart| {}); 166 rx_transfer.start(|_usart| {});
168 fut.await; 167 fut.await;
169 168
@@ -176,6 +175,79 @@ where
176 } 175 }
177} 176}
178 177
178impl<USART, TSTREAM, RSTREAM, CHANNEL> IdleUart for Serial<USART, TSTREAM, RSTREAM, CHANNEL>
179where
180 USART: serial::Instance
181 + PeriAddress<MemSize = u8>
182 + DMASet<TSTREAM, CHANNEL, MemoryToPeripheral>
183 + DMASet<RSTREAM, CHANNEL, PeripheralToMemory>
184 + WithInterrupt
185 + 'static,
186 TSTREAM: Stream + WithInterrupt + 'static,
187 RSTREAM: Stream + WithInterrupt + 'static,
188 CHANNEL: Channel + 'static,
189{
190 type ReceiveFuture<'a> = impl Future<Output = Result<usize, Error>> + 'a;
191
192 /// Receives serial data.
193 ///
194 /// The future is pending until either the buffer is completely full, or the RX line falls idle after receiving some data.
195 ///
196 /// Returns the number of bytes read.
197 fn receive_until_idle<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a> {
198 let static_buf = unsafe { core::mem::transmute::<&'a mut [u8], &'static mut [u8]>(buf) };
199
200 let rx_stream = self.rx_stream.take().unwrap();
201 let usart = self.usart.take().unwrap();
202
203 async move {
204 unsafe {
205 /* __HAL_UART_ENABLE_IT(&uart->UartHandle, UART_IT_IDLE); */
206 (*USART::ptr()).cr1.modify(|_, w| w.idleie().set_bit());
207
208 /* __HAL_UART_CLEAR_IDLEFLAG(&uart->UartHandle); */
209 (*USART::ptr()).sr.read();
210 (*USART::ptr()).dr.read();
211 };
212
213 let mut rx_transfer = Transfer::init(
214 rx_stream,
215 usart,
216 static_buf,
217 None,
218 DmaConfig::default()
219 .transfer_complete_interrupt(true)
220 .memory_increment(true)
221 .double_buffer(false),
222 );
223
224 let total_bytes = RSTREAM::get_number_of_transfers() as usize;
225
226 let fut = InterruptFuture::new(&mut self.rx_int);
227 let fut_idle = InterruptFuture::new(&mut self.usart_int);
228
229 rx_transfer.start(|_usart| {});
230
231 select_biased! {
232 () = fut.fuse() => {},
233 () = fut_idle.fuse() => {},
234 }
235
236 let (rx_stream, usart, _, _) = rx_transfer.free();
237
238 let remaining_bytes = RSTREAM::get_number_of_transfers() as usize;
239
240 unsafe {
241 (*USART::ptr()).cr1.modify(|_, w| w.idleie().clear_bit());
242 }
243 self.rx_stream.replace(rx_stream);
244 self.usart.replace(usart);
245
246 Ok(total_bytes - remaining_bytes)
247 }
248 }
249}
250
179mod private { 251mod private {
180 pub trait Sealed {} 252 pub trait Sealed {}
181} 253}
@@ -278,6 +350,6 @@ usart! {
278 350
279 UART4 => (UART4), 351 UART4 => (UART4),
280 UART5 => (UART5), 352 UART5 => (UART5),
281 UART7 => (UART7), 353// UART7 => (UART7),
282 UART8 => (UART8), 354// UART8 => (UART8),
283} 355}
diff --git a/embassy-stm32l0/src/exti.rs b/embassy-stm32l0/src/exti.rs
deleted file mode 100644
index f50c3ae8e..000000000
--- a/embassy-stm32l0/src/exti.rs
+++ /dev/null
@@ -1,268 +0,0 @@
1use core::future::Future;
2use core::mem;
3use core::pin::Pin;
4
5use embassy::traits::gpio::{
6 WaitForAnyEdge, WaitForFallingEdge, WaitForHigh, WaitForLow, WaitForRisingEdge,
7};
8use embassy::util::InterruptFuture;
9
10use crate::hal::{
11 exti::{Exti, ExtiLine, GpioLine, TriggerEdge},
12 gpio,
13 syscfg::SYSCFG,
14};
15use crate::interrupt;
16use crate::pac::EXTI;
17use embedded_hal::digital::v2::InputPin;
18
19pub struct ExtiPin<T: PinWithInterrupt> {
20 pin: T,
21 interrupt: T::Interrupt,
22}
23
24impl<T: PinWithInterrupt + 'static> ExtiPin<T> {
25 pub fn new(pin: T, interrupt: T::Interrupt) -> ExtiPin<T> {
26 ExtiPin { pin, interrupt }
27 }
28
29 fn wait_for_edge<'a>(
30 self: Pin<&'a mut Self>,
31 edge: TriggerEdge,
32 ) -> impl Future<Output = ()> + 'a {
33 let line = self.pin.line();
34 let s = unsafe { self.get_unchecked_mut() };
35
36 Exti::unpend(line);
37
38 async move {
39 let exti: EXTI = unsafe { mem::transmute(()) };
40 let mut exti = Exti::new(exti);
41
42 let fut = InterruptFuture::new(&mut s.interrupt);
43
44 let port = s.pin.port();
45 cortex_m::interrupt::free(|_| {
46 let mut syscfg: SYSCFG = unsafe { mem::transmute(()) };
47 exti.listen_gpio(&mut syscfg, port, line, edge);
48 });
49
50 fut.await;
51
52 Exti::unpend(line);
53 }
54 }
55}
56
57impl<T: InputPin + PinWithInterrupt + 'static> ExtiPin<T> {
58 fn wait_for_state<'a>(self: Pin<&'a mut Self>, state: bool) -> impl Future<Output = ()> + 'a {
59 let line = self.pin.line();
60 let s = unsafe { self.get_unchecked_mut() };
61
62 Exti::unpend(line);
63
64 async move {
65 let exti: EXTI = unsafe { mem::transmute(()) };
66 let mut exti = Exti::new(exti);
67
68 let fut = InterruptFuture::new(&mut s.interrupt);
69
70 let port = s.pin.port();
71 cortex_m::interrupt::free(|_| {
72 let mut syscfg: SYSCFG = unsafe { mem::transmute(()) };
73 let edge = if state {
74 TriggerEdge::Rising
75 } else {
76 TriggerEdge::Falling
77 };
78 exti.listen_gpio(&mut syscfg, port, line, edge);
79 });
80
81 let pin_has_state = if state {
82 s.pin.is_high()
83 } else {
84 s.pin.is_low()
85 }
86 .unwrap_or(false);
87 if pin_has_state {
88 return ();
89 }
90
91 fut.await;
92
93 Exti::unpend(line);
94 }
95 }
96}
97
98impl<T: PinWithInterrupt + 'static> WaitForRisingEdge for ExtiPin<T> {
99 type Future<'a> = impl Future<Output = ()> + 'a;
100
101 fn wait_for_rising_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
102 self.wait_for_edge(TriggerEdge::Rising)
103 }
104}
105
106impl<T: PinWithInterrupt + 'static> WaitForFallingEdge for ExtiPin<T> {
107 type Future<'a> = impl Future<Output = ()> + 'a;
108
109 fn wait_for_falling_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
110 self.wait_for_edge(TriggerEdge::Falling)
111 }
112}
113
114impl<T: PinWithInterrupt + 'static> WaitForAnyEdge for ExtiPin<T> {
115 type Future<'a> = impl Future<Output = ()> + 'a;
116
117 fn wait_for_any_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
118 self.wait_for_edge(TriggerEdge::Both)
119 }
120}
121
122impl<T: InputPin + PinWithInterrupt + 'static> WaitForHigh for ExtiPin<T> {
123 type Future<'a> = impl Future<Output = ()> + 'a;
124
125 fn wait_for_high<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
126 self.wait_for_state(true)
127 }
128}
129
130impl<T: InputPin + PinWithInterrupt + 'static> WaitForLow for ExtiPin<T> {
131 type Future<'a> = impl Future<Output = ()> + 'a;
132
133 fn wait_for_low<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
134 self.wait_for_state(false)
135 }
136}
137
138mod private {
139 pub trait Sealed {}
140}
141
142pub trait PinWithInterrupt: private::Sealed {
143 type Interrupt: interrupt::Interrupt;
144 fn port(&self) -> gpio::Port;
145 fn line(&self) -> GpioLine;
146}
147
148macro_rules! exti {
149 ($set:ident, [
150 $($INT:ident => $pin:ident,)+
151 ]) => {
152 $(
153 impl<T> private::Sealed for gpio::$set::$pin<T> {}
154 impl<T> PinWithInterrupt for gpio::$set::$pin<T> {
155 type Interrupt = interrupt::$INT;
156 fn port(&self) -> gpio::Port {
157 self.port()
158 }
159 fn line(&self) -> GpioLine {
160 GpioLine::from_raw_line(self.pin_number()).unwrap()
161 }
162 }
163 )+
164
165 };
166}
167
168exti!(gpioa, [
169 EXTI0_1 => PA0,
170 EXTI0_1 => PA1,
171 EXTI2_3 => PA2,
172 EXTI2_3 => PA3,
173 EXTI4_15 => PA4,
174 EXTI4_15 => PA5,
175 EXTI4_15 => PA6,
176 EXTI4_15 => PA7,
177 EXTI4_15 => PA8,
178 EXTI4_15 => PA9,
179 EXTI4_15 => PA10,
180 EXTI4_15 => PA11,
181 EXTI4_15 => PA12,
182 EXTI4_15 => PA13,
183 EXTI4_15 => PA14,
184 EXTI4_15 => PA15,
185]);
186
187exti!(gpiob, [
188 EXTI0_1 => PB0,
189 EXTI0_1 => PB1,
190 EXTI2_3 => PB2,
191 EXTI2_3 => PB3,
192 EXTI4_15 => PB4,
193 EXTI4_15 => PB5,
194 EXTI4_15 => PB6,
195 EXTI4_15 => PB7,
196 EXTI4_15 => PB8,
197 EXTI4_15 => PB9,
198 EXTI4_15 => PB10,
199 EXTI4_15 => PB11,
200 EXTI4_15 => PB12,
201 EXTI4_15 => PB13,
202 EXTI4_15 => PB14,
203 EXTI4_15 => PB15,
204]);
205
206exti!(gpioc, [
207 EXTI0_1 => PC0,
208 EXTI0_1 => PC1,
209 EXTI2_3 => PC2,
210 EXTI2_3 => PC3,
211 EXTI4_15 => PC4,
212 EXTI4_15 => PC5,
213 EXTI4_15 => PC6,
214 EXTI4_15 => PC7,
215 EXTI4_15 => PC8,
216 EXTI4_15 => PC9,
217 EXTI4_15 => PC10,
218 EXTI4_15 => PC11,
219 EXTI4_15 => PC12,
220 EXTI4_15 => PC13,
221 EXTI4_15 => PC14,
222 EXTI4_15 => PC15,
223]);
224
225exti!(gpiod, [
226 EXTI0_1 => PD0,
227 EXTI0_1 => PD1,
228 EXTI2_3 => PD2,
229 EXTI2_3 => PD3,
230 EXTI4_15 => PD4,
231 EXTI4_15 => PD5,
232 EXTI4_15 => PD6,
233 EXTI4_15 => PD7,
234 EXTI4_15 => PD8,
235 EXTI4_15 => PD9,
236 EXTI4_15 => PD10,
237 EXTI4_15 => PD11,
238 EXTI4_15 => PD12,
239 EXTI4_15 => PD13,
240 EXTI4_15 => PD14,
241 EXTI4_15 => PD15,
242]);
243
244exti!(gpioe, [
245 EXTI0_1 => PE0,
246 EXTI0_1 => PE1,
247 EXTI2_3 => PE2,
248 EXTI2_3 => PE3,
249 EXTI4_15 => PE4,
250 EXTI4_15 => PE5,
251 EXTI4_15 => PE6,
252 EXTI4_15 => PE7,
253 EXTI4_15 => PE8,
254 EXTI4_15 => PE9,
255 EXTI4_15 => PE10,
256 EXTI4_15 => PE11,
257 EXTI4_15 => PE12,
258 EXTI4_15 => PE13,
259 EXTI4_15 => PE14,
260 EXTI4_15 => PE15,
261]);
262
263exti!(gpioh, [
264 EXTI0_1 => PH0,
265 EXTI0_1 => PH1,
266 EXTI4_15 => PH9,
267 EXTI4_15 => PH10,
268]);
diff --git a/embassy-stm32l0/src/lib.rs b/embassy-stm32l0/src/lib.rs
index e80fe6cb4..a684c4e3e 100644
--- a/embassy-stm32l0/src/lib.rs
+++ b/embassy-stm32l0/src/lib.rs
@@ -19,6 +19,4 @@ compile_error!(
19 "Multile chip features activated. You must activate exactly one of the following features: " 19 "Multile chip features activated. You must activate exactly one of the following features: "
20); 20);
21 21
22pub use embassy_stm32::{fmt, hal, interrupt, pac}; 22pub use embassy_stm32::{exti, fmt, hal, interrupt, pac};
23
24pub mod exti;
diff --git a/embassy-traits/src/delay.rs b/embassy-traits/src/delay.rs
index b893ee4a3..1e763350b 100644
--- a/embassy-traits/src/delay.rs
+++ b/embassy-traits/src/delay.rs
@@ -4,6 +4,9 @@ use core::pin::Pin;
4pub trait Delay { 4pub trait Delay {
5 type DelayFuture<'a>: Future<Output = ()> + 'a; 5 type DelayFuture<'a>: Future<Output = ()> + 'a;
6 6
7 /// Future that completes after now + millis
7 fn delay_ms<'a>(self: Pin<&'a mut Self>, millis: u64) -> Self::DelayFuture<'a>; 8 fn delay_ms<'a>(self: Pin<&'a mut Self>, millis: u64) -> Self::DelayFuture<'a>;
9
10 /// Future that completes after now + micros
8 fn delay_us<'a>(self: Pin<&'a mut Self>, micros: u64) -> Self::DelayFuture<'a>; 11 fn delay_us<'a>(self: Pin<&'a mut Self>, micros: u64) -> Self::DelayFuture<'a>;
9} 12}
diff --git a/embassy-traits/src/uart.rs b/embassy-traits/src/uart.rs
index b40b9e9bd..441747181 100644
--- a/embassy-traits/src/uart.rs
+++ b/embassy-traits/src/uart.rs
@@ -10,6 +10,15 @@ pub enum Error {
10pub trait Uart { 10pub trait Uart {
11 type ReceiveFuture<'a>: Future<Output = Result<(), Error>>; 11 type ReceiveFuture<'a>: Future<Output = Result<(), Error>>;
12 type SendFuture<'a>: Future<Output = Result<(), Error>>; 12 type SendFuture<'a>: Future<Output = Result<(), Error>>;
13 /// Receive into the buffer until the buffer is full
13 fn receive<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a>; 14 fn receive<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a>;
15 /// Send the specified buffer, and return when the transmission has completed
14 fn send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a>; 16 fn send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a>;
15} 17}
18
19pub trait IdleUart {
20 type ReceiveFuture<'a>: Future<Output = Result<usize, Error>>;
21 /// Receive into the buffer until the buffer is full or the line is idle after some bytes are received
22 /// Return the number of bytes received
23 fn receive_until_idle<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a>;
24}
diff --git a/embassy/src/executor/timer.rs b/embassy/src/executor/timer.rs
index 256ecf665..541f96f59 100644
--- a/embassy/src/executor/timer.rs
+++ b/embassy/src/executor/timer.rs
@@ -7,6 +7,7 @@ use futures::Stream;
7use super::raw; 7use super::raw;
8use crate::time::{Duration, Instant}; 8use crate::time::{Duration, Instant};
9 9
10/// Delay abstraction using embassy's clock.
10pub struct Delay { 11pub struct Delay {
11 _data: PhantomData<bool>, 12 _data: PhantomData<bool>,
12} 13}
@@ -30,12 +31,14 @@ impl crate::traits::delay::Delay for Delay {
30 } 31 }
31} 32}
32 33
34/// A future that completes at a specified [Instant](struct.Instant.html).
33pub struct Timer { 35pub struct Timer {
34 expires_at: Instant, 36 expires_at: Instant,
35 yielded_once: bool, 37 yielded_once: bool,
36} 38}
37 39
38impl Timer { 40impl Timer {
41 /// Expire at specified [Instant](struct.Instant.html)
39 pub fn at(expires_at: Instant) -> Self { 42 pub fn at(expires_at: Instant) -> Self {
40 Self { 43 Self {
41 expires_at, 44 expires_at,
@@ -43,6 +46,26 @@ impl Timer {
43 } 46 }
44 } 47 }
45 48
49 /// Expire after specified [Duration](struct.Duration.html).
50 /// This can be used as a `sleep` abstraction.
51 ///
52 /// Example:
53 /// ``` no_run
54 /// # #![feature(trait_alias)]
55 /// # #![feature(min_type_alias_impl_trait)]
56 /// # #![feature(impl_trait_in_bindings)]
57 /// # #![feature(type_alias_impl_trait)]
58 /// #
59 /// # fn foo() {}
60 /// use embassy::executor::task;
61 /// use embassy::time::{Duration, Timer};
62 ///
63 /// #[task]
64 /// async fn demo_sleep_seconds() {
65 /// // suspend this task for one second.
66 /// Timer::after(Duration::from_secs(1)).await;
67 /// }
68 /// ```
46 pub fn after(duration: Duration) -> Self { 69 pub fn after(duration: Duration) -> Self {
47 Self { 70 Self {
48 expires_at: Instant::now() + duration, 71 expires_at: Instant::now() + duration,
@@ -66,12 +89,62 @@ impl Future for Timer {
66 } 89 }
67} 90}
68 91
92/// Asynchronous stream that yields every Duration, indefinitely.
93///
94/// This stream will tick at uniform intervals, even if blocking work is performed between ticks.
95///
96/// For instance, consider the following code fragment.
97/// ``` no_run
98/// # #![feature(trait_alias)]
99/// # #![feature(min_type_alias_impl_trait)]
100/// # #![feature(impl_trait_in_bindings)]
101/// # #![feature(type_alias_impl_trait)]
102/// #
103/// use embassy::executor::task;
104/// use embassy::time::{Duration, Timer};
105/// # fn foo() {}
106///
107/// #[task]
108/// async fn ticker_example_0() {
109/// loop {
110/// foo();
111/// Timer::after(Duration::from_secs(1)).await;
112/// }
113/// }
114/// ```
115///
116/// This fragment will not call `foo` every second.
117/// Instead, it will call it every second + the time it took to previously call `foo`.
118///
119/// Example using ticker, which will consistently call `foo` once a second.
120///
121/// ``` no_run
122/// # #![feature(trait_alias)]
123/// # #![feature(min_type_alias_impl_trait)]
124/// # #![feature(impl_trait_in_bindings)]
125/// # #![feature(type_alias_impl_trait)]
126/// #
127/// use embassy::executor::task;
128/// use embassy::time::{Duration, Ticker};
129/// use futures::StreamExt;
130/// # fn foo(){}
131///
132/// #[task]
133/// async fn ticker_example_1() {
134/// let mut ticker = Ticker::every(Duration::from_secs(1));
135/// loop {
136/// foo();
137/// ticker.next().await;
138/// }
139/// }
140/// ```
69pub struct Ticker { 141pub struct Ticker {
70 expires_at: Instant, 142 expires_at: Instant,
71 duration: Duration, 143 duration: Duration,
72} 144}
73 145
74impl Ticker { 146impl Ticker {
147 /// Creates a new ticker that ticks at the specified duration interval.
75 pub fn every(duration: Duration) -> Self { 148 pub fn every(duration: Duration) -> Self {
76 let expires_at = Instant::now() + duration; 149 let expires_at = Instant::now() + duration;
77 Self { 150 Self {
diff --git a/embassy/src/time/duration.rs b/embassy/src/time/duration.rs
index e04afa184..5157450ad 100644
--- a/embassy/src/time/duration.rs
+++ b/embassy/src/time/duration.rs
@@ -5,6 +5,7 @@ use super::TICKS_PER_SECOND;
5 5
6#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 6#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))] 7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8/// Represents the difference between two [Instant](struct.Instant.html)s
8pub struct Duration { 9pub struct Duration {
9 pub(crate) ticks: u64, 10 pub(crate) ticks: u64,
10} 11}
@@ -26,49 +27,55 @@ impl Duration {
26 self.ticks * 1_000_000 / TICKS_PER_SECOND 27 self.ticks * 1_000_000 / TICKS_PER_SECOND
27 } 28 }
28 29
30 /// Creates a duration from the specified number of clock ticks
29 pub const fn from_ticks(ticks: u64) -> Duration { 31 pub const fn from_ticks(ticks: u64) -> Duration {
30 Duration { ticks } 32 Duration { ticks }
31 } 33 }
32 34
35 /// Creates a duration from the specified number of seconds
33 pub const fn from_secs(secs: u64) -> Duration { 36 pub const fn from_secs(secs: u64) -> Duration {
34 Duration { 37 Duration {
35 ticks: secs * TICKS_PER_SECOND, 38 ticks: secs * TICKS_PER_SECOND,
36 } 39 }
37 } 40 }
38 41
42 /// Creates a duration from the specified number of milliseconds
39 pub const fn from_millis(millis: u64) -> Duration { 43 pub const fn from_millis(millis: u64) -> Duration {
40 Duration { 44 Duration {
41 ticks: millis * TICKS_PER_SECOND / 1000, 45 ticks: millis * TICKS_PER_SECOND / 1000,
42 } 46 }
43 } 47 }
44 48
45 /* 49 /// Creates a duration from the specified number of microseconds
46 NOTE: us delays may not be as accurate 50 /// NOTE: Delays this small may be inaccurate.
47 */
48 pub const fn from_micros(micros: u64) -> Duration { 51 pub const fn from_micros(micros: u64) -> Duration {
49 Duration { 52 Duration {
50 ticks: micros * TICKS_PER_SECOND / 1_000_000, 53 ticks: micros * TICKS_PER_SECOND / 1_000_000,
51 } 54 }
52 } 55 }
53 56
57 /// Adds one Duration to another, returning a new Duration or None in the event of an overflow.
54 pub fn checked_add(self, rhs: Duration) -> Option<Duration> { 58 pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
55 self.ticks 59 self.ticks
56 .checked_add(rhs.ticks) 60 .checked_add(rhs.ticks)
57 .map(|ticks| Duration { ticks }) 61 .map(|ticks| Duration { ticks })
58 } 62 }
59 63
64 /// Subtracts one Duration to another, returning a new Duration or None in the event of an overflow.
60 pub fn checked_sub(self, rhs: Duration) -> Option<Duration> { 65 pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
61 self.ticks 66 self.ticks
62 .checked_sub(rhs.ticks) 67 .checked_sub(rhs.ticks)
63 .map(|ticks| Duration { ticks }) 68 .map(|ticks| Duration { ticks })
64 } 69 }
65 70
71 /// Multiplies one Duration by a scalar u32, returning a new Duration or None in the event of an overflow.
66 pub fn checked_mul(self, rhs: u32) -> Option<Duration> { 72 pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
67 self.ticks 73 self.ticks
68 .checked_mul(rhs as _) 74 .checked_mul(rhs as _)
69 .map(|ticks| Duration { ticks }) 75 .map(|ticks| Duration { ticks })
70 } 76 }
71 77
78 /// Divides one Duration a scalar u32, returning a new Duration or None in the event of an overflow.
72 pub fn checked_div(self, rhs: u32) -> Option<Duration> { 79 pub fn checked_div(self, rhs: u32) -> Option<Duration> {
73 self.ticks 80 self.ticks
74 .checked_div(rhs as _) 81 .checked_div(rhs as _)
diff --git a/embassy/src/time/instant.rs b/embassy/src/time/instant.rs
index 06ab84c75..61a61defe 100644
--- a/embassy/src/time/instant.rs
+++ b/embassy/src/time/instant.rs
@@ -6,6 +6,7 @@ use super::{now, Duration};
6 6
7#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 7#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))] 8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9/// An Instant in time, based on the MCU's clock ticks since startup.
9pub struct Instant { 10pub struct Instant {
10 ticks: u64, 11 ticks: u64,
11} 12}
@@ -14,44 +15,55 @@ impl Instant {
14 pub const MIN: Instant = Instant { ticks: u64::MIN }; 15 pub const MIN: Instant = Instant { ticks: u64::MIN };
15 pub const MAX: Instant = Instant { ticks: u64::MAX }; 16 pub const MAX: Instant = Instant { ticks: u64::MAX };
16 17
18 /// Returns an Instant representing the current time.
17 pub fn now() -> Instant { 19 pub fn now() -> Instant {
18 Instant { ticks: now() } 20 Instant { ticks: now() }
19 } 21 }
20 22
23 /// Instant as clock ticks since MCU start.
21 pub const fn from_ticks(ticks: u64) -> Self { 24 pub const fn from_ticks(ticks: u64) -> Self {
22 Self { ticks } 25 Self { ticks }
23 } 26 }
24 27
28 /// Instant as milliseconds since MCU start.
25 pub const fn from_millis(millis: u64) -> Self { 29 pub const fn from_millis(millis: u64) -> Self {
26 Self { 30 Self {
27 ticks: millis * TICKS_PER_SECOND as u64 / 1000, 31 ticks: millis * TICKS_PER_SECOND as u64 / 1000,
28 } 32 }
29 } 33 }
30 34
35 /// Instant representing seconds since MCU start.
31 pub const fn from_secs(seconds: u64) -> Self { 36 pub const fn from_secs(seconds: u64) -> Self {
32 Self { 37 Self {
33 ticks: seconds * TICKS_PER_SECOND as u64, 38 ticks: seconds * TICKS_PER_SECOND as u64,
34 } 39 }
35 } 40 }
36 41
42 /// Instant as ticks since MCU start.
43
37 pub const fn as_ticks(&self) -> u64 { 44 pub const fn as_ticks(&self) -> u64 {
38 self.ticks 45 self.ticks
39 } 46 }
47 /// Instant as seconds since MCU start.
40 48
41 pub const fn as_secs(&self) -> u64 { 49 pub const fn as_secs(&self) -> u64 {
42 self.ticks / TICKS_PER_SECOND as u64 50 self.ticks / TICKS_PER_SECOND as u64
43 } 51 }
52 /// Instant as miliseconds since MCU start.
44 53
45 pub const fn as_millis(&self) -> u64 { 54 pub const fn as_millis(&self) -> u64 {
46 self.ticks * 1000 / TICKS_PER_SECOND as u64 55 self.ticks * 1000 / TICKS_PER_SECOND as u64
47 } 56 }
48 57
58 /// Duration between this Instant and another Instant
59 /// Panics on over/underflow.
49 pub fn duration_since(&self, earlier: Instant) -> Duration { 60 pub fn duration_since(&self, earlier: Instant) -> Duration {
50 Duration { 61 Duration {
51 ticks: self.ticks.checked_sub(earlier.ticks).unwrap(), 62 ticks: self.ticks.checked_sub(earlier.ticks).unwrap(),
52 } 63 }
53 } 64 }
54 65
66 /// Duration between this Instant and another Instant
55 pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> { 67 pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
56 if self.ticks < earlier.ticks { 68 if self.ticks < earlier.ticks {
57 None 69 None
@@ -62,6 +74,8 @@ impl Instant {
62 } 74 }
63 } 75 }
64 76
77 /// Returns the duration since the "earlier" Instant.
78 /// If the "earlier" instant is in the future, the duration is set to zero.
65 pub fn saturating_duration_since(&self, earlier: Instant) -> Duration { 79 pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
66 Duration { 80 Duration {
67 ticks: if self.ticks < earlier.ticks { 81 ticks: if self.ticks < earlier.ticks {
@@ -72,6 +86,7 @@ impl Instant {
72 } 86 }
73 } 87 }
74 88
89 /// Duration elapsed since this Instant.
75 pub fn elapsed(&self) -> Duration { 90 pub fn elapsed(&self) -> Duration {
76 Instant::now() - *self 91 Instant::now() - *self
77 } 92 }
diff --git a/embassy/src/time/mod.rs b/embassy/src/time/mod.rs
index b45a608dd..4e9b5f592 100644
--- a/embassy/src/time/mod.rs
+++ b/embassy/src/time/mod.rs
@@ -1,3 +1,6 @@
1//! Time abstractions
2//! To use these abstractions, first call `set_clock` with an instance of an [Clock](trait.Clock.html).
3//!
1mod duration; 4mod duration;
2mod instant; 5mod instant;
3mod traits; 6mod traits;
@@ -14,10 +17,16 @@ pub const TICKS_PER_SECOND: u64 = 32768;
14 17
15static mut CLOCK: Option<&'static dyn Clock> = None; 18static mut CLOCK: Option<&'static dyn Clock> = None;
16 19
20/// Sets the clock used for the timing abstractions
21///
22/// Safety: Sets a mutable global.
17pub unsafe fn set_clock(clock: &'static dyn Clock) { 23pub unsafe fn set_clock(clock: &'static dyn Clock) {
18 CLOCK = Some(clock); 24 CLOCK = Some(clock);
19} 25}
20 26
27/// Return the current timestamp in ticks.
28/// This is guaranteed to be monotonic, i.e. a call to now() will always return
29/// a greater or equal value than earler calls.
21pub(crate) fn now() -> u64 { 30pub(crate) fn now() -> u64 {
22 unsafe { unwrap!(CLOCK, "No clock set").now() } 31 unsafe { unwrap!(CLOCK, "No clock set").now() }
23} 32}
diff --git a/embassy/src/util/drop_bomb.rs b/embassy/src/util/drop_bomb.rs
index b2b0684e5..388209a23 100644
--- a/embassy/src/util/drop_bomb.rs
+++ b/embassy/src/util/drop_bomb.rs
@@ -1,6 +1,12 @@
1use crate::fmt::panic; 1use crate::fmt::panic;
2use core::mem; 2use core::mem;
3 3
4/// An explosive ordinance that panics if it is improperly disposed of.
5///
6/// This is to forbid dropping futures, when there is absolutely no other choice.
7///
8/// To correctly dispose of this device, call the [defuse](struct.DropBomb.html#method.defuse)
9/// method before this object is dropped.
4pub struct DropBomb { 10pub struct DropBomb {
5 _private: (), 11 _private: (),
6} 12}
@@ -10,6 +16,7 @@ impl DropBomb {
10 Self { _private: () } 16 Self { _private: () }
11 } 17 }
12 18
19 /// Diffuses the bomb, rendering it safe to drop.
13 pub fn defuse(self) { 20 pub fn defuse(self) {
14 mem::forget(self) 21 mem::forget(self)
15 } 22 }
diff --git a/embassy/src/util/forever.rs b/embassy/src/util/forever.rs
index ac23a3ce3..efa96f30e 100644
--- a/embassy/src/util/forever.rs
+++ b/embassy/src/util/forever.rs
@@ -3,6 +3,25 @@ use core::mem::MaybeUninit;
3 3
4use atomic_polyfill::{AtomicBool, Ordering}; 4use atomic_polyfill::{AtomicBool, Ordering};
5 5
6/// Type with static lifetime that may be written to once at runtime.
7///
8/// This may be used to initialize static objects at runtime, typically in the init routine.
9/// This is useful for objects such as Embassy's RTC, which cannot be initialized in a const
10/// context.
11///
12/// Note: IF a global mutable variable is desired, use a CriticalSectionMutex or ThreadModeMutex instead.
13///
14/// ```
15/// use embassy::util::Forever;
16/// // Using an integer for the sake of keeping this example self-contained,
17/// // see https://github.com/embassy-rs/embassy/wiki/Getting-Started for a more "proper" example.
18/// static SOME_INT: Forever<u32> =Forever::new();
19///
20/// // put returns a mutable pointer to the object stored in the forever, which may then be passed
21/// // around.
22/// let mut x = SOME_INT.put(42);
23/// assert_eq!(*x, 42);
24/// ```
6pub struct Forever<T> { 25pub struct Forever<T> {
7 used: AtomicBool, 26 used: AtomicBool,
8 t: UnsafeCell<MaybeUninit<T>>, 27 t: UnsafeCell<MaybeUninit<T>>,
@@ -19,6 +38,11 @@ impl<T> Forever<T> {
19 } 38 }
20 } 39 }
21 40
41 /// Gives this `Forever` a value.
42 ///
43 /// Panics if this `Forever` already has a value.
44 ///
45 /// Returns a mutable reference to the stored value.
22 pub fn put(&'static self, val: T) -> &'static mut T { 46 pub fn put(&'static self, val: T) -> &'static mut T {
23 if self 47 if self
24 .used 48 .used
diff --git a/embassy/src/util/mod.rs b/embassy/src/util/mod.rs
index e64e7f1f1..6917e9993 100644
--- a/embassy/src/util/mod.rs
+++ b/embassy/src/util/mod.rs
@@ -1,3 +1,4 @@
1//! Async utilities
1mod drop_bomb; 2mod drop_bomb;
2mod forever; 3mod forever;
3mod mutex; 4mod mutex;
diff --git a/embassy/src/util/signal.rs b/embassy/src/util/signal.rs
index 41e27d4ca..0fd5c9275 100644
--- a/embassy/src/util/signal.rs
+++ b/embassy/src/util/signal.rs
@@ -10,6 +10,9 @@ use crate::executor;
10use crate::fmt::panic; 10use crate::fmt::panic;
11use crate::interrupt::{Interrupt, InterruptExt}; 11use crate::interrupt::{Interrupt, InterruptExt};
12 12
13/// Synchronization primitive. Allows creating awaitable signals that may be passed between tasks.
14///
15/// For more advanced use cases, please consider [futures-intrusive](https://crates.io/crates/futures-intrusive) channels or mutexes.
13pub struct Signal<T> { 16pub struct Signal<T> {
14 state: UnsafeCell<State<T>>, 17 state: UnsafeCell<State<T>>,
15} 18}
@@ -30,6 +33,7 @@ impl<T: Send> Signal<T> {
30 } 33 }
31 } 34 }
32 35
36 /// Mark this Signal as completed.
33 pub fn signal(&self, val: T) { 37 pub fn signal(&self, val: T) {
34 cortex_m::interrupt::free(|_| unsafe { 38 cortex_m::interrupt::free(|_| unsafe {
35 let state = &mut *self.state.get(); 39 let state = &mut *self.state.get();
@@ -64,10 +68,12 @@ impl<T: Send> Signal<T> {
64 }) 68 })
65 } 69 }
66 70
71 /// Future that completes when this Signal has been signaled.
67 pub fn wait(&self) -> impl Future<Output = T> + '_ { 72 pub fn wait(&self) -> impl Future<Output = T> + '_ {
68 futures::future::poll_fn(move |cx| self.poll_wait(cx)) 73 futures::future::poll_fn(move |cx| self.poll_wait(cx))
69 } 74 }
70 75
76 /// non-blocking method to check whether this signal has been signaled.
71 pub fn signaled(&self) -> bool { 77 pub fn signaled(&self) -> bool {
72 cortex_m::interrupt::free(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_))) 78 cortex_m::interrupt::free(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_)))
73 } 79 }
@@ -80,6 +86,25 @@ unsafe impl cortex_m::interrupt::Nr for NrWrap {
80 } 86 }
81} 87}
82 88
89/// Creates a future that completes when the specified Interrupt is triggered.
90///
91/// The input handler is unregistered when this Future is dropped.
92///
93/// Example:
94/// ``` no_compile
95/// use embassy::traits::*;
96/// use embassy::util::InterruptFuture;
97/// use embassy::executor::task;
98/// use embassy_stm32f4::interrupt; // Adjust this to your MCU's embassy HAL.
99/// #[task]
100/// async fn demo_interrupt_future() {
101/// // Using STM32f446 interrupt names, adjust this to your application as necessary.
102/// // Wait for TIM2 to tick.
103/// let mut tim2_interrupt = interrupt::take!(TIM2);
104/// InterruptFuture::new(&mut tim2_interrupt).await;
105/// // TIM2 interrupt went off, do something...
106/// }
107/// ```
83pub struct InterruptFuture<'a, I: Interrupt> { 108pub struct InterruptFuture<'a, I: Interrupt> {
84 interrupt: &'a mut I, 109 interrupt: &'a mut I,
85} 110}