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:
commit
374c92a4f0
@ -58,7 +58,7 @@ sdio-host = "0.5.0"
|
|||||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
atomic-polyfill = "1.0.1"
|
atomic-polyfill = "1.0.1"
|
||||||
stm32-metapac = "6"
|
stm32-metapac = "7"
|
||||||
vcell = "0.1.3"
|
vcell = "0.1.3"
|
||||||
bxcan = "0.7.0"
|
bxcan = "0.7.0"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] }
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
proc-macro2 = "1.0.36"
|
proc-macro2 = "1.0.36"
|
||||||
quote = "1.0.15"
|
quote = "1.0.15"
|
||||||
stm32-metapac = { version = "6", default-features = false, features = ["metadata"]}
|
stm32-metapac = { version = "7", default-features = false, features = ["metadata"]}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["stm32-metapac/rt"]
|
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)
|
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(
|
pub fn new_with_de(
|
||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + '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);
|
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 {
|
unsafe {
|
||||||
r.cr1().modify(|w| {
|
r.cr1().modify(|w| {
|
||||||
|
@ -12,10 +12,11 @@ use futures::future::{select, Either};
|
|||||||
|
|
||||||
use crate::dma::{NoDma, Transfer};
|
use crate::dma::{NoDma, Transfer};
|
||||||
use crate::gpio::sealed::AFType;
|
use crate::gpio::sealed::AFType;
|
||||||
#[cfg(any(lpuart_v1, lpuart_v2))]
|
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||||
use crate::pac::lpuart::{regs, vals, Lpuart as Regs};
|
use crate::pac::usart::Lpuart as Regs;
|
||||||
#[cfg(not(any(lpuart_v1, lpuart_v2)))]
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
use crate::pac::usart::{regs, vals, Usart as Regs};
|
use crate::pac::usart::Usart as Regs;
|
||||||
|
use crate::pac::usart::{regs, vals};
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
use crate::{peripherals, Peripheral};
|
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);
|
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!
|
// create state once!
|
||||||
let _s = T::state();
|
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);
|
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.set_handler(Self::on_interrupt);
|
||||||
irq.unpend();
|
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)
|
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(
|
pub fn new_with_de(
|
||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<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);
|
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.set_handler(UartRx::<T, RxDma>::on_interrupt);
|
||||||
irq.unpend();
|
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 {
|
if !enable_rx && !enable_tx {
|
||||||
panic!("USART: At least one of RX or TX should be enabled");
|
panic!("USART: At least one of RX or TX should be enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: better calculation, including error checking and OVER8 if possible.
|
#[cfg(not(usart_v4))]
|
||||||
let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * multiplier;
|
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 {
|
unsafe {
|
||||||
r.brr().write_value(regs::Brr(div));
|
|
||||||
r.cr2().write(|w| {
|
r.cr2().write(|w| {
|
||||||
w.set_stop(match config.stop_bits {
|
w.set_stop(match config.stop_bits {
|
||||||
StopBits::STOP0P5 => vals::Stop::STOP0P5,
|
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,
|
Parity::ParityEven => vals::Ps::EVEN,
|
||||||
_ => 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))]
|
#[cfg(not(gpdma))]
|
||||||
pub use rx_ringbuffered::RingBufferedUartRx;
|
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 {
|
fn tdr(r: crate::pac::usart::Usart) -> *mut u8 {
|
||||||
r.dr().ptr() as _
|
r.dr().ptr() as _
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(usart_v1)]
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
|
fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
|
||||||
r.dr().ptr() as _
|
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> {
|
fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> {
|
||||||
r.sr()
|
r.sr()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(usart_v1)]
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) {
|
unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) {
|
||||||
// On v1 the flags are cleared implicitly by reads and writes to DR.
|
// 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 {
|
fn tdr(r: Regs) -> *mut u8 {
|
||||||
r.tdr().ptr() as _
|
r.tdr().ptr() as _
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(usart_v2)]
|
#[cfg(any(usart_v3, usart_v4))]
|
||||||
fn rdr(r: Regs) -> *mut u8 {
|
fn rdr(r: Regs) -> *mut u8 {
|
||||||
r.rdr().ptr() as _
|
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> {
|
fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> {
|
||||||
r.isr()
|
r.isr()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(usart_v2)]
|
#[cfg(any(usart_v3, usart_v4))]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
|
unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
|
||||||
r.icr().write(|w| *w = regs::Icr(sr.0));
|
r.icr().write(|w| *w = regs::Icr(sr.0));
|
||||||
@ -1033,6 +1096,13 @@ pub(crate) mod sealed {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Kind {
|
||||||
|
Uart,
|
||||||
|
#[cfg(any(usart_v3, usart_v4))]
|
||||||
|
Lpuart,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub rx_waker: AtomicWaker,
|
pub rx_waker: AtomicWaker,
|
||||||
pub tx_waker: AtomicWaker,
|
pub tx_waker: AtomicWaker,
|
||||||
@ -1048,7 +1118,7 @@ pub(crate) mod sealed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait BasicInstance: crate::rcc::RccPeripheral {
|
pub trait BasicInstance: crate::rcc::RccPeripheral {
|
||||||
const MULTIPLIER: u32;
|
const KIND: Kind;
|
||||||
type Interrupt: crate::interrupt::Interrupt;
|
type Interrupt: crate::interrupt::Interrupt;
|
||||||
|
|
||||||
fn regs() -> Regs;
|
fn regs() -> Regs;
|
||||||
@ -1077,10 +1147,10 @@ pin_trait!(DePin, BasicInstance);
|
|||||||
dma_trait!(TxDma, BasicInstance);
|
dma_trait!(TxDma, BasicInstance);
|
||||||
dma_trait!(RxDma, BasicInstance);
|
dma_trait!(RxDma, BasicInstance);
|
||||||
|
|
||||||
macro_rules! impl_lpuart {
|
macro_rules! impl_usart {
|
||||||
($inst:ident, $irq:ident, $mul:expr) => {
|
($inst:ident, $irq:ident, $kind:expr) => {
|
||||||
impl sealed::BasicInstance for crate::peripherals::$inst {
|
impl sealed::BasicInstance for crate::peripherals::$inst {
|
||||||
const MULTIPLIER: u32 = $mul;
|
const KIND: Kind = $kind;
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::$irq;
|
||||||
|
|
||||||
fn regs() -> Regs {
|
fn regs() -> Regs {
|
||||||
@ -1104,21 +1174,19 @@ macro_rules! impl_lpuart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach_interrupt!(
|
foreach_interrupt!(
|
||||||
($inst:ident, lpuart, $block:ident, $signal_name:ident, $irq:ident) => {
|
($inst:ident, usart, LPUART, $signal_name:ident, $irq:ident) => {
|
||||||
impl_lpuart!($inst, $irq, 256);
|
impl_usart!($inst, $irq, Kind::Lpuart);
|
||||||
};
|
};
|
||||||
|
|
||||||
($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => {
|
($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 {
|
impl sealed::FullInstance for peripherals::$inst {
|
||||||
|
|
||||||
fn regs_uart() -> crate::pac::usart::Usart {
|
fn regs_uart() -> crate::pac::usart::Usart {
|
||||||
crate::pac::$inst
|
crate::pac::$inst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FullInstance for peripherals::$inst {
|
impl FullInstance for peripherals::$inst {}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
);
|
);
|
||||||
|
@ -3,6 +3,7 @@ edition = "2021"
|
|||||||
name = "embassy-stm32-tests"
|
name = "embassy-stm32-tests"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
autobins = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill
|
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());
|
let out = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||||
fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap();
|
fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap();
|
||||||
println!("cargo:rustc-link-search={}", out.display());
|
println!("cargo:rustc-link-search={}", out.display());
|
||||||
println!("cargo:rerun-if-changed=link_ram.x");
|
|
||||||
|
|
||||||
println!("cargo:rustc-link-arg-bins=--nmagic");
|
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||||
|
|
||||||
// too little RAM to run from RAM.
|
// too little RAM to run from RAM.
|
||||||
#[cfg(any(feature = "stm32c031c6"))]
|
if cfg!(any(feature = "stm32f103c8", feature = "stm32c031c6")) {
|
||||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||||
#[cfg(not(any(feature = "stm32c031c6")))]
|
println!("cargo:rerun-if-changed=link.x");
|
||||||
|
} else {
|
||||||
println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
|
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");
|
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||||
|
|
||||||
|
@ -35,7 +35,6 @@ async fn main(_spawner: Spawner) {
|
|||||||
#[cfg(feature = "stm32c031c6")]
|
#[cfg(feature = "stm32c031c6")]
|
||||||
let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
|
let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
|
||||||
|
|
||||||
info!("asdfa;");
|
|
||||||
let mut spi = Spi::new(
|
let mut spi = Spi::new(
|
||||||
spi,
|
spi,
|
||||||
sck, // Arduino D13
|
sck, // Arduino D13
|
||||||
|
@ -9,6 +9,7 @@ use embassy_executor::Spawner;
|
|||||||
use embassy_stm32::dma::NoDma;
|
use embassy_stm32::dma::NoDma;
|
||||||
use embassy_stm32::interrupt;
|
use embassy_stm32::interrupt;
|
||||||
use embassy_stm32::usart::{Config, Uart};
|
use embassy_stm32::usart::{Config, Uart};
|
||||||
|
use embassy_time::{Duration, Instant};
|
||||||
use example_common::*;
|
use example_common::*;
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
@ -19,26 +20,27 @@ async fn main(_spawner: Spawner) {
|
|||||||
// Arduino pins D0 and D1
|
// Arduino pins D0 and D1
|
||||||
// They're connected together with a 1K resistor.
|
// They're connected together with a 1K resistor.
|
||||||
#[cfg(feature = "stm32f103c8")]
|
#[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")]
|
#[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")]
|
#[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")]
|
#[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")]
|
#[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")]
|
#[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")]
|
#[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")]
|
#[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")]
|
#[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 config = Config::default();
|
||||||
let mut usart = Uart::new(usart, rx, tx, irq, NoDma, NoDma, config);
|
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.
|
// 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.
|
// This is because we aren't sending+receiving at the same time.
|
||||||
@ -49,6 +51,45 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut buf = [0; 2];
|
let mut buf = [0; 2];
|
||||||
usart.blocking_read(&mut buf).unwrap();
|
usart.blocking_read(&mut buf).unwrap();
|
||||||
assert_eq!(buf, data);
|
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");
|
info!("Test OK");
|
||||||
cortex_m::asm::bkpt();
|
cortex_m::asm::bkpt();
|
||||||
|
@ -94,6 +94,9 @@ async fn main(_spawner: Spawner) {
|
|||||||
let rx_fut = async {
|
let rx_fut = async {
|
||||||
rx.read(&mut rx_buf).await.unwrap();
|
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;
|
join(rx_fut, tx_fut).await;
|
||||||
|
|
||||||
assert_eq!(tx_buf, rx_buf);
|
assert_eq!(tx_buf, rx_buf);
|
||||||
|
@ -145,13 +145,16 @@ async fn main(spawner: Spawner) {
|
|||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn transmit_task(mut tx: UartTx<'static, board::Uart, board::TxDma>) {
|
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);
|
let mut rng = ChaCha8Rng::seed_from_u64(1337);
|
||||||
|
|
||||||
info!("Starting random transmissions into void...");
|
info!("Starting random transmissions into void...");
|
||||||
|
|
||||||
let mut i: u8 = 0;
|
let mut i: u8 = 0;
|
||||||
loop {
|
loop {
|
||||||
let mut buf = [0; 32];
|
let mut buf = [0; 256];
|
||||||
let len = 1 + (rng.next_u32() as usize % buf.len());
|
let len = 1 + (rng.next_u32() as usize % buf.len());
|
||||||
for b in &mut buf[..len] {
|
for b in &mut buf[..len] {
|
||||||
*b = i;
|
*b = i;
|
||||||
@ -172,7 +175,7 @@ async fn receive_task(mut rx: RingBufferedUartRx<'static, board::Uart, board::Rx
|
|||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut expected = 0;
|
let mut expected = 0;
|
||||||
loop {
|
loop {
|
||||||
let mut buf = [0; 100];
|
let mut buf = [0; 256];
|
||||||
let max_len = 1 + (rng.next_u32() as usize % buf.len());
|
let max_len = 1 + (rng.next_u32() as usize % buf.len());
|
||||||
let received = match rx.read(&mut buf[..max_len]).await {
|
let received = match rx.read(&mut buf[..max_len]).await {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
|
@ -16,5 +16,10 @@ pub fn config() -> Config {
|
|||||||
config.rcc.pll1.q_ck = Some(Hertz(100_000_000));
|
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
|
config
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user