From eff61648fef3c50b144bbf9611ef7ee893e2c5f7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 28 Sep 2023 05:16:41 +0200 Subject: [PATCH 1/2] tests/stm32: add eth test. --- tests/stm32/Cargo.toml | 14 ++++- tests/stm32/src/bin/eth.rs | 113 +++++++++++++++++++++++++++++++++++++ tests/stm32/src/common.rs | 35 ++++++++++++ 3 files changed, 159 insertions(+), 3 deletions(-) create mode 100644 tests/stm32/src/bin/eth.rs diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index bfe5bc82..2b01def5 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -7,13 +7,13 @@ autobins = false [features] stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill -stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "stop", "can", "not-gpdma", "dac-adc-pin"] # Nucleo "sdmmc" +stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac-adc-pin"] # Nucleo "sdmmc" stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma", "dac-adc-pin"] # Nucleo stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo -stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma", "dac-adc-pin"] # Nucleo +stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma", "eth", "dac-adc-pin"] # Nucleo stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble", "mac" ] # Nucleo -stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo +stm32h563zi = ["embassy-stm32/stm32h563zi", "eth"] # Nucleo stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board stm32l073rz = ["embassy-stm32/stm32l073rz", "not-gpdma"] # Nucleo stm32l152re = ["embassy-stm32/stm32l152re", "not-gpdma"] # Nucleo @@ -21,6 +21,7 @@ stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "not-gpdma"] # Nucleo stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "not-gpdma"] # Nucleo stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma"] # Nucleo +eth = [] sdmmc = [] stop = ["embassy-stm32/low-power"] chrono = ["embassy-stm32/chrono", "dep:chrono"] @@ -40,6 +41,8 @@ embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["de 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" } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } +embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +perf-client = { path = "../perf-client" } defmt = "0.3.0" defmt-rtt = "0.4" @@ -69,6 +72,11 @@ name = "dac" path = "src/bin/dac.rs" required-features = [ "dac-adc-pin",] +[[bin]] +name = "eth" +path = "src/bin/eth.rs" +required-features = [ "eth",] + [[bin]] name = "gpio" path = "src/bin/gpio.rs" diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs new file mode 100644 index 00000000..0b32b60b --- /dev/null +++ b/tests/stm32/src/bin/eth.rs @@ -0,0 +1,113 @@ +// required-features: eth +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../common.rs"] +mod common; +use common::*; +use embassy_executor::Spawner; +use embassy_net::{Stack, StackResources}; +use embassy_stm32::eth::generic_smi::GenericSMI; +use embassy_stm32::eth::{Ethernet, PacketQueue}; +use embassy_stm32::peripherals::ETH; +use embassy_stm32::rng::Rng; +use embassy_stm32::{bind_interrupts, eth, peripherals, rng}; +use rand_core::RngCore; +use static_cell::make_static; +use {defmt_rtt as _, panic_probe as _}; + +teleprobe_meta::timeout!(120); + +#[cfg(not(feature = "stm32h563zi"))] +bind_interrupts!(struct Irqs { + ETH => eth::InterruptHandler; + HASH_RNG => rng::InterruptHandler; +}); +#[cfg(feature = "stm32h563zi")] +bind_interrupts!(struct Irqs { + ETH => eth::InterruptHandler; + RNG => rng::InterruptHandler; +}); + +type Device = Ethernet<'static, ETH, GenericSMI>; + +#[embassy_executor::task] +async fn net_task(stack: &'static Stack) -> ! { + stack.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_stm32::init(config()); + info!("Hello World!"); + + // Generate random seed. + let mut rng = Rng::new(p.RNG, Irqs); + let mut seed = [0; 8]; + rng.fill_bytes(&mut seed); + let seed = u64::from_le_bytes(seed); + + // Ensure different boards get different MAC + // so running tests concurrently doesn't break (they're all in the same LAN) + #[cfg(feature = "stm32f429zi")] + let n = 1; + #[cfg(feature = "stm32h755zi")] + let n = 2; + #[cfg(feature = "stm32h563zi")] + let n = 3; + + let mac_addr = [0x00, n, 0xDE, 0xAD, 0xBE, 0xEF]; + + let device = Ethernet::new( + make_static!(PacketQueue::<4, 4>::new()), + p.ETH, + Irqs, + p.PA1, + p.PA2, + p.PC1, + p.PA7, + p.PC4, + p.PC5, + p.PG13, + #[cfg(not(feature = "stm32h563zi"))] + p.PB13, + #[cfg(feature = "stm32h563zi")] + p.PB15, + p.PG11, + GenericSMI::new(), + mac_addr, + 0, + ); + + let config = embassy_net::Config::dhcpv4(Default::default()); + //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { + // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), + // dns_servers: Vec::new(), + // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), + //}); + + // Init network stack + let stack = &*make_static!(Stack::new( + device, + config, + make_static!(StackResources::<2>::new()), + seed + )); + + // Launch network task + unwrap!(spawner.spawn(net_task(&stack))); + + perf_client::run( + stack, + perf_client::Expected { + down_kbps: 1000, + up_kbps: 1000, + updown_kbps: 1000, + }, + ) + .await; + + info!("Test OK"); + cortex_m::asm::bkpt(); +} diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 9c0b8c39..6bf5c36e 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -154,11 +154,46 @@ pub fn config() -> Config { #[allow(unused_mut)] let mut config = Config::default(); + #[cfg(feature = "stm32f429zi")] + { + // TODO: stm32f429zi can do up to 180mhz, but that makes tests fail. + // perhaps we have some bug w.r.t overdrive. + config.rcc.sys_ck = Some(Hertz(168_000_000)); + config.rcc.pclk1 = Some(Hertz(42_000_000)); + config.rcc.pclk2 = Some(Hertz(84_000_000)); + } + + #[cfg(feature = "stm32h563zi")] + { + use embassy_stm32::rcc::*; + config.rcc.hsi = None; + config.rcc.hsi48 = true; // needed for rng + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::BypassDigital, + }); + config.rcc.pll1 = Some(Pll { + source: PllSource::Hse, + prediv: 2, + mul: 125, + divp: Some(2), + divq: Some(2), + divr: None, + }); + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV1; + config.rcc.apb2_pre = APBPrescaler::DIV1; + config.rcc.apb3_pre = APBPrescaler::DIV1; + config.rcc.sys = Sysclk::Pll1P; + config.rcc.voltage_scale = VoltageScale::Scale0; + } + #[cfg(feature = "stm32h755zi")] { use embassy_stm32::rcc::*; config.rcc.hsi = Some(Hsi::Mhz64); config.rcc.csi = true; + config.rcc.hsi48 = true; // needed for RNG config.rcc.pll_src = PllSource::Hsi; config.rcc.pll1 = Some(Pll { prediv: 4, From b856d760f4e47bc2b6176eb6ef3b5cb9cf7eee3d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 2 Oct 2023 22:03:18 +0200 Subject: [PATCH 2/2] stm32/rcc: reset backup domain before enabling LSE. --- embassy-stm32/src/rcc/bd.rs | 93 +++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index de27130f..026c89d6 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -88,6 +88,12 @@ impl BackupDomain { ))] #[allow(dead_code, unused_variables)] pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option) { + match clock_source { + RtcClockSource::LSI => assert!(lsi), + RtcClockSource::LSE => assert!(&lse.is_some()), + _ => {} + }; + if lsi { #[cfg(rtc_v3u5)] let csr = crate::pac::RCC.bdcr(); @@ -111,6 +117,40 @@ impl BackupDomain { while !csr.read().lsi1rdy() {} } + // backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets. + // once set, changing it requires a backup domain reset. + // first check if the configuration matches what we want. + + // check if it's already enabled and in the source we want. + let reg = Self::read(); + let mut ok = true; + ok &= reg.rtcsel() == clock_source; + #[cfg(not(rcc_wba))] + { + ok &= reg.rtcen() == (clock_source != RtcClockSource::NOCLOCK); + } + ok &= reg.lseon() == lse.is_some(); + #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] + if let Some(lse_drive) = lse { + ok &= reg.lsedrv() == lse_drive.into(); + } + + // if configuration is OK, we're done. + if ok { + // RTC code assumes backup domain is unlocked + Self::modify(|w| {}); + + trace!("BDCR ok: {:08x}", Self::read().0); + return; + } + + // If not OK, reset backup domain and configure it. + #[cfg(not(any(rcc_l0, rcc_l1)))] + { + Self::modify(|w| w.set_bdrst(true)); + Self::modify(|w| w.set_bdrst(false)); + } + if let Some(lse_drive) = lse { Self::modify(|w| { #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] @@ -121,56 +161,17 @@ impl BackupDomain { while !Self::read().lserdy() {} } - match clock_source { - RtcClockSource::LSI => assert!(lsi), - RtcClockSource::LSE => assert!(&lse.is_some()), - _ => {} - }; - - if clock_source == RtcClockSource::NOCLOCK { - // disable it + if clock_source != RtcClockSource::NOCLOCK { Self::modify(|w| { + #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] + assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet."); + #[cfg(not(rcc_wba))] - w.set_rtcen(false); + w.set_rtcen(true); w.set_rtcsel(clock_source); }); - } else { - // check if it's already enabled and in the source we want. - let reg = Self::read(); - let ok = reg.rtcsel() == clock_source; - #[cfg(not(rcc_wba))] - let ok = ok & reg.rtcen(); - - // if not, configure it. - if !ok { - #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); - - #[cfg(not(any(rcc_l0, rcc_l1)))] - Self::modify(|w| w.set_bdrst(true)); - - Self::modify(|w| { - // Reset - #[cfg(not(any(rcc_l0, rcc_l1)))] - w.set_bdrst(false); - - #[cfg(not(rcc_wba))] - w.set_rtcen(true); - w.set_rtcsel(clock_source); - - // Restore bcdr - #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - w.set_lscosel(reg.lscosel()); - #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - w.set_lscoen(reg.lscoen()); - - w.set_lseon(reg.lseon()); - - #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); - }); - } } + + trace!("BDCR configured: {:08x}", Self::read().0); } }