diff options
| -rw-r--r-- | embassy-stm32f4-examples/Cargo.toml | 1 | ||||
| -rw-r--r-- | embassy-stm32f4-examples/src/bin/can.rs | 64 | ||||
| -rw-r--r-- | embassy-stm32f4/Cargo.toml | 2 | ||||
| -rw-r--r-- | embassy-stm32f4/src/can.rs | 103 | ||||
| -rw-r--r-- | embassy-stm32f4/src/lib.rs | 1 |
5 files changed, 171 insertions, 0 deletions
diff --git a/embassy-stm32f4-examples/Cargo.toml b/embassy-stm32f4-examples/Cargo.toml index 94f24c75e..60ba44554 100644 --- a/embassy-stm32f4-examples/Cargo.toml +++ b/embassy-stm32f4-examples/Cargo.toml | |||
| @@ -31,3 +31,4 @@ panic-probe = "0.1.0" | |||
| 31 | stm32f4xx-hal = { version = "0.8.3", features = ["rt", "stm32f405"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"} | 31 | stm32f4xx-hal = { version = "0.8.3", features = ["rt", "stm32f405"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"} |
| 32 | futures = { version = "0.3.8", default-features = false, features = ["async-await"] } | 32 | futures = { version = "0.3.8", default-features = false, features = ["async-await"] } |
| 33 | rtt-target = { version = "0.3", features = ["cortex-m"] } | 33 | rtt-target = { version = "0.3", features = ["cortex-m"] } |
| 34 | bxcan = "0.5.0" \ No newline at end of file | ||
diff --git a/embassy-stm32f4-examples/src/bin/can.rs b/embassy-stm32f4-examples/src/bin/can.rs new file mode 100644 index 000000000..c91447623 --- /dev/null +++ b/embassy-stm32f4-examples/src/bin/can.rs | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(trait_alias)] | ||
| 4 | #![feature(type_alias_impl_trait)] | ||
| 5 | |||
| 6 | #[path = "../example_common.rs"] | ||
| 7 | mod example_common; | ||
| 8 | use example_common::{panic, *}; | ||
| 9 | |||
| 10 | use cortex_m_rt::entry; | ||
| 11 | use embassy::executor::{task, Executor}; | ||
| 12 | use embassy::traits::gpio::*; | ||
| 13 | use embassy::util::Forever; | ||
| 14 | use embassy_stm32f4::can; | ||
| 15 | use embassy_stm32f4::exti; | ||
| 16 | use embassy_stm32f4::interrupt; | ||
| 17 | use futures::pin_mut; | ||
| 18 | use stm32f4xx_hal::prelude::*; | ||
| 19 | use stm32f4xx_hal::stm32; | ||
| 20 | |||
| 21 | static EXTI: Forever<exti::ExtiManager> = Forever::new(); | ||
| 22 | |||
| 23 | #[task] | ||
| 24 | async fn run(dp: stm32::Peripherals, _cp: cortex_m::Peripherals) { | ||
| 25 | let rx = gpioa.pa11.into_alternate_af9(); | ||
| 26 | let tx = gpioa.pa12.into_alternate_af9(); | ||
| 27 | let mut can = bxcan::Can::new(Can::new(dp.CAN1, (tx, rx))); | ||
| 28 | |||
| 29 | // APB1 (PCLK1): 24MHz, Bit rate: 20kBit/s, Sample Point 87.5% | ||
| 30 | // Value was calculated with http://www.bittiming.can-wiki.info/ | ||
| 31 | can.modify_config().set_bit_timing(0x001c_004a); | ||
| 32 | // Configure filters so that can frames can be received. | ||
| 33 | can.modify_filters().enable_bank(0, Mask32::accept_all()); | ||
| 34 | |||
| 35 | block!(can.enable()).unwrap(); | ||
| 36 | |||
| 37 | let can = can::Can::new( | ||
| 38 | can, | ||
| 39 | interrupt::take!(CAN1_TX), | ||
| 40 | interrupt::take!(CAN1_RX0), | ||
| 41 | )); | ||
| 42 | |||
| 43 | let frame = can.receive().await; | ||
| 44 | } | ||
| 45 | |||
| 46 | static EXECUTOR: Forever<Executor> = Forever::new(); | ||
| 47 | |||
| 48 | #[entry] | ||
| 49 | fn main() -> ! { | ||
| 50 | let dp = stm32::Peripherals::take().unwrap(); | ||
| 51 | let cp = cortex_m::peripheral::Peripherals::take().unwrap(); | ||
| 52 | |||
| 53 | dp.DBGMCU.cr.modify(|_, w| { | ||
| 54 | w.dbg_sleep().set_bit(); | ||
| 55 | w.dbg_standby().set_bit(); | ||
| 56 | w.dbg_stop().set_bit() | ||
| 57 | }); | ||
| 58 | dp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); | ||
| 59 | |||
| 60 | let executor = EXECUTOR.put(Executor::new()); | ||
| 61 | executor.run(|spawner| { | ||
| 62 | unwrap!(spawner.spawn(run(dp, cp))); | ||
| 63 | }); | ||
| 64 | } | ||
diff --git a/embassy-stm32f4/Cargo.toml b/embassy-stm32f4/Cargo.toml index f9a931b7e..afe771eb0 100644 --- a/embassy-stm32f4/Cargo.toml +++ b/embassy-stm32f4/Cargo.toml | |||
| @@ -39,3 +39,5 @@ cortex-m = "0.7.1" | |||
| 39 | embedded-hal = { version = "0.2.4" } | 39 | embedded-hal = { version = "0.2.4" } |
| 40 | embedded-dma = { version = "0.1.2" } | 40 | embedded-dma = { version = "0.1.2" } |
| 41 | stm32f4xx-hal = { version = "0.8.3", features = ["rt"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"} | 41 | stm32f4xx-hal = { version = "0.8.3", features = ["rt"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"} |
| 42 | bxcan = "0.5.0" | ||
| 43 | nb = "*" | ||
diff --git a/embassy-stm32f4/src/can.rs b/embassy-stm32f4/src/can.rs new file mode 100644 index 000000000..eb1699c5a --- /dev/null +++ b/embassy-stm32f4/src/can.rs | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | //! Async low power Serial. | ||
| 2 | //! | ||
| 3 | //! The peripheral is autmatically enabled and disabled as required to save power. | ||
| 4 | //! Lowest power consumption can only be guaranteed if the send receive futures | ||
| 5 | //! are dropped correctly (e.g. not using `mem::forget()`). | ||
| 6 | |||
| 7 | use bxcan; | ||
| 8 | use bxcan::Interrupts; | ||
| 9 | use core::future::Future; | ||
| 10 | use embassy::interrupt::Interrupt; | ||
| 11 | use embassy::util::InterruptFuture; | ||
| 12 | use embassy::util::Signal; | ||
| 13 | use nb; | ||
| 14 | use nb::block; | ||
| 15 | |||
| 16 | use crate::hal::prelude::*; | ||
| 17 | use crate::interrupt; | ||
| 18 | |||
| 19 | /// Interface to the Serial peripheral | ||
| 20 | pub struct Can<T: Instance> { | ||
| 21 | can: bxcan::Can<T>, | ||
| 22 | tx_int: T::TInterrupt, | ||
| 23 | rx_int: T::RInterrupt, | ||
| 24 | } | ||
| 25 | |||
| 26 | impl<T: Instance> Can<T> { | ||
| 27 | pub fn new(mut can: bxcan::Can<T>, tx_int: T::TInterrupt, rx_int: T::RInterrupt) -> Self { | ||
| 28 | // Sync to the bus and start normal operation. | ||
| 29 | can.enable_interrupts( | ||
| 30 | Interrupts::TRANSMIT_MAILBOX_EMPTY | Interrupts::FIFO0_MESSAGE_PENDING, | ||
| 31 | ); | ||
| 32 | block!(can.enable()).unwrap(); | ||
| 33 | |||
| 34 | Can { | ||
| 35 | can: can, | ||
| 36 | tx_int: tx_int, | ||
| 37 | rx_int: rx_int, | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | /// Sends can frame. | ||
| 42 | /// | ||
| 43 | /// This method async-blocks until the frame is transmitted. | ||
| 44 | pub fn transmit<'a>(&'a mut self, frame: &'a bxcan::Frame) -> impl Future<Output = ()> + 'a { | ||
| 45 | async move { | ||
| 46 | let fut = InterruptFuture::new(&mut self.tx_int); | ||
| 47 | self.can.transmit(frame); | ||
| 48 | |||
| 49 | fut.await; | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | /// Receive can frame. | ||
| 54 | /// | ||
| 55 | /// This method async-blocks until the frame is received. | ||
| 56 | pub fn receive<'a>(&'a mut self) -> impl Future<Output = (bxcan::Frame)> + 'a { | ||
| 57 | async move { | ||
| 58 | let mut frame: Option<bxcan::Frame> = None; | ||
| 59 | |||
| 60 | loop { | ||
| 61 | let fut = InterruptFuture::new(&mut self.rx_int); | ||
| 62 | frame = match self.can.receive() { | ||
| 63 | Ok(frame) => Some(frame), | ||
| 64 | Err(nb::Error::WouldBlock) => None, | ||
| 65 | Err(nb::Error::Other(_)) => None, // Ignore overrun errors. | ||
| 66 | }; | ||
| 67 | if frame.is_some() { | ||
| 68 | break; | ||
| 69 | } | ||
| 70 | fut.await; | ||
| 71 | } | ||
| 72 | |||
| 73 | frame.unwrap() | ||
| 74 | } | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | mod private { | ||
| 79 | pub trait Sealed {} | ||
| 80 | } | ||
| 81 | |||
| 82 | pub trait Instance: bxcan::Instance + private::Sealed { | ||
| 83 | type TInterrupt: Interrupt; | ||
| 84 | type RInterrupt: Interrupt; | ||
| 85 | } | ||
| 86 | |||
| 87 | macro_rules! can { | ||
| 88 | ($($can:ident => ($tint:ident, $rint:ident),)+) => { | ||
| 89 | $( | ||
| 90 | impl<T> private::Sealed for crate::hal::can::Can<crate::pac::$can> {} | ||
| 91 | impl<T> Instance for crate::hal::can::Can<crate::pac::$can> { | ||
| 92 | type TInterrupt = interrupt::$tint; | ||
| 93 | type RInterrupt = interrupt::$rint; | ||
| 94 | } | ||
| 95 | )+ | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | #[cfg(any(feature = "stm32f405",))] | ||
| 100 | can! { | ||
| 101 | CAN1 => (CAN1_TX, CAN1_RX0), | ||
| 102 | CAN2 => (CAN2_TX, CAN2_RX0), | ||
| 103 | } | ||
diff --git a/embassy-stm32f4/src/lib.rs b/embassy-stm32f4/src/lib.rs index aa99068c2..5d4354bcc 100644 --- a/embassy-stm32f4/src/lib.rs +++ b/embassy-stm32f4/src/lib.rs | |||
| @@ -311,6 +311,7 @@ pub use stm32f4xx_hal::stm32 as pac; | |||
| 311 | // This mod MUST go first, so that the others see its macros. | 311 | // This mod MUST go first, so that the others see its macros. |
| 312 | pub(crate) mod fmt; | 312 | pub(crate) mod fmt; |
| 313 | 313 | ||
| 314 | pub mod can; | ||
| 314 | pub mod exti; | 315 | pub mod exti; |
| 315 | pub mod interrupt; | 316 | pub mod interrupt; |
| 316 | pub mod qei; | 317 | pub mod qei; |
