diff options
| author | xoviat <[email protected]> | 2021-03-27 21:24:21 -0500 |
|---|---|---|
| committer | xoviat <[email protected]> | 2021-03-27 21:24:21 -0500 |
| commit | 3242990690927e7a1c07774078f1d6a55dced5be (patch) | |
| tree | b14960ab0a2a25bf666bd7e634134da1b1346296 | |
| parent | d4f35c17290ac1c76690cc057c52072054e1485f (diff) | |
| parent | 19b959b0f8690d7eead40df699c48a37345639b3 (diff) | |
Merge branch 'master' of https://github.com/akiles/embassy into st-usb
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, |
| @@ -1,6 +1,7 @@ | |||
| 1 | # Embassy | 1 | # Embassy |
| 2 | 2 | ||
| 3 | Embassy is a project to make async/await a first-class option for embedded development. | 3 | Embassy is a project to make async/await a first-class option for embedded development. For more information and instructions to |
| 4 | get 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" | |||
| 43 | cortex-m = "0.7.1" | 43 | cortex-m = "0.7.1" |
| 44 | embedded-hal = { version = "0.2.4" } | 44 | embedded-hal = { version = "0.2.4" } |
| 45 | embedded-dma = { version = "0.1.2" } | 45 | embedded-dma = { version = "0.1.2" } |
| 46 | bxcan = "0.5.0" | ||
| 47 | nb = "*" | ||
| 46 | stm32f4xx-hal = { version = "0.8.3", features = ["rt", "can"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git", optional = true } | 48 | stm32f4xx-hal = { version = "0.8.3", features = ["rt", "can"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git", optional = true } |
| 47 | stm32l0xx-hal = { version = "0.7.0", features = ["rt"], git = "https://github.com/stm32-rs/stm32l0xx-hal.git", optional = true } \ No newline at end of file | 49 | stm32l0xx-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 | ))] | ||
| 98 | can! { | 117 | can! { |
| 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; | |||
| 3 | use core::pin::Pin; | 3 | use core::pin::Pin; |
| 4 | use cortex_m; | 4 | use cortex_m; |
| 5 | 5 | ||
| 6 | use embassy::traits::gpio::{WaitForFallingEdge, WaitForRisingEdge}; | ||
| 7 | use embassy::util::InterruptFuture; | ||
| 8 | |||
| 9 | use crate::hal::gpio; | 6 | use crate::hal::gpio; |
| 10 | use 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 | ))] | ||
| 11 | use crate::hal::syscfg::SysCfg; | 27 | use crate::hal::syscfg::SysCfg; |
| 12 | use crate::pac::EXTI; | 28 | |
| 29 | #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] | ||
| 30 | use crate::hal::syscfg::SYSCFG as SysCfg; | ||
| 31 | |||
| 32 | use embassy::traits::gpio::{ | ||
| 33 | WaitForAnyEdge, WaitForFallingEdge, WaitForHigh, WaitForLow, WaitForRisingEdge, | ||
| 34 | }; | ||
| 35 | use embassy::util::InterruptFuture; | ||
| 36 | |||
| 13 | use embedded_hal::digital::v2 as digital; | 37 | use embedded_hal::digital::v2 as digital; |
| 14 | 38 | ||
| 15 | use crate::interrupt; | 39 | use crate::interrupt; |
| 16 | 40 | ||
| 17 | pub struct ExtiPin<T: gpio::ExtiPin + WithInterrupt> { | 41 | pub struct ExtiPin<T: Instance> { |
| 18 | pin: T, | 42 | pin: T, |
| 19 | interrupt: T::Interrupt, | 43 | interrupt: T::Interrupt, |
| 20 | } | 44 | } |
| 21 | 45 | ||
| 22 | impl<T: gpio::ExtiPin + WithInterrupt> ExtiPin<T> { | 46 | impl<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 | ||
| 34 | impl<T: gpio::ExtiPin + WithInterrupt + digital::OutputPin> digital::OutputPin for ExtiPin<T> { | 56 | impl<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 | ||
| 46 | impl<T: gpio::ExtiPin + WithInterrupt + digital::StatefulOutputPin> digital::StatefulOutputPin | 68 | impl<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 | ||
| 58 | impl<T: gpio::ExtiPin + WithInterrupt + digital::ToggleableOutputPin> digital::ToggleableOutputPin | 78 | impl<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 | ||
| 68 | impl<T: gpio::ExtiPin + WithInterrupt + digital::InputPin> digital::InputPin for ExtiPin<T> { | 86 | impl<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 | /* | 98 | impl<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 | |||
| 91 | impl<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 | ||
| 114 | impl<T: gpio::ExtiPin + WithInterrupt + 'static> WaitForFallingEdge for ExtiPin<T> { | 127 | impl<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 | ||
| 149 | impl<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 | |||
| 157 | impl<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 | |||
| 176 | impl<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 | |||
| 184 | impl<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 | |||
| 192 | impl<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 | |||
| 137 | mod private { | 200 | mod private { |
| 138 | pub trait Sealed {} | 201 | pub trait Sealed {} |
| 139 | } | 202 | } |
| 140 | 203 | ||
| 204 | #[derive(Copy, Clone)] | ||
| 205 | pub enum EdgeOption { | ||
| 206 | Rising, | ||
| 207 | Falling, | ||
| 208 | RisingFalling, | ||
| 209 | } | ||
| 210 | |||
| 141 | pub trait WithInterrupt: private::Sealed { | 211 | pub trait WithInterrupt: private::Sealed { |
| 142 | type Interrupt: interrupt::Interrupt; | 212 | type Interrupt: interrupt::Interrupt; |
| 143 | } | 213 | } |
| 144 | 214 | ||
| 215 | pub 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 | |||
| 145 | macro_rules! exti { | 221 | macro_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",))] | ||
| 694 | exti!(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",))] | ||
| 714 | exti!(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",))] | ||
| 734 | exti!(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",))] | ||
| 754 | exti!(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",))] | ||
| 774 | exti!(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",))] | ||
| 794 | exti!(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 | ||
| 33 | pub mod fmt; | 33 | pub mod fmt; |
| 34 | 34 | ||
| 35 | pub mod exti; | ||
| 35 | pub mod interrupt; | 36 | pub 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 | ))] | ||
| 55 | pub 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 | ))] |
| 76 | pub mod rtc; | ||
| 77 | |||
| 55 | unsafe impl embassy_extras::usb::USBInterrupt for interrupt::OTG_FS {} | 78 | unsafe 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 } | |||
| 37 | log = { version = "0.4.11", optional = true } | 37 | log = { version = "0.4.11", optional = true } |
| 38 | cortex-m-rt = "0.6.13" | 38 | cortex-m-rt = "0.6.13" |
| 39 | cortex-m = "0.7.1" | 39 | cortex-m = "0.7.1" |
| 40 | futures = { version = "0.3.5", default-features = false, features = ["async-await"] } | ||
| 40 | embedded-hal = { version = "0.2.4" } | 41 | embedded-hal = { version = "0.2.4" } |
| 41 | embedded-dma = { version = "0.1.2" } | 42 | embedded-dma = { version = "0.1.2" } |
| 42 | stm32f4xx-hal = { version = "0.8.3", features = ["rt", "can"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"} | 43 | stm32f4xx-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 | ||
| 310 | pub use embassy_stm32::{fmt, hal, interrupt, pac}; | 310 | pub 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",)))] |
| 313 | pub mod can; | 313 | pub use embassy_stm32::can; |
| 314 | pub mod exti; | 314 | |
| 315 | #[cfg(not(feature = "stm32f410"))] | 315 | #[cfg(not(feature = "stm32f410"))] |
| 316 | pub mod qei; | 316 | pub mod qei; |
| 317 | pub mod rtc; | ||
| 318 | pub mod serial; | 317 | pub 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 @@ | |||
| 7 | use core::future::Future; | 7 | use core::future::Future; |
| 8 | use core::marker::PhantomData; | 8 | use core::marker::PhantomData; |
| 9 | 9 | ||
| 10 | use futures::{select_biased, FutureExt}; | ||
| 11 | |||
| 10 | use embassy::interrupt::Interrupt; | 12 | use embassy::interrupt::Interrupt; |
| 11 | use embassy::traits::uart::{Error, Uart}; | 13 | use embassy::traits::uart::{Error, IdleUart, Uart}; |
| 12 | use embassy::util::InterruptFuture; | 14 | use embassy::util::InterruptFuture; |
| 13 | 15 | ||
| 14 | use crate::hal::{ | 16 | use 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 | }; |
| 24 | use crate::interrupt; | 26 | use crate::interrupt; |
| 25 | use crate::pac; | 27 | use 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 | ||
| 178 | impl<USART, TSTREAM, RSTREAM, CHANNEL> IdleUart for Serial<USART, TSTREAM, RSTREAM, CHANNEL> | ||
| 179 | where | ||
| 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 | |||
| 179 | mod private { | 251 | mod 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 @@ | |||
| 1 | use core::future::Future; | ||
| 2 | use core::mem; | ||
| 3 | use core::pin::Pin; | ||
| 4 | |||
| 5 | use embassy::traits::gpio::{ | ||
| 6 | WaitForAnyEdge, WaitForFallingEdge, WaitForHigh, WaitForLow, WaitForRisingEdge, | ||
| 7 | }; | ||
| 8 | use embassy::util::InterruptFuture; | ||
| 9 | |||
| 10 | use crate::hal::{ | ||
| 11 | exti::{Exti, ExtiLine, GpioLine, TriggerEdge}, | ||
| 12 | gpio, | ||
| 13 | syscfg::SYSCFG, | ||
| 14 | }; | ||
| 15 | use crate::interrupt; | ||
| 16 | use crate::pac::EXTI; | ||
| 17 | use embedded_hal::digital::v2::InputPin; | ||
| 18 | |||
| 19 | pub struct ExtiPin<T: PinWithInterrupt> { | ||
| 20 | pin: T, | ||
| 21 | interrupt: T::Interrupt, | ||
| 22 | } | ||
| 23 | |||
| 24 | impl<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 | |||
| 57 | impl<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 | |||
| 98 | impl<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 | |||
| 106 | impl<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 | |||
| 114 | impl<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 | |||
| 122 | impl<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 | |||
| 130 | impl<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 | |||
| 138 | mod private { | ||
| 139 | pub trait Sealed {} | ||
| 140 | } | ||
| 141 | |||
| 142 | pub trait PinWithInterrupt: private::Sealed { | ||
| 143 | type Interrupt: interrupt::Interrupt; | ||
| 144 | fn port(&self) -> gpio::Port; | ||
| 145 | fn line(&self) -> GpioLine; | ||
| 146 | } | ||
| 147 | |||
| 148 | macro_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 | |||
| 168 | exti!(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 | |||
| 187 | exti!(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 | |||
| 206 | exti!(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 | |||
| 225 | exti!(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 | |||
| 244 | exti!(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 | |||
| 263 | exti!(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 | ||
| 22 | pub use embassy_stm32::{fmt, hal, interrupt, pac}; | 22 | pub use embassy_stm32::{exti, fmt, hal, interrupt, pac}; |
| 23 | |||
| 24 | pub 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; | |||
| 4 | pub trait Delay { | 4 | pub 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 { | |||
| 10 | pub trait Uart { | 10 | pub 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 | |||
| 19 | pub 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; | |||
| 7 | use super::raw; | 7 | use super::raw; |
| 8 | use crate::time::{Duration, Instant}; | 8 | use crate::time::{Duration, Instant}; |
| 9 | 9 | ||
| 10 | /// Delay abstraction using embassy's clock. | ||
| 10 | pub struct Delay { | 11 | pub 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). | ||
| 33 | pub struct Timer { | 35 | pub struct Timer { |
| 34 | expires_at: Instant, | 36 | expires_at: Instant, |
| 35 | yielded_once: bool, | 37 | yielded_once: bool, |
| 36 | } | 38 | } |
| 37 | 39 | ||
| 38 | impl Timer { | 40 | impl 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 | /// ``` | ||
| 69 | pub struct Ticker { | 141 | pub struct Ticker { |
| 70 | expires_at: Instant, | 142 | expires_at: Instant, |
| 71 | duration: Duration, | 143 | duration: Duration, |
| 72 | } | 144 | } |
| 73 | 145 | ||
| 74 | impl Ticker { | 146 | impl 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 | ||
| 8 | pub struct Duration { | 9 | pub 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. | ||
| 9 | pub struct Instant { | 10 | pub 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 | //! | ||
| 1 | mod duration; | 4 | mod duration; |
| 2 | mod instant; | 5 | mod instant; |
| 3 | mod traits; | 6 | mod traits; |
| @@ -14,10 +17,16 @@ pub const TICKS_PER_SECOND: u64 = 32768; | |||
| 14 | 17 | ||
| 15 | static mut CLOCK: Option<&'static dyn Clock> = None; | 18 | static 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. | ||
| 17 | pub unsafe fn set_clock(clock: &'static dyn Clock) { | 23 | pub 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. | ||
| 21 | pub(crate) fn now() -> u64 { | 30 | pub(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 @@ | |||
| 1 | use crate::fmt::panic; | 1 | use crate::fmt::panic; |
| 2 | use core::mem; | 2 | use 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. | ||
| 4 | pub struct DropBomb { | 10 | pub 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 | ||
| 4 | use atomic_polyfill::{AtomicBool, Ordering}; | 4 | use 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 | /// ``` | ||
| 6 | pub struct Forever<T> { | 25 | pub 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 | ||
| 1 | mod drop_bomb; | 2 | mod drop_bomb; |
| 2 | mod forever; | 3 | mod forever; |
| 3 | mod mutex; | 4 | mod 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; | |||
| 10 | use crate::fmt::panic; | 10 | use crate::fmt::panic; |
| 11 | use crate::interrupt::{Interrupt, InterruptExt}; | 11 | use 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. | ||
| 13 | pub struct Signal<T> { | 16 | pub 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 | /// ``` | ||
| 83 | pub struct InterruptFuture<'a, I: Interrupt> { | 108 | pub struct InterruptFuture<'a, I: Interrupt> { |
| 84 | interrupt: &'a mut I, | 109 | interrupt: &'a mut I, |
| 85 | } | 110 | } |
