diff --git a/Cargo.toml b/Cargo.toml index 5ba9ba7d..3e036b61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,9 @@ members = [ "embassy", "embassy-nrf", + "embassy-stm32f4", "embassy-nrf-examples", + "embassy-stm32f4-examples", "embassy-macros", ] diff --git a/embassy-stm32f4-examples/Cargo.toml b/embassy-stm32f4-examples/Cargo.toml new file mode 100644 index 00000000..6502a77a --- /dev/null +++ b/embassy-stm32f4-examples/Cargo.toml @@ -0,0 +1,39 @@ +[package] +authors = ["Dario Nieuwenhuis "] +edition = "2018" +name = "embassy-stm32f4-examples" +version = "0.1.0" + +[features] +default = [ + "defmt-default", +] +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] + + +[dependencies] +embassy = { version = "0.1.0", path = "../embassy", features = ["defmt", "defmt-trace"] } +embassy-stm32f4 = { version = "*", path = "../embassy-stm32f4", features = ["stm32f405"] } + +defmt = "0.1.3" +defmt-rtt = "0.1.0" + +cortex-m = { version = "0.6.3" } +cortex-m-rt = "0.6.13" +embedded-hal = { version = "0.2.4" } +panic-probe = "0.1.0" +stm32f4xx-hal = { version = "0.8.3", features = ["rt", "stm32f405"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"} +futures = { version = "0.3.8", default-features = false, features = ["async-await"] } +cortex-m-rtic = "0.5" +rtt-target = { version = "0.3", features = ["cortex-m"] } + + + +[[bin]] +name = "serial" +path = "src/serial.rs" \ No newline at end of file diff --git a/embassy-stm32f4-examples/src/serial.rs b/embassy-stm32f4-examples/src/serial.rs new file mode 100644 index 00000000..baed2e52 --- /dev/null +++ b/embassy-stm32f4-examples/src/serial.rs @@ -0,0 +1,64 @@ +#![no_std] +#![no_main] +#![feature(trait_alias)] +#![feature(type_alias_impl_trait)] + +// extern crate panic_halt; + +use cortex_m::singleton; +use cortex_m_rt::entry; +use embassy::executor::{task, Executor}; +use embassy::util::Forever; +use embassy_stm32f4::interrupt; +use embassy_stm32f4::serial; +use stm32f4xx_hal::stm32; +use stm32f4xx_hal::{prelude::*, serial::config}; + +#[task] +async fn run(dp: stm32::Peripherals, cp: cortex_m::Peripherals) { + // https://gist.github.com/thalesfragoso/a07340c5df6eee3b04c42fdc69ecdcb1 + let gpioa = dp.GPIOA.split(); + let rcc = dp.RCC.constrain(); + + let clocks = rcc + .cfgr + .use_hse(16.mhz()) + .sysclk(48.mhz()) + .pclk1(24.mhz()) + .freeze(); + + let mut serial = serial::Serial::new( + gpioa.pa9.into_alternate_af7(), + gpioa.pa10.into_alternate_af7(), + interrupt::take!(DMA2_STREAM7), + interrupt::take!(DMA2_STREAM2), + interrupt::take!(USART1), + dp.DMA2, + dp.USART1, + config::Parity::ParityNone, + 9600.bps(), + clocks, + ); + + let buf = singleton!(: [u8; 30] = [0; 30]).unwrap(); + + buf[5] = 0x01; + + serial.send(buf).await; +} + +static EXECUTOR: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + let dp = stm32::Peripherals::take().unwrap(); + let cp = cortex_m::peripheral::Peripherals::take().unwrap(); + + let executor = EXECUTOR.put(Executor::new(cortex_m::asm::sev)); + executor.spawn(run(dp, cp)); + + loop { + executor.run(); + cortex_m::asm::wfe(); + } +} diff --git a/embassy-stm32f4/Cargo.toml b/embassy-stm32f4/Cargo.toml new file mode 100644 index 00000000..44cf3db9 --- /dev/null +++ b/embassy-stm32f4/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "embassy-stm32f4" +version = "0.1.0" +authors = ["Dario Nieuwenhuis "] +edition = "2018" + +[features] +defmt-trace = [ ] +defmt-debug = [ ] +defmt-info = [ ] +defmt-warn = [ ] +defmt-error = [ ] + +stm32f401 = ["stm32f4xx-hal/stm32f401"] +stm32f405 = ["stm32f4xx-hal/stm32f405"] +stm32f407 = ["stm32f4xx-hal/stm32f407"] +stm32f410 = ["stm32f4xx-hal/stm32f410"] +stm32f411 = ["stm32f4xx-hal/stm32f411"] +stm32f412 = ["stm32f4xx-hal/stm32f412"] +stm32f413 = ["stm32f4xx-hal/stm32f413"] +stm32f415 = ["stm32f4xx-hal/stm32f405"] +stm32f417 = ["stm32f4xx-hal/stm32f407"] +stm32f423 = ["stm32f4xx-hal/stm32f413"] +stm32f427 = ["stm32f4xx-hal/stm32f427"] +stm32f429 = ["stm32f4xx-hal/stm32f429"] +stm32f437 = ["stm32f4xx-hal/stm32f427"] +stm32f439 = ["stm32f4xx-hal/stm32f429"] +stm32f446 = ["stm32f4xx-hal/stm32f446"] +stm32f469 = ["stm32f4xx-hal/stm32f469"] +stm32f479 = ["stm32f4xx-hal/stm32f469"] + +default = ["stm32f405"] + +[dependencies] +embassy = { version = "0.1.0", path = "../embassy" } + +defmt = { version = "0.1.3", optional = true } +log = { version = "0.4.11", optional = true } +cortex-m-rt = "0.6.13" +cortex-m = { version = "0.6.4" } +embedded-hal = { version = "0.2.4" } +embedded-dma = { version = "0.1.2" } +stm32f4xx-hal = { version = "0.8.3", features = ["rt"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"} diff --git a/embassy-stm32f4/src/fmt.rs b/embassy-stm32f4/src/fmt.rs new file mode 100644 index 00000000..4da69766 --- /dev/null +++ b/embassy-stm32f4/src/fmt.rs @@ -0,0 +1,118 @@ +#![macro_use] + +#[cfg(all(feature = "defmt", feature = "log"))] +compile_error!("You may not enable both `defmt` and `log` features."); + +pub use fmt::*; + +#[cfg(feature = "defmt")] +mod fmt { + pub use defmt::{ + assert, assert_eq, assert_ne, debug, debug_assert, debug_assert_eq, debug_assert_ne, error, + info, panic, todo, trace, unreachable, unwrap, warn, + }; +} + +#[cfg(feature = "log")] +mod fmt { + pub use core::{ + assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, panic, todo, + unreachable, + }; + pub use log::{debug, error, info, trace, warn}; +} + +#[cfg(not(any(feature = "defmt", feature = "log")))] +mod fmt { + #![macro_use] + + pub use core::{ + assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, panic, todo, + unreachable, + }; + + #[macro_export] + macro_rules! trace { + ($($msg:expr),+ $(,)?) => { + () + }; + } + + #[macro_export] + macro_rules! debug { + ($($msg:expr),+ $(,)?) => { + () + }; + } + + #[macro_export] + macro_rules! info { + ($($msg:expr),+ $(,)?) => { + () + }; + } + + #[macro_export] + macro_rules! warn { + ($($msg:expr),+ $(,)?) => { + () + }; + } + + #[macro_export] + macro_rules! error { + ($($msg:expr),+ $(,)?) => { + () + }; + } +} + +#[cfg(not(feature = "defmt"))] +#[macro_export] +macro_rules! unwrap { + ($arg:expr) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); + } + } + }; + ($arg:expr, $($msg:expr),+ $(,)? ) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); + } + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct NoneError; + +pub trait Try { + type Ok; + type Error; + fn into_result(self) -> Result; +} + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result { + self.ok_or(NoneError) + } +} + +impl Try for Result { + type Ok = T; + type Error = E; + + #[inline] + fn into_result(self) -> Self { + self + } +} diff --git a/embassy-stm32f4/src/interrupt.rs b/embassy-stm32f4/src/interrupt.rs new file mode 100644 index 00000000..502d666e --- /dev/null +++ b/embassy-stm32f4/src/interrupt.rs @@ -0,0 +1,193 @@ +//! Interrupt management +//! +//! This module implements an API for managing interrupts compatible with +//! nrf_softdevice::interrupt. Intended for switching between the two at compile-time. + +use core::sync::atomic::{compiler_fence, Ordering}; + +use crate::pac::NVIC_PRIO_BITS; + +// Re-exports +pub use crate::pac::Interrupt; +pub use crate::pac::Interrupt::*; // needed for cortex-m-rt #[interrupt] +pub use cortex_m::interrupt::{CriticalSection, Mutex}; +pub use embassy::interrupt::{declare, take, OwnedInterrupt}; + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum Priority { + Level0 = 0, + Level1 = 1, + Level2 = 2, + Level3 = 3, + Level4 = 4, + Level5 = 5, + Level6 = 6, + Level7 = 7, + Level8 = 8, + Level9 = 9, + Level10 = 10, + Level11 = 11, + Level12 = 12, + Level13 = 13, + Level14 = 14, + Level15 = 15, +} + +impl From for Priority { + fn from(priority: u8) -> Self { + match priority >> (8 - NVIC_PRIO_BITS) { + 0 => Self::Level0, + 1 => Self::Level1, + 2 => Self::Level2, + 3 => Self::Level3, + 4 => Self::Level4, + 5 => Self::Level5, + 6 => Self::Level6, + 7 => Self::Level7, + 8 => Self::Level8, + 9 => Self::Level9, + 10 => Self::Level10, + 11 => Self::Level11, + 12 => Self::Level12, + 13 => Self::Level13, + 14 => Self::Level14, + 15 => Self::Level15, + _ => unreachable!(), + } + } +} + +impl From for u8 { + fn from(p: Priority) -> Self { + (p as u8) << (8 - NVIC_PRIO_BITS) + } +} + +#[inline] +pub fn free(f: F) -> R +where + F: FnOnce(&CriticalSection) -> R, +{ + unsafe { + // TODO: assert that we're in privileged level + // Needed because disabling irqs in non-privileged level is a noop, which would break safety. + + let primask: u32; + asm!("mrs {}, PRIMASK", out(reg) primask); + + asm!("cpsid i"); + + // Prevent compiler from reordering operations inside/outside the critical section. + compiler_fence(Ordering::SeqCst); + + let r = f(&CriticalSection::new()); + + compiler_fence(Ordering::SeqCst); + + if primask & 1 == 0 { + asm!("cpsie i"); + } + + r + } +} + +#[cfg(feature = "stm32f405")] +mod irqs { + use super::*; + declare!(WWDG); + declare!(PVD); + declare!(TAMP_STAMP); + declare!(RTC_WKUP); + // declare!(FLASH); + declare!(RCC); + declare!(EXTI0); + declare!(EXTI1); + declare!(EXTI2); + declare!(EXTI3); + declare!(EXTI4); + declare!(DMA1_STREAM0); + declare!(DMA1_STREAM1); + declare!(DMA1_STREAM2); + declare!(DMA1_STREAM3); + declare!(DMA1_STREAM4); + declare!(DMA1_STREAM5); + declare!(DMA1_STREAM6); + declare!(ADC); + declare!(CAN1_TX); + declare!(CAN1_RX0); + declare!(CAN1_RX1); + declare!(CAN1_SCE); + declare!(EXTI9_5); + declare!(TIM1_BRK_TIM9); + declare!(TIM1_UP_TIM10); + declare!(TIM1_TRG_COM_TIM11); + declare!(TIM1_CC); + declare!(TIM2); + declare!(TIM3); + declare!(TIM4); + declare!(I2C1_EV); + declare!(I2C1_ER); + declare!(I2C2_EV); + declare!(I2C2_ER); + declare!(SPI1); + declare!(SPI2); + declare!(USART1); + declare!(USART2); + declare!(USART3); + declare!(EXTI15_10); + declare!(RTC_ALARM); + declare!(OTG_FS_WKUP); + declare!(TIM8_BRK_TIM12); + declare!(TIM8_UP_TIM13); + declare!(TIM8_TRG_COM_TIM14); + declare!(TIM8_CC); + declare!(DMA1_STREAM7); + // declare!(FMC); + declare!(SDIO); + declare!(TIM5); + declare!(SPI3); + declare!(UART4); + declare!(UART5); + declare!(TIM6_DAC); + declare!(TIM7); + declare!(DMA2_STREAM0); + declare!(DMA2_STREAM1); + declare!(DMA2_STREAM2); + declare!(DMA2_STREAM3); + declare!(DMA2_STREAM4); + declare!(ETH); + declare!(ETH_WKUP); + declare!(CAN2_TX); + declare!(CAN2_RX0); + declare!(CAN2_RX1); + declare!(CAN2_SCE); + declare!(OTG_FS); + declare!(DMA2_STREAM5); + declare!(DMA2_STREAM6); + declare!(DMA2_STREAM7); + declare!(USART6); + declare!(I2C3_EV); + declare!(I2C3_ER); + declare!(OTG_HS_EP1_OUT); + declare!(OTG_HS_EP1_IN); + declare!(OTG_HS_WKUP); + declare!(OTG_HS); + declare!(DCMI); + declare!(CRYP); + declare!(HASH_RNG); + declare!(FPU); + // declare!(UART7); + // declare!(UART8); + // declare!(SPI4); + // declare!(SPI5); + // declare!(SPI6); + // declare!(SAI1); + declare!(LCD_TFT); + declare!(LCD_TFT_1); + // declare!(DMA2D); +} + +pub use irqs::*; diff --git a/embassy-stm32f4/src/lib.rs b/embassy-stm32f4/src/lib.rs new file mode 100644 index 00000000..0f4a70bb --- /dev/null +++ b/embassy-stm32f4/src/lib.rs @@ -0,0 +1,317 @@ +#![no_std] +#![feature(generic_associated_types)] +#![feature(asm)] +#![feature(type_alias_impl_trait)] +#![feature(let_chains)] + +#[cfg(not(any( + feature = "stm32f401", + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f410", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f415", + feature = "stm32f417", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479", +)))] +compile_error!( + "No chip feature activated. You must activate exactly one of the following features: " +); + +#[cfg(any( + all(feature = "stm32f401", feature = "stm32f405"), + all(feature = "stm32f401", feature = "stm32f407"), + all(feature = "stm32f401", feature = "stm32f410"), + all(feature = "stm32f401", feature = "stm32f411"), + all(feature = "stm32f401", feature = "stm32f412"), + all(feature = "stm32f401", feature = "stm32f413"), + all(feature = "stm32f401", feature = "stm32f415"), + all(feature = "stm32f401", feature = "stm32f417"), + all(feature = "stm32f401", feature = "stm32f423"), + all(feature = "stm32f401", feature = "stm32f427"), + all(feature = "stm32f401", feature = "stm32f429"), + all(feature = "stm32f401", feature = "stm32f437"), + all(feature = "stm32f401", feature = "stm32f439"), + all(feature = "stm32f401", feature = "stm32f446"), + all(feature = "stm32f401", feature = "stm32f469"), + all(feature = "stm32f401", feature = "stm32f479"), + all(feature = "stm32f405", feature = "stm32f401"), + all(feature = "stm32f405", feature = "stm32f407"), + all(feature = "stm32f405", feature = "stm32f410"), + all(feature = "stm32f405", feature = "stm32f411"), + all(feature = "stm32f405", feature = "stm32f412"), + all(feature = "stm32f405", feature = "stm32f413"), + all(feature = "stm32f405", feature = "stm32f415"), + all(feature = "stm32f405", feature = "stm32f417"), + all(feature = "stm32f405", feature = "stm32f423"), + all(feature = "stm32f405", feature = "stm32f427"), + all(feature = "stm32f405", feature = "stm32f429"), + all(feature = "stm32f405", feature = "stm32f437"), + all(feature = "stm32f405", feature = "stm32f439"), + all(feature = "stm32f405", feature = "stm32f446"), + all(feature = "stm32f405", feature = "stm32f469"), + all(feature = "stm32f405", feature = "stm32f479"), + all(feature = "stm32f407", feature = "stm32f401"), + all(feature = "stm32f407", feature = "stm32f405"), + all(feature = "stm32f407", feature = "stm32f410"), + all(feature = "stm32f407", feature = "stm32f411"), + all(feature = "stm32f407", feature = "stm32f412"), + all(feature = "stm32f407", feature = "stm32f413"), + all(feature = "stm32f407", feature = "stm32f415"), + all(feature = "stm32f407", feature = "stm32f417"), + all(feature = "stm32f407", feature = "stm32f423"), + all(feature = "stm32f407", feature = "stm32f427"), + all(feature = "stm32f407", feature = "stm32f429"), + all(feature = "stm32f407", feature = "stm32f437"), + all(feature = "stm32f407", feature = "stm32f439"), + all(feature = "stm32f407", feature = "stm32f446"), + all(feature = "stm32f407", feature = "stm32f469"), + all(feature = "stm32f407", feature = "stm32f479"), + all(feature = "stm32f410", feature = "stm32f401"), + all(feature = "stm32f410", feature = "stm32f405"), + all(feature = "stm32f410", feature = "stm32f407"), + all(feature = "stm32f410", feature = "stm32f411"), + all(feature = "stm32f410", feature = "stm32f412"), + all(feature = "stm32f410", feature = "stm32f413"), + all(feature = "stm32f410", feature = "stm32f415"), + all(feature = "stm32f410", feature = "stm32f417"), + all(feature = "stm32f410", feature = "stm32f423"), + all(feature = "stm32f410", feature = "stm32f427"), + all(feature = "stm32f410", feature = "stm32f429"), + all(feature = "stm32f410", feature = "stm32f437"), + all(feature = "stm32f410", feature = "stm32f439"), + all(feature = "stm32f410", feature = "stm32f446"), + all(feature = "stm32f410", feature = "stm32f469"), + all(feature = "stm32f410", feature = "stm32f479"), + all(feature = "stm32f411", feature = "stm32f401"), + all(feature = "stm32f411", feature = "stm32f405"), + all(feature = "stm32f411", feature = "stm32f407"), + all(feature = "stm32f411", feature = "stm32f410"), + all(feature = "stm32f411", feature = "stm32f412"), + all(feature = "stm32f411", feature = "stm32f413"), + all(feature = "stm32f411", feature = "stm32f415"), + all(feature = "stm32f411", feature = "stm32f417"), + all(feature = "stm32f411", feature = "stm32f423"), + all(feature = "stm32f411", feature = "stm32f427"), + all(feature = "stm32f411", feature = "stm32f429"), + all(feature = "stm32f411", feature = "stm32f437"), + all(feature = "stm32f411", feature = "stm32f439"), + all(feature = "stm32f411", feature = "stm32f446"), + all(feature = "stm32f411", feature = "stm32f469"), + all(feature = "stm32f411", feature = "stm32f479"), + all(feature = "stm32f412", feature = "stm32f401"), + all(feature = "stm32f412", feature = "stm32f405"), + all(feature = "stm32f412", feature = "stm32f407"), + all(feature = "stm32f412", feature = "stm32f410"), + all(feature = "stm32f412", feature = "stm32f411"), + all(feature = "stm32f412", feature = "stm32f413"), + all(feature = "stm32f412", feature = "stm32f415"), + all(feature = "stm32f412", feature = "stm32f417"), + all(feature = "stm32f412", feature = "stm32f423"), + all(feature = "stm32f412", feature = "stm32f427"), + all(feature = "stm32f412", feature = "stm32f429"), + all(feature = "stm32f412", feature = "stm32f437"), + all(feature = "stm32f412", feature = "stm32f439"), + all(feature = "stm32f412", feature = "stm32f446"), + all(feature = "stm32f412", feature = "stm32f469"), + all(feature = "stm32f412", feature = "stm32f479"), + all(feature = "stm32f413", feature = "stm32f401"), + all(feature = "stm32f413", feature = "stm32f405"), + all(feature = "stm32f413", feature = "stm32f407"), + all(feature = "stm32f413", feature = "stm32f410"), + all(feature = "stm32f413", feature = "stm32f411"), + all(feature = "stm32f413", feature = "stm32f412"), + all(feature = "stm32f413", feature = "stm32f415"), + all(feature = "stm32f413", feature = "stm32f417"), + all(feature = "stm32f413", feature = "stm32f423"), + all(feature = "stm32f413", feature = "stm32f427"), + all(feature = "stm32f413", feature = "stm32f429"), + all(feature = "stm32f413", feature = "stm32f437"), + all(feature = "stm32f413", feature = "stm32f439"), + all(feature = "stm32f413", feature = "stm32f446"), + all(feature = "stm32f413", feature = "stm32f469"), + all(feature = "stm32f413", feature = "stm32f479"), + all(feature = "stm32f415", feature = "stm32f401"), + all(feature = "stm32f415", feature = "stm32f405"), + all(feature = "stm32f415", feature = "stm32f407"), + all(feature = "stm32f415", feature = "stm32f410"), + all(feature = "stm32f415", feature = "stm32f411"), + all(feature = "stm32f415", feature = "stm32f412"), + all(feature = "stm32f415", feature = "stm32f413"), + all(feature = "stm32f415", feature = "stm32f417"), + all(feature = "stm32f415", feature = "stm32f423"), + all(feature = "stm32f415", feature = "stm32f427"), + all(feature = "stm32f415", feature = "stm32f429"), + all(feature = "stm32f415", feature = "stm32f437"), + all(feature = "stm32f415", feature = "stm32f439"), + all(feature = "stm32f415", feature = "stm32f446"), + all(feature = "stm32f415", feature = "stm32f469"), + all(feature = "stm32f415", feature = "stm32f479"), + all(feature = "stm32f417", feature = "stm32f401"), + all(feature = "stm32f417", feature = "stm32f405"), + all(feature = "stm32f417", feature = "stm32f407"), + all(feature = "stm32f417", feature = "stm32f410"), + all(feature = "stm32f417", feature = "stm32f411"), + all(feature = "stm32f417", feature = "stm32f412"), + all(feature = "stm32f417", feature = "stm32f413"), + all(feature = "stm32f417", feature = "stm32f415"), + all(feature = "stm32f417", feature = "stm32f423"), + all(feature = "stm32f417", feature = "stm32f427"), + all(feature = "stm32f417", feature = "stm32f429"), + all(feature = "stm32f417", feature = "stm32f437"), + all(feature = "stm32f417", feature = "stm32f439"), + all(feature = "stm32f417", feature = "stm32f446"), + all(feature = "stm32f417", feature = "stm32f469"), + all(feature = "stm32f417", feature = "stm32f479"), + all(feature = "stm32f423", feature = "stm32f401"), + all(feature = "stm32f423", feature = "stm32f405"), + all(feature = "stm32f423", feature = "stm32f407"), + all(feature = "stm32f423", feature = "stm32f410"), + all(feature = "stm32f423", feature = "stm32f411"), + all(feature = "stm32f423", feature = "stm32f412"), + all(feature = "stm32f423", feature = "stm32f413"), + all(feature = "stm32f423", feature = "stm32f415"), + all(feature = "stm32f423", feature = "stm32f417"), + all(feature = "stm32f423", feature = "stm32f427"), + all(feature = "stm32f423", feature = "stm32f429"), + all(feature = "stm32f423", feature = "stm32f437"), + all(feature = "stm32f423", feature = "stm32f439"), + all(feature = "stm32f423", feature = "stm32f446"), + all(feature = "stm32f423", feature = "stm32f469"), + all(feature = "stm32f423", feature = "stm32f479"), + all(feature = "stm32f427", feature = "stm32f401"), + all(feature = "stm32f427", feature = "stm32f405"), + all(feature = "stm32f427", feature = "stm32f407"), + all(feature = "stm32f427", feature = "stm32f410"), + all(feature = "stm32f427", feature = "stm32f411"), + all(feature = "stm32f427", feature = "stm32f412"), + all(feature = "stm32f427", feature = "stm32f413"), + all(feature = "stm32f427", feature = "stm32f415"), + all(feature = "stm32f427", feature = "stm32f417"), + all(feature = "stm32f427", feature = "stm32f423"), + all(feature = "stm32f427", feature = "stm32f429"), + all(feature = "stm32f427", feature = "stm32f437"), + all(feature = "stm32f427", feature = "stm32f439"), + all(feature = "stm32f427", feature = "stm32f446"), + all(feature = "stm32f427", feature = "stm32f469"), + all(feature = "stm32f427", feature = "stm32f479"), + all(feature = "stm32f429", feature = "stm32f401"), + all(feature = "stm32f429", feature = "stm32f405"), + all(feature = "stm32f429", feature = "stm32f407"), + all(feature = "stm32f429", feature = "stm32f410"), + all(feature = "stm32f429", feature = "stm32f411"), + all(feature = "stm32f429", feature = "stm32f412"), + all(feature = "stm32f429", feature = "stm32f413"), + all(feature = "stm32f429", feature = "stm32f415"), + all(feature = "stm32f429", feature = "stm32f417"), + all(feature = "stm32f429", feature = "stm32f423"), + all(feature = "stm32f429", feature = "stm32f427"), + all(feature = "stm32f429", feature = "stm32f437"), + all(feature = "stm32f429", feature = "stm32f439"), + all(feature = "stm32f429", feature = "stm32f446"), + all(feature = "stm32f429", feature = "stm32f469"), + all(feature = "stm32f429", feature = "stm32f479"), + all(feature = "stm32f437", feature = "stm32f401"), + all(feature = "stm32f437", feature = "stm32f405"), + all(feature = "stm32f437", feature = "stm32f407"), + all(feature = "stm32f437", feature = "stm32f410"), + all(feature = "stm32f437", feature = "stm32f411"), + all(feature = "stm32f437", feature = "stm32f412"), + all(feature = "stm32f437", feature = "stm32f413"), + all(feature = "stm32f437", feature = "stm32f415"), + all(feature = "stm32f437", feature = "stm32f417"), + all(feature = "stm32f437", feature = "stm32f423"), + all(feature = "stm32f437", feature = "stm32f427"), + all(feature = "stm32f437", feature = "stm32f429"), + all(feature = "stm32f437", feature = "stm32f439"), + all(feature = "stm32f437", feature = "stm32f446"), + all(feature = "stm32f437", feature = "stm32f469"), + all(feature = "stm32f437", feature = "stm32f479"), + all(feature = "stm32f439", feature = "stm32f401"), + all(feature = "stm32f439", feature = "stm32f405"), + all(feature = "stm32f439", feature = "stm32f407"), + all(feature = "stm32f439", feature = "stm32f410"), + all(feature = "stm32f439", feature = "stm32f411"), + all(feature = "stm32f439", feature = "stm32f412"), + all(feature = "stm32f439", feature = "stm32f413"), + all(feature = "stm32f439", feature = "stm32f415"), + all(feature = "stm32f439", feature = "stm32f417"), + all(feature = "stm32f439", feature = "stm32f423"), + all(feature = "stm32f439", feature = "stm32f427"), + all(feature = "stm32f439", feature = "stm32f429"), + all(feature = "stm32f439", feature = "stm32f437"), + all(feature = "stm32f439", feature = "stm32f446"), + all(feature = "stm32f439", feature = "stm32f469"), + all(feature = "stm32f439", feature = "stm32f479"), + all(feature = "stm32f446", feature = "stm32f401"), + all(feature = "stm32f446", feature = "stm32f405"), + all(feature = "stm32f446", feature = "stm32f407"), + all(feature = "stm32f446", feature = "stm32f410"), + all(feature = "stm32f446", feature = "stm32f411"), + all(feature = "stm32f446", feature = "stm32f412"), + all(feature = "stm32f446", feature = "stm32f413"), + all(feature = "stm32f446", feature = "stm32f415"), + all(feature = "stm32f446", feature = "stm32f417"), + all(feature = "stm32f446", feature = "stm32f423"), + all(feature = "stm32f446", feature = "stm32f427"), + all(feature = "stm32f446", feature = "stm32f429"), + all(feature = "stm32f446", feature = "stm32f437"), + all(feature = "stm32f446", feature = "stm32f439"), + all(feature = "stm32f446", feature = "stm32f469"), + all(feature = "stm32f446", feature = "stm32f479"), + all(feature = "stm32f469", feature = "stm32f401"), + all(feature = "stm32f469", feature = "stm32f405"), + all(feature = "stm32f469", feature = "stm32f407"), + all(feature = "stm32f469", feature = "stm32f410"), + all(feature = "stm32f469", feature = "stm32f411"), + all(feature = "stm32f469", feature = "stm32f412"), + all(feature = "stm32f469", feature = "stm32f413"), + all(feature = "stm32f469", feature = "stm32f415"), + all(feature = "stm32f469", feature = "stm32f417"), + all(feature = "stm32f469", feature = "stm32f423"), + all(feature = "stm32f469", feature = "stm32f427"), + all(feature = "stm32f469", feature = "stm32f429"), + all(feature = "stm32f469", feature = "stm32f437"), + all(feature = "stm32f469", feature = "stm32f439"), + all(feature = "stm32f469", feature = "stm32f446"), + all(feature = "stm32f469", feature = "stm32f479"), + all(feature = "stm32f479", feature = "stm32f401"), + all(feature = "stm32f479", feature = "stm32f405"), + all(feature = "stm32f479", feature = "stm32f407"), + all(feature = "stm32f479", feature = "stm32f410"), + all(feature = "stm32f479", feature = "stm32f411"), + all(feature = "stm32f479", feature = "stm32f412"), + all(feature = "stm32f479", feature = "stm32f413"), + all(feature = "stm32f479", feature = "stm32f415"), + all(feature = "stm32f479", feature = "stm32f417"), + all(feature = "stm32f479", feature = "stm32f423"), + all(feature = "stm32f479", feature = "stm32f427"), + all(feature = "stm32f479", feature = "stm32f429"), + all(feature = "stm32f479", feature = "stm32f437"), + all(feature = "stm32f479", feature = "stm32f439"), + all(feature = "stm32f479", feature = "stm32f446"), + all(feature = "stm32f479", feature = "stm32f469"), +))] +compile_error!( + "Multile chip features activated. You must activate exactly one of the following features: " +); + +pub use stm32f4xx_hal as hal; +pub use stm32f4xx_hal::stm32 as pac; + +// This mod MUST go first, so that the others see its macros. +pub(crate) mod fmt; + +pub mod interrupt; +pub mod serial; + +pub use cortex_m_rt::interrupt; diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs new file mode 100644 index 00000000..cc55ef32 --- /dev/null +++ b/embassy-stm32f4/src/serial.rs @@ -0,0 +1,224 @@ +//! Async low power Serial. +//! +//! The peripheral is autmatically enabled and disabled as required to save power. +//! Lowest power consumption can only be guaranteed if the send receive futures +//! are dropped correctly (e.g. not using `mem::forget()`). + +use core::future::Future; +use core::ptr; +use core::sync::atomic::{self, Ordering}; +use core::task::{Context, Poll}; + +use embassy::interrupt::OwnedInterrupt; +use embassy::util::Signal; +use embedded_dma::{StaticReadBuffer, StaticWriteBuffer, WriteBuffer}; + +use crate::hal::dma::config::DmaConfig; +use crate::hal::dma::traits::{PeriAddress, Stream}; +use crate::hal::dma::{ + Channel4, MemoryToPeripheral, PeripheralToMemory, Stream2, Stream7, StreamsTuple, Transfer, +}; +use crate::hal::gpio::gpioa::{PA10, PA9}; +use crate::hal::gpio::{Alternate, AF7}; +use crate::hal::prelude::*; +use crate::hal::rcc::Clocks; +use crate::hal::serial::config::{ + Config as SerialConfig, DmaConfig as SerialDmaConfig, Parity, StopBits, WordLength, +}; +use crate::hal::serial::{Event as SerialEvent, Serial as HalSerial}; +use crate::hal::time::Bps; + +use crate::interrupt; + +use crate::pac::Interrupt; +use crate::pac::{DMA2, USART1}; + +/// Interface to the Serial peripheral +pub struct Serial, TSTREAM: Stream, RSTREAM: Stream> { + tx_stream: Option, + rx_stream: Option, + usart: Option, + tx_int: interrupt::DMA2_STREAM7Interrupt, + rx_int: interrupt::DMA2_STREAM2Interrupt, + usart_int: interrupt::USART1Interrupt, +} + +struct State { + tx_int: Signal<()>, + rx_int: Signal<()>, +} + +static STATE: State = State { + tx_int: Signal::new(), + rx_int: Signal::new(), +}; + +static mut INSTANCE: *const Serial, Stream2> = ptr::null_mut(); + +impl Serial, Stream2> { + pub fn new( + txd: PA9>, + rxd: PA10>, + tx_int: interrupt::DMA2_STREAM7Interrupt, + rx_int: interrupt::DMA2_STREAM2Interrupt, + usart_int: interrupt::USART1Interrupt, + dma: DMA2, + usart: USART1, + parity: Parity, + baudrate: Bps, + clocks: Clocks, + ) -> Self { + let mut serial = HalSerial::usart1( + usart, + (txd, rxd), + SerialConfig { + baudrate: baudrate, + wordlength: WordLength::DataBits8, + parity: Parity::ParityNone, + stopbits: StopBits::STOP1, + dma: SerialDmaConfig::TxRx, + }, + clocks, + ) + .unwrap(); + + serial.listen(SerialEvent::Idle); + // serial.listen(SerialEvent::Txe); + + let (usart, _) = serial.release(); + + // Register ISR + tx_int.set_handler(Self::on_tx_irq); + rx_int.set_handler(Self::on_rx_irq); + usart_int.set_handler(Self::on_rx_irq); + // usart_int.unpend(); + // usart_int.enable(); + + let streams = StreamsTuple::new(dma); + + Serial { + tx_stream: Some(streams.7), + rx_stream: Some(streams.2), + usart: Some(usart), + tx_int: tx_int, + rx_int: rx_int, + usart_int: usart_int, + } + } + + unsafe fn on_tx_irq() { + let s = &(*INSTANCE); + + s.tx_int.disable(); + + STATE.tx_int.signal(()); + } + + unsafe fn on_rx_irq() { + let s = &(*INSTANCE); + + atomic::compiler_fence(Ordering::Acquire); + s.rx_int.disable(); + s.usart_int.disable(); + atomic::compiler_fence(Ordering::Release); + + STATE.rx_int.signal(()); + } + + unsafe fn on_usart_irq() { + let s = &(*INSTANCE); + + atomic::compiler_fence(Ordering::Acquire); + s.rx_int.disable(); + s.usart_int.disable(); + atomic::compiler_fence(Ordering::Release); + + STATE.rx_int.signal(()); + } + + /// Sends serial data. + /// + /// `tx_buffer` is marked as static as per `embedded-dma` requirements. + /// It it safe to use a buffer with a non static lifetime if memory is not + /// reused until the future has finished. + pub fn send<'a, B: 'a>(&'a mut self, tx_buffer: B) -> impl Future + 'a + where + B: StaticWriteBuffer, + { + unsafe { INSTANCE = self }; + + let tx_stream = self.tx_stream.take().unwrap(); + let usart = self.usart.take().unwrap(); + STATE.tx_int.reset(); + + async move { + let mut tx_transfer = Transfer::init( + tx_stream, + usart, + tx_buffer, + None, + DmaConfig::default() + .transfer_complete_interrupt(true) + .memory_increment(true) + .double_buffer(false), + ); + + self.tx_int.unpend(); + self.tx_int.enable(); + tx_transfer.start(|_usart| {}); + + STATE.tx_int.wait().await; + + let (tx_stream, usart, _buf, _) = tx_transfer.free(); + self.tx_stream.replace(tx_stream); + self.usart.replace(usart); + } + } + + /// Receives serial data. + /// + /// The future is pending until the buffer is completely filled. + /// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel + /// unfinished transfers after a timeout to prevent lockup when no more data + /// is incoming. + /// + /// `rx_buffer` is marked as static as per `embedded-dma` requirements. + /// It it safe to use a buffer with a non static lifetime if memory is not + /// reused until the future has finished. + pub fn receive<'a, B: 'a>(&'a mut self, rx_buffer: B) -> impl Future + 'a + where + B: StaticWriteBuffer + Unpin, + { + unsafe { INSTANCE = self }; + + let rx_stream = self.rx_stream.take().unwrap(); + let usart = self.usart.take().unwrap(); + STATE.rx_int.reset(); + + async move { + let mut rx_transfer = Transfer::init( + rx_stream, + usart, + rx_buffer, + None, + DmaConfig::default() + .transfer_complete_interrupt(true) + .memory_increment(true) + .double_buffer(false), + ); + + self.rx_int.unpend(); + self.rx_int.enable(); + + rx_transfer.start(|_usart| {}); + + STATE.rx_int.wait().await; + + let (rx_stream, usart, buf, _) = rx_transfer.free(); + self.rx_stream.replace(rx_stream); + self.usart.replace(usart); + + buf + } + } +}