From 18cd87ae12fb7ec925a0f50bc8e0b307d67dc716 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 28 Dec 2020 09:17:36 -0600 Subject: [PATCH 01/30] create stm32f4 crate --- Cargo.toml | 1 + embassy-stm32f4/Cargo.toml | 40 +++ embassy-stm32f4/src/fmt.rs | 118 +++++++ embassy-stm32f4/src/interrupt.rs | 129 +++++++ embassy-stm32f4/src/lib.rs | 316 +++++++++++++++++ embassy-stm32f4/src/uarte.rs | 561 +++++++++++++++++++++++++++++++ 6 files changed, 1165 insertions(+) create mode 100644 embassy-stm32f4/Cargo.toml create mode 100644 embassy-stm32f4/src/fmt.rs create mode 100644 embassy-stm32f4/src/interrupt.rs create mode 100644 embassy-stm32f4/src/lib.rs create mode 100644 embassy-stm32f4/src/uarte.rs diff --git a/Cargo.toml b/Cargo.toml index 792804046..e1a1c34b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "embassy", "embassy-nrf", + "embassy-stm32f4", "embassy-macros", "examples", ] diff --git a/embassy-stm32f4/Cargo.toml b/embassy-stm32f4/Cargo.toml new file mode 100644 index 000000000..52ecba612 --- /dev/null +++ b/embassy-stm32f4/Cargo.toml @@ -0,0 +1,40 @@ +[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"] + +[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" } +stm32f4xx-hal = { version = "0.8.3", features = ["rt"]} diff --git a/embassy-stm32f4/src/fmt.rs b/embassy-stm32f4/src/fmt.rs new file mode 100644 index 000000000..4da69766c --- /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 000000000..17fc9ab34 --- /dev/null +++ b/embassy-stm32f4/src/interrupt.rs @@ -0,0 +1,129 @@ +//! 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, 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}; + +#[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, +} + +impl Priority { + #[inline] + fn to_nvic(self) -> u8 { + (self as u8) << (8 - NVIC_PRIO_BITS) + } + + #[inline] + fn from_nvic(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, + _ => unreachable!(), + } + } +} + +#[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 + } +} + +#[inline] +pub fn enable(irq: Interrupt) { + unsafe { + NVIC::unmask(irq); + } +} + +#[inline] +pub fn disable(irq: Interrupt) { + NVIC::mask(irq); +} + +#[inline] +pub fn is_active(irq: Interrupt) -> bool { + NVIC::is_active(irq) +} + +#[inline] +pub fn is_enabled(irq: Interrupt) -> bool { + NVIC::is_enabled(irq) +} + +#[inline] +pub fn is_pending(irq: Interrupt) -> bool { + NVIC::is_pending(irq) +} + +#[inline] +pub fn pend(irq: Interrupt) { + NVIC::pend(irq) +} + +#[inline] +pub fn unpend(irq: Interrupt) { + NVIC::unpend(irq) +} + +#[inline] +pub fn get_priority(irq: Interrupt) -> Priority { + Priority::from_nvic(NVIC::get_priority(irq)) +} + +#[inline] +pub fn set_priority(irq: Interrupt, prio: Priority) { + unsafe { + cortex_m::peripheral::Peripherals::steal() + .NVIC + .set_priority(irq, prio.to_nvic()) + } +} diff --git a/embassy-stm32f4/src/lib.rs b/embassy-stm32f4/src/lib.rs new file mode 100644 index 000000000..fc4110889 --- /dev/null +++ b/embassy-stm32f4/src/lib.rs @@ -0,0 +1,316 @@ +#![no_std] +#![feature(generic_associated_types)] +#![feature(asm)] +#![feature(type_alias_impl_trait)] + +#[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 uarte; + +pub use cortex_m_rt::interrupt; diff --git a/embassy-stm32f4/src/uarte.rs b/embassy-stm32f4/src/uarte.rs new file mode 100644 index 000000000..3a33e7597 --- /dev/null +++ b/embassy-stm32f4/src/uarte.rs @@ -0,0 +1,561 @@ +//! HAL interface to the UARTE peripheral +//! +//! See product specification: +//! +//! - nrf52832: Section 35 +//! - nrf52840: Section 6.34 +use core::cell::UnsafeCell; +use core::cmp::min; +use core::marker::PhantomPinned; +use core::ops::Deref; +use core::pin::Pin; +use core::ptr; +use core::sync::atomic::{compiler_fence, Ordering}; +use core::task::{Context, Poll}; + +use embedded_hal::digital::v2::OutputPin; + +use crate::hal::gpio::{Floating, Input, Output, Pin as GpioPin, Port as GpioPort, PushPull}; +use crate::interrupt; +use crate::interrupt::CriticalSection; +#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] +use crate::pac::UARTE1; +use crate::pac::{uarte0, Interrupt, UARTE0}; + +// Re-export SVD variants to allow user to directly set values +pub use uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; + +use embassy::io::{AsyncBufRead, AsyncWrite, Result}; +use embassy::util::WakerStore; + +use crate::fmt::{assert, panic, todo, *}; + +//use crate::trace; + +const RINGBUF_SIZE: usize = 512; +struct RingBuf { + buf: [u8; RINGBUF_SIZE], + start: usize, + end: usize, + empty: bool, +} + +impl RingBuf { + fn new() -> Self { + RingBuf { + buf: [0; RINGBUF_SIZE], + start: 0, + end: 0, + empty: true, + } + } + + fn push_buf(&mut self) -> &mut [u8] { + if self.start == self.end && !self.empty { + trace!(" ringbuf: push_buf empty"); + return &mut self.buf[..0]; + } + + let n = if self.start <= self.end { + RINGBUF_SIZE - self.end + } else { + self.start - self.end + }; + + trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n); + &mut self.buf[self.end..self.end + n] + } + + fn push(&mut self, n: usize) { + trace!(" ringbuf: push {:?}", n); + if n == 0 { + return; + } + + self.end = Self::wrap(self.end + n); + self.empty = false; + } + + fn pop_buf(&mut self) -> &mut [u8] { + if self.empty { + trace!(" ringbuf: pop_buf empty"); + return &mut self.buf[..0]; + } + + let n = if self.end <= self.start { + RINGBUF_SIZE - self.start + } else { + self.end - self.start + }; + + trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n); + &mut self.buf[self.start..self.start + n] + } + + fn pop(&mut self, n: usize) { + trace!(" ringbuf: pop {:?}", n); + if n == 0 { + return; + } + + self.start = Self::wrap(self.start + n); + self.empty = self.start == self.end; + } + + fn wrap(n: usize) -> usize { + assert!(n <= RINGBUF_SIZE); + if n == RINGBUF_SIZE { + 0 + } else { + n + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +enum RxState { + Idle, + Receiving, + ReceivingReady, + Stopping, +} +#[derive(Copy, Clone, Debug, PartialEq)] +enum TxState { + Idle, + Transmitting(usize), +} + +/// Interface to a UARTE instance +/// +/// This is a very basic interface that comes with the following limitations: +/// - The UARTE instances share the same address space with instances of UART. +/// You need to make sure that conflicting instances +/// are disabled before using `Uarte`. See product specification: +/// - nrf52832: Section 15.2 +/// - nrf52840: Section 6.1.2 +pub struct Uarte { + started: bool, + state: UnsafeCell>, +} + +// public because it needs to be used in Instance::{get_state, set_state}, but +// should not be used outside the module +#[doc(hidden)] +pub struct UarteState { + inner: T, + + rx: RingBuf, + rx_state: RxState, + rx_waker: WakerStore, + + tx: RingBuf, + tx_state: TxState, + tx_waker: WakerStore, + + _pin: PhantomPinned, +} + +#[cfg(any(feature = "52833", feature = "52840"))] +fn port_bit(port: GpioPort) -> bool { + match port { + GpioPort::Port0 => false, + GpioPort::Port1 => true, + } +} + +impl Uarte { + pub fn new(uarte: T, mut pins: Pins, parity: Parity, baudrate: Baudrate) -> Self { + // Select pins + uarte.psel.rxd.write(|w| { + let w = unsafe { w.pin().bits(pins.rxd.pin()) }; + #[cfg(any(feature = "52833", feature = "52840"))] + let w = w.port().bit(port_bit(pins.rxd.port())); + w.connect().connected() + }); + pins.txd.set_high().unwrap(); + uarte.psel.txd.write(|w| { + let w = unsafe { w.pin().bits(pins.txd.pin()) }; + #[cfg(any(feature = "52833", feature = "52840"))] + let w = w.port().bit(port_bit(pins.txd.port())); + w.connect().connected() + }); + + // Optional pins + uarte.psel.cts.write(|w| { + if let Some(ref pin) = pins.cts { + let w = unsafe { w.pin().bits(pin.pin()) }; + #[cfg(any(feature = "52833", feature = "52840"))] + let w = w.port().bit(port_bit(pin.port())); + w.connect().connected() + } else { + w.connect().disconnected() + } + }); + + uarte.psel.rts.write(|w| { + if let Some(ref pin) = pins.rts { + let w = unsafe { w.pin().bits(pin.pin()) }; + #[cfg(any(feature = "52833", feature = "52840"))] + let w = w.port().bit(port_bit(pin.port())); + w.connect().connected() + } else { + w.connect().disconnected() + } + }); + + // Enable UARTE instance + uarte.enable.write(|w| w.enable().enabled()); + + // Enable interrupts + uarte.intenset.write(|w| w.endrx().set().endtx().set()); + + // Configure + let hardware_flow_control = pins.rts.is_some() && pins.cts.is_some(); + uarte + .config + .write(|w| w.hwfc().bit(hardware_flow_control).parity().variant(parity)); + + // Configure frequency + uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); + + Uarte { + started: false, + state: UnsafeCell::new(UarteState { + inner: uarte, + + rx: RingBuf::new(), + rx_state: RxState::Idle, + rx_waker: WakerStore::new(), + + tx: RingBuf::new(), + tx_state: TxState::Idle, + tx_waker: WakerStore::new(), + + _pin: PhantomPinned, + }), + } + } + + fn with_state<'a, R>( + self: Pin<&'a mut Self>, + f: impl FnOnce(Pin<&'a mut UarteState>) -> R, + ) -> R { + let Self { state, started } = unsafe { self.get_unchecked_mut() }; + + interrupt::free(|cs| { + let ptr = state.get(); + + if !*started { + T::set_state(cs, ptr); + + *started = true; + + // safety: safe because critical section ensures only one *mut UartState + // exists at the same time. + unsafe { Pin::new_unchecked(&mut *ptr) }.start(); + } + + // safety: safe because critical section ensures only one *mut UartState + // exists at the same time. + f(unsafe { Pin::new_unchecked(&mut *ptr) }) + }) + } +} + +impl Drop for Uarte { + fn drop(&mut self) { + // stop DMA before dropping, because DMA is using the buffer in `self`. + todo!() + } +} + +impl AsyncBufRead for Uarte { + fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.with_state(|s| s.poll_fill_buf(cx)) + } + + fn consume(self: Pin<&mut Self>, amt: usize) { + self.with_state(|s| s.consume(amt)) + } +} + +impl AsyncWrite for Uarte { + fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { + self.with_state(|s| s.poll_write(cx, buf)) + } +} + +impl UarteState { + pub fn start(self: Pin<&mut Self>) { + interrupt::set_priority(T::interrupt(), interrupt::Priority::Level7); + interrupt::enable(T::interrupt()); + interrupt::pend(T::interrupt()); + } + + fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let this = unsafe { self.get_unchecked_mut() }; + + // Conservative compiler fence to prevent optimizations that do not + // take in to account actions by DMA. The fence has been placed here, + // before any DMA action has started + compiler_fence(Ordering::SeqCst); + trace!("poll_read"); + + // We have data ready in buffer? Return it. + let buf = this.rx.pop_buf(); + if buf.len() != 0 { + trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len()); + return Poll::Ready(Ok(buf)); + } + + trace!(" empty"); + + if this.rx_state == RxState::ReceivingReady { + trace!(" stopping"); + this.rx_state = RxState::Stopping; + this.inner.tasks_stoprx.write(|w| unsafe { w.bits(1) }); + } + + this.rx_waker.store(cx.waker()); + Poll::Pending + } + + fn consume(self: Pin<&mut Self>, amt: usize) { + let this = unsafe { self.get_unchecked_mut() }; + trace!("consume {:?}", amt); + this.rx.pop(amt); + interrupt::pend(T::interrupt()); + } + + fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { + let this = unsafe { self.get_unchecked_mut() }; + + trace!("poll_write: {:?}", buf.len()); + + let tx_buf = this.tx.push_buf(); + if tx_buf.len() == 0 { + trace!("poll_write: pending"); + this.tx_waker.store(cx.waker()); + return Poll::Pending; + } + + let n = min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + this.tx.push(n); + + trace!("poll_write: queued {:?}", n); + + // Conservative compiler fence to prevent optimizations that do not + // take in to account actions by DMA. The fence has been placed here, + // before any DMA action has started + compiler_fence(Ordering::SeqCst); + + interrupt::pend(T::interrupt()); + + Poll::Ready(Ok(n)) + } + + fn on_interrupt(&mut self) { + trace!("irq: start"); + let mut more_work = true; + while more_work { + more_work = false; + match self.rx_state { + RxState::Idle => { + trace!(" irq_rx: in state idle"); + + if self.inner.events_rxdrdy.read().bits() != 0 { + trace!(" irq_rx: rxdrdy?????"); + self.inner.events_rxdrdy.reset(); + } + + if self.inner.events_endrx.read().bits() != 0 { + panic!("unexpected endrx"); + } + + let buf = self.rx.push_buf(); + if buf.len() != 0 { + trace!(" irq_rx: starting {:?}", buf.len()); + self.rx_state = RxState::Receiving; + + // Set up the DMA read + self.inner.rxd.ptr.write(|w| + // The PTR field is a full 32 bits wide and accepts the full range + // of values. + unsafe { w.ptr().bits(buf.as_ptr() as u32) }); + self.inner.rxd.maxcnt.write(|w| + // We're giving it the length of the buffer, so no danger of + // accessing invalid memory. We have verified that the length of the + // buffer fits in an `u8`, so the cast to `u8` is also fine. + // + // The MAXCNT field is at least 8 bits wide and accepts the full + // range of values. + unsafe { w.maxcnt().bits(buf.len() as _) }); + trace!(" irq_rx: buf {:?} {:?}", buf.as_ptr() as u32, buf.len()); + + // Enable RXRDY interrupt. + self.inner.events_rxdrdy.reset(); + self.inner.intenset.write(|w| w.rxdrdy().set()); + + // Start UARTE Receive transaction + self.inner.tasks_startrx.write(|w| + // `1` is a valid value to write to task registers. + unsafe { w.bits(1) }); + } + } + RxState::Receiving => { + trace!(" irq_rx: in state receiving"); + if self.inner.events_rxdrdy.read().bits() != 0 { + trace!(" irq_rx: rxdrdy"); + + // Disable the RXRDY event interrupt + // RXRDY is triggered for every byte, but we only care about whether we have + // some bytes or not. So as soon as we have at least one, disable it, to avoid + // wasting CPU cycles in interrupts. + self.inner.intenclr.write(|w| w.rxdrdy().clear()); + + self.inner.events_rxdrdy.reset(); + + self.rx_waker.wake(); + self.rx_state = RxState::ReceivingReady; + more_work = true; // in case we also have endrx pending + } + } + RxState::ReceivingReady | RxState::Stopping => { + trace!(" irq_rx: in state ReceivingReady"); + + if self.inner.events_rxdrdy.read().bits() != 0 { + trace!(" irq_rx: rxdrdy"); + self.inner.events_rxdrdy.reset(); + } + + if self.inner.events_endrx.read().bits() != 0 { + let n: usize = self.inner.rxd.amount.read().amount().bits() as usize; + trace!(" irq_rx: endrx {:?}", n); + self.rx.push(n); + + self.inner.events_endrx.reset(); + + self.rx_waker.wake(); + self.rx_state = RxState::Idle; + more_work = true; // start another rx if possible + } + } + } + } + + more_work = true; + while more_work { + more_work = false; + match self.tx_state { + TxState::Idle => { + trace!(" irq_tx: in state Idle"); + let buf = self.tx.pop_buf(); + if buf.len() != 0 { + trace!(" irq_tx: starting {:?}", buf.len()); + self.tx_state = TxState::Transmitting(buf.len()); + + // Set up the DMA write + self.inner.txd.ptr.write(|w| + // The PTR field is a full 32 bits wide and accepts the full range + // of values. + unsafe { w.ptr().bits(buf.as_ptr() as u32) }); + self.inner.txd.maxcnt.write(|w| + // We're giving it the length of the buffer, so no danger of + // accessing invalid memory. We have verified that the length of the + // buffer fits in an `u8`, so the cast to `u8` is also fine. + // + // The MAXCNT field is 8 bits wide and accepts the full range of + // values. + unsafe { w.maxcnt().bits(buf.len() as _) }); + + // Start UARTE Transmit transaction + self.inner.tasks_starttx.write(|w| + // `1` is a valid value to write to task registers. + unsafe { w.bits(1) }); + } + } + TxState::Transmitting(n) => { + trace!(" irq_tx: in state Transmitting"); + if self.inner.events_endtx.read().bits() != 0 { + self.inner.events_endtx.reset(); + + trace!(" irq_tx: endtx {:?}", n); + self.tx.pop(n); + self.tx_waker.wake(); + self.tx_state = TxState::Idle; + more_work = true; // start another tx if possible + } + } + } + } + trace!("irq: end"); + } +} + +pub struct Pins { + pub rxd: GpioPin>, + pub txd: GpioPin>, + pub cts: Option>>, + pub rts: Option>>, +} + +mod private { + pub trait Sealed {} + + impl Sealed for crate::pac::UARTE0 {} + #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] + impl Sealed for crate::pac::UARTE1 {} +} + +pub trait Instance: Deref + Sized + private::Sealed { + fn interrupt() -> Interrupt; + + #[doc(hidden)] + fn get_state(_cs: &CriticalSection) -> *mut UarteState; + + #[doc(hidden)] + fn set_state(_cs: &CriticalSection, state: *mut UarteState); +} + +#[interrupt] +unsafe fn UARTE0_UART0() { + interrupt::free(|cs| UARTE0::get_state(cs).as_mut().unwrap().on_interrupt()); +} + +#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] +#[interrupt] +unsafe fn UARTE1() { + interrupt::free(|cs| UARTE1::get_state(cs).as_mut().unwrap().on_interrupt()); +} + +static mut UARTE0_STATE: *mut UarteState = ptr::null_mut(); +#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] +static mut UARTE1_STATE: *mut UarteState = ptr::null_mut(); + +impl Instance for UARTE0 { + fn interrupt() -> Interrupt { + Interrupt::UARTE0_UART0 + } + + fn get_state(_cs: &CriticalSection) -> *mut UarteState { + unsafe { UARTE0_STATE } // Safe because of CriticalSection + } + fn set_state(_cs: &CriticalSection, state: *mut UarteState) { + unsafe { UARTE0_STATE = state } // Safe because of CriticalSection + } +} + +#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] +impl Instance for UARTE1 { + fn interrupt() -> Interrupt { + Interrupt::UARTE1 + } + + fn get_state(_cs: &CriticalSection) -> *mut UarteState { + unsafe { UARTE1_STATE } // Safe because of CriticalSection + } + fn set_state(_cs: &CriticalSection, state: *mut UarteState) { + unsafe { UARTE1_STATE = state } // Safe because of CriticalSection + } +} From 12fa5909c3b79b136de87024475d775913169f4a Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 28 Dec 2020 09:55:49 -0600 Subject: [PATCH 02/30] set-up draft serial interface --- embassy-stm32f4/src/uarte.rs | 83 ++++++++++++++---------------------- 1 file changed, 31 insertions(+), 52 deletions(-) diff --git a/embassy-stm32f4/src/uarte.rs b/embassy-stm32f4/src/uarte.rs index 3a33e7597..423f9fd0b 100644 --- a/embassy-stm32f4/src/uarte.rs +++ b/embassy-stm32f4/src/uarte.rs @@ -13,14 +13,15 @@ use core::ptr; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::{Context, Poll}; -use embedded_hal::digital::v2::OutputPin; - +use crate::hal::gpio::{Alternate, AF10, AF7, AF9}; use crate::hal::gpio::{Floating, Input, Output, Pin as GpioPin, Port as GpioPort, PushPull}; +use crate::hal::serial::{DmaConfig, Event, Parity, StopBits, WordLength}; use crate::interrupt; use crate::interrupt::CriticalSection; #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] use crate::pac::UARTE1; use crate::pac::{uarte0, Interrupt, UARTE0}; +use embedded_hal::digital::v2::OutputPin; // Re-export SVD variants to allow user to directly set values pub use uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; @@ -166,57 +167,35 @@ fn port_bit(port: GpioPort) -> bool { impl Uarte { pub fn new(uarte: T, mut pins: Pins, parity: Parity, baudrate: Baudrate) -> Self { // Select pins - uarte.psel.rxd.write(|w| { - let w = unsafe { w.pin().bits(pins.rxd.pin()) }; - #[cfg(any(feature = "52833", feature = "52840"))] - let w = w.port().bit(port_bit(pins.rxd.port())); - w.connect().connected() - }); - pins.txd.set_high().unwrap(); - uarte.psel.txd.write(|w| { - let w = unsafe { w.pin().bits(pins.txd.pin()) }; - #[cfg(any(feature = "52833", feature = "52840"))] - let w = w.port().bit(port_bit(pins.txd.port())); - w.connect().connected() - }); - - // Optional pins - uarte.psel.cts.write(|w| { - if let Some(ref pin) = pins.cts { - let w = unsafe { w.pin().bits(pin.pin()) }; - #[cfg(any(feature = "52833", feature = "52840"))] - let w = w.port().bit(port_bit(pin.port())); - w.connect().connected() - } else { - w.connect().disconnected() - } - }); - - uarte.psel.rts.write(|w| { - if let Some(ref pin) = pins.rts { - let w = unsafe { w.pin().bits(pin.pin()) }; - #[cfg(any(feature = "52833", feature = "52840"))] - let w = w.port().bit(port_bit(pin.port())); - w.connect().connected() - } else { - w.connect().disconnected() - } - }); - - // Enable UARTE instance - uarte.enable.write(|w| w.enable().enabled()); + // Serial>, PA10>)> + let mut serial = Serial::usart1( + dp.USART1, + (pins.txd, pins.rxd), + Config { + baudrate: 9600.bps(), + wordlength: WordLength::DataBits8, + parity: Parity::ParityNone, + stopbits: StopBits::STOP1, + dma: DmaConfig::TxRx, + }, + clocks, + ) + .unwrap(); // Enable interrupts - uarte.intenset.write(|w| w.endrx().set().endtx().set()); + serial.listen(Event::Txe); + serial.listen(Event::Txe); + + // TODO: Enable idle interrupt? Use DMA interrupt? // Configure - let hardware_flow_control = pins.rts.is_some() && pins.cts.is_some(); - uarte - .config - .write(|w| w.hwfc().bit(hardware_flow_control).parity().variant(parity)); + //let hardware_flow_control = pins.rts.is_some() && pins.cts.is_some(); + //uarte + // .config + // .write(|w| w.hwfc().bit(hardware_flow_control).parity().variant(parity)); // Configure frequency - uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); + // uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); Uarte { started: false, @@ -494,10 +473,10 @@ impl UarteState { } pub struct Pins { - pub rxd: GpioPin>, - pub txd: GpioPin>, - pub cts: Option>>, - pub rts: Option>>, + pub rxd: PA10>, + pub txd: PA9>, + // pub cts: Option>>, + // pub rts: Option>>, } mod private { @@ -533,7 +512,7 @@ static mut UARTE0_STATE: *mut UarteState = ptr::null_mut(); #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] static mut UARTE1_STATE: *mut UarteState = ptr::null_mut(); -impl Instance for UARTE0 { +impl Instance for DMA_CHANNEL1 { fn interrupt() -> Interrupt { Interrupt::UARTE0_UART0 } From 56db0e1c614dc69855aa8c8f1a767efed41a5d8a Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 28 Dec 2020 13:13:43 -0600 Subject: [PATCH 03/30] add dma transfer logic --- embassy-stm32f4/Cargo.toml | 4 ++- embassy-stm32f4/src/uarte.rs | 62 ++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/embassy-stm32f4/Cargo.toml b/embassy-stm32f4/Cargo.toml index 52ecba612..fe2d1eadc 100644 --- a/embassy-stm32f4/Cargo.toml +++ b/embassy-stm32f4/Cargo.toml @@ -29,6 +29,8 @@ stm32f446 = ["stm32f4xx-hal/stm32f446"] stm32f469 = ["stm32f4xx-hal/stm32f469"] stm32f479 = ["stm32f4xx-hal/stm32f469"] +default = ["stm32f405"] + [dependencies] embassy = { version = "0.1.0", path = "../embassy" } @@ -37,4 +39,4 @@ 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" } -stm32f4xx-hal = { version = "0.8.3", features = ["rt"]} +stm32f4xx-hal = { version = "0.8.3", features = ["rt"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git" } diff --git a/embassy-stm32f4/src/uarte.rs b/embassy-stm32f4/src/uarte.rs index 423f9fd0b..222d4ba4d 100644 --- a/embassy-stm32f4/src/uarte.rs +++ b/embassy-stm32f4/src/uarte.rs @@ -12,15 +12,21 @@ use core::pin::Pin; use core::ptr; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::{Context, Poll}; +use cortex_m::singleton; +use crate::hal::dma::config::DmaConfig; +use crate::hal::dma::{Channel4, PeripheralToMemory, Stream2, StreamsTuple, Transfer}; use crate::hal::gpio::{Alternate, AF10, AF7, AF9}; -use crate::hal::gpio::{Floating, Input, Output, Pin as GpioPin, Port as GpioPort, PushPull}; +use crate::hal::gpio::{ + Floating, Input, Output, Pin as GpioPin, Port as GpioPort, PushPull, Rx, Tx, +}; use crate::hal::serial::{DmaConfig, Event, Parity, StopBits, WordLength}; + use crate::interrupt; use crate::interrupt::CriticalSection; +use crate::pac::{uarte0, Interrupt, UARTE0, USART1}; #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] -use crate::pac::UARTE1; -use crate::pac::{uarte0, Interrupt, UARTE0}; +use crate::pac::{DMA2, UARTE1}; use embedded_hal::digital::v2::OutputPin; // Re-export SVD variants to allow user to directly set values @@ -188,6 +194,54 @@ impl Uarte { // TODO: Enable idle interrupt? Use DMA interrupt? + // STREAM: Stream, + // CHANNEL: Channel, + // DIR: Direction, + // PERIPHERAL: PeriAddress, + // BUF: WriteBuffer::MemSize> + 'static, + // + // (Stream2, Channel4, Rx, PeripheralToMemory), //USART1_RX + // (Stream7, Channel4, Tx, MemoryToPeripheral), //USART1_TX + + /* + Taken from https://gist.github.com/thalesfragoso/a07340c5df6eee3b04c42fdc69ecdcb1 + */ + + // configure dma transfer + let stream_7 = StreamsTuple::new(pins.dma).7; + let config = DmaConfig::default() + .transfer_complete_interrupt(true) + .memory_increment(true) + .double_buffer(true); + + // let rcc = unsafe { &*RCC::ptr() }; + // rcc.apb2enr.modify(|_, w| w.adc1en().enabled()); + // rcc.apb2rstr.modify(|_, w| w.adcrst().set_bit()); + // rcc.apb2rstr.modify(|_, w| w.adcrst().clear_bit()); + // let adc = cx.device.ADC1; + // adc.cr2.modify(|_, w| { + // w.dma() + // .enabled() + // .cont() + // .continuous() + // .dds() + // .continuous() + // .adon() + // .enabled() + // }); + + let first_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); + let second_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); + let triple_buffer = Some(singleton!(: [u8; 128] = [0; 128]).unwrap()); + + let transfer = Transfer::init( + stream_7, + pins.usart, + first_buffer, + Some(second_buffer), + config, + ); + // Configure //let hardware_flow_control = pins.rts.is_some() && pins.cts.is_some(); //uarte @@ -475,6 +529,8 @@ impl UarteState { pub struct Pins { pub rxd: PA10>, pub txd: PA9>, + pub dma: DMA2, + pub usart: USART1, // pub cts: Option>>, // pub rts: Option>>, } From b5e0116f76a4b6023a637c5edb3e6a7995c954ca Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 28 Dec 2020 13:31:18 -0600 Subject: [PATCH 04/30] add interrupt channels, waker --- embassy-stm32f4/src/lib.rs | 49 ++++++++++++++++++++++++++++++++++++ embassy-stm32f4/src/uarte.rs | 5 ++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/embassy-stm32f4/src/lib.rs b/embassy-stm32f4/src/lib.rs index fc4110889..f2304c94f 100644 --- a/embassy-stm32f4/src/lib.rs +++ b/embassy-stm32f4/src/lib.rs @@ -307,6 +307,55 @@ compile_error!( pub use stm32f4xx_hal as hal; pub use stm32f4xx_hal::stm32 as pac; +/// Creates a new interrupt waking a [`Waker`]. +/// +/// As this interrupt will be declared in this macro, it can't be used for anything else. +/// +/// # Examples +/// +/// This macro is useful for implementing [`Future::poll`]: +/// +/// ``` +/// fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { +/// if self.is_ready() { +/// Poll::Ready(()) +/// } else { +/// waker_interrupt!(TIM2, cx.waker().clone()); +/// Poll::Pending +/// } +/// } +/// ``` +/// +/// [`Waker`]: core::task::Waker +/// [`Future::poll`]: core::future::Future::poll +macro_rules! waker_interrupt { + ($INT:ident, $waker:expr) => {{ + use core::sync::atomic::{self, Ordering}; + use stm32f4xx_hal::pac::{interrupt, Interrupt, NVIC}; + + static mut WAKER: Option = None; + + #[interrupt] + fn $INT() { + // Safety: This context is disabled while the lower priority context accesses WAKER + if let Some(waker) = unsafe { WAKER.as_ref() } { + waker.wake_by_ref(); + + NVIC::mask(Interrupt::$INT); + } + } + + NVIC::mask(Interrupt::$INT); + atomic::compiler_fence(Ordering::Acquire); + // Safety: The other relevant context, the interrupt, is disabled + unsafe { WAKER = Some($waker) } + NVIC::unpend(Interrupt::$INT); + atomic::compiler_fence(Ordering::Release); + // Safety: This is the end of a mask-based critical section + unsafe { NVIC::unmask(Interrupt::$INT) } + }}; +} + // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; diff --git a/embassy-stm32f4/src/uarte.rs b/embassy-stm32f4/src/uarte.rs index 222d4ba4d..2d0fd9af5 100644 --- a/embassy-stm32f4/src/uarte.rs +++ b/embassy-stm32f4/src/uarte.rs @@ -554,13 +554,12 @@ pub trait Instance: Deref + Sized + private::Sea } #[interrupt] -unsafe fn UARTE0_UART0() { +unsafe fn DMA2_CHANNEL2() { interrupt::free(|cs| UARTE0::get_state(cs).as_mut().unwrap().on_interrupt()); } -#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] #[interrupt] -unsafe fn UARTE1() { +unsafe fn DMA2_CHANNEL7() { interrupt::free(|cs| UARTE1::get_state(cs).as_mut().unwrap().on_interrupt()); } From 3cf85df176a857a644739f0a53e7fc337eddf76d Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 28 Dec 2020 16:43:29 -0600 Subject: [PATCH 05/30] add dma transfer example --- embassy-stm32f4/src/uarte.rs | 72 +++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/embassy-stm32f4/src/uarte.rs b/embassy-stm32f4/src/uarte.rs index 2d0fd9af5..7bcd654a8 100644 --- a/embassy-stm32f4/src/uarte.rs +++ b/embassy-stm32f4/src/uarte.rs @@ -17,20 +17,23 @@ use cortex_m::singleton; use crate::hal::dma::config::DmaConfig; use crate::hal::dma::{Channel4, PeripheralToMemory, Stream2, StreamsTuple, Transfer}; use crate::hal::gpio::{Alternate, AF10, AF7, AF9}; -use crate::hal::gpio::{ - Floating, Input, Output, Pin as GpioPin, Port as GpioPort, PushPull, Rx, Tx, +use crate::hal::gpio::{Floating, Input, Output, PushPull}; +use crate::hal::rcc::Clocks; +use crate::hal::serial::config::{ + Config as SerialConfig, DmaConfig as SerialDmaConfig, Parity, StopBits, WordLength, }; -use crate::hal::serial::{DmaConfig, Event, Parity, StopBits, WordLength}; +use crate::hal::serial::Serial; +use crate::hal::time::Bps; use crate::interrupt; use crate::interrupt::CriticalSection; -use crate::pac::{uarte0, Interrupt, UARTE0, USART1}; -#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] -use crate::pac::{DMA2, UARTE1}; +use crate::pac::Interrupt; +use crate::pac::{DMA2, USART1}; + use embedded_hal::digital::v2::OutputPin; // Re-export SVD variants to allow user to directly set values -pub use uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; +// pub use uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; use embassy::io::{AsyncBufRead, AsyncWrite, Result}; use embassy::util::WakerStore; @@ -171,26 +174,29 @@ fn port_bit(port: GpioPort) -> bool { } impl Uarte { - pub fn new(uarte: T, mut pins: Pins, parity: Parity, baudrate: Baudrate) -> Self { + pub fn new(uarte: T, mut pins: Pins, parity: Parity, baudrate: Bps, clocks: Clocks) -> Self { // Select pins // Serial>, PA10>)> let mut serial = Serial::usart1( - dp.USART1, + pins.usart, (pins.txd, pins.rxd), - Config { - baudrate: 9600.bps(), + SerialConfig { + baudrate: baudrate, wordlength: WordLength::DataBits8, parity: Parity::ParityNone, stopbits: StopBits::STOP1, - dma: DmaConfig::TxRx, + dma: SerialDmaConfig::TxRx, }, clocks, ) .unwrap(); + let isr = pins.dma.hisr; + // self.isr().$tcifX().bit_is_clear() + // Enable interrupts - serial.listen(Event::Txe); - serial.listen(Event::Txe); + // serial.listen(Event::Txe); + // serial.listen(Event::Txe); // TODO: Enable idle interrupt? Use DMA interrupt? @@ -207,13 +213,6 @@ impl Uarte { Taken from https://gist.github.com/thalesfragoso/a07340c5df6eee3b04c42fdc69ecdcb1 */ - // configure dma transfer - let stream_7 = StreamsTuple::new(pins.dma).7; - let config = DmaConfig::default() - .transfer_complete_interrupt(true) - .memory_increment(true) - .double_buffer(true); - // let rcc = unsafe { &*RCC::ptr() }; // rcc.apb2enr.modify(|_, w| w.adc1en().enabled()); // rcc.apb2rstr.modify(|_, w| w.adcrst().set_bit()); @@ -230,18 +229,6 @@ impl Uarte { // .enabled() // }); - let first_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); - let second_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); - let triple_buffer = Some(singleton!(: [u8; 128] = [0; 128]).unwrap()); - - let transfer = Transfer::init( - stream_7, - pins.usart, - first_buffer, - Some(second_buffer), - config, - ); - // Configure //let hardware_flow_control = pins.rts.is_some() && pins.cts.is_some(); //uarte @@ -510,6 +497,25 @@ impl UarteState { } TxState::Transmitting(n) => { trace!(" irq_tx: in state Transmitting"); + // Start the DMA transfer + // See https://github.com/mwkroening/async-stm32f1xx/blob/78c46d1bff124eae4ebc7a2f4d40e6ed74def8b5/src/serial.rs#L118-L129 + // https://github.com/stm32-rs/stm32f1xx-hal/blob/68fd3d6f282173816fd3181e795988d314cb17d0/src/serial.rs#L649-L671 + + let first_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); + let second_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); + let triple_buffer = Some(singleton!(: [u8; 128] = [0; 128]).unwrap()); + + let transfer = Transfer::init( + StreamsTuple::new(pins.dma).7, + pins.usart, + first_buffer, + Some(second_buffer), + DmaConfig::default() + .transfer_complete_interrupt(true) + .memory_increment(true) + .double_buffer(true), + ); + if self.inner.events_endtx.read().bits() != 0 { self.inner.events_endtx.reset(); From 04944b6379814560a1d3732ed76b56751023f055 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 28 Dec 2020 20:48:26 -0600 Subject: [PATCH 06/30] overhaul implementation --- embassy-stm32f4/Cargo.toml | 1 + embassy-stm32f4/src/interrupt.rs | 129 ------ embassy-stm32f4/src/lib.rs | 2 +- embassy-stm32f4/src/uarte.rs | 758 ++++++++++--------------------- 4 files changed, 250 insertions(+), 640 deletions(-) delete mode 100644 embassy-stm32f4/src/interrupt.rs diff --git a/embassy-stm32f4/Cargo.toml b/embassy-stm32f4/Cargo.toml index fe2d1eadc..654ea69a6 100644 --- a/embassy-stm32f4/Cargo.toml +++ b/embassy-stm32f4/Cargo.toml @@ -39,4 +39,5 @@ 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/interrupt.rs b/embassy-stm32f4/src/interrupt.rs deleted file mode 100644 index 17fc9ab34..000000000 --- a/embassy-stm32f4/src/interrupt.rs +++ /dev/null @@ -1,129 +0,0 @@ -//! 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, 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}; - -#[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, -} - -impl Priority { - #[inline] - fn to_nvic(self) -> u8 { - (self as u8) << (8 - NVIC_PRIO_BITS) - } - - #[inline] - fn from_nvic(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, - _ => unreachable!(), - } - } -} - -#[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 - } -} - -#[inline] -pub fn enable(irq: Interrupt) { - unsafe { - NVIC::unmask(irq); - } -} - -#[inline] -pub fn disable(irq: Interrupt) { - NVIC::mask(irq); -} - -#[inline] -pub fn is_active(irq: Interrupt) -> bool { - NVIC::is_active(irq) -} - -#[inline] -pub fn is_enabled(irq: Interrupt) -> bool { - NVIC::is_enabled(irq) -} - -#[inline] -pub fn is_pending(irq: Interrupt) -> bool { - NVIC::is_pending(irq) -} - -#[inline] -pub fn pend(irq: Interrupt) { - NVIC::pend(irq) -} - -#[inline] -pub fn unpend(irq: Interrupt) { - NVIC::unpend(irq) -} - -#[inline] -pub fn get_priority(irq: Interrupt) -> Priority { - Priority::from_nvic(NVIC::get_priority(irq)) -} - -#[inline] -pub fn set_priority(irq: Interrupt, prio: Priority) { - unsafe { - cortex_m::peripheral::Peripherals::steal() - .NVIC - .set_priority(irq, prio.to_nvic()) - } -} diff --git a/embassy-stm32f4/src/lib.rs b/embassy-stm32f4/src/lib.rs index f2304c94f..40386085a 100644 --- a/embassy-stm32f4/src/lib.rs +++ b/embassy-stm32f4/src/lib.rs @@ -331,6 +331,7 @@ pub use stm32f4xx_hal::stm32 as pac; macro_rules! waker_interrupt { ($INT:ident, $waker:expr) => {{ use core::sync::atomic::{self, Ordering}; + use core::task::Waker; use stm32f4xx_hal::pac::{interrupt, Interrupt, NVIC}; static mut WAKER: Option = None; @@ -359,7 +360,6 @@ macro_rules! waker_interrupt { // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; -pub mod interrupt; pub mod uarte; pub use cortex_m_rt::interrupt; diff --git a/embassy-stm32f4/src/uarte.rs b/embassy-stm32f4/src/uarte.rs index 7bcd654a8..9e253dd9f 100644 --- a/embassy-stm32f4/src/uarte.rs +++ b/embassy-stm32f4/src/uarte.rs @@ -1,11 +1,12 @@ -//! HAL interface to the UARTE peripheral +//! Async low power UARTE. //! -//! See product specification: -//! -//! - nrf52832: Section 35 -//! - nrf52840: Section 6.34 +//! 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::cell::UnsafeCell; use core::cmp::min; +use core::future::Future; use core::marker::PhantomPinned; use core::ops::Deref; use core::pin::Pin; @@ -14,10 +15,17 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::{Context, Poll}; use cortex_m::singleton; +use embassy::util::Signal; +use embedded_dma::{StaticReadBuffer, StaticWriteBuffer}; + +use crate::fmt::assert; use crate::hal::dma::config::DmaConfig; use crate::hal::dma::{Channel4, PeripheralToMemory, Stream2, StreamsTuple, Transfer}; +use crate::hal::gpio::gpioa::{PA10, PA9}; use crate::hal::gpio::{Alternate, AF10, AF7, AF9}; use crate::hal::gpio::{Floating, Input, Output, PushPull}; +use crate::hal::pac; +use crate::hal::prelude::*; use crate::hal::rcc::Clocks; use crate::hal::serial::config::{ Config as SerialConfig, DmaConfig as SerialDmaConfig, Parity, StopBits, WordLength, @@ -26,156 +34,51 @@ use crate::hal::serial::Serial; use crate::hal::time::Bps; use crate::interrupt; -use crate::interrupt::CriticalSection; + use crate::pac::Interrupt; use crate::pac::{DMA2, USART1}; use embedded_hal::digital::v2::OutputPin; -// Re-export SVD variants to allow user to directly set values -// pub use uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; +// Re-export SVD variants to allow user to directly set values. +// pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; -use embassy::io::{AsyncBufRead, AsyncWrite, Result}; -use embassy::util::WakerStore; - -use crate::fmt::{assert, panic, todo, *}; - -//use crate::trace; - -const RINGBUF_SIZE: usize = 512; -struct RingBuf { - buf: [u8; RINGBUF_SIZE], - start: usize, - end: usize, - empty: bool, +/// Interface to the UARTE peripheral +pub struct Uarte { + instance: Serial>, PA10>)>, + usart: USART1, + dma: DMA2, } -impl RingBuf { - fn new() -> Self { - RingBuf { - buf: [0; RINGBUF_SIZE], - start: 0, - end: 0, - empty: true, - } - } - - fn push_buf(&mut self) -> &mut [u8] { - if self.start == self.end && !self.empty { - trace!(" ringbuf: push_buf empty"); - return &mut self.buf[..0]; - } - - let n = if self.start <= self.end { - RINGBUF_SIZE - self.end - } else { - self.start - self.end - }; - - trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n); - &mut self.buf[self.end..self.end + n] - } - - fn push(&mut self, n: usize) { - trace!(" ringbuf: push {:?}", n); - if n == 0 { - return; - } - - self.end = Self::wrap(self.end + n); - self.empty = false; - } - - fn pop_buf(&mut self) -> &mut [u8] { - if self.empty { - trace!(" ringbuf: pop_buf empty"); - return &mut self.buf[..0]; - } - - let n = if self.end <= self.start { - RINGBUF_SIZE - self.start - } else { - self.end - self.start - }; - - trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n); - &mut self.buf[self.start..self.start + n] - } - - fn pop(&mut self, n: usize) { - trace!(" ringbuf: pop {:?}", n); - if n == 0 { - return; - } - - self.start = Self::wrap(self.start + n); - self.empty = self.start == self.end; - } - - fn wrap(n: usize) -> usize { - assert!(n <= RINGBUF_SIZE); - if n == RINGBUF_SIZE { - 0 - } else { - n - } - } +struct State { + tx_done: Signal<()>, + rx_done: Signal, } -#[derive(Copy, Clone, Debug, PartialEq)] -enum RxState { - Idle, - Receiving, - ReceivingReady, - Stopping, -} -#[derive(Copy, Clone, Debug, PartialEq)] -enum TxState { - Idle, - Transmitting(usize), +static STATE: State = State { + tx_done: Signal::new(), + rx_done: Signal::new(), +}; + +pub struct Pins { + pub rxd: PA10>, + pub txd: PA9>, + pub dma: DMA2, + pub usart: USART1, } -/// Interface to a UARTE instance -/// -/// This is a very basic interface that comes with the following limitations: -/// - The UARTE instances share the same address space with instances of UART. -/// You need to make sure that conflicting instances -/// are disabled before using `Uarte`. See product specification: -/// - nrf52832: Section 15.2 -/// - nrf52840: Section 6.1.2 -pub struct Uarte { - started: bool, - state: UnsafeCell>, -} +impl Uarte { + pub fn new(mut pins: Pins, parity: Parity, baudrate: Bps, clocks: Clocks) -> Self { + // // Enable interrupts + // uarte.events_endtx.reset(); + // uarte.events_endrx.reset(); + // uarte + // .intenset + // .write(|w| w.endtx().set().txstopped().set().endrx().set().rxto().set()); + // // TODO: Set interrupt priority? + // interrupt::unpend(interrupt::UARTE0_UART0); + // interrupt::enable(interrupt::UARTE0_UART0); -// public because it needs to be used in Instance::{get_state, set_state}, but -// should not be used outside the module -#[doc(hidden)] -pub struct UarteState { - inner: T, - - rx: RingBuf, - rx_state: RxState, - rx_waker: WakerStore, - - tx: RingBuf, - tx_state: TxState, - tx_waker: WakerStore, - - _pin: PhantomPinned, -} - -#[cfg(any(feature = "52833", feature = "52840"))] -fn port_bit(port: GpioPort) -> bool { - match port { - GpioPort::Port0 => false, - GpioPort::Port1 => true, - } -} - -impl Uarte { - pub fn new(uarte: T, mut pins: Pins, parity: Parity, baudrate: Bps, clocks: Clocks) -> Self { - // Select pins // Serial>, PA10>)> let mut serial = Serial::usart1( pins.usart, @@ -191,411 +94,246 @@ impl Uarte { ) .unwrap(); - let isr = pins.dma.hisr; - // self.isr().$tcifX().bit_is_clear() + let isr = pins.dma.hisr;0 - // Enable interrupts - // serial.listen(Event::Txe); - // serial.listen(Event::Txe); + Uarte { instance: serial, dma: pins.dma, usart: pins.usart } + } - // TODO: Enable idle interrupt? Use DMA interrupt? + /// Sets the baudrate, parity and assigns the pins to the UARTE peripheral. + // TODO: Make it take the same `Pins` structs nrf-hal (with optional RTS/CTS). + // // TODO: #[cfg()] for smaller device variants without port register (nrf52810, ...). + // pub fn configure( + // &mut self, + // rxd: &Pin>, + // txd: &mut Pin>, + // parity: Parity, + // baudrate: Baudrate, + // ) { + // let uarte = &self.instance; + // assert!(uarte.enable.read().enable().is_disabled()); + // + // uarte.psel.rxd.write(|w| { + // let w = unsafe { w.pin().bits(rxd.pin()) }; + // let w = w.port().bit(rxd.port().bit()); + // w.connect().connected() + // }); + // + // txd.set_high().unwrap(); + // uarte.psel.txd.write(|w| { + // let w = unsafe { w.pin().bits(txd.pin()) }; + // let w = w.port().bit(txd.port().bit()); + // w.connect().connected() + // }); + // + // uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); + // uarte.config.write(|w| w.parity().variant(parity)); + // } - // STREAM: Stream, - // CHANNEL: Channel, - // DIR: Direction, - // PERIPHERAL: PeriAddress, - // BUF: WriteBuffer::MemSize> + 'static, - // - // (Stream2, Channel4, Rx, PeripheralToMemory), //USART1_RX - // (Stream7, Channel4, Tx, MemoryToPeripheral), //USART1_TX + // fn enable(&mut self) { + // self.instance.enable.write(|w| w.enable().enabled()); + // } - /* - Taken from https://gist.github.com/thalesfragoso/a07340c5df6eee3b04c42fdc69ecdcb1 - */ + /// 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 mut self, tx_buffer: B) -> SendFuture<'a, B> + where + B: StaticReadBuffer, + { + // Panic if TX is running which can happen if the user has called + // `mem::forget()` on a previous future after polling it once. + assert!(!self.tx_started()); - // let rcc = unsafe { &*RCC::ptr() }; - // rcc.apb2enr.modify(|_, w| w.adc1en().enabled()); - // rcc.apb2rstr.modify(|_, w| w.adcrst().set_bit()); - // rcc.apb2rstr.modify(|_, w| w.adcrst().clear_bit()); - // let adc = cx.device.ADC1; - // adc.cr2.modify(|_, w| { - // w.dma() - // .enabled() - // .cont() - // .continuous() - // .dds() - // .continuous() - // .adon() - // .enabled() - // }); + self.enable(); - // Configure - //let hardware_flow_control = pins.rts.is_some() && pins.cts.is_some(); - //uarte - // .config - // .write(|w| w.hwfc().bit(hardware_flow_control).parity().variant(parity)); - - // Configure frequency - // uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); - - Uarte { - started: false, - state: UnsafeCell::new(UarteState { - inner: uarte, - - rx: RingBuf::new(), - rx_state: RxState::Idle, - rx_waker: WakerStore::new(), - - tx: RingBuf::new(), - tx_state: TxState::Idle, - tx_waker: WakerStore::new(), - - _pin: PhantomPinned, - }), + SendFuture { + uarte: self, + buf: tx_buffer, } } - fn with_state<'a, R>( - self: Pin<&'a mut Self>, - f: impl FnOnce(Pin<&'a mut UarteState>) -> R, - ) -> R { - let Self { state, started } = unsafe { self.get_unchecked_mut() }; - - interrupt::free(|cs| { - let ptr = state.get(); - - if !*started { - T::set_state(cs, ptr); - - *started = true; - - // safety: safe because critical section ensures only one *mut UartState - // exists at the same time. - unsafe { Pin::new_unchecked(&mut *ptr) }.start(); - } - - // safety: safe because critical section ensures only one *mut UartState - // exists at the same time. - f(unsafe { Pin::new_unchecked(&mut *ptr) }) - }) - } -} - -impl Drop for Uarte { - fn drop(&mut self) { - // stop DMA before dropping, because DMA is using the buffer in `self`. - todo!() - } -} - -impl AsyncBufRead for Uarte { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.with_state(|s| s.poll_fill_buf(cx)) + fn tx_started(&self) -> bool { + // self.instance.events_txstarted.read().bits() != 0 + false } - fn consume(self: Pin<&mut Self>, amt: usize) { - self.with_state(|s| s.consume(amt)) - } -} + /// 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 mut self, rx_buffer: B) -> ReceiveFuture<'a, B> + where + B: StaticWriteBuffer, + { + // Panic if RX is running which can happen if the user has called + // `mem::forget()` on a previous future after polling it once. + assert!(!self.rx_started()); -impl AsyncWrite for Uarte { - fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { - self.with_state(|s| s.poll_write(cx, buf)) - } -} + self.enable(); -impl UarteState { - pub fn start(self: Pin<&mut Self>) { - interrupt::set_priority(T::interrupt(), interrupt::Priority::Level7); - interrupt::enable(T::interrupt()); - interrupt::pend(T::interrupt()); - } - - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = unsafe { self.get_unchecked_mut() }; - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // before any DMA action has started - compiler_fence(Ordering::SeqCst); - trace!("poll_read"); - - // We have data ready in buffer? Return it. - let buf = this.rx.pop_buf(); - if buf.len() != 0 { - trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len()); - return Poll::Ready(Ok(buf)); + ReceiveFuture { + uarte: self, + buf: Some(rx_buffer), } + } - trace!(" empty"); + fn rx_started(&self) -> bool { + self.instance.events_rxstarted.read().bits() != 0 + } +} - if this.rx_state == RxState::ReceivingReady { - trace!(" stopping"); - this.rx_state = RxState::Stopping; - this.inner.tasks_stoprx.write(|w| unsafe { w.bits(1) }); +/// Future for the [`LowPowerUarte::send()`] method. +pub struct SendFuture<'a, B> { + uarte: &'a Uarte, + buf: B, +} + +impl<'a, B> Drop for SendFuture<'a, B> { + fn drop(self: &mut Self) { + if self.uarte.tx_started() { + trace!("stoptx"); + + // Stop the transmitter to minimize the current consumption. + self.uarte + .instance + .tasks_stoptx + .write(|w| unsafe { w.bits(1) }); + self.uarte.instance.events_txstarted.reset(); } - - this.rx_waker.store(cx.waker()); - Poll::Pending } +} - fn consume(self: Pin<&mut Self>, amt: usize) { - let this = unsafe { self.get_unchecked_mut() }; - trace!("consume {:?}", amt); - this.rx.pop(amt); - interrupt::pend(T::interrupt()); - } +impl<'a, B> Future for SendFuture<'a, B> +where + B: StaticReadBuffer, +{ + type Output = (); - fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { - let this = unsafe { self.get_unchecked_mut() }; + fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + if self.is_ready() { + Poll::Ready(()) + } else { + // Start DMA transaction + let uarte = &self.uarte.instance; - trace!("poll_write: {:?}", buf.len()); + STATE.tx_done.reset(); - let tx_buf = this.tx.push_buf(); - if tx_buf.len() == 0 { - trace!("poll_write: pending"); - this.tx_waker.store(cx.waker()); - return Poll::Pending; + let (ptr, len) = unsafe { self.buf.read_buffer() }; + // assert!(len <= EASY_DMA_SIZE); + // TODO: panic if buffer is not in SRAM + + compiler_fence(Ordering::SeqCst); + // uarte.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); + // uarte + // .txd + // .maxcnt + // .write(|w| unsafe { w.maxcnt().bits(len as _) }); + + // Start the DMA transfer + // See https://github.com/mwkroening/async-stm32f1xx/blob/78c46d1bff124eae4ebc7a2f4d40e6ed74def8b5/src/serial.rs#L118-L129 + // https://github.com/stm32-rs/stm32f1xx-hal/blob/68fd3d6f282173816fd3181e795988d314cb17d0/src/serial.rs#L649-L671 + + // let first_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); + // let second_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); + // let triple_buffer = Some(singleton!(: [u8; 128] = [0; 128]).unwrap()); + + let transfer = Transfer::init( + StreamsTuple::new(self.dma).2, + self.usart, + self.buf, + // Some(second_buffer), + None, + DmaConfig::default() + .transfer_complete_interrupt(true) + .memory_increment(true) + .double_buffer(false), + ); + + waker_interrupt!(DMA2_STREAM2, cx.waker().clone()); + Poll::Pending } - - let n = min(tx_buf.len(), buf.len()); - tx_buf[..n].copy_from_slice(&buf[..n]); - this.tx.push(n); - - trace!("poll_write: queued {:?}", n); - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // before any DMA action has started - compiler_fence(Ordering::SeqCst); - - interrupt::pend(T::interrupt()); - - Poll::Ready(Ok(n)) } +} - fn on_interrupt(&mut self) { - trace!("irq: start"); - let mut more_work = true; - while more_work { - more_work = false; - match self.rx_state { - RxState::Idle => { - trace!(" irq_rx: in state idle"); +/// Future for the [`Uarte::receive()`] method. +pub struct ReceiveFuture<'a, B> { + uarte: &'a Uarte, + buf: Option, +} - if self.inner.events_rxdrdy.read().bits() != 0 { - trace!(" irq_rx: rxdrdy?????"); - self.inner.events_rxdrdy.reset(); - } +impl<'a, B> Drop for ReceiveFuture<'a, B> { + fn drop(self: &mut Self) { + if self.uarte.rx_started() { + trace!("stoprx"); - if self.inner.events_endrx.read().bits() != 0 { - panic!("unexpected endrx"); - } - - let buf = self.rx.push_buf(); - if buf.len() != 0 { - trace!(" irq_rx: starting {:?}", buf.len()); - self.rx_state = RxState::Receiving; - - // Set up the DMA read - self.inner.rxd.ptr.write(|w| - // The PTR field is a full 32 bits wide and accepts the full range - // of values. - unsafe { w.ptr().bits(buf.as_ptr() as u32) }); - self.inner.rxd.maxcnt.write(|w| - // We're giving it the length of the buffer, so no danger of - // accessing invalid memory. We have verified that the length of the - // buffer fits in an `u8`, so the cast to `u8` is also fine. - // - // The MAXCNT field is at least 8 bits wide and accepts the full - // range of values. - unsafe { w.maxcnt().bits(buf.len() as _) }); - trace!(" irq_rx: buf {:?} {:?}", buf.as_ptr() as u32, buf.len()); - - // Enable RXRDY interrupt. - self.inner.events_rxdrdy.reset(); - self.inner.intenset.write(|w| w.rxdrdy().set()); - - // Start UARTE Receive transaction - self.inner.tasks_startrx.write(|w| - // `1` is a valid value to write to task registers. - unsafe { w.bits(1) }); - } - } - RxState::Receiving => { - trace!(" irq_rx: in state receiving"); - if self.inner.events_rxdrdy.read().bits() != 0 { - trace!(" irq_rx: rxdrdy"); - - // Disable the RXRDY event interrupt - // RXRDY is triggered for every byte, but we only care about whether we have - // some bytes or not. So as soon as we have at least one, disable it, to avoid - // wasting CPU cycles in interrupts. - self.inner.intenclr.write(|w| w.rxdrdy().clear()); - - self.inner.events_rxdrdy.reset(); - - self.rx_waker.wake(); - self.rx_state = RxState::ReceivingReady; - more_work = true; // in case we also have endrx pending - } - } - RxState::ReceivingReady | RxState::Stopping => { - trace!(" irq_rx: in state ReceivingReady"); - - if self.inner.events_rxdrdy.read().bits() != 0 { - trace!(" irq_rx: rxdrdy"); - self.inner.events_rxdrdy.reset(); - } - - if self.inner.events_endrx.read().bits() != 0 { - let n: usize = self.inner.rxd.amount.read().amount().bits() as usize; - trace!(" irq_rx: endrx {:?}", n); - self.rx.push(n); - - self.inner.events_endrx.reset(); - - self.rx_waker.wake(); - self.rx_state = RxState::Idle; - more_work = true; // start another rx if possible - } - } - } + self.uarte + .instance + .tasks_stoprx + .write(|w| unsafe { w.bits(1) }); + self.uarte.instance.events_rxstarted.reset(); } + } +} - more_work = true; - while more_work { - more_work = false; - match self.tx_state { - TxState::Idle => { - trace!(" irq_tx: in state Idle"); - let buf = self.tx.pop_buf(); - if buf.len() != 0 { - trace!(" irq_tx: starting {:?}", buf.len()); - self.tx_state = TxState::Transmitting(buf.len()); +impl<'a, B> Future for ReceiveFuture<'a, B> +where + B: StaticWriteBuffer, +{ + type Output = B; - // Set up the DMA write - self.inner.txd.ptr.write(|w| - // The PTR field is a full 32 bits wide and accepts the full range - // of values. - unsafe { w.ptr().bits(buf.as_ptr() as u32) }); - self.inner.txd.maxcnt.write(|w| - // We're giving it the length of the buffer, so no danger of - // accessing invalid memory. We have verified that the length of the - // buffer fits in an `u8`, so the cast to `u8` is also fine. - // - // The MAXCNT field is 8 bits wide and accepts the full range of - // values. - unsafe { w.maxcnt().bits(buf.len() as _) }); + fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + if self.is_ready() { + Poll::Ready(()) + } else { + // Start DMA transaction + compiler_fence(Ordering::SeqCst); + // uarte.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); + // uarte + // .txd + // .maxcnt + // .write(|w| unsafe { w.maxcnt().bits(len as _) }); - // Start UARTE Transmit transaction - self.inner.tasks_starttx.write(|w| - // `1` is a valid value to write to task registers. - unsafe { w.bits(1) }); - } - } - TxState::Transmitting(n) => { - trace!(" irq_tx: in state Transmitting"); - // Start the DMA transfer - // See https://github.com/mwkroening/async-stm32f1xx/blob/78c46d1bff124eae4ebc7a2f4d40e6ed74def8b5/src/serial.rs#L118-L129 - // https://github.com/stm32-rs/stm32f1xx-hal/blob/68fd3d6f282173816fd3181e795988d314cb17d0/src/serial.rs#L649-L671 + // Start the DMA transfer + // See https://github.com/mwkroening/async-stm32f1xx/blob/78c46d1bff124eae4ebc7a2f4d40e6ed74def8b5/src/serial.rs#L118-L129 + // https://github.com/stm32-rs/stm32f1xx-hal/blob/68fd3d6f282173816fd3181e795988d314cb17d0/src/serial.rs#L649-L671 - let first_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); - let second_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); - let triple_buffer = Some(singleton!(: [u8; 128] = [0; 128]).unwrap()); + // let first_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); + // let second_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); + // let triple_buffer = Some(singleton!(: [u8; 128] = [0; 128]).unwrap()); - let transfer = Transfer::init( - StreamsTuple::new(pins.dma).7, - pins.usart, - first_buffer, - Some(second_buffer), - DmaConfig::default() - .transfer_complete_interrupt(true) - .memory_increment(true) - .double_buffer(true), - ); + let transfer = Transfer::init( + StreamsTuple::new(self.dma).7, + self.usart, + self.buf, + // Some(second_buffer), + None, + DmaConfig::default() + .transfer_complete_interrupt(true) + .memory_increment(true) + .double_buffer(false), + ); - if self.inner.events_endtx.read().bits() != 0 { - self.inner.events_endtx.reset(); - - trace!(" irq_tx: endtx {:?}", n); - self.tx.pop(n); - self.tx_waker.wake(); - self.tx_state = TxState::Idle; - more_work = true; // start another tx if possible - } - } - } + waker_interrupt!(DMA2_STREAM7, cx.waker().clone()); + Poll::Pending } - trace!("irq: end"); } } -pub struct Pins { - pub rxd: PA10>, - pub txd: PA9>, - pub dma: DMA2, - pub usart: USART1, - // pub cts: Option>>, - // pub rts: Option>>, -} - -mod private { - pub trait Sealed {} - - impl Sealed for crate::pac::UARTE0 {} - #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] - impl Sealed for crate::pac::UARTE1 {} -} - -pub trait Instance: Deref + Sized + private::Sealed { - fn interrupt() -> Interrupt; - - #[doc(hidden)] - fn get_state(_cs: &CriticalSection) -> *mut UarteState; - - #[doc(hidden)] - fn set_state(_cs: &CriticalSection, state: *mut UarteState); -} - -#[interrupt] -unsafe fn DMA2_CHANNEL2() { - interrupt::free(|cs| UARTE0::get_state(cs).as_mut().unwrap().on_interrupt()); -} - -#[interrupt] -unsafe fn DMA2_CHANNEL7() { - interrupt::free(|cs| UARTE1::get_state(cs).as_mut().unwrap().on_interrupt()); -} - -static mut UARTE0_STATE: *mut UarteState = ptr::null_mut(); -#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] -static mut UARTE1_STATE: *mut UarteState = ptr::null_mut(); - -impl Instance for DMA_CHANNEL1 { - fn interrupt() -> Interrupt { - Interrupt::UARTE0_UART0 - } - - fn get_state(_cs: &CriticalSection) -> *mut UarteState { - unsafe { UARTE0_STATE } // Safe because of CriticalSection - } - fn set_state(_cs: &CriticalSection, state: *mut UarteState) { - unsafe { UARTE0_STATE = state } // Safe because of CriticalSection - } -} - -#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] -impl Instance for UARTE1 { - fn interrupt() -> Interrupt { - Interrupt::UARTE1 - } - - fn get_state(_cs: &CriticalSection) -> *mut UarteState { - unsafe { UARTE1_STATE } // Safe because of CriticalSection - } - fn set_state(_cs: &CriticalSection, state: *mut UarteState) { - unsafe { UARTE1_STATE = state } // Safe because of CriticalSection +/// Future for the [`receive()`] method. +impl<'a, B> ReceiveFuture<'a, B> { + /// Stops the ongoing reception and returns the number of bytes received. + pub async fn stop(mut self) -> (B, usize) { + let buf = self.buf.take().unwrap(); + drop(self); + let len = STATE.rx_done.wait().await; + (buf, len as _) } } From 74b5d4693c91c23d0c2b75f213323ba1fc4d8bce Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 29 Dec 2020 12:33:50 -0600 Subject: [PATCH 07/30] implement prelim draft --- embassy-stm32f4/Cargo.toml | 2 +- embassy-stm32f4/src/lib.rs | 1 + embassy-stm32f4/src/uarte.rs | 246 ++++++++++------------------------- 3 files changed, 72 insertions(+), 177 deletions(-) diff --git a/embassy-stm32f4/Cargo.toml b/embassy-stm32f4/Cargo.toml index 654ea69a6..1891a5596 100644 --- a/embassy-stm32f4/Cargo.toml +++ b/embassy-stm32f4/Cargo.toml @@ -40,4 +40,4 @@ 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" } +stm32f4xx-hal = { version = "0.8.3", features = ["rt"], git = "https://github.com/xoviat/stm32f4xx-hal.git", branch = "dma-is-done"} diff --git a/embassy-stm32f4/src/lib.rs b/embassy-stm32f4/src/lib.rs index 40386085a..e6d523d21 100644 --- a/embassy-stm32f4/src/lib.rs +++ b/embassy-stm32f4/src/lib.rs @@ -2,6 +2,7 @@ #![feature(generic_associated_types)] #![feature(asm)] #![feature(type_alias_impl_trait)] +#![feature(let_chains)] #[cfg(not(any( feature = "stm32f401", diff --git a/embassy-stm32f4/src/uarte.rs b/embassy-stm32f4/src/uarte.rs index 9e253dd9f..273c384cb 100644 --- a/embassy-stm32f4/src/uarte.rs +++ b/embassy-stm32f4/src/uarte.rs @@ -16,11 +16,14 @@ use core::task::{Context, Poll}; use cortex_m::singleton; use embassy::util::Signal; -use embedded_dma::{StaticReadBuffer, StaticWriteBuffer}; +use embedded_dma::{StaticReadBuffer, StaticWriteBuffer, WriteBuffer}; use crate::fmt::assert; use crate::hal::dma::config::DmaConfig; -use crate::hal::dma::{Channel4, PeripheralToMemory, Stream2, StreamsTuple, Transfer}; +use crate::hal::dma::{ + Channel4, Channel7, MemoryToPeripheral, PeripheralToMemory, Stream2, Stream7, StreamsTuple, + Transfer, +}; use crate::hal::gpio::gpioa::{PA10, PA9}; use crate::hal::gpio::{Alternate, AF10, AF7, AF9}; use crate::hal::gpio::{Floating, Input, Output, PushPull}; @@ -94,45 +97,15 @@ impl Uarte { ) .unwrap(); - let isr = pins.dma.hisr;0 + // let is_set = dma.hifcr.read().tcif7.bit_is_set(); - Uarte { instance: serial, dma: pins.dma, usart: pins.usart } + Uarte { + instance: serial, + dma: pins.dma, + usart: pins.usart, + } } - /// Sets the baudrate, parity and assigns the pins to the UARTE peripheral. - // TODO: Make it take the same `Pins` structs nrf-hal (with optional RTS/CTS). - // // TODO: #[cfg()] for smaller device variants without port register (nrf52810, ...). - // pub fn configure( - // &mut self, - // rxd: &Pin>, - // txd: &mut Pin>, - // parity: Parity, - // baudrate: Baudrate, - // ) { - // let uarte = &self.instance; - // assert!(uarte.enable.read().enable().is_disabled()); - // - // uarte.psel.rxd.write(|w| { - // let w = unsafe { w.pin().bits(rxd.pin()) }; - // let w = w.port().bit(rxd.port().bit()); - // w.connect().connected() - // }); - // - // txd.set_high().unwrap(); - // uarte.psel.txd.write(|w| { - // let w = unsafe { w.pin().bits(txd.pin()) }; - // let w = w.port().bit(txd.port().bit()); - // w.connect().connected() - // }); - // - // uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); - // uarte.config.write(|w| w.parity().variant(parity)); - // } - - // fn enable(&mut self) { - // self.instance.enable.write(|w| w.enable().enabled()); - // } - /// Sends serial data. /// /// `tx_buffer` is marked as static as per `embedded-dma` requirements. @@ -140,25 +113,15 @@ impl Uarte { /// reused until the future has finished. pub fn send<'a, B>(&'a mut self, tx_buffer: B) -> SendFuture<'a, B> where - B: StaticReadBuffer, + B: WriteBuffer + 'static, { - // Panic if TX is running which can happen if the user has called - // `mem::forget()` on a previous future after polling it once. - assert!(!self.tx_started()); - - self.enable(); - SendFuture { uarte: self, buf: tx_buffer, + transfer: None, } } - fn tx_started(&self) -> bool { - // self.instance.events_txstarted.read().bits() != 0 - false - } - /// Receives serial data. /// /// The future is pending until the buffer is completely filled. @@ -171,83 +134,45 @@ impl Uarte { /// reused until the future has finished. pub fn receive<'a, B>(&'a mut self, rx_buffer: B) -> ReceiveFuture<'a, B> where - B: StaticWriteBuffer, + B: WriteBuffer + 'static, { - // Panic if RX is running which can happen if the user has called - // `mem::forget()` on a previous future after polling it once. - assert!(!self.rx_started()); - - self.enable(); - ReceiveFuture { uarte: self, - buf: Some(rx_buffer), + buf: rx_buffer, + transfer: None, } } - - fn rx_started(&self) -> bool { - self.instance.events_rxstarted.read().bits() != 0 - } } /// Future for the [`LowPowerUarte::send()`] method. -pub struct SendFuture<'a, B> { +pub struct SendFuture<'a, B: WriteBuffer + 'static> { uarte: &'a Uarte, + transfer: Option<&'a Transfer, Channel4, USART1, MemoryToPeripheral, B>>, buf: B, } -impl<'a, B> Drop for SendFuture<'a, B> { +impl<'a, B> Drop for SendFuture<'a, B> +where + B: WriteBuffer + 'static, +{ fn drop(self: &mut Self) { - if self.uarte.tx_started() { - trace!("stoptx"); - - // Stop the transmitter to minimize the current consumption. - self.uarte - .instance - .tasks_stoptx - .write(|w| unsafe { w.bits(1) }); - self.uarte.instance.events_txstarted.reset(); - } + drop(self.transfer); } } impl<'a, B> Future for SendFuture<'a, B> where - B: StaticReadBuffer, + B: WriteBuffer + 'static, { type Output = (); fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { - if self.is_ready() { + if !self.transfer.is_none() && self.transfer.unwrap().is_done() { Poll::Ready(()) } else { - // Start DMA transaction - let uarte = &self.uarte.instance; - - STATE.tx_done.reset(); - - let (ptr, len) = unsafe { self.buf.read_buffer() }; - // assert!(len <= EASY_DMA_SIZE); - // TODO: panic if buffer is not in SRAM - - compiler_fence(Ordering::SeqCst); - // uarte.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - // uarte - // .txd - // .maxcnt - // .write(|w| unsafe { w.maxcnt().bits(len as _) }); - - // Start the DMA transfer - // See https://github.com/mwkroening/async-stm32f1xx/blob/78c46d1bff124eae4ebc7a2f4d40e6ed74def8b5/src/serial.rs#L118-L129 - // https://github.com/stm32-rs/stm32f1xx-hal/blob/68fd3d6f282173816fd3181e795988d314cb17d0/src/serial.rs#L649-L671 - - // let first_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); - // let second_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); - // let triple_buffer = Some(singleton!(: [u8; 128] = [0; 128]).unwrap()); - - let transfer = Transfer::init( - StreamsTuple::new(self.dma).2, - self.usart, + self.transfer = Some(&mut Transfer::init( + StreamsTuple::new(self.uarte.dma).7, + self.uarte.usart, self.buf, // Some(second_buffer), None, @@ -255,71 +180,7 @@ where .transfer_complete_interrupt(true) .memory_increment(true) .double_buffer(false), - ); - - waker_interrupt!(DMA2_STREAM2, cx.waker().clone()); - Poll::Pending - } - } -} - -/// Future for the [`Uarte::receive()`] method. -pub struct ReceiveFuture<'a, B> { - uarte: &'a Uarte, - buf: Option, -} - -impl<'a, B> Drop for ReceiveFuture<'a, B> { - fn drop(self: &mut Self) { - if self.uarte.rx_started() { - trace!("stoprx"); - - self.uarte - .instance - .tasks_stoprx - .write(|w| unsafe { w.bits(1) }); - self.uarte.instance.events_rxstarted.reset(); - } - } -} - -impl<'a, B> Future for ReceiveFuture<'a, B> -where - B: StaticWriteBuffer, -{ - type Output = B; - - fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - if self.is_ready() { - Poll::Ready(()) - } else { - // Start DMA transaction - compiler_fence(Ordering::SeqCst); - // uarte.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - // uarte - // .txd - // .maxcnt - // .write(|w| unsafe { w.maxcnt().bits(len as _) }); - - // Start the DMA transfer - // See https://github.com/mwkroening/async-stm32f1xx/blob/78c46d1bff124eae4ebc7a2f4d40e6ed74def8b5/src/serial.rs#L118-L129 - // https://github.com/stm32-rs/stm32f1xx-hal/blob/68fd3d6f282173816fd3181e795988d314cb17d0/src/serial.rs#L649-L671 - - // let first_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); - // let second_buffer = singleton!(: [u8; 128] = [0; 128]).unwrap(); - // let triple_buffer = Some(singleton!(: [u8; 128] = [0; 128]).unwrap()); - - let transfer = Transfer::init( - StreamsTuple::new(self.dma).7, - self.usart, - self.buf, - // Some(second_buffer), - None, - DmaConfig::default() - .transfer_complete_interrupt(true) - .memory_increment(true) - .double_buffer(false), - ); + )); waker_interrupt!(DMA2_STREAM7, cx.waker().clone()); Poll::Pending @@ -327,13 +188,46 @@ where } } -/// Future for the [`receive()`] method. -impl<'a, B> ReceiveFuture<'a, B> { - /// Stops the ongoing reception and returns the number of bytes received. - pub async fn stop(mut self) -> (B, usize) { - let buf = self.buf.take().unwrap(); - drop(self); - let len = STATE.rx_done.wait().await; - (buf, len as _) +/// Future for the [`Uarte::receive()`] method. +pub struct ReceiveFuture<'a, B: WriteBuffer + 'static> { + uarte: &'a Uarte, + transfer: Option<&'a Transfer, Channel4, USART1, PeripheralToMemory, B>>, + buf: B, +} + +impl<'a, B> Drop for ReceiveFuture<'a, B> +where + B: WriteBuffer + 'static, +{ + fn drop(self: &mut Self) { + drop(self.transfer); + } +} + +impl<'a, B> Future for ReceiveFuture<'a, B> +where + B: WriteBuffer + 'static, +{ + type Output = B; + + fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + if !self.transfer.is_none() && self.transfer.unwrap().is_done() { + Poll::Ready(self.buf.take()); + } else { + self.transfer = Some(&mut Transfer::init( + StreamsTuple::new(self.uarte.dma).2, + self.uarte.usart, + self.buf, + None, + DmaConfig::default() + .transfer_complete_interrupt(true) + .half_transfer_interrupt(true) + .memory_increment(true) + .double_buffer(false), + )); + + waker_interrupt!(DMA2_STREAM2, cx.waker().clone()); + Poll::Pending + } } } From 53c2829eb17a233f848e64162d16491d18d7bafa Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 29 Dec 2020 19:10:47 -0600 Subject: [PATCH 08/30] add dma example; rename uarte --- Cargo.toml | 1 + embassy-stm32f4/src/lib.rs | 2 +- embassy-stm32f4/src/{uarte.rs => serial.rs} | 0 examples-stm32f4/Cargo.toml | 38 ++++++ examples-stm32f4/src/dma_adc.rs | 125 ++++++++++++++++++++ 5 files changed, 165 insertions(+), 1 deletion(-) rename embassy-stm32f4/src/{uarte.rs => serial.rs} (100%) create mode 100644 examples-stm32f4/Cargo.toml create mode 100644 examples-stm32f4/src/dma_adc.rs diff --git a/Cargo.toml b/Cargo.toml index e1a1c34b5..be98b26f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "embassy-stm32f4", "embassy-macros", "examples", + "examples-stm32f4", ] exclude = [ diff --git a/embassy-stm32f4/src/lib.rs b/embassy-stm32f4/src/lib.rs index e6d523d21..cfcb49bcb 100644 --- a/embassy-stm32f4/src/lib.rs +++ b/embassy-stm32f4/src/lib.rs @@ -361,6 +361,6 @@ macro_rules! waker_interrupt { // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; -pub mod uarte; +pub mod serial; pub use cortex_m_rt::interrupt; diff --git a/embassy-stm32f4/src/uarte.rs b/embassy-stm32f4/src/serial.rs similarity index 100% rename from embassy-stm32f4/src/uarte.rs rename to embassy-stm32f4/src/serial.rs diff --git a/examples-stm32f4/Cargo.toml b/examples-stm32f4/Cargo.toml new file mode 100644 index 000000000..0fdb21b4e --- /dev/null +++ b/examples-stm32f4/Cargo.toml @@ -0,0 +1,38 @@ +[package] +authors = ["Dario Nieuwenhuis "] +edition = "2018" +name = "embassy-examples-stm32f4" +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/xoviat/stm32f4xx-hal.git", branch = "dma-is-done"} +futures = { version = "0.3.8", default-features = false, features = ["async-await"] } +cortex-m-rtic = "0.5" # { git = "https://github.com/rtic-rs/cortex-m-rtic", branch = "master"} +rtt-target = { version = "0.3", features = ["cortex-m"] } + + +[[bin]] +name = "dma_adc" +path = "src/dma_adc.rs" \ No newline at end of file diff --git a/examples-stm32f4/src/dma_adc.rs b/examples-stm32f4/src/dma_adc.rs new file mode 100644 index 000000000..110bda306 --- /dev/null +++ b/examples-stm32f4/src/dma_adc.rs @@ -0,0 +1,125 @@ +#![no_std] +#![no_main] +#![feature(lang_items)] + +use core::{ + panic::PanicInfo, + sync::atomic::{compiler_fence, Ordering}, +}; + +use cortex_m::singleton; +use rtic::app; +// use rtt_target::{rprintln, rtt_init_print}; +use stm32f4xx_hal::{ + dma::{config::DmaConfig, Channel0, PeripheralToMemory, Stream0, StreamsTuple, Transfer}, + pac::{ADC1, DMA2, RCC}, + prelude::*, +}; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +type DmaTransfer = + Transfer, Channel0, ADC1, PeripheralToMemory, &'static mut [u16; 128]>; + +#[app(device = stm32f4xx_hal::pac, peripherals = true)] +const APP: () = { + struct Resources { + transfer: DmaTransfer, + triple_buffer: Option<&'static mut [u16; 128]>, + } + + #[init] + fn init(cx: init::Context) -> init::LateResources { + let rcc = cx.device.RCC.constrain(); + + // rtt_init_print!(); + // rprintln!("Init"); + + let _clocks = rcc + .cfgr + .sysclk(84.mhz()) + .pclk2(28.mhz()) + .pclk1(28.mhz()) + .freeze(); + + let gpioa = cx.device.GPIOA.split(); + let _pa0 = gpioa.pa0.into_analog(); + + let stream_0 = StreamsTuple::new(cx.device.DMA2).0; + let config = DmaConfig::default() + .transfer_complete_interrupt(true) + .memory_increment(true) + .double_buffer(true); + + let rcc = unsafe { &*RCC::ptr() }; + rcc.apb2enr.modify(|_, w| w.adc1en().enabled()); + rcc.apb2rstr.modify(|_, w| w.adcrst().set_bit()); + rcc.apb2rstr.modify(|_, w| w.adcrst().clear_bit()); + let adc = cx.device.ADC1; + adc.cr2.modify(|_, w| { + w.dma() + .enabled() + .cont() + .continuous() + .dds() + .continuous() + .adon() + .enabled() + }); + + let first_buffer = singleton!(: [u16; 128] = [0; 128]).unwrap(); + let second_buffer = singleton!(: [u16; 128] = [0; 128]).unwrap(); + let triple_buffer = Some(singleton!(: [u16; 128] = [0; 128]).unwrap()); + + let transfer = Transfer::init(stream_0, adc, first_buffer, Some(second_buffer), config); + + // rprintln!("Finished init"); + init::LateResources { + transfer, + triple_buffer, + } + } + + #[idle(resources = [transfer])] + fn idle(mut cx: idle::Context) -> ! { + cx.resources.transfer.lock(|shared| { + shared.start(|adc| { + adc.cr2.modify(|_, w| w.swstart().start()); + }); + }); + // rprintln!("DMA started"); + loop { + compiler_fence(Ordering::SeqCst); + } + } + + #[task(binds = DMA2_STREAM0, priority = 2, resources = [transfer, triple_buffer])] + fn dma(cx: dma::Context) { + static mut COUNT: usize = 0; + + let triple = cx.resources.triple_buffer.take().unwrap(); + let buf = cx + .resources + .transfer + .next_transfer(triple) + .map_err(|_| {}) + .unwrap() + .0; + if *COUNT % (1 << 14) == 0 { + // rprintln!("Buf: {:?}", &buf[0..10]); + } + *COUNT += 1; + *cx.resources.triple_buffer = Some(buf); + } +}; + +#[inline(never)] +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + cortex_m::interrupt::disable(); + // rprintln!("{}", info); + loop { + compiler_fence(Ordering::SeqCst); + } +} From 41db867d9a643dac2a24916fc170e35c7f32df56 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 29 Dec 2020 22:57:00 -0600 Subject: [PATCH 09/30] fix transfer mutability --- embassy-stm32f4/src/serial.rs | 146 +++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 62 deletions(-) diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index 273c384cb..403512535 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -33,7 +33,7 @@ use crate::hal::rcc::Clocks; use crate::hal::serial::config::{ Config as SerialConfig, DmaConfig as SerialDmaConfig, Parity, StopBits, WordLength, }; -use crate::hal::serial::Serial; +use crate::hal::serial::{Event as SerialEvent, Serial}; use crate::hal::time::Bps; use crate::interrupt; @@ -48,9 +48,11 @@ use embedded_hal::digital::v2::OutputPin; /// Interface to the UARTE peripheral pub struct Uarte { - instance: Serial>, PA10>)>, - usart: USART1, - dma: DMA2, + // tx_transfer: Transfer, Channel4, USART1, MemoryToPeripheral, &mut [u8; 20]>, + // rx_transfer: Transfer, Channel4, USART1, PeripheralToMemory, &mut [u8; 20]>, + tx_stream: Option>, + rx_stream: Option>, + usart: Option, } struct State { @@ -63,15 +65,16 @@ static STATE: State = State { rx_done: Signal::new(), }; -pub struct Pins { - pub rxd: PA10>, - pub txd: PA9>, - pub dma: DMA2, - pub usart: USART1, -} - impl Uarte { - pub fn new(mut pins: Pins, parity: Parity, baudrate: Bps, clocks: Clocks) -> Self { + pub fn new( + rxd: PA10>, + txd: PA9>, + dma: DMA2, + usart: USART1, + parity: Parity, + baudrate: Bps, + clocks: Clocks, + ) -> Self { // // Enable interrupts // uarte.events_endtx.reset(); // uarte.events_endrx.reset(); @@ -83,9 +86,9 @@ impl Uarte { // interrupt::enable(interrupt::UARTE0_UART0); // Serial>, PA10>)> - let mut serial = Serial::usart1( - pins.usart, - (pins.txd, pins.rxd), + let serial = Serial::usart1( + usart, + (txd, rxd), SerialConfig { baudrate: baudrate, wordlength: WordLength::DataBits8, @@ -97,12 +100,24 @@ impl Uarte { ) .unwrap(); - // let is_set = dma.hifcr.read().tcif7.bit_is_set(); + let (usart, _) = serial.release(); + + /* + Note: for our application, it would be approrpiate to listen for idle events, + and to establish a method to capture data until idle. + */ + // serial.listen(SerialEvent::Idle); + + // tx_transfer.start(|usart| { + // // usart.cr2.modify(|_, w| w.swstart().start()); + // }); + + let streams = StreamsTuple::new(dma); Uarte { - instance: serial, - dma: pins.dma, - usart: pins.usart, + tx_stream: Some(streams.7), + rx_stream: Some(streams.2), + usart: Some(usart), } } @@ -115,10 +130,21 @@ impl Uarte { where B: WriteBuffer + 'static, { + let tx_stream = self.tx_stream.take().unwrap(); + let usart = self.usart.take().unwrap(); + SendFuture { uarte: self, - buf: tx_buffer, - transfer: None, + tx_transfer: Transfer::init( + tx_stream, + usart, + tx_buffer, + None, + DmaConfig::default() + .transfer_complete_interrupt(true) + .memory_increment(true) + .double_buffer(false), + ), } } @@ -136,10 +162,22 @@ impl Uarte { where B: WriteBuffer + 'static, { + let rx_stream = self.rx_stream.take().unwrap(); + let usart = self.usart.take().unwrap(); + ReceiveFuture { uarte: self, - buf: rx_buffer, - transfer: None, + rx_transfer: Transfer::init( + rx_stream, + usart, + rx_buffer, + None, + DmaConfig::default() + .transfer_complete_interrupt(true) + .half_transfer_interrupt(true) + .memory_increment(true) + .double_buffer(false), + ), } } } @@ -147,17 +185,14 @@ impl Uarte { /// Future for the [`LowPowerUarte::send()`] method. pub struct SendFuture<'a, B: WriteBuffer + 'static> { uarte: &'a Uarte, - transfer: Option<&'a Transfer, Channel4, USART1, MemoryToPeripheral, B>>, - buf: B, + tx_transfer: Transfer, Channel4, USART1, MemoryToPeripheral, B>, } impl<'a, B> Drop for SendFuture<'a, B> where B: WriteBuffer + 'static, { - fn drop(self: &mut Self) { - drop(self.transfer); - } + fn drop(self: &mut Self) {} } impl<'a, B> Future for SendFuture<'a, B> @@ -167,20 +202,10 @@ where type Output = (); fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { - if !self.transfer.is_none() && self.transfer.unwrap().is_done() { + if self.tx_transfer.is_done() { Poll::Ready(()) } else { - self.transfer = Some(&mut Transfer::init( - StreamsTuple::new(self.uarte.dma).7, - self.uarte.usart, - self.buf, - // Some(second_buffer), - None, - DmaConfig::default() - .transfer_complete_interrupt(true) - .memory_increment(true) - .double_buffer(false), - )); + // self.0.as_mut().tx_transfer.start(|usart| {}); waker_interrupt!(DMA2_STREAM7, cx.waker().clone()); Poll::Pending @@ -191,17 +216,14 @@ where /// Future for the [`Uarte::receive()`] method. pub struct ReceiveFuture<'a, B: WriteBuffer + 'static> { uarte: &'a Uarte, - transfer: Option<&'a Transfer, Channel4, USART1, PeripheralToMemory, B>>, - buf: B, + rx_transfer: Transfer, Channel4, USART1, PeripheralToMemory, B>, } impl<'a, B> Drop for ReceiveFuture<'a, B> where B: WriteBuffer + 'static, { - fn drop(self: &mut Self) { - drop(self.transfer); - } + fn drop(self: &mut Self) {} } impl<'a, B> Future for ReceiveFuture<'a, B> @@ -211,23 +233,23 @@ where type Output = B; fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - if !self.transfer.is_none() && self.transfer.unwrap().is_done() { - Poll::Ready(self.buf.take()); - } else { - self.transfer = Some(&mut Transfer::init( - StreamsTuple::new(self.uarte.dma).2, - self.uarte.usart, - self.buf, - None, - DmaConfig::default() - .transfer_complete_interrupt(true) - .half_transfer_interrupt(true) - .memory_increment(true) - .double_buffer(false), - )); + // if !self.transfer.is_none() && self.transfer.unwrap().is_done() { + // Poll::Ready(self.buf.take()); + // } else { + // self.transfer = Some(&mut Transfer::init( + // StreamsTuple::new(self.uarte.dma).2, + // self.uarte.usart, + // self.buf, + // None, + // DmaConfig::default() + // .transfer_complete_interrupt(true) + // .half_transfer_interrupt(true) + // .memory_increment(true) + // .double_buffer(false), + // )); - waker_interrupt!(DMA2_STREAM2, cx.waker().clone()); - Poll::Pending - } + waker_interrupt!(DMA2_STREAM2, cx.waker().clone()); + Poll::Pending + // } } } From 60c7d112b1718f98681ea16c44f2f5b51b51497c Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 30 Dec 2020 11:05:52 -0600 Subject: [PATCH 10/30] fix borrowing errors --- embassy-stm32f4/src/serial.rs | 113 +++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 48 deletions(-) diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index 403512535..599895100 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -132,19 +132,22 @@ impl Uarte { { let tx_stream = self.tx_stream.take().unwrap(); let usart = self.usart.take().unwrap(); + let mut tx_transfer = Transfer::init( + tx_stream, + usart, + tx_buffer, + None, + DmaConfig::default() + .transfer_complete_interrupt(true) + .memory_increment(true) + .double_buffer(false), + ); SendFuture { uarte: self, - tx_transfer: Transfer::init( - tx_stream, - usart, - tx_buffer, - None, - DmaConfig::default() - .transfer_complete_interrupt(true) - .memory_increment(true) - .double_buffer(false), - ), + tx_transfer: Some(tx_transfer), + // tx_stream: Some(tx_stream), + // usart: Some(usart), } } @@ -164,28 +167,29 @@ impl Uarte { { let rx_stream = self.rx_stream.take().unwrap(); let usart = self.usart.take().unwrap(); + let mut rx_transfer = Transfer::init( + rx_stream, + usart, + rx_buffer, + None, + DmaConfig::default() + .transfer_complete_interrupt(true) + .half_transfer_interrupt(true) + .memory_increment(true) + .double_buffer(false), + ); ReceiveFuture { uarte: self, - rx_transfer: Transfer::init( - rx_stream, - usart, - rx_buffer, - None, - DmaConfig::default() - .transfer_complete_interrupt(true) - .half_transfer_interrupt(true) - .memory_increment(true) - .double_buffer(false), - ), + rx_transfer: Some(rx_transfer), } } } /// Future for the [`LowPowerUarte::send()`] method. pub struct SendFuture<'a, B: WriteBuffer + 'static> { - uarte: &'a Uarte, - tx_transfer: Transfer, Channel4, USART1, MemoryToPeripheral, B>, + uarte: &'a mut Uarte, + tx_transfer: Option, Channel4, USART1, MemoryToPeripheral, B>>, } impl<'a, B> Drop for SendFuture<'a, B> @@ -202,12 +206,23 @@ where type Output = (); fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { - if self.tx_transfer.is_done() { + let Self { uarte, tx_transfer } = unsafe { self.get_unchecked_mut() }; + + if true { + // tx_transfer.unwrap().is_done() { + let (tx_stream, usart, buf, _) = tx_transfer.take().unwrap().free(); + + uarte.tx_stream.replace(tx_stream); + uarte.usart.replace(usart); + Poll::Ready(()) } else { - // self.0.as_mut().tx_transfer.start(|usart| {}); - waker_interrupt!(DMA2_STREAM7, cx.waker().clone()); + // tx_transfer.take().start(|usart| {}); + let mut taken = tx_transfer.take().unwrap(); + taken.start(|usart| {}); + tx_transfer.replace(taken); + Poll::Pending } } @@ -215,8 +230,8 @@ where /// Future for the [`Uarte::receive()`] method. pub struct ReceiveFuture<'a, B: WriteBuffer + 'static> { - uarte: &'a Uarte, - rx_transfer: Transfer, Channel4, USART1, PeripheralToMemory, B>, + uarte: &'a mut Uarte, + rx_transfer: Option, Channel4, USART1, PeripheralToMemory, B>>, } impl<'a, B> Drop for ReceiveFuture<'a, B> @@ -228,28 +243,30 @@ where impl<'a, B> Future for ReceiveFuture<'a, B> where - B: WriteBuffer + 'static, + B: WriteBuffer + 'static + Unpin, { - type Output = B; + type Output = (); - fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // if !self.transfer.is_none() && self.transfer.unwrap().is_done() { - // Poll::Ready(self.buf.take()); - // } else { - // self.transfer = Some(&mut Transfer::init( - // StreamsTuple::new(self.uarte.dma).2, - // self.uarte.usart, - // self.buf, - // None, - // DmaConfig::default() - // .transfer_complete_interrupt(true) - // .half_transfer_interrupt(true) - // .memory_increment(true) - // .double_buffer(false), - // )); + fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let Self { uarte, rx_transfer } = unsafe { self.get_unchecked_mut() }; - waker_interrupt!(DMA2_STREAM2, cx.waker().clone()); - Poll::Pending - // } + if true { + // self.rx_transfer.unwrap().is_done() { + let (rx_stream, usart, buf, _) = rx_transfer.take().unwrap().free(); + + uarte.rx_stream.replace(rx_stream); + uarte.usart.replace(usart); + + // Poll::Ready((buf)) + Poll::Ready(()) + } else { + waker_interrupt!(DMA2_STREAM2, cx.waker().clone()); + + let mut taken = rx_transfer.take().unwrap(); + taken.start(|usart| {}); + rx_transfer.replace(taken); + + Poll::Pending + } } } From c6cf9b801d45f606dc0e900359f975cdc0c2711c Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 30 Dec 2020 12:27:47 -0600 Subject: [PATCH 11/30] minor rework to get tx working (maybe) --- embassy-stm32f4/src/serial.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index 599895100..eac11d31e 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -207,10 +207,9 @@ where fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { let Self { uarte, tx_transfer } = unsafe { self.get_unchecked_mut() }; - - if true { - // tx_transfer.unwrap().is_done() { - let (tx_stream, usart, buf, _) = tx_transfer.take().unwrap().free(); + let mut taken = tx_transfer.take().unwrap(); + if taken.is_done() { + let (tx_stream, usart, buf, _) = taken.free(); uarte.tx_stream.replace(tx_stream); uarte.usart.replace(usart); @@ -218,8 +217,6 @@ where Poll::Ready(()) } else { waker_interrupt!(DMA2_STREAM7, cx.waker().clone()); - // tx_transfer.take().start(|usart| {}); - let mut taken = tx_transfer.take().unwrap(); taken.start(|usart| {}); tx_transfer.replace(taken); From a5cf65a17bf87dddf04d8c3c858710a54bc0c4b3 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 30 Dec 2020 19:45:07 -0600 Subject: [PATCH 12/30] impl. poll:ready --- embassy-stm32f4/src/serial.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index eac11d31e..57c970413 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -242,20 +242,18 @@ impl<'a, B> Future for ReceiveFuture<'a, B> where B: WriteBuffer + 'static + Unpin, { - type Output = (); + type Output = B; - fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let Self { uarte, rx_transfer } = unsafe { self.get_unchecked_mut() }; if true { - // self.rx_transfer.unwrap().is_done() { let (rx_stream, usart, buf, _) = rx_transfer.take().unwrap().free(); uarte.rx_stream.replace(rx_stream); uarte.usart.replace(usart); - // Poll::Ready((buf)) - Poll::Ready(()) + Poll::Ready(buf) } else { waker_interrupt!(DMA2_STREAM2, cx.waker().clone()); From ea36029a3d5cb0288702d5bc9d59c959cc4d4d5d Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 30 Dec 2020 19:50:15 -0600 Subject: [PATCH 13/30] reformat --- embassy-stm32f4/src/serial.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index 57c970413..02a1e8536 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -246,8 +246,8 @@ where fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let Self { uarte, rx_transfer } = unsafe { self.get_unchecked_mut() }; - - if true { + let mut taken = rx_transfer.take().unwrap(); + if taken.is_done() { let (rx_stream, usart, buf, _) = rx_transfer.take().unwrap().free(); uarte.rx_stream.replace(rx_stream); @@ -257,7 +257,6 @@ where } else { waker_interrupt!(DMA2_STREAM2, cx.waker().clone()); - let mut taken = rx_transfer.take().unwrap(); taken.start(|usart| {}); rx_transfer.replace(taken); From 2d979eb4ef01925803da083599bde5460a53f416 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 30 Dec 2020 21:14:56 -0600 Subject: [PATCH 14/30] add interrupts --- embassy-stm32f4/src/interrupt.rs | 177 +++++++++++++++++++++++++++++++ embassy-stm32f4/src/lib.rs | 1 + 2 files changed, 178 insertions(+) create mode 100644 embassy-stm32f4/src/interrupt.rs diff --git a/embassy-stm32f4/src/interrupt.rs b/embassy-stm32f4/src/interrupt.rs new file mode 100644 index 000000000..71f3f483e --- /dev/null +++ b/embassy-stm32f4/src/interrupt.rs @@ -0,0 +1,177 @@ +//! 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, +} + +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, + _ => 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 index cfcb49bcb..40a40ef4b 100644 --- a/embassy-stm32f4/src/lib.rs +++ b/embassy-stm32f4/src/lib.rs @@ -361,6 +361,7 @@ macro_rules! waker_interrupt { // 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; From 43904e8db05ef5b0ded2e7b1fc6beeb76ff63b3f Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 30 Dec 2020 21:24:32 -0600 Subject: [PATCH 15/30] clean-up example --- examples-stm32f4/Cargo.toml | 9 ++- examples-stm32f4/src/dma_adc.rs | 125 -------------------------------- examples-stm32f4/src/serial.rs | 60 +++++++++++++++ 3 files changed, 65 insertions(+), 129 deletions(-) delete mode 100644 examples-stm32f4/src/dma_adc.rs create mode 100644 examples-stm32f4/src/serial.rs diff --git a/examples-stm32f4/Cargo.toml b/examples-stm32f4/Cargo.toml index 0fdb21b4e..a9f2a79d7 100644 --- a/examples-stm32f4/Cargo.toml +++ b/examples-stm32f4/Cargo.toml @@ -18,7 +18,7 @@ defmt-error = [] [dependencies] embassy = { version = "0.1.0", path = "../embassy", features = ["defmt", "defmt-trace"] } -# embassy-stm32f4 = { version = "*", path = "../embassy-stm32f4", features = ["stm32f405"] } +embassy-stm32f4 = { version = "*", path = "../embassy-stm32f4", features = ["stm32f405"] } defmt = "0.1.3" defmt-rtt = "0.1.0" @@ -29,10 +29,11 @@ embedded-hal = { version = "0.2.4" } panic-probe = "0.1.0" stm32f4xx-hal = { version = "0.8.3", features = ["rt", "stm32f405"], git = "https://github.com/xoviat/stm32f4xx-hal.git", branch = "dma-is-done"} futures = { version = "0.3.8", default-features = false, features = ["async-await"] } -cortex-m-rtic = "0.5" # { git = "https://github.com/rtic-rs/cortex-m-rtic", branch = "master"} +cortex-m-rtic = "0.5" rtt-target = { version = "0.3", features = ["cortex-m"] } + [[bin]] -name = "dma_adc" -path = "src/dma_adc.rs" \ No newline at end of file +name = "serial" +path = "src/serial.rs" \ No newline at end of file diff --git a/examples-stm32f4/src/dma_adc.rs b/examples-stm32f4/src/dma_adc.rs deleted file mode 100644 index 110bda306..000000000 --- a/examples-stm32f4/src/dma_adc.rs +++ /dev/null @@ -1,125 +0,0 @@ -#![no_std] -#![no_main] -#![feature(lang_items)] - -use core::{ - panic::PanicInfo, - sync::atomic::{compiler_fence, Ordering}, -}; - -use cortex_m::singleton; -use rtic::app; -// use rtt_target::{rprintln, rtt_init_print}; -use stm32f4xx_hal::{ - dma::{config::DmaConfig, Channel0, PeripheralToMemory, Stream0, StreamsTuple, Transfer}, - pac::{ADC1, DMA2, RCC}, - prelude::*, -}; - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} - -type DmaTransfer = - Transfer, Channel0, ADC1, PeripheralToMemory, &'static mut [u16; 128]>; - -#[app(device = stm32f4xx_hal::pac, peripherals = true)] -const APP: () = { - struct Resources { - transfer: DmaTransfer, - triple_buffer: Option<&'static mut [u16; 128]>, - } - - #[init] - fn init(cx: init::Context) -> init::LateResources { - let rcc = cx.device.RCC.constrain(); - - // rtt_init_print!(); - // rprintln!("Init"); - - let _clocks = rcc - .cfgr - .sysclk(84.mhz()) - .pclk2(28.mhz()) - .pclk1(28.mhz()) - .freeze(); - - let gpioa = cx.device.GPIOA.split(); - let _pa0 = gpioa.pa0.into_analog(); - - let stream_0 = StreamsTuple::new(cx.device.DMA2).0; - let config = DmaConfig::default() - .transfer_complete_interrupt(true) - .memory_increment(true) - .double_buffer(true); - - let rcc = unsafe { &*RCC::ptr() }; - rcc.apb2enr.modify(|_, w| w.adc1en().enabled()); - rcc.apb2rstr.modify(|_, w| w.adcrst().set_bit()); - rcc.apb2rstr.modify(|_, w| w.adcrst().clear_bit()); - let adc = cx.device.ADC1; - adc.cr2.modify(|_, w| { - w.dma() - .enabled() - .cont() - .continuous() - .dds() - .continuous() - .adon() - .enabled() - }); - - let first_buffer = singleton!(: [u16; 128] = [0; 128]).unwrap(); - let second_buffer = singleton!(: [u16; 128] = [0; 128]).unwrap(); - let triple_buffer = Some(singleton!(: [u16; 128] = [0; 128]).unwrap()); - - let transfer = Transfer::init(stream_0, adc, first_buffer, Some(second_buffer), config); - - // rprintln!("Finished init"); - init::LateResources { - transfer, - triple_buffer, - } - } - - #[idle(resources = [transfer])] - fn idle(mut cx: idle::Context) -> ! { - cx.resources.transfer.lock(|shared| { - shared.start(|adc| { - adc.cr2.modify(|_, w| w.swstart().start()); - }); - }); - // rprintln!("DMA started"); - loop { - compiler_fence(Ordering::SeqCst); - } - } - - #[task(binds = DMA2_STREAM0, priority = 2, resources = [transfer, triple_buffer])] - fn dma(cx: dma::Context) { - static mut COUNT: usize = 0; - - let triple = cx.resources.triple_buffer.take().unwrap(); - let buf = cx - .resources - .transfer - .next_transfer(triple) - .map_err(|_| {}) - .unwrap() - .0; - if *COUNT % (1 << 14) == 0 { - // rprintln!("Buf: {:?}", &buf[0..10]); - } - *COUNT += 1; - *cx.resources.triple_buffer = Some(buf); - } -}; - -#[inline(never)] -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - cortex_m::interrupt::disable(); - // rprintln!("{}", info); - loop { - compiler_fence(Ordering::SeqCst); - } -} diff --git a/examples-stm32f4/src/serial.rs b/examples-stm32f4/src/serial.rs new file mode 100644 index 000000000..f7fd525a9 --- /dev/null +++ b/examples-stm32f4/src/serial.rs @@ -0,0 +1,60 @@ +#![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::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::Uarte::new( + gpioa.pa10.into_alternate_af7(), + gpioa.pa9.into_alternate_af7(), + 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(); + } +} From d52e1b22763755b29cdf55443e22ae01eecf8859 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 31 Dec 2020 15:58:35 -0600 Subject: [PATCH 16/30] use transfer_complete_flag; make partially generic --- embassy-stm32f4/src/serial.rs | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index 02a1e8536..0ea635dd4 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -20,6 +20,7 @@ use embedded_dma::{StaticReadBuffer, StaticWriteBuffer, WriteBuffer}; use crate::fmt::assert; use crate::hal::dma::config::DmaConfig; +use crate::hal::dma::traits::{PeriAddress, Stream}; use crate::hal::dma::{ Channel4, Channel7, MemoryToPeripheral, PeripheralToMemory, Stream2, Stream7, StreamsTuple, Transfer, @@ -161,7 +162,10 @@ impl Uarte { /// `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 mut self, rx_buffer: B) -> ReceiveFuture<'a, B> + pub fn receive<'a, B>( + &'a mut self, + rx_buffer: B, + ) -> ReceiveFuture<'a, B, Stream2, Channel4> where B: WriteBuffer + 'static, { @@ -208,7 +212,7 @@ where fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { let Self { uarte, tx_transfer } = unsafe { self.get_unchecked_mut() }; let mut taken = tx_transfer.take().unwrap(); - if taken.is_done() { + if Stream7::::get_transfer_complete_flag() { let (tx_stream, usart, buf, _) = taken.free(); uarte.tx_stream.replace(tx_stream); @@ -226,19 +230,24 @@ where } /// Future for the [`Uarte::receive()`] method. -pub struct ReceiveFuture<'a, B: WriteBuffer + 'static> { +pub struct ReceiveFuture<'a, B: WriteBuffer + 'static, STREAM: Stream, CHANNEL> { uarte: &'a mut Uarte, - rx_transfer: Option, Channel4, USART1, PeripheralToMemory, B>>, + rx_transfer: Option>, } -impl<'a, B> Drop for ReceiveFuture<'a, B> -where - B: WriteBuffer + 'static, -{ - fn drop(self: &mut Self) {} -} +// pub struct ReceiveFuture<'a, B: WriteBuffer + 'static, DMA, STREAM, CHANNEL> { +// uarte: &'a mut Uarte, +// rx_transfer: Option, Channel4, USART1, PeripheralToMemory, B>>, +// } -impl<'a, B> Future for ReceiveFuture<'a, B> +// impl<'a, B> Drop for ReceiveFuture<'a, B, USART1, Stream7, Channel4> +// where +// B: WriteBuffer + 'static, +// { +// fn drop(self: &mut Self) {} +// } + +impl<'a, B> Future for ReceiveFuture<'a, B, Stream2, Channel4> where B: WriteBuffer + 'static + Unpin, { @@ -247,7 +256,8 @@ where fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let Self { uarte, rx_transfer } = unsafe { self.get_unchecked_mut() }; let mut taken = rx_transfer.take().unwrap(); - if taken.is_done() { + + if Stream7::::get_transfer_complete_flag() { let (rx_stream, usart, buf, _) = rx_transfer.take().unwrap().free(); uarte.rx_stream.replace(rx_stream); From 142c01ad01ca1fc1fded25005659f212f36d235d Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 31 Dec 2020 16:11:23 -0600 Subject: [PATCH 17/30] generalize futures --- embassy-stm32f4/src/serial.rs | 45 +++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index 0ea635dd4..dcd71958d 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -127,7 +127,10 @@ impl Uarte { /// `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 mut self, tx_buffer: B) -> SendFuture<'a, B> + pub fn send<'a, B>( + &'a mut self, + tx_buffer: B, + ) -> SendFuture<'a, B, USART1, Stream7, Channel4> where B: WriteBuffer + 'static, { @@ -165,7 +168,7 @@ impl Uarte { pub fn receive<'a, B>( &'a mut self, rx_buffer: B, - ) -> ReceiveFuture<'a, B, Stream2, Channel4> + ) -> ReceiveFuture<'a, B, USART1, Stream2, Channel4> where B: WriteBuffer + 'static, { @@ -191,19 +194,25 @@ impl Uarte { } /// Future for the [`LowPowerUarte::send()`] method. -pub struct SendFuture<'a, B: WriteBuffer + 'static> { - uarte: &'a mut Uarte, - tx_transfer: Option, Channel4, USART1, MemoryToPeripheral, B>>, -} - -impl<'a, B> Drop for SendFuture<'a, B> -where +pub struct SendFuture< + 'a, B: WriteBuffer + 'static, -{ - fn drop(self: &mut Self) {} + USART: PeriAddress, + STREAM: Stream, + CHANNEL, +> { + uarte: &'a mut Uarte, + tx_transfer: Option>, } -impl<'a, B> Future for SendFuture<'a, B> +// impl<'a, B> Drop for SendFuture<'a, B> +// where +// B: WriteBuffer + 'static, +// { +// fn drop(self: &mut Self) {} +// } + +impl<'a, B> Future for SendFuture<'a, B, USART1, Stream7, Channel4> where B: WriteBuffer + 'static, { @@ -230,9 +239,15 @@ where } /// Future for the [`Uarte::receive()`] method. -pub struct ReceiveFuture<'a, B: WriteBuffer + 'static, STREAM: Stream, CHANNEL> { +pub struct ReceiveFuture< + 'a, + B: WriteBuffer + 'static, + USART: PeriAddress, + STREAM: Stream, + CHANNEL, +> { uarte: &'a mut Uarte, - rx_transfer: Option>, + rx_transfer: Option>, } // pub struct ReceiveFuture<'a, B: WriteBuffer + 'static, DMA, STREAM, CHANNEL> { @@ -247,7 +262,7 @@ pub struct ReceiveFuture<'a, B: WriteBuffer + 'static, STREAM: Stream // fn drop(self: &mut Self) {} // } -impl<'a, B> Future for ReceiveFuture<'a, B, Stream2, Channel4> +impl<'a, B> Future for ReceiveFuture<'a, B, USART1, Stream2, Channel4> where B: WriteBuffer + 'static + Unpin, { From 308756f3663161ec283622e4942770f831cb61b6 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 31 Dec 2020 16:38:31 -0600 Subject: [PATCH 18/30] generalize uarte --- embassy-stm32f4/src/serial.rs | 59 ++++++++++------------------------- 1 file changed, 17 insertions(+), 42 deletions(-) diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index dcd71958d..e414dc020 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -44,16 +44,13 @@ use crate::pac::{DMA2, USART1}; use embedded_hal::digital::v2::OutputPin; -// Re-export SVD variants to allow user to directly set values. -// pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; - /// Interface to the UARTE peripheral -pub struct Uarte { +pub struct Uarte, TSTREAM: Stream, RSTREAM: Stream> { // tx_transfer: Transfer, Channel4, USART1, MemoryToPeripheral, &mut [u8; 20]>, // rx_transfer: Transfer, Channel4, USART1, PeripheralToMemory, &mut [u8; 20]>, - tx_stream: Option>, - rx_stream: Option>, - usart: Option, + tx_stream: Option, + rx_stream: Option, + usart: Option, } struct State { @@ -66,7 +63,7 @@ static STATE: State = State { rx_done: Signal::new(), }; -impl Uarte { +impl Uarte, Stream2> { pub fn new( rxd: PA10>, txd: PA9>, @@ -76,17 +73,6 @@ impl Uarte { baudrate: Bps, clocks: Clocks, ) -> Self { - // // Enable interrupts - // uarte.events_endtx.reset(); - // uarte.events_endrx.reset(); - // uarte - // .intenset - // .write(|w| w.endtx().set().txstopped().set().endrx().set().rxto().set()); - // // TODO: Set interrupt priority? - // interrupt::unpend(interrupt::UARTE0_UART0); - // interrupt::enable(interrupt::UARTE0_UART0); - - // Serial>, PA10>)> let serial = Serial::usart1( usart, (txd, rxd), @@ -103,16 +89,8 @@ impl Uarte { let (usart, _) = serial.release(); - /* - Note: for our application, it would be approrpiate to listen for idle events, - and to establish a method to capture data until idle. - */ // serial.listen(SerialEvent::Idle); - // tx_transfer.start(|usart| { - // // usart.cr2.modify(|_, w| w.swstart().start()); - // }); - let streams = StreamsTuple::new(dma); Uarte { @@ -130,7 +108,7 @@ impl Uarte { pub fn send<'a, B>( &'a mut self, tx_buffer: B, - ) -> SendFuture<'a, B, USART1, Stream7, Channel4> + ) -> SendFuture<'a, B, USART1, Stream7, Stream2, Channel4> where B: WriteBuffer + 'static, { @@ -168,7 +146,7 @@ impl Uarte { pub fn receive<'a, B>( &'a mut self, rx_buffer: B, - ) -> ReceiveFuture<'a, B, USART1, Stream2, Channel4> + ) -> ReceiveFuture<'a, B, USART1, Stream7, Stream2, Channel4> where B: WriteBuffer + 'static, { @@ -198,11 +176,12 @@ pub struct SendFuture< 'a, B: WriteBuffer + 'static, USART: PeriAddress, - STREAM: Stream, + TSTREAM: Stream, + RSTREAM: Stream, CHANNEL, > { - uarte: &'a mut Uarte, - tx_transfer: Option>, + uarte: &'a mut Uarte, + tx_transfer: Option>, } // impl<'a, B> Drop for SendFuture<'a, B> @@ -212,7 +191,7 @@ pub struct SendFuture< // fn drop(self: &mut Self) {} // } -impl<'a, B> Future for SendFuture<'a, B, USART1, Stream7, Channel4> +impl<'a, B> Future for SendFuture<'a, B, USART1, Stream7, Stream2, Channel4> where B: WriteBuffer + 'static, { @@ -243,18 +222,14 @@ pub struct ReceiveFuture< 'a, B: WriteBuffer + 'static, USART: PeriAddress, - STREAM: Stream, + TSTREAM: Stream, + RSTREAM: Stream, CHANNEL, > { - uarte: &'a mut Uarte, - rx_transfer: Option>, + uarte: &'a mut Uarte, + rx_transfer: Option>, } -// pub struct ReceiveFuture<'a, B: WriteBuffer + 'static, DMA, STREAM, CHANNEL> { -// uarte: &'a mut Uarte, -// rx_transfer: Option, Channel4, USART1, PeripheralToMemory, B>>, -// } - // impl<'a, B> Drop for ReceiveFuture<'a, B, USART1, Stream7, Channel4> // where // B: WriteBuffer + 'static, @@ -262,7 +237,7 @@ pub struct ReceiveFuture< // fn drop(self: &mut Self) {} // } -impl<'a, B> Future for ReceiveFuture<'a, B, USART1, Stream2, Channel4> +impl<'a, B> Future for ReceiveFuture<'a, B, USART1, Stream7, Stream2, Channel4> where B: WriteBuffer + 'static + Unpin, { From 925ede848ec1fc3389b5bbd22d98d919c808bfe3 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 31 Dec 2020 16:40:51 -0600 Subject: [PATCH 19/30] rename uarte as serial --- embassy-stm32f4/src/serial.rs | 44 +++++++++++++++++++--------------- examples-stm32f4/src/serial.rs | 2 +- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index e414dc020..bb47a9301 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -1,4 +1,4 @@ -//! Async low power UARTE. +//! 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 @@ -34,7 +34,7 @@ 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}; +use crate::hal::serial::{Event as SerialEvent, Serial as HalSerial}; use crate::hal::time::Bps; use crate::interrupt; @@ -44,8 +44,8 @@ use crate::pac::{DMA2, USART1}; use embedded_hal::digital::v2::OutputPin; -/// Interface to the UARTE peripheral -pub struct Uarte, TSTREAM: Stream, RSTREAM: Stream> { +/// Interface to the Serial peripheral +pub struct Serial, TSTREAM: Stream, RSTREAM: Stream> { // tx_transfer: Transfer, Channel4, USART1, MemoryToPeripheral, &mut [u8; 20]>, // rx_transfer: Transfer, Channel4, USART1, PeripheralToMemory, &mut [u8; 20]>, tx_stream: Option, @@ -63,7 +63,7 @@ static STATE: State = State { rx_done: Signal::new(), }; -impl Uarte, Stream2> { +impl Serial, Stream2> { pub fn new( rxd: PA10>, txd: PA9>, @@ -73,7 +73,7 @@ impl Uarte, Stream2> { baudrate: Bps, clocks: Clocks, ) -> Self { - let serial = Serial::usart1( + let serial = HalSerial::usart1( usart, (txd, rxd), SerialConfig { @@ -93,7 +93,7 @@ impl Uarte, Stream2> { let streams = StreamsTuple::new(dma); - Uarte { + Serial { tx_stream: Some(streams.7), rx_stream: Some(streams.2), usart: Some(usart), @@ -126,7 +126,7 @@ impl Uarte, Stream2> { ); SendFuture { - uarte: self, + Serial: self, tx_transfer: Some(tx_transfer), // tx_stream: Some(tx_stream), // usart: Some(usart), @@ -165,13 +165,13 @@ impl Uarte, Stream2> { ); ReceiveFuture { - uarte: self, + Serial: self, rx_transfer: Some(rx_transfer), } } } -/// Future for the [`LowPowerUarte::send()`] method. +/// Future for the [`LowPowerSerial::send()`] method. pub struct SendFuture< 'a, B: WriteBuffer + 'static, @@ -180,7 +180,7 @@ pub struct SendFuture< RSTREAM: Stream, CHANNEL, > { - uarte: &'a mut Uarte, + Serial: &'a mut Serial, tx_transfer: Option>, } @@ -198,13 +198,16 @@ where type Output = (); fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { - let Self { uarte, tx_transfer } = unsafe { self.get_unchecked_mut() }; + let Self { + Serial, + tx_transfer, + } = unsafe { self.get_unchecked_mut() }; let mut taken = tx_transfer.take().unwrap(); if Stream7::::get_transfer_complete_flag() { let (tx_stream, usart, buf, _) = taken.free(); - uarte.tx_stream.replace(tx_stream); - uarte.usart.replace(usart); + Serial.tx_stream.replace(tx_stream); + Serial.usart.replace(usart); Poll::Ready(()) } else { @@ -217,7 +220,7 @@ where } } -/// Future for the [`Uarte::receive()`] method. +/// Future for the [`Serial::receive()`] method. pub struct ReceiveFuture< 'a, B: WriteBuffer + 'static, @@ -226,7 +229,7 @@ pub struct ReceiveFuture< RSTREAM: Stream, CHANNEL, > { - uarte: &'a mut Uarte, + Serial: &'a mut Serial, rx_transfer: Option>, } @@ -244,14 +247,17 @@ where type Output = B; fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let Self { uarte, rx_transfer } = unsafe { self.get_unchecked_mut() }; + let Self { + Serial, + rx_transfer, + } = unsafe { self.get_unchecked_mut() }; let mut taken = rx_transfer.take().unwrap(); if Stream7::::get_transfer_complete_flag() { let (rx_stream, usart, buf, _) = rx_transfer.take().unwrap().free(); - uarte.rx_stream.replace(rx_stream); - uarte.usart.replace(usart); + Serial.rx_stream.replace(rx_stream); + Serial.usart.replace(usart); Poll::Ready(buf) } else { diff --git a/examples-stm32f4/src/serial.rs b/examples-stm32f4/src/serial.rs index f7fd525a9..1f5c0fb7a 100644 --- a/examples-stm32f4/src/serial.rs +++ b/examples-stm32f4/src/serial.rs @@ -26,7 +26,7 @@ async fn run(dp: stm32::Peripherals, cp: cortex_m::Peripherals) { .pclk1(24.mhz()) .freeze(); - let mut serial = serial::Uarte::new( + let mut serial = serial::Serial::new( gpioa.pa10.into_alternate_af7(), gpioa.pa9.into_alternate_af7(), dp.DMA2, From cc0076a0eb9a45e5c87d2dea661336ba2473bb42 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 31 Dec 2020 16:49:27 -0600 Subject: [PATCH 20/30] update hal branch --- embassy-stm32f4/Cargo.toml | 2 +- examples-stm32f4/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32f4/Cargo.toml b/embassy-stm32f4/Cargo.toml index 1891a5596..44cf3db9d 100644 --- a/embassy-stm32f4/Cargo.toml +++ b/embassy-stm32f4/Cargo.toml @@ -40,4 +40,4 @@ 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/xoviat/stm32f4xx-hal.git", branch = "dma-is-done"} +stm32f4xx-hal = { version = "0.8.3", features = ["rt"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"} diff --git a/examples-stm32f4/Cargo.toml b/examples-stm32f4/Cargo.toml index a9f2a79d7..5964cd7a5 100644 --- a/examples-stm32f4/Cargo.toml +++ b/examples-stm32f4/Cargo.toml @@ -27,7 +27,7 @@ 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/xoviat/stm32f4xx-hal.git", branch = "dma-is-done"} +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"] } From cc8d1628597d449e3b2e2e1545af25fc47b0a8a5 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 31 Dec 2020 16:59:42 -0600 Subject: [PATCH 21/30] begin integrate interrupt --- embassy-stm32f4/src/serial.rs | 4 +++- examples-stm32f4/src/serial.rs | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index bb47a9301..5042566db 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -65,8 +65,10 @@ static STATE: State = State { impl Serial, Stream2> { pub fn new( - rxd: PA10>, txd: PA9>, + rxd: PA10>, + tx_int: interrupt::DMA2_STREAM2Interrupt, + rx_int: interrupt::DMA2_STREAM7Interrupt, dma: DMA2, usart: USART1, parity: Parity, diff --git a/examples-stm32f4/src/serial.rs b/examples-stm32f4/src/serial.rs index 1f5c0fb7a..296da4043 100644 --- a/examples-stm32f4/src/serial.rs +++ b/examples-stm32f4/src/serial.rs @@ -9,6 +9,7 @@ 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}; @@ -27,8 +28,10 @@ async fn run(dp: stm32::Peripherals, cp: cortex_m::Peripherals) { .freeze(); let mut serial = serial::Serial::new( - gpioa.pa10.into_alternate_af7(), gpioa.pa9.into_alternate_af7(), + gpioa.pa10.into_alternate_af7(), + interrupt::take!(DMA2_STREAM2), + interrupt::take!(DMA2_STREAM7), dp.DMA2, dp.USART1, config::Parity::ParityNone, From d5cb9bebaa6d33bffa63211ed53ddf8a80ad975b Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 31 Dec 2020 17:59:01 -0600 Subject: [PATCH 22/30] implement on irqs --- embassy-stm32f4/src/lib.rs | 56 ++++++++++++++++----------------- embassy-stm32f4/src/serial.rs | 59 ++++++++++++++++++++++------------- 2 files changed, 65 insertions(+), 50 deletions(-) diff --git a/embassy-stm32f4/src/lib.rs b/embassy-stm32f4/src/lib.rs index 40a40ef4b..2a5a34a2a 100644 --- a/embassy-stm32f4/src/lib.rs +++ b/embassy-stm32f4/src/lib.rs @@ -329,34 +329,34 @@ pub use stm32f4xx_hal::stm32 as pac; /// /// [`Waker`]: core::task::Waker /// [`Future::poll`]: core::future::Future::poll -macro_rules! waker_interrupt { - ($INT:ident, $waker:expr) => {{ - use core::sync::atomic::{self, Ordering}; - use core::task::Waker; - use stm32f4xx_hal::pac::{interrupt, Interrupt, NVIC}; - - static mut WAKER: Option = None; - - #[interrupt] - fn $INT() { - // Safety: This context is disabled while the lower priority context accesses WAKER - if let Some(waker) = unsafe { WAKER.as_ref() } { - waker.wake_by_ref(); - - NVIC::mask(Interrupt::$INT); - } - } - - NVIC::mask(Interrupt::$INT); - atomic::compiler_fence(Ordering::Acquire); - // Safety: The other relevant context, the interrupt, is disabled - unsafe { WAKER = Some($waker) } - NVIC::unpend(Interrupt::$INT); - atomic::compiler_fence(Ordering::Release); - // Safety: This is the end of a mask-based critical section - unsafe { NVIC::unmask(Interrupt::$INT) } - }}; -} +// macro_rules! waker_interrupt { +// ($INT:ident, $waker:expr) => {{ +// use core::sync::atomic::{self, Ordering}; +// use core::task::Waker; +// use stm32f4xx_hal::pac::{interrupt, Interrupt, NVIC}; +// +// static mut WAKER: Option = None; +// +// #[interrupt] +// fn $INT() { +// // Safety: This context is disabled while the lower priority context accesses WAKER +// if let Some(waker) = unsafe { WAKER.as_ref() } { +// waker.wake_by_ref(); +// +// NVIC::mask(Interrupt::$INT); +// } +// } +// +// NVIC::mask(Interrupt::$INT); +// atomic::compiler_fence(Ordering::Acquire); +// // Safety: The other relevant context, the interrupt, is disabled +// unsafe { WAKER = Some($waker) } +// NVIC::unpend(Interrupt::$INT); +// atomic::compiler_fence(Ordering::Release); +// // Safety: This is the end of a mask-based critical section +// unsafe { NVIC::unmask(Interrupt::$INT) } +// }}; +// } // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index 5042566db..5c3e3f1ac 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -4,31 +4,20 @@ //! Lowest power consumption can only be guaranteed if the send receive futures //! are dropped correctly (e.g. not using `mem::forget()`). -use core::cell::UnsafeCell; -use core::cmp::min; use core::future::Future; -use core::marker::PhantomPinned; -use core::ops::Deref; -use core::pin::Pin; -use core::ptr; -use core::sync::atomic::{compiler_fence, Ordering}; use core::task::{Context, Poll}; -use cortex_m::singleton; +use embassy::interrupt::OwnedInterrupt; use embassy::util::Signal; use embedded_dma::{StaticReadBuffer, StaticWriteBuffer, WriteBuffer}; -use crate::fmt::assert; use crate::hal::dma::config::DmaConfig; use crate::hal::dma::traits::{PeriAddress, Stream}; use crate::hal::dma::{ - Channel4, Channel7, MemoryToPeripheral, PeripheralToMemory, Stream2, Stream7, StreamsTuple, - Transfer, + Channel4, MemoryToPeripheral, PeripheralToMemory, Stream2, Stream7, StreamsTuple, Transfer, }; use crate::hal::gpio::gpioa::{PA10, PA9}; -use crate::hal::gpio::{Alternate, AF10, AF7, AF9}; -use crate::hal::gpio::{Floating, Input, Output, PushPull}; -use crate::hal::pac; +use crate::hal::gpio::{Alternate, AF7}; use crate::hal::prelude::*; use crate::hal::rcc::Clocks; use crate::hal::serial::config::{ @@ -42,8 +31,6 @@ use crate::interrupt; use crate::pac::Interrupt; use crate::pac::{DMA2, USART1}; -use embedded_hal::digital::v2::OutputPin; - /// Interface to the Serial peripheral pub struct Serial, TSTREAM: Stream, RSTREAM: Stream> { // tx_transfer: Transfer, Channel4, USART1, MemoryToPeripheral, &mut [u8; 20]>, @@ -55,7 +42,7 @@ pub struct Serial, TSTREAM: Stream, RSTREAM: St struct State { tx_done: Signal<()>, - rx_done: Signal, + rx_done: Signal<()>, } static STATE: State = State { @@ -93,6 +80,15 @@ impl Serial, Stream2> { // serial.listen(SerialEvent::Idle); + // Register ISR + tx_int.set_handler(Self::on_tx_irq); + tx_int.unpend(); + tx_int.enable(); + + rx_int.set_handler(Self::on_rx_irq); + rx_int.unpend(); + rx_int.enable(); + let streams = StreamsTuple::new(dma); Serial { @@ -102,6 +98,13 @@ impl Serial, Stream2> { } } + unsafe fn on_tx_irq() { + STATE.tx_done.signal(()); + } + + unsafe fn on_rx_irq() { + STATE.rx_done.signal(()); + } /// Sends serial data. /// /// `tx_buffer` is marked as static as per `embedded-dma` requirements. @@ -127,6 +130,8 @@ impl Serial, Stream2> { .double_buffer(false), ); + STATE.tx_done.reset(); + SendFuture { Serial: self, tx_transfer: Some(tx_transfer), @@ -166,6 +171,8 @@ impl Serial, Stream2> { .double_buffer(false), ); + STATE.rx_done.reset(); + ReceiveFuture { Serial: self, rx_transfer: Some(rx_transfer), @@ -213,11 +220,12 @@ where Poll::Ready(()) } else { - waker_interrupt!(DMA2_STREAM7, cx.waker().clone()); - taken.start(|usart| {}); + // waker_interrupt!(DMA2_STREAM7, cx.waker().clone()); + taken.start(|_usart| {}); tx_transfer.replace(taken); - Poll::Pending + // Poll::Pending + STATE.tx_done.poll_wait(cx) } } } @@ -263,11 +271,18 @@ where Poll::Ready(buf) } else { - waker_interrupt!(DMA2_STREAM2, cx.waker().clone()); + // waker_interrupt!(DMA2_STREAM2, cx.waker().clone()); - taken.start(|usart| {}); + taken.start(|_usart| {}); rx_transfer.replace(taken); + STATE.rx_done.poll_wait(cx); + + /* + Note: we have to do this because rx_transfer owns the buffer and we can't + access it until the transfer is completed. Therefore we can't pass + the buffer to poll_wait, but we still need to be woken. + */ Poll::Pending } } From 2ee2d184654380c84ee8ea62d00ab701ceacd13c Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 1 Jan 2021 14:59:57 -0600 Subject: [PATCH 23/30] simplify impl. and add interupt idea --- embassy-stm32f4/src/serial.rs | 217 ++++++++++----------------------- examples-stm32f4/src/serial.rs | 1 + 2 files changed, 67 insertions(+), 151 deletions(-) diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index 5c3e3f1ac..7efb4a0bb 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -43,11 +43,13 @@ pub struct Serial, TSTREAM: Stream, RSTREAM: St struct State { tx_done: Signal<()>, rx_done: Signal<()>, + dma_done: Signal<()>, } static STATE: State = State { tx_done: Signal::new(), rx_done: Signal::new(), + dma_done: Signal::new(), }; impl Serial, Stream2> { @@ -56,13 +58,14 @@ impl Serial, Stream2> { rxd: PA10>, tx_int: interrupt::DMA2_STREAM2Interrupt, rx_int: interrupt::DMA2_STREAM7Interrupt, + usart_int: interrupt::USART1Interrupt, dma: DMA2, usart: USART1, parity: Parity, baudrate: Bps, clocks: Clocks, ) -> Self { - let serial = HalSerial::usart1( + let mut serial = HalSerial::usart1( usart, (txd, rxd), SerialConfig { @@ -76,9 +79,10 @@ impl Serial, Stream2> { ) .unwrap(); - let (usart, _) = serial.release(); + serial.listen(SerialEvent::Idle); + serial.listen(SerialEvent::Txe); - // serial.listen(SerialEvent::Idle); + let (usart, _) = serial.release(); // Register ISR tx_int.set_handler(Self::on_tx_irq); @@ -89,6 +93,10 @@ impl Serial, Stream2> { rx_int.unpend(); rx_int.enable(); + // usart_int.set_handler(Self::on_usart_irq); + // usart_int.unpend(); + // usart_int.enable(); + let streams = StreamsTuple::new(dma); Serial { @@ -105,38 +113,50 @@ impl Serial, Stream2> { unsafe fn on_rx_irq() { STATE.rx_done.signal(()); } + + unsafe fn on_usart_irq() { + /* + TODO: Signal tx_done if txe + */ + + /* + TODO: Signal rx_done if idle + */ + + // STATE.rx_done.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 mut self, - tx_buffer: B, - ) -> SendFuture<'a, B, USART1, Stream7, Stream2, Channel4> + pub fn send<'a, B>(&'a mut self, tx_buffer: B) -> impl Future + 'a where B: WriteBuffer + 'static, { let tx_stream = self.tx_stream.take().unwrap(); let usart = self.usart.take().unwrap(); - let mut tx_transfer = Transfer::init( - tx_stream, - usart, - tx_buffer, - None, - DmaConfig::default() - .transfer_complete_interrupt(true) - .memory_increment(true) - .double_buffer(false), - ); - STATE.tx_done.reset(); - SendFuture { - Serial: self, - tx_transfer: Some(tx_transfer), - // tx_stream: Some(tx_stream), - // usart: Some(usart), + 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), + ); + + tx_transfer.start(|_usart| {}); + + STATE.tx_done.wait().await; + + let (tx_stream, usart, _buf, _) = tx_transfer.free(); + self.tx_stream.replace(tx_stream); + self.usart.replace(usart); } } @@ -150,140 +170,35 @@ impl Serial, Stream2> { /// `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 mut self, - rx_buffer: B, - ) -> ReceiveFuture<'a, B, USART1, Stream7, Stream2, Channel4> + pub fn receive<'a, B>(&'a mut self, rx_buffer: B) -> impl Future + 'a where - B: WriteBuffer + 'static, + B: WriteBuffer + 'static + Unpin, { let rx_stream = self.rx_stream.take().unwrap(); let usart = self.usart.take().unwrap(); - let mut rx_transfer = Transfer::init( - rx_stream, - usart, - rx_buffer, - None, - DmaConfig::default() - .transfer_complete_interrupt(true) - .half_transfer_interrupt(true) - .memory_increment(true) - .double_buffer(false), - ); - STATE.rx_done.reset(); - ReceiveFuture { - Serial: self, - rx_transfer: Some(rx_transfer), - } - } -} - -/// Future for the [`LowPowerSerial::send()`] method. -pub struct SendFuture< - 'a, - B: WriteBuffer + 'static, - USART: PeriAddress, - TSTREAM: Stream, - RSTREAM: Stream, - CHANNEL, -> { - Serial: &'a mut Serial, - tx_transfer: Option>, -} - -// impl<'a, B> Drop for SendFuture<'a, B> -// where -// B: WriteBuffer + 'static, -// { -// fn drop(self: &mut Self) {} -// } - -impl<'a, B> Future for SendFuture<'a, B, USART1, Stream7, Stream2, Channel4> -where - B: WriteBuffer + 'static, -{ - type Output = (); - - fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { - let Self { - Serial, - tx_transfer, - } = unsafe { self.get_unchecked_mut() }; - let mut taken = tx_transfer.take().unwrap(); - if Stream7::::get_transfer_complete_flag() { - let (tx_stream, usart, buf, _) = taken.free(); - - Serial.tx_stream.replace(tx_stream); - Serial.usart.replace(usart); - - Poll::Ready(()) - } else { - // waker_interrupt!(DMA2_STREAM7, cx.waker().clone()); - taken.start(|_usart| {}); - tx_transfer.replace(taken); - - // Poll::Pending - STATE.tx_done.poll_wait(cx) - } - } -} - -/// Future for the [`Serial::receive()`] method. -pub struct ReceiveFuture< - 'a, - B: WriteBuffer + 'static, - USART: PeriAddress, - TSTREAM: Stream, - RSTREAM: Stream, - CHANNEL, -> { - Serial: &'a mut Serial, - rx_transfer: Option>, -} - -// impl<'a, B> Drop for ReceiveFuture<'a, B, USART1, Stream7, Channel4> -// where -// B: WriteBuffer + 'static, -// { -// fn drop(self: &mut Self) {} -// } - -impl<'a, B> Future for ReceiveFuture<'a, B, USART1, Stream7, Stream2, Channel4> -where - B: WriteBuffer + 'static + Unpin, -{ - type Output = B; - - fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let Self { - Serial, - rx_transfer, - } = unsafe { self.get_unchecked_mut() }; - let mut taken = rx_transfer.take().unwrap(); - - if Stream7::::get_transfer_complete_flag() { - let (rx_stream, usart, buf, _) = rx_transfer.take().unwrap().free(); - - Serial.rx_stream.replace(rx_stream); - Serial.usart.replace(usart); - - Poll::Ready(buf) - } else { - // waker_interrupt!(DMA2_STREAM2, cx.waker().clone()); - - taken.start(|_usart| {}); - rx_transfer.replace(taken); - - STATE.rx_done.poll_wait(cx); - - /* - Note: we have to do this because rx_transfer owns the buffer and we can't - access it until the transfer is completed. Therefore we can't pass - the buffer to poll_wait, but we still need to be woken. - */ - Poll::Pending + 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), + ); + + rx_transfer.start(|_usart| {}); + + STATE.rx_done.wait().await; + + let (rx_stream, usart, buf, _) = rx_transfer.free(); + self.rx_stream.replace(rx_stream); + self.usart.replace(usart); + + buf } } } diff --git a/examples-stm32f4/src/serial.rs b/examples-stm32f4/src/serial.rs index 296da4043..6c757dd2f 100644 --- a/examples-stm32f4/src/serial.rs +++ b/examples-stm32f4/src/serial.rs @@ -32,6 +32,7 @@ async fn run(dp: stm32::Peripherals, cp: cortex_m::Peripherals) { gpioa.pa10.into_alternate_af7(), interrupt::take!(DMA2_STREAM2), interrupt::take!(DMA2_STREAM7), + interrupt::take!(USART1), dp.DMA2, dp.USART1, config::Parity::ParityNone, From 9bf09488f10b65401ec4c830c5b974c19508624f Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 4 Jan 2021 12:48:13 -0600 Subject: [PATCH 24/30] fix interrupts --- embassy-stm32f4/src/serial.rs | 90 +++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index 7efb4a0bb..cc55ef325 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -5,6 +5,8 @@ //! 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; @@ -33,31 +35,32 @@ use crate::pac::{DMA2, USART1}; /// Interface to the Serial peripheral pub struct Serial, TSTREAM: Stream, RSTREAM: Stream> { - // tx_transfer: Transfer, Channel4, USART1, MemoryToPeripheral, &mut [u8; 20]>, - // rx_transfer: Transfer, Channel4, USART1, PeripheralToMemory, &mut [u8; 20]>, 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_done: Signal<()>, - rx_done: Signal<()>, - dma_done: Signal<()>, + tx_int: Signal<()>, + rx_int: Signal<()>, } static STATE: State = State { - tx_done: Signal::new(), - rx_done: Signal::new(), - dma_done: Signal::new(), + 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_STREAM2Interrupt, - rx_int: interrupt::DMA2_STREAM7Interrupt, + tx_int: interrupt::DMA2_STREAM7Interrupt, + rx_int: interrupt::DMA2_STREAM2Interrupt, usart_int: interrupt::USART1Interrupt, dma: DMA2, usart: USART1, @@ -80,20 +83,14 @@ impl Serial, Stream2> { .unwrap(); serial.listen(SerialEvent::Idle); - serial.listen(SerialEvent::Txe); + // serial.listen(SerialEvent::Txe); let (usart, _) = serial.release(); // Register ISR tx_int.set_handler(Self::on_tx_irq); - tx_int.unpend(); - tx_int.enable(); - rx_int.set_handler(Self::on_rx_irq); - rx_int.unpend(); - rx_int.enable(); - - // usart_int.set_handler(Self::on_usart_irq); + usart_int.set_handler(Self::on_rx_irq); // usart_int.unpend(); // usart_int.enable(); @@ -103,40 +100,56 @@ impl Serial, Stream2> { 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() { - STATE.tx_done.signal(()); + let s = &(*INSTANCE); + + s.tx_int.disable(); + + STATE.tx_int.signal(()); } unsafe fn on_rx_irq() { - STATE.rx_done.signal(()); + 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() { - /* - TODO: Signal tx_done if txe - */ + let s = &(*INSTANCE); - /* - TODO: Signal rx_done if idle - */ + atomic::compiler_fence(Ordering::Acquire); + s.rx_int.disable(); + s.usart_int.disable(); + atomic::compiler_fence(Ordering::Release); - // STATE.rx_done.signal(()); + 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 mut self, tx_buffer: B) -> impl Future + 'a + pub fn send<'a, B: 'a>(&'a mut self, tx_buffer: B) -> impl Future + 'a where - B: WriteBuffer + 'static, + B: StaticWriteBuffer, { + unsafe { INSTANCE = self }; + let tx_stream = self.tx_stream.take().unwrap(); let usart = self.usart.take().unwrap(); - STATE.tx_done.reset(); + STATE.tx_int.reset(); async move { let mut tx_transfer = Transfer::init( @@ -150,9 +163,11 @@ impl Serial, Stream2> { .double_buffer(false), ); + self.tx_int.unpend(); + self.tx_int.enable(); tx_transfer.start(|_usart| {}); - STATE.tx_done.wait().await; + STATE.tx_int.wait().await; let (tx_stream, usart, _buf, _) = tx_transfer.free(); self.tx_stream.replace(tx_stream); @@ -170,13 +185,15 @@ impl Serial, Stream2> { /// `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 mut self, rx_buffer: B) -> impl Future + 'a + pub fn receive<'a, B: 'a>(&'a mut self, rx_buffer: B) -> impl Future + 'a where - B: WriteBuffer + 'static + Unpin, + B: StaticWriteBuffer + Unpin, { + unsafe { INSTANCE = self }; + let rx_stream = self.rx_stream.take().unwrap(); let usart = self.usart.take().unwrap(); - STATE.rx_done.reset(); + STATE.rx_int.reset(); async move { let mut rx_transfer = Transfer::init( @@ -190,9 +207,12 @@ impl Serial, Stream2> { .double_buffer(false), ); + self.rx_int.unpend(); + self.rx_int.enable(); + rx_transfer.start(|_usart| {}); - STATE.rx_done.wait().await; + STATE.rx_int.wait().await; let (rx_stream, usart, buf, _) = rx_transfer.free(); self.rx_stream.replace(rx_stream); From f3676e1eabc4f3079003d8a006d45db7d3afc742 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 4 Jan 2021 12:52:00 -0600 Subject: [PATCH 25/30] rename examples --- {examples-stm32f4 => embassy-stm32f4-examples}/Cargo.toml | 2 +- {examples-stm32f4 => embassy-stm32f4-examples}/src/serial.rs | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename {examples-stm32f4 => embassy-stm32f4-examples}/Cargo.toml (96%) rename {examples-stm32f4 => embassy-stm32f4-examples}/src/serial.rs (100%) diff --git a/examples-stm32f4/Cargo.toml b/embassy-stm32f4-examples/Cargo.toml similarity index 96% rename from examples-stm32f4/Cargo.toml rename to embassy-stm32f4-examples/Cargo.toml index 5964cd7a5..6502a77a5 100644 --- a/examples-stm32f4/Cargo.toml +++ b/embassy-stm32f4-examples/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Dario Nieuwenhuis "] edition = "2018" -name = "embassy-examples-stm32f4" +name = "embassy-stm32f4-examples" version = "0.1.0" [features] diff --git a/examples-stm32f4/src/serial.rs b/embassy-stm32f4-examples/src/serial.rs similarity index 100% rename from examples-stm32f4/src/serial.rs rename to embassy-stm32f4-examples/src/serial.rs From d89462fc16ac5133133a861b60fde470d02f3f25 Mon Sep 17 00:00:00 2001 From: xoviat <49173759+xoviat@users.noreply.github.com> Date: Mon, 4 Jan 2021 12:53:27 -0600 Subject: [PATCH 26/30] remove macros --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 843c5f6c3..3e036b610 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ members = [ "embassy", "embassy-nrf", "embassy-stm32f4", - "embassy-macros", "embassy-nrf-examples", "embassy-stm32f4-examples", "embassy-macros", From f62eb66bf2b60316f7bd6fcc8d64707e7d5e1b0c Mon Sep 17 00:00:00 2001 From: xoviat <49173759+xoviat@users.noreply.github.com> Date: Tue, 5 Jan 2021 17:18:24 -0600 Subject: [PATCH 27/30] add new levels --- embassy-stm32f4/src/interrupt.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/embassy-stm32f4/src/interrupt.rs b/embassy-stm32f4/src/interrupt.rs index 71f3f483e..6cc90f66d 100644 --- a/embassy-stm32f4/src/interrupt.rs +++ b/embassy-stm32f4/src/interrupt.rs @@ -25,6 +25,14 @@ pub enum Priority { Level5 = 5, Level6 = 6, Level7 = 7, + Level8 = 8, + Level9 = 9, + Level10 = 10, + Level11 = 11, + Level12 = 12, + Level13 = 13, + Level14 = 14, + Level14 = 15, } impl From for Priority { From 7bee584808238103e6facdf3e25027652ffc8e21 Mon Sep 17 00:00:00 2001 From: xoviat <49173759+xoviat@users.noreply.github.com> Date: Tue, 5 Jan 2021 17:19:05 -0600 Subject: [PATCH 28/30] remove dead code in waker --- embassy-stm32f4/src/lib.rs | 50 -------------------------------------- 1 file changed, 50 deletions(-) diff --git a/embassy-stm32f4/src/lib.rs b/embassy-stm32f4/src/lib.rs index 2a5a34a2a..0f4a70bba 100644 --- a/embassy-stm32f4/src/lib.rs +++ b/embassy-stm32f4/src/lib.rs @@ -308,56 +308,6 @@ compile_error!( pub use stm32f4xx_hal as hal; pub use stm32f4xx_hal::stm32 as pac; -/// Creates a new interrupt waking a [`Waker`]. -/// -/// As this interrupt will be declared in this macro, it can't be used for anything else. -/// -/// # Examples -/// -/// This macro is useful for implementing [`Future::poll`]: -/// -/// ``` -/// fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { -/// if self.is_ready() { -/// Poll::Ready(()) -/// } else { -/// waker_interrupt!(TIM2, cx.waker().clone()); -/// Poll::Pending -/// } -/// } -/// ``` -/// -/// [`Waker`]: core::task::Waker -/// [`Future::poll`]: core::future::Future::poll -// macro_rules! waker_interrupt { -// ($INT:ident, $waker:expr) => {{ -// use core::sync::atomic::{self, Ordering}; -// use core::task::Waker; -// use stm32f4xx_hal::pac::{interrupt, Interrupt, NVIC}; -// -// static mut WAKER: Option = None; -// -// #[interrupt] -// fn $INT() { -// // Safety: This context is disabled while the lower priority context accesses WAKER -// if let Some(waker) = unsafe { WAKER.as_ref() } { -// waker.wake_by_ref(); -// -// NVIC::mask(Interrupt::$INT); -// } -// } -// -// NVIC::mask(Interrupt::$INT); -// atomic::compiler_fence(Ordering::Acquire); -// // Safety: The other relevant context, the interrupt, is disabled -// unsafe { WAKER = Some($waker) } -// NVIC::unpend(Interrupt::$INT); -// atomic::compiler_fence(Ordering::Release); -// // Safety: This is the end of a mask-based critical section -// unsafe { NVIC::unmask(Interrupt::$INT) } -// }}; -// } - // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; From a9d9f3bf8013d5643a2b8876a8805cb4b939f8ca Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 5 Jan 2021 17:24:27 -0600 Subject: [PATCH 29/30] fix problems --- embassy-stm32f4-examples/src/serial.rs | 2 +- embassy-stm32f4/src/interrupt.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32f4-examples/src/serial.rs b/embassy-stm32f4-examples/src/serial.rs index 6c757dd2f..baed2e525 100644 --- a/embassy-stm32f4-examples/src/serial.rs +++ b/embassy-stm32f4-examples/src/serial.rs @@ -30,8 +30,8 @@ async fn run(dp: stm32::Peripherals, cp: cortex_m::Peripherals) { let mut serial = serial::Serial::new( gpioa.pa9.into_alternate_af7(), gpioa.pa10.into_alternate_af7(), - interrupt::take!(DMA2_STREAM2), interrupt::take!(DMA2_STREAM7), + interrupt::take!(DMA2_STREAM2), interrupt::take!(USART1), dp.DMA2, dp.USART1, diff --git a/embassy-stm32f4/src/interrupt.rs b/embassy-stm32f4/src/interrupt.rs index 6cc90f66d..64f0a6467 100644 --- a/embassy-stm32f4/src/interrupt.rs +++ b/embassy-stm32f4/src/interrupt.rs @@ -32,7 +32,7 @@ pub enum Priority { Level12 = 12, Level13 = 13, Level14 = 14, - Level14 = 15, + Level15 = 15, } impl From for Priority { From 938919367a371614f966ac789cf775114ba18968 Mon Sep 17 00:00:00 2001 From: xoviat <49173759+xoviat@users.noreply.github.com> Date: Tue, 5 Jan 2021 17:38:46 -0600 Subject: [PATCH 30/30] add levels --- embassy-stm32f4/src/interrupt.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/embassy-stm32f4/src/interrupt.rs b/embassy-stm32f4/src/interrupt.rs index 64f0a6467..502d666ee 100644 --- a/embassy-stm32f4/src/interrupt.rs +++ b/embassy-stm32f4/src/interrupt.rs @@ -46,6 +46,14 @@ impl From for Priority { 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!(), } }