From 49455792cb5406f3e2df0f3850c0d650965e6b2b Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 26 Apr 2023 10:51:23 +0200 Subject: Ring-buffered uart rx with one-period overrun detection --- tests/stm32/Cargo.toml | 2 + tests/stm32/src/bin/usart_rx_ringbuffered.rs | 188 +++++++++++++++++++++++++++ tests/utils/Cargo.toml | 10 ++ tests/utils/src/bin/saturate_serial.rs | 52 ++++++++ 4 files changed, 252 insertions(+) create mode 100644 tests/stm32/src/bin/usart_rx_ringbuffered.rs create mode 100644 tests/utils/Cargo.toml create mode 100644 tests/utils/src/bin/saturate_serial.rs (limited to 'tests') diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index d10d01e29..240fad522 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -33,6 +33,8 @@ embedded-hal = "0.2.6" embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } embedded-hal-async = { version = "=0.2.0-alpha.1" } panic-probe = { version = "0.3.0", features = ["print-defmt"] } +rand_core = { version = "0.6", default-features = false } +rand_chacha = { version = "0.3", default-features = false } chrono = { version = "^0.4", default-features = false, optional = true} diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs new file mode 100644 index 000000000..3ea8bfb7b --- /dev/null +++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs @@ -0,0 +1,188 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use embassy_executor::Spawner; +use embassy_stm32::interrupt; +use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx}; +use embassy_time::{Duration, Timer}; +use example_common::*; +use rand_chacha::ChaCha8Rng; +use rand_core::{RngCore, SeedableRng}; + +#[cfg(feature = "stm32f103c8")] +mod board { + pub type Uart = embassy_stm32::peripherals::USART1; + pub type TxDma = embassy_stm32::peripherals::DMA1_CH4; + pub type RxDma = embassy_stm32::peripherals::DMA1_CH5; +} +#[cfg(feature = "stm32g491re")] +mod board { + pub type Uart = embassy_stm32::peripherals::USART1; + pub type TxDma = embassy_stm32::peripherals::DMA1_CH1; + pub type RxDma = embassy_stm32::peripherals::DMA1_CH2; +} +#[cfg(feature = "stm32g071rb")] +mod board { + pub type Uart = embassy_stm32::peripherals::USART1; + pub type TxDma = embassy_stm32::peripherals::DMA1_CH1; + pub type RxDma = embassy_stm32::peripherals::DMA1_CH2; +} +#[cfg(feature = "stm32f429zi")] +mod board { + pub type Uart = embassy_stm32::peripherals::USART2; + pub type TxDma = embassy_stm32::peripherals::DMA1_CH6; + pub type RxDma = embassy_stm32::peripherals::DMA1_CH5; +} +#[cfg(feature = "stm32wb55rg")] +mod board { + pub type Uart = embassy_stm32::peripherals::LPUART1; + pub type TxDma = embassy_stm32::peripherals::DMA1_CH1; + pub type RxDma = embassy_stm32::peripherals::DMA1_CH2; +} +#[cfg(feature = "stm32h755zi")] +mod board { + pub type Uart = embassy_stm32::peripherals::USART1; + pub type TxDma = embassy_stm32::peripherals::DMA1_CH0; + pub type RxDma = embassy_stm32::peripherals::DMA1_CH1; +} +#[cfg(feature = "stm32u585ai")] +mod board { + pub type Uart = embassy_stm32::peripherals::USART3; + pub type TxDma = embassy_stm32::peripherals::GPDMA1_CH0; + pub type RxDma = embassy_stm32::peripherals::GPDMA1_CH1; +} + +const ONE_BYTE_DURATION_US: u32 = 9_000_000 / 115200; + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_stm32::init(config()); + info!("Hello World!"); + + // Arduino pins D0 and D1 + // They're connected together with a 1K resistor. + #[cfg(feature = "stm32f103c8")] + 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, 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, 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, irq, tx_dma, rx_dma) = + (p.PA2, p.PA3, p.USART2, interrupt::take!(USART2), p.DMA1_CH6, p.DMA1_CH5); + #[cfg(feature = "stm32wb55rg")] + 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, 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, irq, tx_dma, rx_dma) = ( + p.PD8, + p.PD9, + p.USART3, + interrupt::take!(USART3), + p.GPDMA1_CH0, + p.GPDMA1_CH1, + ); + + // To run this test, use the saturating_serial test utility to saturate the serial port + + let mut config = Config::default(); + config.baudrate = 115200; + config.data_bits = DataBits::DataBits8; + config.stop_bits = StopBits::STOP1; + config.parity = Parity::ParityNone; + + let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); + let (tx, rx) = usart.split(); + static mut DMA_BUF: [u8; 64] = [0; 64]; + let dma_buf = unsafe { DMA_BUF.as_mut() }; + let rx = rx.into_ring_buffered(dma_buf); + + info!("Spawning tasks"); + spawner.spawn(transmit_task(tx)).unwrap(); + spawner.spawn(receive_task(rx)).unwrap(); +} + +#[embassy_executor::task] +async fn transmit_task(mut tx: UartTx<'static, board::Uart, board::TxDma>) { + let mut rng = ChaCha8Rng::seed_from_u64(1337); + + info!("Starting random transmissions into void..."); + + let mut i: u8 = 0; + loop { + let mut buf = [0; 32]; + let len = 1 + (rng.next_u32() as usize % (buf.len() - 1)); + for b in &mut buf[..len] { + *b = i; + i = i.wrapping_add(1); + } + + tx.write(&buf[..len]).await.unwrap(); + Timer::after(Duration::from_micros((rng.next_u32() % 10000) as _)).await; + + //i += 1; + //if i % 1000 == 0 { + // trace!("Wrote {} times", i); + //} + } +} + +#[embassy_executor::task] +async fn receive_task(mut rx: RingBufferedUartRx<'static, board::Uart, board::RxDma>) { + info!("Ready to receive..."); + + let mut rng = ChaCha8Rng::seed_from_u64(1337); + + let mut i = 0; + let mut expected: Option = None; + loop { + let mut buf = [0; 100]; + let max_len = 1 + (rng.next_u32() as usize % (buf.len() - 1)); + let received = rx.read(&mut buf[..max_len]).await.unwrap(); + + if expected.is_none() { + info!("Test started"); + expected = Some(buf[0]); + } + + for byte in &buf[..received] { + if byte != &expected.unwrap() { + error!("Test fail! received {}, expected {}", *byte, expected.unwrap()); + cortex_m::asm::bkpt(); + return; + } + expected = Some(expected.unwrap().wrapping_add(1)); + } + + if received < max_len { + let byte_count = rng.next_u32() % 64; + Timer::after(Duration::from_micros((byte_count * ONE_BYTE_DURATION_US) as _)).await; + } + + i += 1; + if i % 1000 == 0 { + trace!("Read {} times", i); + } + } +} diff --git a/tests/utils/Cargo.toml b/tests/utils/Cargo.toml new file mode 100644 index 000000000..7d66fd586 --- /dev/null +++ b/tests/utils/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "test-utils" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8" +serial = "0.4" diff --git a/tests/utils/src/bin/saturate_serial.rs b/tests/utils/src/bin/saturate_serial.rs new file mode 100644 index 000000000..28480516d --- /dev/null +++ b/tests/utils/src/bin/saturate_serial.rs @@ -0,0 +1,52 @@ +use std::path::Path; +use std::time::Duration; +use std::{env, io, thread}; + +use rand::random; +use serial::SerialPort; + +pub fn main() { + if let Some(port_name) = env::args().nth(1) { + let sleep = env::args().position(|x| x == "--sleep").is_some(); + + println!("Saturating port {:?} with 115200 8N1", port_name); + println!("Sleep: {}", sleep); + let mut port = serial::open(&port_name).unwrap(); + if saturate(&mut port, sleep).is_err() { + eprintln!("Unable to saturate port"); + } + } else { + let path = env::args().next().unwrap(); + let basepath = Path::new(&path).with_extension(""); + let basename = basepath.file_name().unwrap(); + eprintln!("USAGE: {} ", basename.to_string_lossy()); + } +} + +fn saturate(port: &mut T, sleep: bool) -> io::Result<()> { + port.reconfigure(&|settings| { + settings.set_baud_rate(serial::Baud115200)?; + settings.set_char_size(serial::Bits8); + settings.set_parity(serial::ParityNone); + settings.set_stop_bits(serial::Stop1); + Ok(()) + })?; + + let mut written = 0; + loop { + let len = random::() % 0x1000; + let buf: Vec = (written..written + len).map(|x| x as u8).collect(); + + port.write_all(&buf)?; + + if sleep { + let micros = (random::() % 1000) as u64; + println!("Sleeping {}us", micros); + port.flush().unwrap(); + thread::sleep(Duration::from_micros(micros)); + } + + written += len; + println!("Written: {}", written); + } +} \ No newline at end of file -- cgit From fc268df6f56661d5f43450c7a03850044ae8e136 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Thu, 27 Apr 2023 10:48:38 +0200 Subject: Support overflow detection for more than one ring-period --- tests/stm32/src/bin/usart_rx_ringbuffered.rs | 19 +++++++++++++++---- tests/utils/src/bin/saturate_serial.rs | 15 ++++++++------- 2 files changed, 23 insertions(+), 11 deletions(-) (limited to 'tests') diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs index 3ea8bfb7b..48dc25b0e 100644 --- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs +++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs @@ -56,6 +56,7 @@ mod board { } const ONE_BYTE_DURATION_US: u32 = 9_000_000 / 115200; +const DMA_BUF_SIZE: usize = 64; #[embassy_executor::main] async fn main(spawner: Spawner) { @@ -114,7 +115,7 @@ async fn main(spawner: Spawner) { let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); let (tx, rx) = usart.split(); - static mut DMA_BUF: [u8; 64] = [0; 64]; + static mut DMA_BUF: [u8; DMA_BUF_SIZE] = [0; DMA_BUF_SIZE]; let dma_buf = unsafe { DMA_BUF.as_mut() }; let rx = rx.into_ring_buffered(dma_buf); @@ -159,7 +160,14 @@ async fn receive_task(mut rx: RingBufferedUartRx<'static, board::Uart, board::Rx loop { let mut buf = [0; 100]; let max_len = 1 + (rng.next_u32() as usize % (buf.len() - 1)); - let received = rx.read(&mut buf[..max_len]).await.unwrap(); + let received = match rx.read(&mut buf[..max_len]).await { + Ok(r) => r, + Err(e) => { + error!("Test fail! read error: {:?}", e); + cortex_m::asm::bkpt(); + return; + } + }; if expected.is_none() { info!("Test started"); @@ -176,8 +184,11 @@ async fn receive_task(mut rx: RingBufferedUartRx<'static, board::Uart, board::Rx } if received < max_len { - let byte_count = rng.next_u32() % 64; - Timer::after(Duration::from_micros((byte_count * ONE_BYTE_DURATION_US) as _)).await; + let byte_count = rng.next_u32() % (DMA_BUF_SIZE as u32); + let random_delay_us = (byte_count * ONE_BYTE_DURATION_US) as u64; + if random_delay_us > 200 { + Timer::after(Duration::from_micros(random_delay_us - 200)).await; + } } i += 1; diff --git a/tests/utils/src/bin/saturate_serial.rs b/tests/utils/src/bin/saturate_serial.rs index 28480516d..18ca12fb7 100644 --- a/tests/utils/src/bin/saturate_serial.rs +++ b/tests/utils/src/bin/saturate_serial.rs @@ -1,18 +1,19 @@ use std::path::Path; use std::time::Duration; -use std::{env, io, thread}; +use std::{env, io, process, thread}; use rand::random; use serial::SerialPort; pub fn main() { if let Some(port_name) = env::args().nth(1) { - let sleep = env::args().position(|x| x == "--sleep").is_some(); + let idles = env::args().position(|x| x == "--idles").is_some(); println!("Saturating port {:?} with 115200 8N1", port_name); - println!("Sleep: {}", sleep); + println!("Idles: {}", idles); + println!("Process ID: {}", process::id()); let mut port = serial::open(&port_name).unwrap(); - if saturate(&mut port, sleep).is_err() { + if saturate(&mut port, idles).is_err() { eprintln!("Unable to saturate port"); } } else { @@ -23,7 +24,7 @@ pub fn main() { } } -fn saturate(port: &mut T, sleep: bool) -> io::Result<()> { +fn saturate(port: &mut T, idles: bool) -> io::Result<()> { port.reconfigure(&|settings| { settings.set_baud_rate(serial::Baud115200)?; settings.set_char_size(serial::Bits8); @@ -39,7 +40,7 @@ fn saturate(port: &mut T, sleep: bool) -> io::Result<()> { port.write_all(&buf)?; - if sleep { + if idles { let micros = (random::() % 1000) as u64; println!("Sleeping {}us", micros); port.flush().unwrap(); @@ -49,4 +50,4 @@ fn saturate(port: &mut T, sleep: bool) -> io::Result<()> { written += len; println!("Written: {}", written); } -} \ No newline at end of file +} -- cgit From 96e8a7ddb9b768a2827dffa5c72723b1075381ad Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 1 May 2023 18:15:46 +0200 Subject: stm32/uart: feature-gate ringbuffer out when using gpdma, not supported yet. --- tests/stm32/Cargo.toml | 20 +++++++++++++------- tests/stm32/src/bin/usart_rx_ringbuffered.rs | 2 ++ 2 files changed, 15 insertions(+), 7 deletions(-) (limited to 'tests') diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 240fad522..eca470358 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -5,18 +5,19 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [features] -stm32f103c8 = ["embassy-stm32/stm32f103c8"] # Blue Pill -stm32f429zi = ["embassy-stm32/stm32f429zi", "sdmmc", "chrono"] # Nucleo -stm32g071rb = ["embassy-stm32/stm32g071rb"] # Nucleo -stm32c031c6 = ["embassy-stm32/stm32c031c6"] # Nucleo -stm32g491re = ["embassy-stm32/stm32g491re"] # Nucleo -stm32h755zi = ["embassy-stm32/stm32h755zi-cm7"] # Nucleo -stm32wb55rg = ["embassy-stm32/stm32wb55rg"] # Nucleo +stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill +stm32f429zi = ["embassy-stm32/stm32f429zi", "sdmmc", "chrono", "not-gpdma"] # Nucleo +stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma"] # Nucleo +stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo +stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo +stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo +stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma"] # Nucleo stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board sdmmc = [] chrono = ["embassy-stm32/chrono", "dep:chrono"] +not-gpdma = [] [dependencies] embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } @@ -80,6 +81,11 @@ name = "usart_dma" path = "src/bin/usart_dma.rs" required-features = [] +[[bin]] +name = "usart_rx_ringbuffered" +path = "src/bin/usart_rx_ringbuffered.rs" +required-features = [ "not-gpdma",] + # END TESTS [profile.dev] diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs index 48dc25b0e..86bcfab8d 100644 --- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs +++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs @@ -1,3 +1,5 @@ +// required-features: not-gpdma + #![no_std] #![no_main] #![feature(type_alias_impl_trait)] -- cgit From 1806422763be4e9e47201f741a03e5968fc8dedb Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 1 May 2023 18:16:29 +0200 Subject: stm32/test: add real defmt timestamp --- tests/stm32/Cargo.toml | 3 ++- tests/stm32/src/example_common.rs | 11 ----------- 2 files changed, 2 insertions(+), 12 deletions(-) (limited to 'tests') diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index eca470358..5cd949661 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -22,8 +22,9 @@ not-gpdma = [] [dependencies] embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768"] } +embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3.0" defmt-rtt = "0.4" diff --git a/tests/stm32/src/example_common.rs b/tests/stm32/src/example_common.rs index c47ed75c4..a4f8668c7 100644 --- a/tests/stm32/src/example_common.rs +++ b/tests/stm32/src/example_common.rs @@ -1,22 +1,11 @@ #![macro_use] -use core::sync::atomic::{AtomicUsize, Ordering}; - pub use defmt::*; #[allow(unused)] use embassy_stm32::time::Hertz; use embassy_stm32::Config; use {defmt_rtt as _, panic_probe as _}; -defmt::timestamp! {"{=u64}", { - static COUNT: AtomicUsize = AtomicUsize::new(0); - // NOTE(no-CAS) `timestamps` runs with interrupts disabled - let n = COUNT.load(Ordering::Relaxed); - COUNT.store(n + 1, Ordering::Relaxed); - n as u64 - } -} - pub fn config() -> Config { #[allow(unused_mut)] let mut config = Config::default(); -- cgit From 76017796933f0335bcdadbd6b765721833fdacec Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 1 May 2023 18:17:02 +0200 Subject: stm32/test: cleanup ringbuffer test, exit on success (transferring 100kb) --- tests/stm32/src/bin/usart_rx_ringbuffered.rs | 77 ++++++++++++++-------------- 1 file changed, 38 insertions(+), 39 deletions(-) (limited to 'tests') diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs index 86bcfab8d..2c4a8fdf4 100644 --- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs +++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs @@ -6,6 +6,7 @@ #[path = "../example_common.rs"] mod example_common; +use defmt::{assert_eq, panic}; use embassy_executor::Spawner; use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx}; @@ -34,9 +35,9 @@ mod board { } #[cfg(feature = "stm32f429zi")] mod board { - pub type Uart = embassy_stm32::peripherals::USART2; - pub type TxDma = embassy_stm32::peripherals::DMA1_CH6; - pub type RxDma = embassy_stm32::peripherals::DMA1_CH5; + pub type Uart = embassy_stm32::peripherals::USART6; + pub type TxDma = embassy_stm32::peripherals::DMA2_CH6; + pub type RxDma = embassy_stm32::peripherals::DMA2_CH1; } #[cfg(feature = "stm32wb55rg")] mod board { @@ -56,9 +57,14 @@ mod board { pub type TxDma = embassy_stm32::peripherals::GPDMA1_CH0; pub type RxDma = embassy_stm32::peripherals::GPDMA1_CH1; } +#[cfg(feature = "stm32c031c6")] +mod board { + pub type Uart = embassy_stm32::peripherals::USART1; + pub type TxDma = embassy_stm32::peripherals::DMA1_CH1; + pub type RxDma = embassy_stm32::peripherals::DMA1_CH2; +} -const ONE_BYTE_DURATION_US: u32 = 9_000_000 / 115200; -const DMA_BUF_SIZE: usize = 64; +const DMA_BUF_SIZE: usize = 256; #[embassy_executor::main] async fn main(spawner: Spawner) { @@ -83,8 +89,14 @@ async fn main(spawner: Spawner) { 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, irq, tx_dma, rx_dma) = - (p.PA2, p.PA3, p.USART2, interrupt::take!(USART2), p.DMA1_CH6, p.DMA1_CH5); + 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, irq, tx_dma, rx_dma) = ( p.PA2, @@ -106,11 +118,16 @@ async fn main(spawner: Spawner) { p.GPDMA1_CH0, p.GPDMA1_CH1, ); + #[cfg(feature = "stm32c031c6")] + let (tx, rx, usart, irq, tx_dma, rx_dma) = + (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); // To run this test, use the saturating_serial test utility to saturate the serial port let mut config = Config::default(); - config.baudrate = 115200; + // this is the fastest we can go without tuning RCC + // some chips have default pclk=8mhz, and uart can run at max pclk/16 + config.baudrate = 500_000; config.data_bits = DataBits::DataBits8; config.stop_bits = StopBits::STOP1; config.parity = Parity::ParityNone; @@ -135,19 +152,14 @@ async fn transmit_task(mut tx: UartTx<'static, board::Uart, board::TxDma>) { let mut i: u8 = 0; loop { let mut buf = [0; 32]; - let len = 1 + (rng.next_u32() as usize % (buf.len() - 1)); + let len = 1 + (rng.next_u32() as usize % buf.len()); for b in &mut buf[..len] { *b = i; i = i.wrapping_add(1); } tx.write(&buf[..len]).await.unwrap(); - Timer::after(Duration::from_micros((rng.next_u32() % 10000) as _)).await; - - //i += 1; - //if i % 1000 == 0 { - // trace!("Wrote {} times", i); - //} + Timer::after(Duration::from_micros((rng.next_u32() % 1000) as _)).await; } } @@ -158,44 +170,31 @@ async fn receive_task(mut rx: RingBufferedUartRx<'static, board::Uart, board::Rx let mut rng = ChaCha8Rng::seed_from_u64(1337); let mut i = 0; - let mut expected: Option = None; + let mut expected = 0; loop { let mut buf = [0; 100]; - let max_len = 1 + (rng.next_u32() as usize % (buf.len() - 1)); + let max_len = 1 + (rng.next_u32() as usize % buf.len()); let received = match rx.read(&mut buf[..max_len]).await { Ok(r) => r, Err(e) => { - error!("Test fail! read error: {:?}", e); - cortex_m::asm::bkpt(); - return; + panic!("Test fail! read error: {:?}", e); } }; - if expected.is_none() { - info!("Test started"); - expected = Some(buf[0]); - } - for byte in &buf[..received] { - if byte != &expected.unwrap() { - error!("Test fail! received {}, expected {}", *byte, expected.unwrap()); - cortex_m::asm::bkpt(); - return; - } - expected = Some(expected.unwrap().wrapping_add(1)); + assert_eq!(*byte, expected); + expected = expected.wrapping_add(1); } if received < max_len { - let byte_count = rng.next_u32() % (DMA_BUF_SIZE as u32); - let random_delay_us = (byte_count * ONE_BYTE_DURATION_US) as u64; - if random_delay_us > 200 { - Timer::after(Duration::from_micros(random_delay_us - 200)).await; - } + Timer::after(Duration::from_micros((rng.next_u32() % 1000) as _)).await; } - i += 1; - if i % 1000 == 0 { - trace!("Read {} times", i); + i += received; + + if i > 100000 { + info!("Test OK!"); + cortex_m::asm::bkpt(); } } } -- cgit From a1d45303c336434929eb8eb7e55629c504a95b0e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 1 May 2023 18:17:29 +0200 Subject: stm32/test: fix race condition in uart_dma. --- tests/stm32/src/bin/usart_dma.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'tests') diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs index d673df0f3..de6cd41d1 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_futures::join::join; use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; use example_common::*; @@ -76,18 +77,26 @@ async fn main(_spawner: Spawner) { (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); let config = Config::default(); - let mut usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); + let 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. - // For whatever reason, blocking works with 2 bytes but DMA only with 1?? + const LEN: usize = 128; + let mut tx_buf = [0; LEN]; + let mut rx_buf = [0; LEN]; + for i in 0..LEN { + tx_buf[i] = i as u8; + } - let data = [0x42]; - usart.write(&data).await.unwrap(); + let (mut tx, mut rx) = usart.split(); - let mut buf = [0; 1]; - usart.read(&mut buf).await.unwrap(); - assert_eq!(buf, data); + let tx_fut = async { + tx.write(&tx_buf).await.unwrap(); + }; + let rx_fut = async { + rx.read(&mut rx_buf).await.unwrap(); + }; + join(rx_fut, tx_fut).await; + + assert_eq!(tx_buf, rx_buf); info!("Test OK"); cortex_m::asm::bkpt(); -- cgit