diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index c30bbc20..3be0677b 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -46,16 +46,44 @@ impl<'d, T: BasicInstance> Unpin for BufferedUart<'d, T> {} impl<'d, T: BasicInstance> BufferedUart<'d, T> { pub fn new( state: &'d mut State<'d, T>, - _uart: Uart<'d, T, NoDma, NoDma>, + _peri: impl Peripheral

+ 'd, + rx: impl Peripheral

> + 'd, + tx: impl Peripheral

> + 'd, irq: impl Peripheral

+ 'd, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], + config: Config, ) -> BufferedUart<'d, T> { - into_ref!(irq); + into_ref!(_peri, rx, tx, irq); + + T::enable(); + T::reset(); let r = T::regs(); + + configure(r, &config, T::frequency(), T::MULTIPLIER); + unsafe { - r.cr1().modify(|w| { + rx.set_as_af(rx.af_num(), AFType::Input); + tx.set_as_af(tx.af_num(), AFType::OutputPushPull); + + r.cr2().write(|_w| {}); + r.cr3().write(|_w| {}); + r.cr1().write(|w| { + w.set_ue(true); + w.set_te(true); + w.set_re(true); + w.set_m0(if config.parity != Parity::ParityNone { + vals::M0::BIT9 + } else { + vals::M0::BIT8 + }); + w.set_pce(config.parity != Parity::ParityNone); + w.set_ps(match config.parity { + Parity::ParityOdd => vals::Ps::ODD, + Parity::ParityEven => vals::Ps::EVEN, + _ => vals::Ps::EVEN, + }); w.set_rxneie(true); w.set_idleie(true); }); diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 3f5b9952..dee466b2 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1,7 +1,11 @@ #![macro_use] +use core::future::poll_fn; use core::marker::PhantomData; +use core::task::Poll; +use atomic_polyfill::{compiler_fence, Ordering}; +use embassy_cortex_m::interrupt::InterruptExt; use embassy_hal_common::{into_ref, PeripheralRef}; use crate::dma::NoDma; @@ -10,6 +14,7 @@ use crate::gpio::sealed::AFType; use crate::pac::lpuart::{regs, vals, Lpuart as Regs}; #[cfg(not(any(lpuart_v1, lpuart_v2)))] use crate::pac::usart::{regs, vals, Usart as Regs}; +use crate::time::Hertz; use crate::{peripherals, Peripheral}; #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -44,6 +49,10 @@ pub struct Config { pub data_bits: DataBits, pub stop_bits: StopBits, pub parity: Parity, + /// if true, on read-like method, if there is a latent error pending, + /// read will abort, the error reported and cleared + /// if false, the error is ignored and cleared + pub detect_previous_overrun: bool, } impl Default for Config { @@ -53,6 +62,8 @@ impl Default for Config { data_bits: DataBits::DataBits8, stop_bits: StopBits::STOP1, parity: Parity::ParityNone, + // historical behavior + detect_previous_overrun: false, } } } @@ -70,10 +81,11 @@ pub enum Error { Overrun, /// Parity check error Parity, + /// Buffer too large for DMA + BufferTooLong, } pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { - phantom: PhantomData<&'d mut T>, tx: UartTx<'d, T, TxDma>, rx: UartRx<'d, T, RxDma>, } @@ -84,8 +96,9 @@ pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { } pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { - phantom: PhantomData<&'d mut T>, + _peri: PeripheralRef<'d, T>, rx_dma: PeripheralRef<'d, RxDma>, + detect_previous_overrun: bool, } impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { @@ -135,10 +148,112 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { } impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { - fn new(rx_dma: PeripheralRef<'d, RxDma>) -> Self { + /// usefull if you only want Uart Rx. It saves 1 pin and consumes a little less power + pub fn new( + peri: impl Peripheral

+ 'd, + irq: impl Peripheral

+ 'd, + rx: impl Peripheral

> + 'd, + rx_dma: impl Peripheral

+ 'd, + config: Config, + ) -> Self { + into_ref!(peri, irq, rx, rx_dma); + + T::enable(); + T::reset(); + + let r = T::regs(); + + configure(r, &config, T::frequency(), T::MULTIPLIER); + + unsafe { + rx.set_as_af(rx.af_num(), AFType::Input); + + r.cr2().write(|_w| {}); + r.cr3().write(|w| { + // enable Error Interrupt: (Frame error, Noise error, Overrun error) + w.set_eie(true); + }); + r.cr1().write(|w| { + // enable uart + w.set_ue(true); + // enable receiver + w.set_re(true); + // configure word size + w.set_m0(if config.parity != Parity::ParityNone { + vals::M0::BIT9 + } else { + vals::M0::BIT8 + }); + // configure parity + w.set_pce(config.parity != Parity::ParityNone); + w.set_ps(match config.parity { + Parity::ParityOdd => vals::Ps::ODD, + Parity::ParityEven => vals::Ps::EVEN, + _ => vals::Ps::EVEN, + }); + }); + } + + irq.set_handler(Self::on_interrupt); + irq.unpend(); + irq.enable(); + + // create state once! + let _s = T::state(); + Self { + _peri: peri, rx_dma, - phantom: PhantomData, + detect_previous_overrun: config.detect_previous_overrun, + } + } + + fn on_interrupt(_: *mut ()) { + let r = T::regs(); + let s = T::state(); + + let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) }; + + let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie()); + + if has_errors { + // clear all interrupts and DMA Rx Request + unsafe { + r.cr1().modify(|w| { + // disable RXNE interrupt + w.set_rxneie(false); + // disable parity interrupt + w.set_peie(false); + // disable idle line interrupt + w.set_idleie(false); + }); + r.cr3().modify(|w| { + // disable Error Interrupt: (Frame error, Noise error, Overrun error) + w.set_eie(false); + // disable DMA Rx Request + w.set_dmar(false); + }); + } + + compiler_fence(Ordering::SeqCst); + + s.rx_waker.wake(); + } else if cr1.idleie() && sr.idle() { + // IDLE detected: no more data will come + unsafe { + r.cr1().modify(|w| { + // disable idle line detection + w.set_idleie(false); + }); + + r.cr3().modify(|w| { + // disable DMA Rx Request + w.set_dmar(false); + }); + } + compiler_fence(Ordering::SeqCst); + + s.rx_waker.wake(); } } @@ -146,17 +261,8 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { where RxDma: crate::usart::RxDma, { - let ch = &mut self.rx_dma; - let request = ch.request(); - unsafe { - T::regs().cr3().modify(|reg| { - reg.set_dmar(true); - }); - } - // If we don't assign future to a variable, the data register pointer - // is held across an await and makes the future non-Send. - let transfer = crate::dma::read(ch, request, rdr(T::regs()), buffer); - transfer.await; + self.inner_read(buffer, false).await?; + Ok(()) } @@ -211,13 +317,202 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { } Ok(()) } + + pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result + where + RxDma: crate::usart::RxDma, + { + self.inner_read(buffer, true).await + } + + async fn inner_read(&mut self, buffer: &mut [u8], enable_idle_line_detection: bool) -> Result + where + RxDma: crate::usart::RxDma, + { + if buffer.is_empty() { + return Ok(0); + } else if buffer.len() > 0xFFFF { + return Err(Error::BufferTooLong); + } + + let r = T::regs(); + + let buffer_len = buffer.len(); + + let ch = &mut self.rx_dma; + let request = ch.request(); + + // SAFETY: The only way we might have a problem is using split rx and tx + // here we only modify or read Rx related flags, interrupts and DMA channel + unsafe { + // Start USART DMA + // will not do anything yet because DMAR is not yet set + ch.start_read(request, rdr(r), buffer, Default::default()); + + // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer + if !self.detect_previous_overrun { + let sr = sr(r).read(); + // This read also clears the error and idle interrupt flags on v1. + rdr(r).read_volatile(); + clear_interrupt_flags(r, sr); + } + + r.cr1().modify(|w| { + // disable RXNE interrupt + w.set_rxneie(false); + // enable parity interrupt if not ParityNone + w.set_peie(w.pce()); + }); + + r.cr3().modify(|w| { + // enable Error Interrupt: (Frame error, Noise error, Overrun error) + w.set_eie(true); + // enable DMA Rx Request + w.set_dmar(true); + }); + + compiler_fence(Ordering::SeqCst); + + // In case of errors already pending when reception started, interrupts may have already been raised + // and lead to reception abortion (Overrun error for instance). In such a case, all interrupts + // have been disabled in interrupt handler and DMA Rx Request has been disabled. + + let cr3 = r.cr3().read(); + + if !cr3.dmar() { + // something went wrong + // because the only way to get this flag cleared is to have an interrupt + + // abort DMA transfer + ch.request_stop(); + while ch.is_running() {} + + let sr = sr(r).read(); + // This read also clears the error and idle interrupt flags on v1. + rdr(r).read_volatile(); + clear_interrupt_flags(r, sr); + + if sr.pe() { + return Err(Error::Parity); + } + if sr.fe() { + return Err(Error::Framing); + } + if sr.ne() { + return Err(Error::Noise); + } + if sr.ore() { + return Err(Error::Overrun); + } + + unreachable!(); + } + + // clear idle flag + if enable_idle_line_detection { + let sr = sr(r).read(); + // This read also clears the error and idle interrupt flags on v1. + rdr(r).read_volatile(); + clear_interrupt_flags(r, sr); + + // enable idle interrupt + r.cr1().modify(|w| { + w.set_idleie(true); + }); + } + } + + compiler_fence(Ordering::SeqCst); + + let res = poll_fn(move |cx| { + let s = T::state(); + + ch.set_waker(cx.waker()); + s.rx_waker.register(cx.waker()); + + // SAFETY: read only and we only use Rx related flags + let sr = unsafe { sr(r).read() }; + + // SAFETY: only clears Rx related flags + unsafe { + // This read also clears the error and idle interrupt flags on v1. + rdr(r).read_volatile(); + clear_interrupt_flags(r, sr); + } + + compiler_fence(Ordering::SeqCst); + + let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore(); + + if has_errors { + // all Rx interrupts and Rx DMA Request have already been cleared in interrupt handler + + // stop dma transfer + ch.request_stop(); + while ch.is_running() {} + + if sr.pe() { + return Poll::Ready(Err(Error::Parity)); + } + if sr.fe() { + return Poll::Ready(Err(Error::Framing)); + } + if sr.ne() { + return Poll::Ready(Err(Error::Noise)); + } + if sr.ore() { + return Poll::Ready(Err(Error::Overrun)); + } + } + + if sr.idle() { + // Idle line + + // stop dma transfer + ch.request_stop(); + while ch.is_running() {} + + let n = buffer_len - (ch.remaining_transfers() as usize); + + return Poll::Ready(Ok(n)); + } else if !ch.is_running() { + // DMA complete + return Poll::Ready(Ok(buffer_len)); + } + + Poll::Pending + }) + .await; + + // clear all interrupts and DMA Rx Request + // SAFETY: only clears Rx related flags + unsafe { + r.cr1().modify(|w| { + // disable RXNE interrupt + w.set_rxneie(false); + // disable parity interrupt + w.set_peie(false); + // disable idle line interrupt + w.set_idleie(false); + }); + r.cr3().modify(|w| { + // disable Error Interrupt: (Frame error, Noise error, Overrun error) + w.set_eie(false); + // disable DMA Rx Request + w.set_dmar(false); + }); + } + + res + } } impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { pub fn new( - _inner: impl Peripheral

+ 'd, + peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, tx: impl Peripheral

> + 'd, + irq: impl Peripheral

+ 'd, tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, config: Config, @@ -225,13 +520,14 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { T::enable(); T::reset(); - Self::new_inner(_inner, rx, tx, tx_dma, rx_dma, config) + Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config) } pub fn new_with_rtscts( - _inner: impl Peripheral

+ 'd, + peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, tx: impl Peripheral

> + 'd, + irq: impl Peripheral

+ 'd, rts: impl Peripheral

> + 'd, cts: impl Peripheral

> + 'd, tx_dma: impl Peripheral

+ 'd, @@ -251,32 +547,29 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { w.set_ctse(true); }); } - Self::new_inner(_inner, rx, tx, tx_dma, rx_dma, config) + Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config) } fn new_inner( - _inner: impl Peripheral

+ 'd, + peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, tx: impl Peripheral

> + 'd, + irq: impl Peripheral

+ 'd, tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, config: Config, ) -> Self { - into_ref!(_inner, rx, tx, tx_dma, rx_dma); - - let pclk_freq = T::frequency(); - - // TODO: better calculation, including error checking and OVER8 if possible. - let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * T::MULTIPLIER; + into_ref!(peri, rx, tx, irq, tx_dma, rx_dma); let r = T::regs(); + configure(r, &config, T::frequency(), T::MULTIPLIER); + unsafe { rx.set_as_af(rx.af_num(), AFType::Input); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); r.cr2().write(|_w| {}); - r.brr().write_value(regs::Brr(div)); r.cr1().write(|w| { w.set_ue(true); w.set_te(true); @@ -295,10 +588,20 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { }); } + irq.set_handler(UartRx::::on_interrupt); + irq.unpend(); + irq.enable(); + + // create state once! + let _s = T::state(); + Self { tx: UartTx::new(tx_dma), - rx: UartRx::new(rx_dma), - phantom: PhantomData {}, + rx: UartRx { + _peri: peri, + rx_dma, + detect_previous_overrun: config.detect_previous_overrun, + }, } } @@ -332,6 +635,13 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { self.rx.blocking_read(buffer) } + pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result + where + RxDma: crate::usart::RxDma, + { + self.rx.read_until_idle(buffer).await + } + /// Split the Uart into a transmitter and receiver, which is /// particuarly useful when having two tasks correlating to /// transmitting and receiving. @@ -340,6 +650,15 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { } } +fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32) { + // TODO: better calculation, including error checking and OVER8 if possible. + let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * multiplier; + + unsafe { + r.brr().write_value(regs::Brr(div)); + } +} + mod eh02 { use super::*; @@ -389,6 +708,7 @@ mod eh1 { Self::Noise => embedded_hal_1::serial::ErrorKind::Noise, Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun, Self::Parity => embedded_hal_1::serial::ErrorKind::Parity, + Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other, } } } @@ -573,13 +893,30 @@ unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) { } pub(crate) mod sealed { + use embassy_sync::waitqueue::AtomicWaker; + use super::*; + pub struct State { + pub rx_waker: AtomicWaker, + pub tx_waker: AtomicWaker, + } + + impl State { + pub const fn new() -> Self { + Self { + rx_waker: AtomicWaker::new(), + tx_waker: AtomicWaker::new(), + } + } + } + pub trait BasicInstance: crate::rcc::RccPeripheral { const MULTIPLIER: u32; type Interrupt: crate::interrupt::Interrupt; fn regs() -> Regs; + fn state() -> &'static State; } pub trait FullInstance: BasicInstance { @@ -587,7 +924,7 @@ pub(crate) mod sealed { } } -pub trait BasicInstance: sealed::BasicInstance {} +pub trait BasicInstance: Peripheral

+ sealed::BasicInstance + 'static + Send {} pub trait FullInstance: sealed::FullInstance {} @@ -609,6 +946,11 @@ macro_rules! impl_lpuart { fn regs() -> Regs { Regs(crate::pac::$inst.0) } + + fn state() -> &'static crate::usart::sealed::State { + static STATE: crate::usart::sealed::State = crate::usart::sealed::State::new(); + &STATE + } } impl BasicInstance for peripherals::$inst {} diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs index 3bc5a287..47121acf 100644 --- a/examples/stm32f3/src/bin/usart_dma.rs +++ b/examples/stm32f3/src/bin/usart_dma.rs @@ -7,6 +7,7 @@ use core::fmt::Write; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; +use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; use heapless::String; use {defmt_rtt as _, panic_probe as _}; @@ -17,7 +18,8 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let config = Config::default(); - let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, p.DMA1_CH4, NoDma, config); + let irq = interrupt::take!(USART1); + let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, irq, p.DMA1_CH4, NoDma, config); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs index 90ad882b..8f41bb6c 100644 --- a/examples/stm32f4/src/bin/usart.rs +++ b/examples/stm32f4/src/bin/usart.rs @@ -5,6 +5,7 @@ use cortex_m_rt::entry; use defmt::*; use embassy_stm32::dma::NoDma; +use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; use {defmt_rtt as _, panic_probe as _}; @@ -15,7 +16,8 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config); + let irq = interrupt::take!(USART3); + let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, irq, NoDma, NoDma, config); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); diff --git a/examples/stm32f4/src/bin/usart_buffered.rs b/examples/stm32f4/src/bin/usart_buffered.rs index 7bcecbd2..dd171fe1 100644 --- a/examples/stm32f4/src/bin/usart_buffered.rs +++ b/examples/stm32f4/src/bin/usart_buffered.rs @@ -4,9 +4,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::interrupt; -use embassy_stm32::usart::{BufferedUart, Config, State, Uart}; +use embassy_stm32::usart::{BufferedUart, Config, State}; use embedded_io::asynch::BufRead; use {defmt_rtt as _, panic_probe as _}; @@ -16,13 +15,21 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let config = Config::default(); - let usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config); let mut state = State::new(); let irq = interrupt::take!(USART3); let mut tx_buf = [0u8; 32]; let mut rx_buf = [0u8; 32]; - let mut buf_usart = BufferedUart::new(&mut state, usart, irq, &mut tx_buf, &mut rx_buf); + let mut buf_usart = BufferedUart::new( + &mut state, + p.USART3, + p.PD9, + p.PD8, + irq, + &mut tx_buf, + &mut rx_buf, + config, + ); loop { let buf = buf_usart.fill_buf().await.unwrap(); diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs index bb41b8b4..78baeaa0 100644 --- a/examples/stm32f4/src/bin/usart_dma.rs +++ b/examples/stm32f4/src/bin/usart_dma.rs @@ -7,6 +7,7 @@ use core::fmt::Write; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; +use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; use heapless::String; use {defmt_rtt as _, panic_probe as _}; @@ -17,7 +18,8 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let config = Config::default(); - let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, p.DMA1_CH3, NoDma, config); + let irq = interrupt::take!(USART3); + let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, irq, p.DMA1_CH3, NoDma, config); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32f7/src/bin/usart_dma.rs b/examples/stm32f7/src/bin/usart_dma.rs index 07270479..4827c52a 100644 --- a/examples/stm32f7/src/bin/usart_dma.rs +++ b/examples/stm32f7/src/bin/usart_dma.rs @@ -7,6 +7,7 @@ use core::fmt::Write; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; +use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; use heapless::String; use {defmt_rtt as _, panic_probe as _}; @@ -15,7 +16,8 @@ use {defmt_rtt as _, panic_probe as _}; async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, p.DMA1_CH1, NoDma, config); + let irq = interrupt::take!(UART7); + let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, irq, p.DMA1_CH1, NoDma, config); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs index 87c2b125..405f18ec 100644 --- a/examples/stm32h7/src/bin/usart.rs +++ b/examples/stm32h7/src/bin/usart.rs @@ -6,6 +6,7 @@ use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; use embassy_stm32::dma::NoDma; +use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -15,7 +16,8 @@ async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, NoDma, NoDma, config); + let irq = interrupt::take!(UART7); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, NoDma, NoDma, config); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs index 3adffcbe..6e3491e5 100644 --- a/examples/stm32h7/src/bin/usart_dma.rs +++ b/examples/stm32h7/src/bin/usart_dma.rs @@ -8,6 +8,7 @@ use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; use embassy_stm32::dma::NoDma; +use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; use heapless::String; use static_cell::StaticCell; @@ -18,7 +19,8 @@ async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, NoDma, config); + let irq = interrupt::take!(UART7); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.DMA1_CH0, NoDma, config); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs index df2b600f..f97176ec 100644 --- a/examples/stm32h7/src/bin/usart_split.rs +++ b/examples/stm32h7/src/bin/usart_split.rs @@ -5,6 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; +use embassy_stm32::interrupt; use embassy_stm32::peripherals::{DMA1_CH1, UART7}; use embassy_stm32::usart::{Config, Uart, UartRx}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; @@ -31,7 +32,8 @@ async fn main(spawner: Spawner) -> ! { info!("Hello World!"); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, p.DMA1_CH1, config); + let irq = interrupt::take!(UART7); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.DMA1_CH0, p.DMA1_CH1, config); unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); let (mut tx, rx) = usart.split(); diff --git a/examples/stm32l0/src/bin/usart_dma.rs b/examples/stm32l0/src/bin/usart_dma.rs index 66657d0f..c307f857 100644 --- a/examples/stm32l0/src/bin/usart_dma.rs +++ b/examples/stm32l0/src/bin/usart_dma.rs @@ -4,13 +4,15 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, p.DMA1_CH2, p.DMA1_CH3, Config::default()); + let irq = interrupt::take!(USART1); + let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, irq, p.DMA1_CH2, p.DMA1_CH3, Config::default()); usart.write(b"Hello Embassy World!\r\n").await.unwrap(); info!("wrote Hello, starting echo"); diff --git a/examples/stm32l0/src/bin/usart_irq.rs b/examples/stm32l0/src/bin/usart_irq.rs index 0e223738..8e84cd09 100644 --- a/examples/stm32l0/src/bin/usart_irq.rs +++ b/examples/stm32l0/src/bin/usart_irq.rs @@ -4,9 +4,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::interrupt; -use embassy_stm32::usart::{BufferedUart, Config, State, Uart}; +use embassy_stm32::usart::{BufferedUart, Config, State}; use embedded_io::asynch::{Read, Write}; use {defmt_rtt as _, panic_probe as _}; @@ -21,15 +20,18 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.baudrate = 9600; - let usart = Uart::new(p.USART2, p.PA3, p.PA2, NoDma, NoDma, config); let mut state = State::new(); + let irq = interrupt::take!(USART2); let mut usart = unsafe { BufferedUart::new( &mut state, - usart, - interrupt::take!(USART2), + p.USART2, + p.PA3, + p.PA2, + irq, &mut TX_BUFFER, &mut RX_BUFFER, + config, ) }; diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs index 4a4b46c5..7d874d9d 100644 --- a/examples/stm32l4/src/bin/usart.rs +++ b/examples/stm32l4/src/bin/usart.rs @@ -4,6 +4,7 @@ use defmt::*; use embassy_stm32::dma::NoDma; +use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; use {defmt_rtt as _, panic_probe as _}; @@ -14,7 +15,8 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, NoDma, NoDma, config); + let irq = interrupt::take!(UART4); + let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, irq, NoDma, NoDma, config); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs index 72890689..452bede3 100644 --- a/examples/stm32l4/src/bin/usart_dma.rs +++ b/examples/stm32l4/src/bin/usart_dma.rs @@ -7,6 +7,7 @@ use core::fmt::Write; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; +use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; use heapless::String; use {defmt_rtt as _, panic_probe as _}; @@ -17,7 +18,8 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let config = Config::default(); - let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, p.DMA1_CH3, NoDma, config); + let irq = interrupt::take!(UART4); + let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, irq, p.DMA1_CH3, NoDma, config); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index 7673bfe6..af55867f 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs @@ -7,6 +7,7 @@ mod example_common; use defmt::assert_eq; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; +use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; use example_common::*; @@ -18,22 +19,22 @@ async fn main(_spawner: Spawner) { // Arduino pins D0 and D1 // They're connected together with a 1K resistor. #[cfg(feature = "stm32f103c8")] - let (tx, rx, usart) = (p.PA9, p.PA10, p.USART1); + let (tx, rx, usart, irq) = (p.PA9, p.PA10, p.USART1, interrupt::take!(USART1)); #[cfg(feature = "stm32g491re")] - let (tx, rx, usart) = (p.PC4, p.PC5, p.USART1); + let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); #[cfg(feature = "stm32g071rb")] - let (tx, rx, usart) = (p.PC4, p.PC5, p.USART1); + let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); #[cfg(feature = "stm32f429zi")] - let (tx, rx, usart) = (p.PG14, p.PG9, p.USART6); + let (tx, rx, usart, irq) = (p.PG14, p.PG9, p.USART6, interrupt::take!(USART6)); #[cfg(feature = "stm32wb55rg")] - let (tx, rx, usart) = (p.PA2, p.PA3, p.LPUART1); + let (tx, rx, usart, irq) = (p.PA2, p.PA3, p.LPUART1, interrupt::take!(LPUART1)); #[cfg(feature = "stm32h755zi")] - let (tx, rx, usart) = (p.PB6, p.PB7, p.USART1); + let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1)); #[cfg(feature = "stm32u585ai")] - let (tx, rx, usart) = (p.PD8, p.PD9, p.USART3); + let (tx, rx, usart, irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3)); let config = Config::default(); - let mut usart = Uart::new(usart, rx, tx, NoDma, NoDma, config); + let mut usart = Uart::new(usart, rx, tx, irq, NoDma, NoDma, config); // We can't send too many bytes, they have to fit in the FIFO. // This is because we aren't sending+receiving at the same time. diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs index e0389446..d12605a9 100644 --- a/tests/stm32/src/bin/usart_dma.rs +++ b/tests/stm32/src/bin/usart_dma.rs @@ -6,6 +6,7 @@ mod example_common; use defmt::assert_eq; use embassy_executor::Spawner; +use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; use example_common::*; @@ -17,22 +18,53 @@ async fn main(_spawner: Spawner) { // Arduino pins D0 and D1 // They're connected together with a 1K resistor. #[cfg(feature = "stm32f103c8")] - let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH4, p.DMA1_CH5); + let (tx, rx, usart, irq, tx_dma, rx_dma) = ( + p.PA9, + p.PA10, + p.USART1, + interrupt::take!(USART1), + p.DMA1_CH4, + p.DMA1_CH5, + ); #[cfg(feature = "stm32g491re")] - let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); + let (tx, rx, usart, irq, tx_dma, rx_dma) = + (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); #[cfg(feature = "stm32g071rb")] - let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); + let (tx, rx, usart, irq, tx_dma, rx_dma) = + (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); #[cfg(feature = "stm32f429zi")] - let (tx, rx, usart, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, p.DMA2_CH6, p.DMA2_CH1); + let (tx, rx, usart, irq, tx_dma, rx_dma) = ( + p.PG14, + p.PG9, + p.USART6, + interrupt::take!(USART6), + p.DMA2_CH6, + p.DMA2_CH1, + ); #[cfg(feature = "stm32wb55rg")] - let (tx, rx, usart, tx_dma, rx_dma) = (p.PA2, p.PA3, p.LPUART1, p.DMA1_CH1, p.DMA1_CH2); + let (tx, rx, usart, irq, tx_dma, rx_dma) = ( + p.PA2, + p.PA3, + p.LPUART1, + interrupt::take!(LPUART1), + p.DMA1_CH1, + p.DMA1_CH2, + ); #[cfg(feature = "stm32h755zi")] - let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH0, p.DMA1_CH1); + let (tx, rx, usart, irq, tx_dma, rx_dma) = + (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1), p.DMA1_CH0, p.DMA1_CH1); #[cfg(feature = "stm32u585ai")] - let (tx, rx, usart, tx_dma, rx_dma) = (p.PD8, p.PD9, p.USART3, p.GPDMA1_CH0, p.GPDMA1_CH1); + let (tx, rx, usart, irq, tx_dma, rx_dma) = ( + p.PD8, + p.PD9, + p.USART3, + interrupt::take!(USART3), + p.GPDMA1_CH0, + p.GPDMA1_CH1, + ); let config = Config::default(); - let mut usart = Uart::new(usart, rx, tx, tx_dma, rx_dma, config); + let mut usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); // We can't send too many bytes, they have to fit in the FIFO. // This is because we aren't sending+receiving at the same time.