Merge #1420
1420: stm32/usart: add OVER8 and PRESC, add baudrate test. r=Dirbaio a=Dirbaio Fixes #1183 Fixes #1418 bors r+ Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
This commit is contained in:
		@@ -58,7 +58,7 @@ sdio-host = "0.5.0"
 | 
			
		||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
 | 
			
		||||
critical-section = "1.1"
 | 
			
		||||
atomic-polyfill = "1.0.1"
 | 
			
		||||
stm32-metapac = "6"
 | 
			
		||||
stm32-metapac = "7"
 | 
			
		||||
vcell = "0.1.3"
 | 
			
		||||
bxcan = "0.7.0"
 | 
			
		||||
nb = "1.0.0"
 | 
			
		||||
@@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] }
 | 
			
		||||
[build-dependencies]
 | 
			
		||||
proc-macro2 = "1.0.36"
 | 
			
		||||
quote = "1.0.15"
 | 
			
		||||
stm32-metapac = { version = "6", default-features = false, features = ["metadata"]}
 | 
			
		||||
stm32-metapac = { version = "7", default-features = false, features = ["metadata"]}
 | 
			
		||||
 | 
			
		||||
[features]
 | 
			
		||||
default = ["stm32-metapac/rt"]
 | 
			
		||||
 
 | 
			
		||||
@@ -84,7 +84,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
 | 
			
		||||
        Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[cfg(not(usart_v1))]
 | 
			
		||||
    #[cfg(not(any(usart_v1, usart_v2)))]
 | 
			
		||||
    pub fn new_with_de(
 | 
			
		||||
        peri: impl Peripheral<P = T> + 'd,
 | 
			
		||||
        irq: impl Peripheral<P = T::Interrupt> + 'd,
 | 
			
		||||
@@ -133,7 +133,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
 | 
			
		||||
            tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        configure(r, &config, T::frequency(), T::MULTIPLIER, true, true);
 | 
			
		||||
        configure(r, &config, T::frequency(), T::KIND, true, true);
 | 
			
		||||
 | 
			
		||||
        unsafe {
 | 
			
		||||
            r.cr1().modify(|w| {
 | 
			
		||||
 
 | 
			
		||||
@@ -12,10 +12,11 @@ use futures::future::{select, Either};
 | 
			
		||||
 | 
			
		||||
use crate::dma::{NoDma, Transfer};
 | 
			
		||||
use crate::gpio::sealed::AFType;
 | 
			
		||||
#[cfg(any(lpuart_v1, lpuart_v2))]
 | 
			
		||||
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};
 | 
			
		||||
#[cfg(not(any(usart_v1, usart_v2)))]
 | 
			
		||||
use crate::pac::usart::Lpuart as Regs;
 | 
			
		||||
#[cfg(any(usart_v1, usart_v2))]
 | 
			
		||||
use crate::pac::usart::Usart as Regs;
 | 
			
		||||
use crate::pac::usart::{regs, vals};
 | 
			
		||||
use crate::time::Hertz;
 | 
			
		||||
use crate::{peripherals, Peripheral};
 | 
			
		||||
 | 
			
		||||
@@ -159,7 +160,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
 | 
			
		||||
            tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        configure(r, &config, T::frequency(), T::MULTIPLIER, false, true);
 | 
			
		||||
        configure(r, &config, T::frequency(), T::KIND, false, true);
 | 
			
		||||
 | 
			
		||||
        // create state once!
 | 
			
		||||
        let _s = T::state();
 | 
			
		||||
@@ -261,7 +262,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
 | 
			
		||||
            rx.set_as_af(rx.af_num(), AFType::Input);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        configure(r, &config, T::frequency(), T::MULTIPLIER, true, false);
 | 
			
		||||
        configure(r, &config, T::frequency(), T::KIND, true, false);
 | 
			
		||||
 | 
			
		||||
        irq.set_handler(Self::on_interrupt);
 | 
			
		||||
        irq.unpend();
 | 
			
		||||
@@ -653,7 +654,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
 | 
			
		||||
        Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[cfg(not(usart_v1))]
 | 
			
		||||
    #[cfg(not(any(usart_v1, usart_v2)))]
 | 
			
		||||
    pub fn new_with_de(
 | 
			
		||||
        peri: impl Peripheral<P = T> + 'd,
 | 
			
		||||
        rx: impl Peripheral<P = impl RxPin<T>> + 'd,
 | 
			
		||||
@@ -696,7 +697,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
 | 
			
		||||
            tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        configure(r, &config, T::frequency(), T::MULTIPLIER, true, true);
 | 
			
		||||
        configure(r, &config, T::frequency(), T::KIND, true, true);
 | 
			
		||||
 | 
			
		||||
        irq.set_handler(UartRx::<T, RxDma>::on_interrupt);
 | 
			
		||||
        irq.unpend();
 | 
			
		||||
@@ -763,16 +764,74 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32, enable_rx: bool, enable_tx: bool) {
 | 
			
		||||
fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: bool, enable_tx: bool) {
 | 
			
		||||
    if !enable_rx && !enable_tx {
 | 
			
		||||
        panic!("USART: At least one of RX or TX should be enabled");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO: better calculation, including error checking and OVER8 if possible.
 | 
			
		||||
    let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * multiplier;
 | 
			
		||||
    #[cfg(not(usart_v4))]
 | 
			
		||||
    static DIVS: [(u16, ()); 1] = [(1, ())];
 | 
			
		||||
 | 
			
		||||
    #[cfg(usart_v4)]
 | 
			
		||||
    static DIVS: [(u16, vals::Presc); 12] = [
 | 
			
		||||
        (1, vals::Presc::DIV1),
 | 
			
		||||
        (2, vals::Presc::DIV2),
 | 
			
		||||
        (4, vals::Presc::DIV4),
 | 
			
		||||
        (6, vals::Presc::DIV6),
 | 
			
		||||
        (8, vals::Presc::DIV8),
 | 
			
		||||
        (10, vals::Presc::DIV10),
 | 
			
		||||
        (12, vals::Presc::DIV12),
 | 
			
		||||
        (16, vals::Presc::DIV16),
 | 
			
		||||
        (32, vals::Presc::DIV32),
 | 
			
		||||
        (64, vals::Presc::DIV64),
 | 
			
		||||
        (128, vals::Presc::DIV128),
 | 
			
		||||
        (256, vals::Presc::DIV256),
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    let (mul, brr_min, brr_max) = match kind {
 | 
			
		||||
        #[cfg(any(usart_v3, usart_v4))]
 | 
			
		||||
        Kind::Lpuart => (256, 0x300, 0x10_0000),
 | 
			
		||||
        Kind::Uart => (1, 0x10, 0x1_0000),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    #[cfg(not(usart_v1))]
 | 
			
		||||
    let mut over8 = false;
 | 
			
		||||
    let mut found = false;
 | 
			
		||||
    for &(presc, _presc_val) in &DIVS {
 | 
			
		||||
        let denom = (config.baudrate * presc as u32) as u64;
 | 
			
		||||
        let div = (pclk_freq.0 as u64 * mul + (denom / 2)) / denom;
 | 
			
		||||
        trace!("USART: presc={} div={:08x}", presc, div);
 | 
			
		||||
 | 
			
		||||
        if div < brr_min {
 | 
			
		||||
            #[cfg(not(usart_v1))]
 | 
			
		||||
            if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) {
 | 
			
		||||
                over8 = true;
 | 
			
		||||
                let div = div as u32;
 | 
			
		||||
                unsafe {
 | 
			
		||||
                    r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07)));
 | 
			
		||||
                    #[cfg(usart_v4)]
 | 
			
		||||
                    r.presc().write(|w| w.set_prescaler(_presc_val));
 | 
			
		||||
                }
 | 
			
		||||
                found = true;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            panic!("USART: baudrate too high");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if div < brr_max {
 | 
			
		||||
            unsafe {
 | 
			
		||||
                r.brr().write_value(regs::Brr(div as u32));
 | 
			
		||||
                #[cfg(usart_v4)]
 | 
			
		||||
                r.presc().write(|w| w.set_prescaler(_presc_val));
 | 
			
		||||
            }
 | 
			
		||||
            found = true;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    assert!(found, "USART: baudrate too low");
 | 
			
		||||
 | 
			
		||||
    unsafe {
 | 
			
		||||
        r.brr().write_value(regs::Brr(div));
 | 
			
		||||
        r.cr2().write(|w| {
 | 
			
		||||
            w.set_stop(match config.stop_bits {
 | 
			
		||||
                StopBits::STOP0P5 => vals::Stop::STOP0P5,
 | 
			
		||||
@@ -801,6 +860,8 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32, enable
 | 
			
		||||
                Parity::ParityEven => vals::Ps::EVEN,
 | 
			
		||||
                _ => vals::Ps::EVEN,
 | 
			
		||||
            });
 | 
			
		||||
            #[cfg(not(usart_v1))]
 | 
			
		||||
            w.set_over8(vals::Over8(over8 as _));
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -986,43 +1047,45 @@ mod rx_ringbuffered;
 | 
			
		||||
#[cfg(not(gpdma))]
 | 
			
		||||
pub use rx_ringbuffered::RingBufferedUartRx;
 | 
			
		||||
 | 
			
		||||
#[cfg(usart_v1)]
 | 
			
		||||
use self::sealed::Kind;
 | 
			
		||||
 | 
			
		||||
#[cfg(any(usart_v1, usart_v2))]
 | 
			
		||||
fn tdr(r: crate::pac::usart::Usart) -> *mut u8 {
 | 
			
		||||
    r.dr().ptr() as _
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(usart_v1)]
 | 
			
		||||
#[cfg(any(usart_v1, usart_v2))]
 | 
			
		||||
fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
 | 
			
		||||
    r.dr().ptr() as _
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(usart_v1)]
 | 
			
		||||
#[cfg(any(usart_v1, usart_v2))]
 | 
			
		||||
fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> {
 | 
			
		||||
    r.sr()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(usart_v1)]
 | 
			
		||||
#[cfg(any(usart_v1, usart_v2))]
 | 
			
		||||
#[allow(unused)]
 | 
			
		||||
unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) {
 | 
			
		||||
    // On v1 the flags are cleared implicitly by reads and writes to DR.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(usart_v2)]
 | 
			
		||||
#[cfg(any(usart_v3, usart_v4))]
 | 
			
		||||
fn tdr(r: Regs) -> *mut u8 {
 | 
			
		||||
    r.tdr().ptr() as _
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(usart_v2)]
 | 
			
		||||
#[cfg(any(usart_v3, usart_v4))]
 | 
			
		||||
fn rdr(r: Regs) -> *mut u8 {
 | 
			
		||||
    r.rdr().ptr() as _
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(usart_v2)]
 | 
			
		||||
#[cfg(any(usart_v3, usart_v4))]
 | 
			
		||||
fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> {
 | 
			
		||||
    r.isr()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(usart_v2)]
 | 
			
		||||
#[cfg(any(usart_v3, usart_v4))]
 | 
			
		||||
#[allow(unused)]
 | 
			
		||||
unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
 | 
			
		||||
    r.icr().write(|w| *w = regs::Icr(sr.0));
 | 
			
		||||
@@ -1033,6 +1096,13 @@ pub(crate) mod sealed {
 | 
			
		||||
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[derive(Clone, Copy, PartialEq, Eq)]
 | 
			
		||||
    pub enum Kind {
 | 
			
		||||
        Uart,
 | 
			
		||||
        #[cfg(any(usart_v3, usart_v4))]
 | 
			
		||||
        Lpuart,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub struct State {
 | 
			
		||||
        pub rx_waker: AtomicWaker,
 | 
			
		||||
        pub tx_waker: AtomicWaker,
 | 
			
		||||
@@ -1048,7 +1118,7 @@ pub(crate) mod sealed {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub trait BasicInstance: crate::rcc::RccPeripheral {
 | 
			
		||||
        const MULTIPLIER: u32;
 | 
			
		||||
        const KIND: Kind;
 | 
			
		||||
        type Interrupt: crate::interrupt::Interrupt;
 | 
			
		||||
 | 
			
		||||
        fn regs() -> Regs;
 | 
			
		||||
@@ -1077,10 +1147,10 @@ pin_trait!(DePin, BasicInstance);
 | 
			
		||||
dma_trait!(TxDma, BasicInstance);
 | 
			
		||||
dma_trait!(RxDma, BasicInstance);
 | 
			
		||||
 | 
			
		||||
macro_rules! impl_lpuart {
 | 
			
		||||
    ($inst:ident, $irq:ident, $mul:expr) => {
 | 
			
		||||
macro_rules! impl_usart {
 | 
			
		||||
    ($inst:ident, $irq:ident, $kind:expr) => {
 | 
			
		||||
        impl sealed::BasicInstance for crate::peripherals::$inst {
 | 
			
		||||
            const MULTIPLIER: u32 = $mul;
 | 
			
		||||
            const KIND: Kind = $kind;
 | 
			
		||||
            type Interrupt = crate::interrupt::$irq;
 | 
			
		||||
 | 
			
		||||
            fn regs() -> Regs {
 | 
			
		||||
@@ -1104,21 +1174,19 @@ macro_rules! impl_lpuart {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
foreach_interrupt!(
 | 
			
		||||
    ($inst:ident, lpuart, $block:ident, $signal_name:ident, $irq:ident) => {
 | 
			
		||||
        impl_lpuart!($inst, $irq, 256);
 | 
			
		||||
    ($inst:ident, usart, LPUART, $signal_name:ident, $irq:ident) => {
 | 
			
		||||
        impl_usart!($inst, $irq, Kind::Lpuart);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => {
 | 
			
		||||
        impl_lpuart!($inst, $irq, 1);
 | 
			
		||||
        impl_usart!($inst, $irq, Kind::Uart);
 | 
			
		||||
 | 
			
		||||
        impl sealed::FullInstance for peripherals::$inst {
 | 
			
		||||
 | 
			
		||||
            fn regs_uart() -> crate::pac::usart::Usart {
 | 
			
		||||
                crate::pac::$inst
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl FullInstance for peripherals::$inst {
 | 
			
		||||
        }
 | 
			
		||||
        impl FullInstance for peripherals::$inst {}
 | 
			
		||||
    };
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ edition = "2021"
 | 
			
		||||
name = "embassy-stm32-tests"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
license = "MIT OR Apache-2.0"
 | 
			
		||||
autobins = false
 | 
			
		||||
 | 
			
		||||
[features]
 | 
			
		||||
stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"]     # Blue Pill
 | 
			
		||||
 
 | 
			
		||||
@@ -6,15 +6,16 @@ fn main() -> Result<(), Box<dyn Error>> {
 | 
			
		||||
    let out = PathBuf::from(env::var("OUT_DIR").unwrap());
 | 
			
		||||
    fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap();
 | 
			
		||||
    println!("cargo:rustc-link-search={}", out.display());
 | 
			
		||||
    println!("cargo:rerun-if-changed=link_ram.x");
 | 
			
		||||
 | 
			
		||||
    println!("cargo:rustc-link-arg-bins=--nmagic");
 | 
			
		||||
 | 
			
		||||
    // too little RAM to run from RAM.
 | 
			
		||||
    #[cfg(any(feature = "stm32c031c6"))]
 | 
			
		||||
    println!("cargo:rustc-link-arg-bins=-Tlink.x");
 | 
			
		||||
    #[cfg(not(any(feature = "stm32c031c6")))]
 | 
			
		||||
    println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
 | 
			
		||||
    if cfg!(any(feature = "stm32f103c8", feature = "stm32c031c6")) {
 | 
			
		||||
        println!("cargo:rustc-link-arg-bins=-Tlink.x");
 | 
			
		||||
        println!("cargo:rerun-if-changed=link.x");
 | 
			
		||||
    } else {
 | 
			
		||||
        println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
 | 
			
		||||
        println!("cargo:rerun-if-changed=link_ram.x");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,6 @@ async fn main(_spawner: Spawner) {
 | 
			
		||||
    #[cfg(feature = "stm32c031c6")]
 | 
			
		||||
    let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
 | 
			
		||||
 | 
			
		||||
    info!("asdfa;");
 | 
			
		||||
    let mut spi = Spi::new(
 | 
			
		||||
        spi,
 | 
			
		||||
        sck,  // Arduino D13
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::dma::NoDma;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::usart::{Config, Uart};
 | 
			
		||||
use embassy_time::{Duration, Instant};
 | 
			
		||||
use example_common::*;
 | 
			
		||||
 | 
			
		||||
#[embassy_executor::main]
 | 
			
		||||
@@ -19,36 +20,76 @@ 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, irq) = (p.PA9, p.PA10, p.USART1, interrupt::take!(USART1));
 | 
			
		||||
    let (mut tx, mut rx, mut usart, mut irq) = (p.PA9, p.PA10, p.USART1, interrupt::take!(USART1));
 | 
			
		||||
    #[cfg(feature = "stm32g491re")]
 | 
			
		||||
    let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1));
 | 
			
		||||
    let (mut tx, mut rx, mut usart, mut irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1));
 | 
			
		||||
    #[cfg(feature = "stm32g071rb")]
 | 
			
		||||
    let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1));
 | 
			
		||||
    let (mut tx, mut rx, mut usart, mut irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1));
 | 
			
		||||
    #[cfg(feature = "stm32f429zi")]
 | 
			
		||||
    let (tx, rx, usart, irq) = (p.PG14, p.PG9, p.USART6, interrupt::take!(USART6));
 | 
			
		||||
    let (mut tx, mut rx, mut usart, mut irq) = (p.PG14, p.PG9, p.USART6, interrupt::take!(USART6));
 | 
			
		||||
    #[cfg(feature = "stm32wb55rg")]
 | 
			
		||||
    let (tx, rx, usart, irq) = (p.PA2, p.PA3, p.LPUART1, interrupt::take!(LPUART1));
 | 
			
		||||
    let (mut tx, mut rx, mut usart, mut irq) = (p.PA2, p.PA3, p.LPUART1, interrupt::take!(LPUART1));
 | 
			
		||||
    #[cfg(feature = "stm32h755zi")]
 | 
			
		||||
    let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1));
 | 
			
		||||
    let (mut tx, mut rx, mut usart, mut irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1));
 | 
			
		||||
    #[cfg(feature = "stm32u585ai")]
 | 
			
		||||
    let (tx, rx, usart, irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3));
 | 
			
		||||
    let (mut tx, mut rx, mut usart, mut irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3));
 | 
			
		||||
    #[cfg(feature = "stm32h563zi")]
 | 
			
		||||
    let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.LPUART1, interrupt::take!(LPUART1));
 | 
			
		||||
    let (mut tx, mut rx, mut usart, mut irq) = (p.PB6, p.PB7, p.LPUART1, interrupt::take!(LPUART1));
 | 
			
		||||
    #[cfg(feature = "stm32c031c6")]
 | 
			
		||||
    let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1));
 | 
			
		||||
    let (mut tx, mut rx, mut usart, mut irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1));
 | 
			
		||||
 | 
			
		||||
    let config = Config::default();
 | 
			
		||||
    let mut usart = Uart::new(usart, rx, tx, irq, NoDma, NoDma, config);
 | 
			
		||||
    {
 | 
			
		||||
        let config = Config::default();
 | 
			
		||||
        let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, &mut 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.
 | 
			
		||||
        // 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.
 | 
			
		||||
 | 
			
		||||
    let data = [0xC0, 0xDE];
 | 
			
		||||
    usart.blocking_write(&data).unwrap();
 | 
			
		||||
        let data = [0xC0, 0xDE];
 | 
			
		||||
        usart.blocking_write(&data).unwrap();
 | 
			
		||||
 | 
			
		||||
    let mut buf = [0; 2];
 | 
			
		||||
    usart.blocking_read(&mut buf).unwrap();
 | 
			
		||||
    assert_eq!(buf, data);
 | 
			
		||||
        let mut buf = [0; 2];
 | 
			
		||||
        usart.blocking_read(&mut buf).unwrap();
 | 
			
		||||
        assert_eq!(buf, data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Test that baudrate divider is calculated correctly.
 | 
			
		||||
    // Do it by comparing the time it takes to send a known number of bytes.
 | 
			
		||||
    for baudrate in [
 | 
			
		||||
        300,
 | 
			
		||||
        9600,
 | 
			
		||||
        115200,
 | 
			
		||||
        250_000,
 | 
			
		||||
        337_934,
 | 
			
		||||
        #[cfg(not(feature = "stm32f103c8"))]
 | 
			
		||||
        1_000_000,
 | 
			
		||||
        #[cfg(not(feature = "stm32f103c8"))]
 | 
			
		||||
        2_000_000,
 | 
			
		||||
    ] {
 | 
			
		||||
        info!("testing baudrate {}", baudrate);
 | 
			
		||||
 | 
			
		||||
        let mut config = Config::default();
 | 
			
		||||
        config.baudrate = baudrate;
 | 
			
		||||
        let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, &mut irq, NoDma, NoDma, config);
 | 
			
		||||
 | 
			
		||||
        let n = (baudrate as usize / 100).max(64);
 | 
			
		||||
 | 
			
		||||
        let start = Instant::now();
 | 
			
		||||
        for _ in 0..n {
 | 
			
		||||
            usart.blocking_write(&[0x00]).unwrap();
 | 
			
		||||
        }
 | 
			
		||||
        let dur = Instant::now() - start;
 | 
			
		||||
        let want_dur = Duration::from_micros(n as u64 * 10 * 1_000_000 / (baudrate as u64));
 | 
			
		||||
        let fuzz = want_dur / 5;
 | 
			
		||||
        if dur < want_dur - fuzz || dur > want_dur + fuzz {
 | 
			
		||||
            defmt::panic!(
 | 
			
		||||
                "bad duration for baudrate {}: got {:?} want {:?}",
 | 
			
		||||
                baudrate,
 | 
			
		||||
                dur,
 | 
			
		||||
                want_dur
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    info!("Test OK");
 | 
			
		||||
    cortex_m::asm::bkpt();
 | 
			
		||||
 
 | 
			
		||||
@@ -94,6 +94,9 @@ async fn main(_spawner: Spawner) {
 | 
			
		||||
    let rx_fut = async {
 | 
			
		||||
        rx.read(&mut rx_buf).await.unwrap();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // note: rx needs to be polled first, to workaround this bug:
 | 
			
		||||
    // https://github.com/embassy-rs/embassy/issues/1426
 | 
			
		||||
    join(rx_fut, tx_fut).await;
 | 
			
		||||
 | 
			
		||||
    assert_eq!(tx_buf, rx_buf);
 | 
			
		||||
 
 | 
			
		||||
@@ -145,13 +145,16 @@ async fn main(spawner: Spawner) {
 | 
			
		||||
 | 
			
		||||
#[embassy_executor::task]
 | 
			
		||||
async fn transmit_task(mut tx: UartTx<'static, board::Uart, board::TxDma>) {
 | 
			
		||||
    // workaround https://github.com/embassy-rs/embassy/issues/1426
 | 
			
		||||
    Timer::after(Duration::from_millis(100) as _).await;
 | 
			
		||||
 | 
			
		||||
    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 mut buf = [0; 256];
 | 
			
		||||
        let len = 1 + (rng.next_u32() as usize % buf.len());
 | 
			
		||||
        for b in &mut buf[..len] {
 | 
			
		||||
            *b = i;
 | 
			
		||||
@@ -172,7 +175,7 @@ async fn receive_task(mut rx: RingBufferedUartRx<'static, board::Uart, board::Rx
 | 
			
		||||
    let mut i = 0;
 | 
			
		||||
    let mut expected = 0;
 | 
			
		||||
    loop {
 | 
			
		||||
        let mut buf = [0; 100];
 | 
			
		||||
        let mut buf = [0; 256];
 | 
			
		||||
        let max_len = 1 + (rng.next_u32() as usize % buf.len());
 | 
			
		||||
        let received = match rx.read(&mut buf[..max_len]).await {
 | 
			
		||||
            Ok(r) => r,
 | 
			
		||||
 
 | 
			
		||||
@@ -16,5 +16,10 @@ pub fn config() -> Config {
 | 
			
		||||
        config.rcc.pll1.q_ck = Some(Hertz(100_000_000));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[cfg(feature = "stm32u585ai")]
 | 
			
		||||
    {
 | 
			
		||||
        config.rcc.mux = embassy_stm32::rcc::ClockSrc::MSI(embassy_stm32::rcc::MSIRange::Range48mhz);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    config
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user