From fb67fe0a6c155191534955f1230dccaea0e11a94 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 1 May 2024 02:21:06 +0200 Subject: [PATCH] stm32: add support for STM32H7[RS] "bootflash line", add HIL tests. --- ci.sh | 6 + embassy-stm32/Cargo.toml | 24 ++- embassy-stm32/build.rs | 17 +- embassy-stm32/src/can/fd/peripheral.rs | 30 +-- embassy-stm32/src/can/fdcan.rs | 4 +- embassy-stm32/src/cryp/mod.rs | 133 ++++++------- embassy-stm32/src/eth/v2/mod.rs | 36 +--- embassy-stm32/src/lib.rs | 6 +- embassy-stm32/src/rcc/bd.rs | 13 +- embassy-stm32/src/rcc/h.rs | 215 ++++++++++++++++------ embassy-stm32/src/rcc/hsi48.rs | 4 +- embassy-stm32/src/rcc/mco.rs | 26 ++- embassy-stm32/src/rcc/mod.rs | 2 +- embassy-stm32/src/ucpd.rs | 2 +- embassy-stm32/src/usb/otg.rs | 4 +- examples/stm32h7rs/.cargo/config.toml | 8 + examples/stm32h7rs/Cargo.toml | 73 ++++++++ examples/stm32h7rs/build.rs | 5 + examples/stm32h7rs/src/bin/blinky.rs | 51 +++++ examples/stm32h7rs/src/bin/button_exti.rs | 25 +++ examples/stm32h7rs/src/bin/can.rs | 98 ++++++++++ examples/stm32h7rs/src/bin/mco.rs | 29 +++ examples/stm32h7rs/src/bin/multiprio.rs | 150 +++++++++++++++ examples/stm32h7rs/src/bin/rng.rs | 26 +++ examples/stm32h7rs/src/bin/rtc.rs | 36 ++++ examples/stm32h7rs/src/bin/signal.rs | 36 ++++ examples/stm32h7rs/src/bin/spi.rs | 50 +++++ examples/stm32h7rs/src/bin/spi_dma.rs | 46 +++++ examples/stm32h7rs/src/bin/usart.rs | 39 ++++ examples/stm32h7rs/src/bin/usart_dma.rs | 47 +++++ examples/stm32h7rs/src/bin/usart_split.rs | 48 +++++ tests/stm32/.cargo/config.toml | 2 +- tests/stm32/Cargo.toml | 1 + tests/stm32/src/bin/cordic.rs | 7 +- tests/stm32/src/bin/fdcan.rs | 14 ++ tests/stm32/src/bin/gpio.rs | 7 +- tests/stm32/src/bin/hash.rs | 3 +- tests/stm32/src/common.rs | 33 +++- 38 files changed, 1162 insertions(+), 194 deletions(-) create mode 100644 examples/stm32h7rs/.cargo/config.toml create mode 100644 examples/stm32h7rs/Cargo.toml create mode 100644 examples/stm32h7rs/build.rs create mode 100644 examples/stm32h7rs/src/bin/blinky.rs create mode 100644 examples/stm32h7rs/src/bin/button_exti.rs create mode 100644 examples/stm32h7rs/src/bin/can.rs create mode 100644 examples/stm32h7rs/src/bin/mco.rs create mode 100644 examples/stm32h7rs/src/bin/multiprio.rs create mode 100644 examples/stm32h7rs/src/bin/rng.rs create mode 100644 examples/stm32h7rs/src/bin/rtc.rs create mode 100644 examples/stm32h7rs/src/bin/signal.rs create mode 100644 examples/stm32h7rs/src/bin/spi.rs create mode 100644 examples/stm32h7rs/src/bin/spi_dma.rs create mode 100644 examples/stm32h7rs/src/bin/usart.rs create mode 100644 examples/stm32h7rs/src/bin/usart_dma.rs create mode 100644 examples/stm32h7rs/src/bin/usart_split.rs diff --git a/ci.sh b/ci.sh index 9e2237703..1ba00f404 100755 --- a/ci.sh +++ b/ci.sh @@ -125,6 +125,10 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h725re,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-tim1,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7r3z8,defmt,exti,time-driver-tim1,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7r7a8,defmt,exti,time-driver-tim1,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7s3a8,defmt,exti,time-driver-tim1,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7s7z8,defmt,exti,time-driver-tim1,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l431cb,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l422cb,defmt,exti,time-driver-any,time \ @@ -189,6 +193,7 @@ cargo batch \ --- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32g4 \ --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32h5 \ --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \ + --- build --release --manifest-path examples/stm32h7rs/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7rs \ --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \ --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \ --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \ @@ -240,6 +245,7 @@ cargo batch \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303ze --out-dir out/tests/stm32f303ze \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --out-dir out/tests/stm32l496zg \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --out-dir out/tests/stm32wl55jc \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7s3l8 --out-dir out/tests/stm32h7s3l8 \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f091rc --out-dir out/tests/stm32f091rc \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h503rb --out-dir out/tests/stm32h503rb \ --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \ diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 6492d69f7..cc126b3af 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,7 +72,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-37a0941112fd16fee53aaa2005fd67b77adab59c" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-afee4331adc717f4cc52caab16838c95334535be" } vcell = "0.1.3" nb = "1.0.0" @@ -98,7 +98,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-37a0941112fd16fee53aaa2005fd67b77adab59c", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-afee4331adc717f4cc52caab16838c95334535be", default-features = false, features = ["metadata"]} [features] default = ["rt"] @@ -1095,6 +1095,26 @@ stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi" ] stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri" ] stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi" ] stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi" ] +stm32h7r3a8 = [ "stm32-metapac/stm32h7r3a8" ] +stm32h7r3i8 = [ "stm32-metapac/stm32h7r3i8" ] +stm32h7r3l8 = [ "stm32-metapac/stm32h7r3l8" ] +stm32h7r3r8 = [ "stm32-metapac/stm32h7r3r8" ] +stm32h7r3v8 = [ "stm32-metapac/stm32h7r3v8" ] +stm32h7r3z8 = [ "stm32-metapac/stm32h7r3z8" ] +stm32h7r7a8 = [ "stm32-metapac/stm32h7r7a8" ] +stm32h7r7i8 = [ "stm32-metapac/stm32h7r7i8" ] +stm32h7r7l8 = [ "stm32-metapac/stm32h7r7l8" ] +stm32h7r7z8 = [ "stm32-metapac/stm32h7r7z8" ] +stm32h7s3a8 = [ "stm32-metapac/stm32h7s3a8" ] +stm32h7s3i8 = [ "stm32-metapac/stm32h7s3i8" ] +stm32h7s3l8 = [ "stm32-metapac/stm32h7s3l8" ] +stm32h7s3r8 = [ "stm32-metapac/stm32h7s3r8" ] +stm32h7s3v8 = [ "stm32-metapac/stm32h7s3v8" ] +stm32h7s3z8 = [ "stm32-metapac/stm32h7s3z8" ] +stm32h7s7a8 = [ "stm32-metapac/stm32h7s7a8" ] +stm32h7s7i8 = [ "stm32-metapac/stm32h7s7i8" ] +stm32h7s7l8 = [ "stm32-metapac/stm32h7s7l8" ] +stm32h7s7z8 = [ "stm32-metapac/stm32h7s7z8" ] stm32l010c6 = [ "stm32-metapac/stm32l010c6" ] stm32l010f4 = [ "stm32-metapac/stm32l010f4" ] stm32l010k4 = [ "stm32-metapac/stm32l010k4" ] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index ba3af2550..ba118f338 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -406,7 +406,16 @@ fn main() { }, ); } - if chip_name.starts_with("stm32h7") { + + if chip_name.starts_with("stm32h7r") || chip_name.starts_with("stm32h7s") { + clock_gen.chained_muxes.insert( + "PER", + &PeripheralRccRegister { + register: "AHBPERCKSELR", + field: "PERSEL", + }, + ); + } else if chip_name.starts_with("stm32h7") { clock_gen.chained_muxes.insert( "PER", &PeripheralRccRegister { @@ -1585,7 +1594,11 @@ fn main() { println!("cargo:rustc-cfg=package_{}", &chip_name[10..11]); println!("cargo:rustc-cfg=flashsize_{}", &chip_name[11..12]); } else { - println!("cargo:rustc-cfg={}", &chip_name[..7]); // stm32f4 + if &chip_name[..8] == "stm32h7r" || &chip_name[..8] == "stm32h7s" { + println!("cargo:rustc-cfg=stm32h7rs"); + } else { + println!("cargo:rustc-cfg={}", &chip_name[..7]); // stm32f4 + } println!("cargo:rustc-cfg={}", &chip_name[..9]); // stm32f429 println!("cargo:rustc-cfg={}x", &chip_name[..8]); // stm32f42x println!("cargo:rustc-cfg={}x{}", &chip_name[..7], &chip_name[8..9]); // stm32f4x9 diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index e5cfee528..9cd5f0785 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -30,10 +30,10 @@ impl Registers { &mut self.msg_ram_mut().transmit.tbsa[bufidx] } pub fn msg_ram_mut(&self) -> &mut RegisterBlock { - #[cfg(stm32h7)] + #[cfg(can_fdcan_h7)] let ptr = self.msgram.ram(self.msg_ram_offset / 4).as_ptr() as *mut RegisterBlock; - #[cfg(not(stm32h7))] + #[cfg(not(can_fdcan_h7))] let ptr = self.msgram.as_ptr() as *mut RegisterBlock; unsafe { &mut (*ptr) } @@ -105,7 +105,7 @@ impl Registers { return Some(BusError::BusWarning); } else { cfg_if! { - if #[cfg(stm32h7)] { + if #[cfg(can_fdcan_h7)] { let lec = err.lec(); } else { let lec = err.lec().to_bits(); @@ -334,14 +334,14 @@ impl Registers { // set extended filters list size to 8 // REQUIRED: we use the memory map as if these settings are set // instead of re-calculating them. - #[cfg(not(stm32h7))] + #[cfg(not(can_fdcan_h7))] { self.regs.rxgfc().modify(|w| { w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX); w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX); }); } - #[cfg(stm32h7)] + #[cfg(can_fdcan_h7)] { self.regs .sidfc() @@ -354,11 +354,11 @@ impl Registers { self.configure_msg_ram(); // Enable timestamping - #[cfg(not(stm32h7))] + #[cfg(not(can_fdcan_h7))] self.regs .tscc() .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT)); - #[cfg(stm32h7)] + #[cfg(can_fdcan_h7)] self.regs.tscc().write(|w| w.set_tss(0x01)); // this isn't really documented in the reference manual @@ -491,9 +491,9 @@ impl Registers { self.regs.cccr().modify(|w| { w.set_fdoe(fdoe); - #[cfg(stm32h7)] + #[cfg(can_fdcan_h7)] w.set_bse(brse); - #[cfg(not(stm32h7))] + #[cfg(not(can_fdcan_h7))] w.set_brse(brse); }); } @@ -508,14 +508,14 @@ impl Registers { #[inline] #[allow(unused)] pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) { - #[cfg(stm32h7)] + #[cfg(can_fdcan_h7)] let (tcp, tss) = match select { TimestampSource::None => (0, 0), TimestampSource::Prescaler(p) => (p as u8, 1), TimestampSource::FromTIM3 => (0, 2), }; - #[cfg(not(stm32h7))] + #[cfg(not(can_fdcan_h7))] let (tcp, tss) = match select { TimestampSource::None => (0, stm32_metapac::can::vals::Tss::ZERO), TimestampSource::Prescaler(p) => (p as u8, stm32_metapac::can::vals::Tss::INCREMENT), @@ -528,7 +528,7 @@ impl Registers { }); } - #[cfg(not(stm32h7))] + #[cfg(not(can_fdcan_h7))] /// Configures the global filter settings #[inline] pub fn set_global_filter(&mut self, filter: GlobalFilter) { @@ -551,7 +551,7 @@ impl Registers { }); } - #[cfg(stm32h7)] + #[cfg(can_fdcan_h7)] /// Configures the global filter settings #[inline] pub fn set_global_filter(&mut self, filter: GlobalFilter) { @@ -575,10 +575,10 @@ impl Registers { }); } - #[cfg(not(stm32h7))] + #[cfg(not(can_fdcan_h7))] fn configure_msg_ram(&mut self) {} - #[cfg(stm32h7)] + #[cfg(can_fdcan_h7)] fn configure_msg_ram(&mut self) { let r = self.regs; diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 6144ba520..81ceb06aa 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -975,7 +975,7 @@ macro_rules! impl_fdcan { }; } -#[cfg(not(stm32h7))] +#[cfg(not(can_fdcan_h7))] foreach_peripheral!( (can, FDCAN) => { impl_fdcan!(FDCAN, FDCANRAM); }; (can, FDCAN1) => { impl_fdcan!(FDCAN1, FDCANRAM1); }; @@ -983,7 +983,7 @@ foreach_peripheral!( (can, FDCAN3) => { impl_fdcan!(FDCAN3, FDCANRAM3); }; ); -#[cfg(stm32h7)] +#[cfg(can_fdcan_h7)] foreach_peripheral!( (can, FDCAN1) => { impl_fdcan!(FDCAN1, FDCANRAM, 0x0000); }; (can, FDCAN2) => { impl_fdcan!(FDCAN2, FDCANRAM, 0x0C00); }; diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 18b5ec918..f19c94fda 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -1,5 +1,5 @@ //! Crypto Accelerator (CRYP) -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] use core::cmp::min; use core::marker::PhantomData; use core::ptr; @@ -7,7 +7,7 @@ use core::ptr; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; -use crate::dma::{NoDma, Priority, Transfer, TransferOptions}; +use crate::dma::{NoDma, Transfer, TransferOptions}; use crate::interrupt::typelevel::Interrupt; use crate::{interrupt, pac, peripherals, Peripheral}; @@ -147,7 +147,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesEcb<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(0)); } - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] { p.cr().modify(|w| w.set_algomode0(0)); p.cr().modify(|w| w.set_algomode3(false)); @@ -189,7 +189,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesCbc<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(1)); } - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] { p.cr().modify(|w| w.set_algomode0(1)); p.cr().modify(|w| w.set_algomode3(false)); @@ -231,7 +231,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesEcb<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(2)); } - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] { p.cr().modify(|w| w.set_algomode0(2)); p.cr().modify(|w| w.set_algomode3(false)); @@ -272,7 +272,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesCbc<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(3)); } - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] { p.cr().modify(|w| w.set_algomode0(3)); p.cr().modify(|w| w.set_algomode3(false)); @@ -313,7 +313,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(7)); } - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] { p.cr().modify(|w| w.set_algomode0(7)); p.cr().modify(|w| w.set_algomode3(false)); @@ -327,7 +327,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(2)); } - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] { p.cr().modify(|w| w.set_algomode0(2)); p.cr().modify(|w| w.set_algomode3(false)); @@ -370,7 +370,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(7)); } - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] { p.cr().modify(|w| w.set_algomode0(7)); p.cr().modify(|w| w.set_algomode3(false)); @@ -384,7 +384,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(5)); } - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] { p.cr().modify(|w| w.set_algomode0(5)); p.cr().modify(|w| w.set_algomode3(false)); @@ -426,7 +426,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCtr<'c, KEY_SIZE> { { p.cr().modify(|w| w.set_algomode(6)); } - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] { p.cr().modify(|w| w.set_algomode0(6)); p.cr().modify(|w| w.set_algomode3(false)); @@ -439,14 +439,14 @@ impl<'c> CipherSized for AesCtr<'c, { 192 / 8 }> {} impl<'c> CipherSized for AesCtr<'c, { 256 / 8 }> {} impl<'c, const KEY_SIZE: usize> IVSized for AesCtr<'c, KEY_SIZE> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] ///AES-GCM Cipher Mode pub struct AesGcm<'c, const KEY_SIZE: usize> { iv: [u8; 16], key: &'c [u8; KEY_SIZE], } -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> { /// Constucts a new AES-GCM cipher for a cryptographic operation. pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self { @@ -457,7 +457,7 @@ impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> { } } -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { const BLOCK_SIZE: usize = AES_BLOCK_SIZE; @@ -504,7 +504,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { [0; 4] } - #[cfg(cryp_v3)] + #[cfg(any(cryp_v3, cryp_v4))] fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { //Handle special GCM partial block process. p.cr().modify(|w| w.set_npblb(padding_len as u8)); @@ -573,25 +573,25 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { } } -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c> CipherSized for AesGcm<'c, { 128 / 8 }> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c> CipherSized for AesGcm<'c, { 192 / 8 }> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c> CipherSized for AesGcm<'c, { 256 / 8 }> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGcm<'c, KEY_SIZE> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize> IVSized for AesGcm<'c, KEY_SIZE> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] /// AES-GMAC Cipher Mode pub struct AesGmac<'c, const KEY_SIZE: usize> { iv: [u8; 16], key: &'c [u8; KEY_SIZE], } -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> { /// Constructs a new AES-GMAC cipher for a cryptographic operation. pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self { @@ -602,7 +602,7 @@ impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> { } } -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { const BLOCK_SIZE: usize = AES_BLOCK_SIZE; @@ -649,7 +649,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { [0; 4] } - #[cfg(cryp_v3)] + #[cfg(any(cryp_v3, cryp_v4))] fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { //Handle special GCM partial block process. p.cr().modify(|w| w.set_npblb(padding_len as u8)); @@ -716,18 +716,18 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { } } -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c> CipherSized for AesGmac<'c, { 128 / 8 }> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c> CipherSized for AesGmac<'c, { 192 / 8 }> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c> CipherSized for AesGmac<'c, { 256 / 8 }> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGmac<'c, KEY_SIZE> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize> IVSized for AesGmac<'c, KEY_SIZE> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] /// AES-CCM Cipher Mode pub struct AesCcm<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> { key: &'c [u8; KEY_SIZE], @@ -737,7 +737,7 @@ pub struct AesCcm<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZ ctr: [u8; 16], } -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE> { /// Constructs a new AES-CCM cipher for a cryptographic operation. pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; IV_SIZE], aad_len: usize, payload_len: usize) -> Self { @@ -801,7 +801,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Aes } } -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE> { @@ -865,7 +865,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip return temp1; } - #[cfg(cryp_v3)] + #[cfg(any(cryp_v3, cryp_v4))] fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { //Handle special GCM partial block process. p.cr().modify(|w| w.set_npblb(padding_len as u8)); @@ -950,39 +950,39 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip } } -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 128 / 8 }, TAG_SIZE, IV_SIZE> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 192 / 8 }, TAG_SIZE, IV_SIZE> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 256 / 8 }, TAG_SIZE, IV_SIZE> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<4> for AesCcm<'c, KEY_SIZE, 4, IV_SIZE> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<6> for AesCcm<'c, KEY_SIZE, 6, IV_SIZE> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<8> for AesCcm<'c, KEY_SIZE, 8, IV_SIZE> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<10> for AesCcm<'c, KEY_SIZE, 10, IV_SIZE> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<12> for AesCcm<'c, KEY_SIZE, 12, IV_SIZE> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<14> for AesCcm<'c, KEY_SIZE, 14, IV_SIZE> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<16> for AesCcm<'c, KEY_SIZE, 16, IV_SIZE> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 7> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 8> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 9> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 10> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 11> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 12> {} -#[cfg(any(cryp_v2, cryp_v3))] +#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 13> {} #[allow(dead_code)] @@ -1205,7 +1205,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { ctx } - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] /// Controls the header phase of cipher processing. /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC. /// All additional associated data (AAD) must be supplied to this function prior to starting the payload phase with `payload_blocking`. @@ -1302,7 +1302,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { self.store_context(ctx); } - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] /// Controls the header phase of cipher processing. /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC. /// All additional associated data (AAD) must be supplied to this function prior to starting the payload phase with `payload`. @@ -1420,7 +1420,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { if !ctx.aad_complete && ctx.header_len > 0 { panic!("Additional associated data must be processed first!"); } else if !ctx.aad_complete { - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] { ctx.aad_complete = true; T::regs().cr().modify(|w| w.set_crypen(false)); @@ -1512,7 +1512,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { if !ctx.aad_complete && ctx.header_len > 0 { panic!("Additional associated data must be processed first!"); } else if !ctx.aad_complete { - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] { ctx.aad_complete = true; T::regs().cr().modify(|w| w.set_crypen(false)); @@ -1585,7 +1585,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { self.store_context(ctx); } - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] /// Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC. /// Called after the all data has been encrypted/decrypted by `payload`. pub fn finish_blocking< @@ -1614,7 +1614,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { payloadlen1.swap_bytes(), payloadlen2.swap_bytes(), ]; - #[cfg(cryp_v3)] + #[cfg(any(cryp_v3, cryp_v4))] let footer: [u32; 4] = [headerlen1, headerlen2, payloadlen1, payloadlen2]; self.write_words_blocking(C::BLOCK_SIZE, &footer); @@ -1631,7 +1631,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { tag } - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] // Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC. /// Called after the all data has been encrypted/decrypted by `payload`. pub async fn finish< @@ -1664,7 +1664,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { payloadlen1.swap_bytes(), payloadlen2.swap_bytes(), ]; - #[cfg(cryp_v3)] + #[cfg(any(cryp_v3, cryp_v4))] let footer: [u32; 4] = [headerlen1, headerlen2, payloadlen1, payloadlen2]; let write = Self::write_words(&mut self.indma, C::BLOCK_SIZE, &footer); @@ -1735,7 +1735,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { ctx.iv[2] = T::regs().init(1).ivlr().read(); ctx.iv[3] = T::regs().init(1).ivrr().read(); - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] for i in 0..8 { ctx.csgcmccm[i] = T::regs().csgcmccmr(i).read(); ctx.csgcm[i] = T::regs().csgcmr(i).read(); @@ -1750,7 +1750,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { T::regs().init(1).ivlr().write_value(ctx.iv[2]); T::regs().init(1).ivrr().write_value(ctx.iv[3]); - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] for i in 0..8 { T::regs().csgcmccmr(i).write_value(ctx.csgcmccm[i]); T::regs().csgcmr(i).write_value(ctx.csgcm[i]); @@ -1797,7 +1797,8 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { let num_words = blocks.len() / 4; let src_ptr = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); let options = TransferOptions { - priority: Priority::High, + #[cfg(not(gpdma))] + priority: crate::dma::Priority::High, ..Default::default() }; let dma_transfer = unsafe { Transfer::new_write_raw(dma, dma_request, src_ptr, dst_ptr, options) }; @@ -1806,7 +1807,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { dma_transfer.await; } - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] fn write_words_blocking(&self, block_size: usize, blocks: &[u32]) { assert_eq!((blocks.len() * 4) % block_size, 0); let mut byte_counter: usize = 0; @@ -1820,7 +1821,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { } } - #[cfg(any(cryp_v2, cryp_v3))] + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] async fn write_words(dma: &mut PeripheralRef<'_, DmaIn>, block_size: usize, blocks: &[u32]) where DmaIn: crate::cryp::DmaIn, @@ -1836,7 +1837,8 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { let num_words = blocks.len(); let src_ptr = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); let options = TransferOptions { - priority: Priority::High, + #[cfg(not(gpdma))] + priority: crate::dma::Priority::High, ..Default::default() }; let dma_transfer = unsafe { Transfer::new_write_raw(dma, dma_request, src_ptr, dst_ptr, options) }; @@ -1875,7 +1877,8 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { let num_words = blocks.len() / 4; let dst_ptr = ptr::slice_from_raw_parts_mut(blocks.as_mut_ptr().cast(), num_words); let options = TransferOptions { - priority: Priority::VeryHigh, + #[cfg(not(gpdma))] + priority: crate::dma::Priority::VeryHigh, ..Default::default() }; let dma_transfer = unsafe { Transfer::new_read_raw(dma, dma_request, src_ptr, dst_ptr, options) }; diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index 37f460574..a19aa42cf 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -4,6 +4,7 @@ use core::marker::PhantomData; use core::sync::atomic::{fence, Ordering}; use embassy_hal_internal::{into_ref, PeripheralRef}; +use stm32_metapac::syscfg::vals::EthSelPhy; pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; use super::*; @@ -80,19 +81,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { phy: P, mac_addr: [u8; 6], ) -> Self { - // Enable the necessary Clocks - #[cfg(not(rcc_h5))] - critical_section::with(|_| { - crate::pac::RCC.ahb1enr().modify(|w| { - w.set_eth1macen(true); - w.set_eth1txen(true); - w.set_eth1rxen(true); - }); - - crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100)); - }); - - #[cfg(rcc_h5)] + // Enable the necessary clocks critical_section::with(|_| { crate::pac::RCC.ahb1enr().modify(|w| { w.set_ethen(true); @@ -100,9 +89,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { w.set_ethrxen(true); }); - crate::pac::SYSCFG - .pmcr() - .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4)); + crate::pac::SYSCFG.pmcr().modify(|w| w.set_eth_sel_phy(EthSelPhy::RMII)); }); into_ref!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); @@ -145,19 +132,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { phy: P, mac_addr: [u8; 6], ) -> Self { - // Enable necessary clocks. - #[cfg(not(rcc_h5))] - critical_section::with(|_| { - crate::pac::RCC.ahb1enr().modify(|w| { - w.set_eth1macen(true); - w.set_eth1txen(true); - w.set_eth1rxen(true); - }); - - crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b000)); - }); - - #[cfg(rcc_h5)] + // Enable the necessary clocks critical_section::with(|_| { crate::pac::RCC.ahb1enr().modify(|w| { w.set_ethen(true); @@ -165,10 +140,9 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { w.set_ethrxen(true); }); - // TODO: This is for RMII - what would MII need here? crate::pac::SYSCFG .pmcr() - .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4)); + .modify(|w| w.set_eth_sel_phy(EthSelPhy::MII_GMII)); }); into_ref!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 7d2b49ff4..1f4e9ab1e 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -2,7 +2,7 @@ #![allow(async_fn_in_trait)] #![cfg_attr( docsrs, - doc = "

You might want to browse the `embassy-stm32` documentation on the Embassy website instead.

The documentation here on `docs.rs` is built for a single chip only (STM32H755 in particular), while on the Embassy website you can pick your exact chip from the top menu. Available peripherals and their APIs change depending on the chip.

\n\n" + doc = "

You might want to browse the `embassy-stm32` documentation on the Embassy website instead.

The documentation here on `docs.rs` is built for a single chip only (stm32h7, stm32h7rs55 in particular), while on the Embassy website you can pick your exact chip from the top menu. Available peripherals and their APIs change depending on the chip.

\n\n" )] #![doc = include_str!("../README.md")] #![warn(missing_docs)] @@ -303,9 +303,9 @@ pub fn init(config: Config) -> Peripherals { #[cfg(not(any(stm32f1, stm32wb, stm32wl)))] peripherals::SYSCFG::enable_and_reset_with_cs(cs); - #[cfg(not(any(stm32h5, stm32h7, stm32wb, stm32wl)))] + #[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))] peripherals::PWR::enable_and_reset_with_cs(cs); - #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] + #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs)))] peripherals::FLASH::enable_and_reset_with_cs(cs); // Enable the VDDIO2 power supply on chips that have it. diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 54d3c662b..f3ac4fdbe 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -198,7 +198,7 @@ impl LsConfig { } // If not OK, reset backup domain and configure it. - #[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32c0)))] + #[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32h7rs, stm32c0)))] { bdcr().modify(|w| w.set_bdrst(true)); bdcr().modify(|w| w.set_bdrst(false)); @@ -210,11 +210,12 @@ impl LsConfig { // letting half our RAM go magically *poof*. // STM32H503CB/EB/KB/RB device errata - 2.2.8 SRAM2 unduly erased upon a backup domain reset // STM32H562xx/563xx/573xx device errata - 2.2.14 SRAM2 is erased when the backup domain is reset - //#[cfg(any(stm32h5))] - //{ - // bdcr().modify(|w| w.set_vswrst(true)); - // bdcr().modify(|w| w.set_vswrst(false)); - //} + //#[cfg(any(stm32h5, stm32h7rs))] + #[cfg(any(stm32h7rs))] + { + bdcr().modify(|w| w.set_vswrst(true)); + bdcr().modify(|w| w.set_vswrst(false)); + } #[cfg(any(stm32c0, stm32l0))] { bdcr().modify(|w| w.set_rtcrst(true)); diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index aa8c4b1f7..5d47d400c 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -1,7 +1,6 @@ use core::ops::RangeInclusive; use crate::pac; -use crate::pac::pwr::vals::Vos; pub use crate::pac::rcc::vals::{ Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk, }; @@ -22,9 +21,12 @@ const VCO_WIDE_RANGE: RangeInclusive = Hertz(128_000_000)..=Hertz(560_000 const VCO_WIDE_RANGE: RangeInclusive = Hertz(192_000_000)..=Hertz(836_000_000); #[cfg(any(pwr_h7rm0399, pwr_h7rm0433))] const VCO_WIDE_RANGE: RangeInclusive = Hertz(192_000_000)..=Hertz(960_000_000); +#[cfg(any(stm32h7rs))] +const VCO_WIDE_RANGE: RangeInclusive = Hertz(384_000_000)..=Hertz(1672_000_000); pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; +#[cfg(any(stm32h5, stm32h7))] #[derive(Clone, Copy, Eq, PartialEq)] pub enum VoltageScale { Scale0, @@ -32,6 +34,8 @@ pub enum VoltageScale { Scale2, Scale3, } +#[cfg(any(stm32h7rs))] +pub use crate::pac::pwr::vals::Vos as VoltageScale; #[derive(Clone, Copy, Eq, PartialEq)] pub enum HseMode { @@ -40,7 +44,7 @@ pub enum HseMode { /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) Bypass, /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1) - #[cfg(any(rcc_h5, rcc_h50))] + #[cfg(any(rcc_h5, rcc_h50, rcc_h7rs))] BypassDigital, } @@ -65,8 +69,8 @@ pub struct Pll { /// PLL P division factor. If None, PLL P output is disabled. /// On PLL1, it must be even for most series (in particular, - /// it cannot be 1 in series other than STM32H723/733, - /// STM32H725/735 and STM32H730.) + /// it cannot be 1 in series other than stm32h7, stm32h7rs23/733, + /// stm32h7, stm32h7rs25/735 and stm32h7, stm32h7rs30.) pub divp: Option, /// PLL Q division factor. If None, PLL Q output is disabled. pub divq: Option, @@ -115,7 +119,7 @@ impl From for Timpre { /// Power supply configuration /// See RM0433 Rev 4 7.4 -#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] +#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))] #[derive(PartialEq)] pub enum SupplyConfig { /// Default power supply configuration. @@ -164,8 +168,15 @@ pub enum SupplyConfig { /// SMPS step-down converter voltage output level. /// This is only used in certain power supply configurations: /// SMPSLDO, SMPSExternalLDO, SMPSExternalLDOBypass. -#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] -pub use pac::pwr::vals::Sdlevel as SMPSSupplyVoltage; +#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))] +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub enum SMPSSupplyVoltage { + /// 1.8v + V1_8, + /// 2.5v + #[cfg(not(pwr_h7rs))] + V2_5, +} /// Configuration of the core clocks #[non_exhaustive] @@ -178,22 +189,26 @@ pub struct Config { pub pll1: Option, pub pll2: Option, - #[cfg(any(rcc_h5, stm32h7))] + #[cfg(any(rcc_h5, stm32h7, stm32h7rs))] pub pll3: Option, + #[cfg(any(stm32h7, stm32h7rs))] pub d1c_pre: AHBPrescaler, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, + #[cfg(not(stm32h7rs))] pub apb3_pre: APBPrescaler, - #[cfg(stm32h7)] + #[cfg(any(stm32h7, stm32h7rs))] pub apb4_pre: APBPrescaler, + #[cfg(stm32h7rs)] + pub apb5_pre: APBPrescaler, pub timer_prescaler: TimerPrescaler, pub voltage_scale: VoltageScale, pub ls: super::LsConfig, - #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] + #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))] pub supply_config: SupplyConfig, /// Per-peripheral kernel clock selection muxes @@ -210,23 +225,30 @@ impl Default for Config { sys: Sysclk::HSI, pll1: None, pll2: None, - #[cfg(any(rcc_h5, stm32h7))] + #[cfg(any(rcc_h5, stm32h7, stm32h7rs))] pll3: None, + #[cfg(any(stm32h7, stm32h7rs))] d1c_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, + #[cfg(not(stm32h7rs))] apb3_pre: APBPrescaler::DIV1, - #[cfg(stm32h7)] + #[cfg(any(stm32h7, stm32h7rs))] apb4_pre: APBPrescaler::DIV1, + #[cfg(stm32h7rs)] + apb5_pre: APBPrescaler::DIV1, timer_prescaler: TimerPrescaler::DefaultX2, + #[cfg(not(rcc_h7rs))] voltage_scale: VoltageScale::Scale0, + #[cfg(rcc_h7rs)] + voltage_scale: VoltageScale::HIGH, ls: Default::default(), - #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] - supply_config: SupplyConfig::Default, + #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))] + supply_config: SupplyConfig::LDO, mux: Default::default(), } @@ -234,24 +256,30 @@ impl Default for Config { } pub(crate) unsafe fn init(config: Config) { + #[cfg(any(stm32h7))] + let pwr_reg = PWR.cr3(); + #[cfg(any(stm32h7rs))] + let pwr_reg = PWR.csr2(); + // NB. The lower bytes of CR3 can only be written once after // POR, and must be written with a valid combination. Refer to // RM0433 Rev 7 6.8.4. This is partially enforced by dropping // `self` at the end of this method, but of course we cannot // know what happened between the previous POR and here. #[cfg(pwr_h7rm0433)] - PWR.cr3().modify(|w| { + pwr_reg.modify(|w| { w.set_scuen(true); w.set_ldoen(true); w.set_bypass(false); }); - #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] + #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))] { + use pac::pwr::vals::Sdlevel; match config.supply_config { SupplyConfig::Default => { - PWR.cr3().modify(|w| { - w.set_sdlevel(SMPSSupplyVoltage::RESET); + pwr_reg.modify(|w| { + w.set_sdlevel(Sdlevel::RESET); w.set_sdexthp(false); w.set_sden(true); w.set_ldoen(true); @@ -259,25 +287,30 @@ pub(crate) unsafe fn init(config: Config) { }); } SupplyConfig::LDO => { - PWR.cr3().modify(|w| { + pwr_reg.modify(|w| { w.set_sden(false); w.set_ldoen(true); w.set_bypass(false); }); } SupplyConfig::DirectSMPS => { - PWR.cr3().modify(|w| { + pwr_reg.modify(|w| { w.set_sdexthp(false); w.set_sden(true); w.set_ldoen(false); w.set_bypass(false); }); } - SupplyConfig::SMPSLDO(smps_supply_voltage) - | SupplyConfig::SMPSExternalLDO(smps_supply_voltage) - | SupplyConfig::SMPSExternalLDOBypass(smps_supply_voltage) => { - PWR.cr3().modify(|w| { - w.set_sdlevel(smps_supply_voltage); + SupplyConfig::SMPSLDO(sdlevel) + | SupplyConfig::SMPSExternalLDO(sdlevel) + | SupplyConfig::SMPSExternalLDOBypass(sdlevel) => { + let sdlevel = match sdlevel { + SMPSSupplyVoltage::V1_8 => Sdlevel::V1_8, + #[cfg(not(pwr_h7rs))] + SMPSSupplyVoltage::V2_5 => Sdlevel::V2_5, + }; + pwr_reg.modify(|w| { + w.set_sdlevel(sdlevel); w.set_sdexthp(matches!( config.supply_config, SupplyConfig::SMPSExternalLDO(_) | SupplyConfig::SMPSExternalLDOBypass(_) @@ -291,7 +324,7 @@ pub(crate) unsafe fn init(config: Config) { }); } SupplyConfig::SMPSDisabledLDOBypass => { - PWR.cr3().modify(|w| { + pwr_reg.modify(|w| { w.set_sden(false); w.set_ldoen(false); w.set_bypass(true); @@ -305,43 +338,49 @@ pub(crate) unsafe fn init(config: Config) { // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset // VOS = Scale 3, so check that the voltage on the VCAP pins = // 1.0V. - #[cfg(any(pwr_h7rm0433, pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] + #[cfg(any(stm32h7))] while !PWR.csr1().read().actvosrdy() {} + #[cfg(any(stm32h7rs))] + while !PWR.sr1().read().actvosrdy() {} // Configure voltage scale. #[cfg(any(pwr_h5, pwr_h50))] { PWR.voscr().modify(|w| { w.set_vos(match config.voltage_scale { - VoltageScale::Scale0 => Vos::SCALE0, - VoltageScale::Scale1 => Vos::SCALE1, - VoltageScale::Scale2 => Vos::SCALE2, - VoltageScale::Scale3 => Vos::SCALE3, + VoltageScale::Scale0 => crate::pac::pwr::vals::Vos::SCALE0, + VoltageScale::Scale1 => crate::pac::pwr::vals::Vos::SCALE1, + VoltageScale::Scale2 => crate::pac::pwr::vals::Vos::SCALE2, + VoltageScale::Scale3 => crate::pac::pwr::vals::Vos::SCALE3, }) }); while !PWR.vossr().read().vosrdy() {} } - #[cfg(syscfg_h7)] { // in chips without the overdrive bit, we can go from any scale to any scale directly. PWR.d3cr().modify(|w| { w.set_vos(match config.voltage_scale { - VoltageScale::Scale0 => Vos::SCALE0, - VoltageScale::Scale1 => Vos::SCALE1, - VoltageScale::Scale2 => Vos::SCALE2, - VoltageScale::Scale3 => Vos::SCALE3, + VoltageScale::Scale0 => crate::pac::pwr::vals::Vos::SCALE0, + VoltageScale::Scale1 => crate::pac::pwr::vals::Vos::SCALE1, + VoltageScale::Scale2 => crate::pac::pwr::vals::Vos::SCALE2, + VoltageScale::Scale3 => crate::pac::pwr::vals::Vos::SCALE3, }) }); while !PWR.d3cr().read().vosrdy() {} } + #[cfg(pwr_h7rs)] + { + PWR.csr4().modify(|w| w.set_vos(config.voltage_scale)); + while !PWR.csr4().read().vosrdy() {} + } #[cfg(syscfg_h7od)] { match config.voltage_scale { VoltageScale::Scale0 => { // to go to scale0, we must go to Scale1 first... - PWR.d3cr().modify(|w| w.set_vos(Vos::SCALE1)); + PWR.d3cr().modify(|w| w.set_vos(crate::pac::pwr::vals::Vos::SCALE1)); while !PWR.d3cr().read().vosrdy() {} // Then enable overdrive. @@ -353,9 +392,9 @@ pub(crate) unsafe fn init(config: Config) { PWR.d3cr().modify(|w| { w.set_vos(match config.voltage_scale { VoltageScale::Scale0 => unreachable!(), - VoltageScale::Scale1 => Vos::SCALE1, - VoltageScale::Scale2 => Vos::SCALE2, - VoltageScale::Scale3 => Vos::SCALE3, + VoltageScale::Scale1 => crate::pac::pwr::vals::Vos::SCALE1, + VoltageScale::Scale2 => crate::pac::pwr::vals::Vos::SCALE2, + VoltageScale::Scale3 => crate::pac::pwr::vals::Vos::SCALE3, }) }); while !PWR.d3cr().read().vosrdy() {} @@ -388,7 +427,7 @@ pub(crate) unsafe fn init(config: Config) { Some(hse) => { RCC.cr().modify(|w| { w.set_hsebyp(hse.mode != HseMode::Oscillator); - #[cfg(any(rcc_h5, rcc_h50))] + #[cfg(any(rcc_h5, rcc_h50, rcc_h7rs))] w.set_hseext(match hse.mode { HseMode::Oscillator | HseMode::Bypass => pac::rcc::vals::Hseext::ANALOG, HseMode::BypassDigital => pac::rcc::vals::Hseext::DIGITAL, @@ -414,7 +453,7 @@ pub(crate) unsafe fn init(config: Config) { }; // H7 has shared PLLSRC, check it's equal in all PLLs. - #[cfg(stm32h7)] + #[cfg(any(stm32h7, stm32h7rs))] { let plls = [&config.pll1, &config.pll2, &config.pll3]; if !super::util::all_equal(plls.into_iter().flatten().map(|p| p.source)) { @@ -426,7 +465,7 @@ pub(crate) unsafe fn init(config: Config) { let pll_input = PllInput { csi, hse, hsi }; let pll1 = init_pll(0, config.pll1, &pll_input); let pll2 = init_pll(1, config.pll2, &pll_input); - #[cfg(any(rcc_h5, stm32h7))] + #[cfg(any(rcc_h5, stm32h7, stm32h7rs))] let pll3 = init_pll(2, config.pll3, &pll_input); // Configure sysclk @@ -474,8 +513,13 @@ pub(crate) unsafe fn init(config: Config) { VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)), VoltageScale::Scale3 => (Hertz(200_000_000), Hertz(100_000_000), Hertz(50_000_000)), }; + #[cfg(stm32h7rs)] + let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { + VoltageScale::HIGH => (Hertz(600_000_000), Hertz(300_000_000), Hertz(150_000_000)), + VoltageScale::LOW => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), + }; - #[cfg(stm32h7)] + #[cfg(any(stm32h7, stm32h7rs))] let hclk = { let d1cpre_clk = sys / config.d1c_pre; assert!(d1cpre_clk <= d1cpre_clk_max); @@ -491,12 +535,18 @@ pub(crate) unsafe fn init(config: Config) { let apb2 = hclk / config.apb2_pre; let apb2_tim = apb_div_tim(&config.apb2_pre, hclk, config.timer_prescaler); assert!(apb2 <= pclk_max); + #[cfg(not(stm32h7rs))] let apb3 = hclk / config.apb3_pre; + #[cfg(not(stm32h7rs))] assert!(apb3 <= pclk_max); - #[cfg(stm32h7)] + #[cfg(any(stm32h7, stm32h7rs))] let apb4 = hclk / config.apb4_pre; - #[cfg(stm32h7)] + #[cfg(any(stm32h7, stm32h7rs))] assert!(apb4 <= pclk_max); + #[cfg(stm32h7rs)] + let apb5 = hclk / config.apb5_pre; + #[cfg(stm32h7rs)] + assert!(apb5 <= pclk_max); flash_setup(hclk, config.voltage_scale); @@ -520,6 +570,25 @@ pub(crate) unsafe fn init(config: Config) { w.set_d3ppre(config.apb4_pre); }); } + #[cfg(stm32h7rs)] + { + RCC.cdcfgr().write(|w| { + w.set_cpre(config.d1c_pre); + }); + while RCC.cdcfgr().read().cpre() != config.d1c_pre {} + + RCC.bmcfgr().write(|w| { + w.set_bmpre(config.ahb_pre); + }); + while RCC.bmcfgr().read().bmpre() != config.ahb_pre {} + + RCC.apbcfgr().modify(|w| { + w.set_ppre1(config.apb1_pre); + w.set_ppre2(config.apb2_pre); + w.set_ppre4(config.apb4_pre); + w.set_ppre5(config.apb5_pre); + }); + } #[cfg(stm32h5)] { // Set hpre @@ -540,7 +609,7 @@ pub(crate) unsafe fn init(config: Config) { while RCC.cfgr().read().sws() != config.sys {} // IO compensation cell - Requires CSI clock and SYSCFG - #[cfg(stm32h7)] // TODO h5 + #[cfg(any(stm32h7))] // TODO h5, h7rs if csi.is_some() { // Enable the compensation cell, using back-bias voltage code // provide by the cell. @@ -551,7 +620,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_hslv(false); }) }); - while !pac::SYSCFG.cccsr().read().ready() {} + while !pac::SYSCFG.cccsr().read().rdy() {} } config.mux.init(); @@ -562,11 +631,17 @@ pub(crate) unsafe fn init(config: Config) { hclk2: Some(hclk), hclk3: Some(hclk), hclk4: Some(hclk), + #[cfg(stm32h7rs)] + hclk5: Some(hclk), pclk1: Some(apb1), pclk2: Some(apb2), + #[cfg(not(stm32h7rs))] pclk3: Some(apb3), - #[cfg(stm32h7)] + #[cfg(any(stm32h7, stm32h7rs))] pclk4: Some(apb4), + #[cfg(stm32h7rs)] + pclk5: Some(apb5), + pclk1_tim: Some(apb1_tim), pclk2_tim: Some(apb2_tim), rtc: rtc, @@ -584,11 +659,15 @@ pub(crate) unsafe fn init(config: Config) { pll2_p: pll2.p, pll2_q: pll2.q, pll2_r: pll2.r, - #[cfg(any(rcc_h5, stm32h7))] + #[cfg(stm32h7rs)] + pll2_s: None, // TODO + #[cfg(stm32h7rs)] + pll2_t: None, // TODO + #[cfg(any(rcc_h5, stm32h7, stm32h7rs))] pll3_p: pll3.p, - #[cfg(any(rcc_h5, stm32h7))] + #[cfg(any(rcc_h5, stm32h7, stm32h7rs))] pll3_q: pll3.q, - #[cfg(any(rcc_h5, stm32h7))] + #[cfg(any(rcc_h5, stm32h7, stm32h7rs))] pll3_r: pll3.r, #[cfg(rcc_h50)] @@ -601,8 +680,14 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(stm32h5)] audioclk: None, i2s_ckin: None, - #[cfg(stm32h7)] + #[cfg(any(stm32h7, stm32h7rs))] dsi_phy: None, // TODO + #[cfg(stm32h7rs)] + spdifrx_symb: None, // TODO + #[cfg(stm32h7rs)] + clk48mohci: None, // TODO + #[cfg(stm32h7rs)] + usb: None, // TODO ); } @@ -627,7 +712,7 @@ fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { while RCC.cr().read().pllrdy(num) {} // "To save power when PLL1 is not used, the value of PLL1M must be set to 0."" - #[cfg(stm32h7)] + #[cfg(any(stm32h7, stm32h7rs))] RCC.pllckselr().write(|w| w.set_divm(num, PllPreDiv::from_bits(0))); #[cfg(stm32h5)] RCC.pllcfgr(num).write(|w| w.set_divm(PllPreDiv::from_bits(0))); @@ -696,7 +781,7 @@ fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { w.set_pllren(r.is_some()); }); - #[cfg(stm32h7)] + #[cfg(any(stm32h7, stm32h7rs))] { RCC.pllckselr().modify(|w| { w.set_divm(num, config.prediv); @@ -850,6 +935,26 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) { (VoltageScale::Scale3, ..=88) => (3, 1), _ => unreachable!(), }; + #[cfg(flash_h7rs)] + let (latency, wrhighfreq) = match (vos, clk.0) { + // VOS high range VCORE 1.30V - 1.40V + (VoltageScale::HIGH, ..=40_000_000) => (0, 0), + (VoltageScale::HIGH, ..=80_000_000) => (1, 0), + (VoltageScale::HIGH, ..=120_000_000) => (2, 1), + (VoltageScale::HIGH, ..=160_000_000) => (3, 1), + (VoltageScale::HIGH, ..=200_000_000) => (4, 2), + (VoltageScale::HIGH, ..=240_000_000) => (5, 2), + (VoltageScale::HIGH, ..=280_000_000) => (6, 3), + (VoltageScale::HIGH, ..=320_000_000) => (7, 3), + // VOS low range VCORE 1.15V - 1.26V + (VoltageScale::LOW, ..=36_000_000) => (0, 0), + (VoltageScale::LOW, ..=72_000_000) => (1, 0), + (VoltageScale::LOW, ..=108_000_000) => (2, 1), + (VoltageScale::LOW, ..=144_000_000) => (3, 1), + (VoltageScale::LOW, ..=180_000_000) => (4, 2), + (VoltageScale::LOW, ..=216_000_000) => (5, 2), + _ => unreachable!(), + }; debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); diff --git a/embassy-stm32/src/rcc/hsi48.rs b/embassy-stm32/src/rcc/hsi48.rs index 6f0d7b379..da81abc34 100644 --- a/embassy-stm32/src/rcc/hsi48.rs +++ b/embassy-stm32/src/rcc/hsi48.rs @@ -33,9 +33,9 @@ pub(crate) fn init_hsi48(config: Hsi48Config) -> Hertz { }); // Enable HSI48 - #[cfg(not(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32u5, stm32wba, stm32f0)))] + #[cfg(not(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32h7rs, stm32u5, stm32wba, stm32f0)))] let r = RCC.crrcr(); - #[cfg(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32u5, stm32wba))] + #[cfg(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32h7rs, stm32u5, stm32wba))] let r = RCC.cr(); #[cfg(any(stm32f0))] let r = RCC.cr2(); diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index 4b22a099d..40e963466 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs @@ -5,9 +5,31 @@ use embassy_hal_internal::into_ref; use crate::gpio::{AFType, Speed}; #[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; -#[cfg(not(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7)))] +#[cfg(not(any( + rcc_f2, + rcc_f410, + rcc_f4, + rcc_f7, + rcc_h50, + rcc_h5, + rcc_h7ab, + rcc_h7rm0433, + rcc_h7, + rcc_h7rs +)))] pub use crate::pac::rcc::vals::Mcosel as McoSource; -#[cfg(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7))] +#[cfg(any( + rcc_f2, + rcc_f410, + rcc_f4, + rcc_f7, + rcc_h50, + rcc_h5, + rcc_h7ab, + rcc_h7rm0433, + rcc_h7, + rcc_h7rs +))] pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; use crate::pac::RCC; use crate::{peripherals, Peripheral}; diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index a4e497fe7..a585940bc 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -24,7 +24,7 @@ pub use hsi48::*; #[cfg_attr(stm32c0, path = "c0.rs")] #[cfg_attr(stm32g0, path = "g0.rs")] #[cfg_attr(stm32g4, path = "g4.rs")] -#[cfg_attr(any(stm32h5, stm32h7), path = "h.rs")] +#[cfg_attr(any(stm32h5, stm32h7, stm32h7rs), path = "h.rs")] #[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl, stm32u0), path = "l.rs")] #[cfg_attr(stm32u5, path = "u5.rs")] #[cfg_attr(stm32wba, path = "wba.rs")] diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index fe614b811..63412f9b7 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -58,7 +58,7 @@ pub(crate) fn init( }) } - #[cfg(any(stm32h5, stm32u5))] + #[cfg(any(stm32h5, stm32u5, stm32h7rs))] { crate::pac::PWR.ucpdr().modify(|w| { w.set_ucpd_dbdis(!ucpd1_db_enable); diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 5d0e1116e..3debd5079 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -371,7 +371,7 @@ foreach_interrupt!( } else if #[cfg(stm32g0x1)] { const FIFO_DEPTH_WORDS: u16 = 512; const ENDPOINT_COUNT: usize = 8; - } else if #[cfg(stm32h7)] { + } else if #[cfg(any(stm32h7, stm32h7rs))] { const FIFO_DEPTH_WORDS: u16 = 1024; const ENDPOINT_COUNT: usize = 9; } else if #[cfg(stm32u5)] { @@ -420,7 +420,7 @@ foreach_interrupt!( stm32f469, stm32f479, stm32f7, - stm32h7, + stm32h7, stm32h7rs, ))] { const FIFO_DEPTH_WORDS: u16 = 1024; const ENDPOINT_COUNT: usize = 9; diff --git a/examples/stm32h7rs/.cargo/config.toml b/examples/stm32h7rs/.cargo/config.toml new file mode 100644 index 000000000..44dbda94f --- /dev/null +++ b/examples/stm32h7rs/.cargo/config.toml @@ -0,0 +1,8 @@ +[target.thumbv7em-none-eabihf] +runner = 'probe-rs run --chip STM32H7S3L8Hx' + +[build] +target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) + +[env] +DEFMT_LOG = "trace" diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml new file mode 100644 index 000000000..ad661411d --- /dev/null +++ b/examples/stm32h7rs/Cargo.toml @@ -0,0 +1,73 @@ +[package] +edition = "2021" +name = "embassy-stm32h7-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +# Change stm32h743bi to your chip name, if necessary. +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } +embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-nal-async = { version = "0.7.1" } +embedded-io-async = { version = "0.6.1" } +panic-probe = { version = "0.3", features = ["print-defmt"] } +heapless = { version = "0.8", default-features = false } +rand_core = "0.6.3" +critical-section = "1.1" +micromath = "2.0.0" +stm32-fmc = "0.3.0" +embedded-storage = "0.3.1" +static_cell = "2" +chrono = { version = "^0.4", default-features = false } + +# cargo build/run +[profile.dev] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo test +[profile.test] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo build/run --release +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- + +# cargo test --release +[profile.bench] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- diff --git a/examples/stm32h7rs/build.rs b/examples/stm32h7rs/build.rs new file mode 100644 index 000000000..8cd32d7ed --- /dev/null +++ b/examples/stm32h7rs/build.rs @@ -0,0 +1,5 @@ +fn main() { + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/stm32h7rs/src/bin/blinky.rs b/examples/stm32h7rs/src/bin/blinky.rs new file mode 100644 index 000000000..137c585b7 --- /dev/null +++ b/examples/stm32h7rs/src/bin/blinky.rs @@ -0,0 +1,51 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::time::Hertz; +use embassy_stm32::Config; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(24_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll1 = Some(Pll { + source: PllSource::HSE, + prediv: PllPreDiv::DIV3, + mul: PllMul::MUL150, + divp: Some(PllDiv::DIV2), + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.voltage_scale = VoltageScale::HIGH; + } + let p = embassy_stm32::init(config); + info!("Hello World!"); + + let mut led = Output::new(p.PD10, Level::High, Speed::Low); + + loop { + info!("high"); + led.set_high(); + Timer::after_millis(500).await; + + info!("low"); + led.set_low(); + Timer::after_millis(500).await; + } +} diff --git a/examples/stm32h7rs/src/bin/button_exti.rs b/examples/stm32h7rs/src/bin/button_exti.rs new file mode 100644 index 000000000..34a08bbc6 --- /dev/null +++ b/examples/stm32h7rs/src/bin/button_exti.rs @@ -0,0 +1,25 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::exti::ExtiInput; +use embassy_stm32::gpio::Pull; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); + + info!("Press the USER button..."); + + loop { + button.wait_for_falling_edge().await; + info!("Pressed!"); + button.wait_for_rising_edge().await; + info!("Released!"); + } +} diff --git a/examples/stm32h7rs/src/bin/can.rs b/examples/stm32h7rs/src/bin/can.rs new file mode 100644 index 000000000..0af11ef3e --- /dev/null +++ b/examples/stm32h7rs/src/bin/can.rs @@ -0,0 +1,98 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::peripherals::*; +use embassy_stm32::{bind_interrupts, can, rcc, Config}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + FDCAN1_IT0 => can::IT0InterruptHandler; + FDCAN1_IT1 => can::IT1InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.rcc.hse = Some(rcc::Hse { + freq: embassy_stm32::time::Hertz(25_000_000), + mode: rcc::HseMode::Oscillator, + }); + config.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; + + let peripherals = embassy_stm32::init(config); + + let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); + + // 250k bps + can.set_bitrate(250_000); + + //let mut can = can.into_internal_loopback_mode(); + let mut can = can.into_normal_mode(); + + info!("CAN Configured"); + + let mut i = 0; + let mut last_read_ts = embassy_time::Instant::now(); + + loop { + let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); + info!("Writing frame"); + _ = can.write(&frame).await; + + match can.read().await { + Ok(envelope) => { + let (rx_frame, ts) = envelope.parts(); + let delta = (ts - last_read_ts).as_millis(); + last_read_ts = ts; + info!( + "Rx: {:x} {:x} {:x} {:x} --- NEW {}", + rx_frame.data()[0], + rx_frame.data()[1], + rx_frame.data()[2], + rx_frame.data()[3], + delta, + ) + } + Err(_err) => error!("Error in frame"), + } + + Timer::after_millis(250).await; + + i += 1; + if i > 3 { + break; + } + } + + let (mut tx, mut rx, _props) = can.split(); + // With split + loop { + let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); + info!("Writing frame"); + _ = tx.write(&frame).await; + + match rx.read().await { + Ok(envelope) => { + let (rx_frame, ts) = envelope.parts(); + let delta = (ts - last_read_ts).as_millis(); + last_read_ts = ts; + info!( + "Rx: {:x} {:x} {:x} {:x} --- NEW {}", + rx_frame.data()[0], + rx_frame.data()[1], + rx_frame.data()[2], + rx_frame.data()[3], + delta, + ) + } + Err(_err) => error!("Error in frame"), + } + + Timer::after_millis(250).await; + + i = i.wrapping_add(1); + } +} diff --git a/examples/stm32h7rs/src/bin/mco.rs b/examples/stm32h7rs/src/bin/mco.rs new file mode 100644 index 000000000..a6ee27625 --- /dev/null +++ b/examples/stm32h7rs/src/bin/mco.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut led = Output::new(p.PB14, Level::High, Speed::Low); + + let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV8); + + loop { + info!("high"); + led.set_high(); + Timer::after_millis(500).await; + + info!("low"); + led.set_low(); + Timer::after_millis(500).await; + } +} diff --git a/examples/stm32h7rs/src/bin/multiprio.rs b/examples/stm32h7rs/src/bin/multiprio.rs new file mode 100644 index 000000000..fcbb6c653 --- /dev/null +++ b/examples/stm32h7rs/src/bin/multiprio.rs @@ -0,0 +1,150 @@ +//! This example showcases how to create multiple Executor instances to run tasks at +//! different priority levels. +//! +//! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling +//! there's work in the queue, and `wfe` for waiting for work. +//! +//! Medium and high priority executors run in two interrupts with different priorities. +//! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since +//! when there's work the interrupt will trigger and run the executor. +//! +//! Sample output below. Note that high priority ticks can interrupt everything else, and +//! medium priority computations can interrupt low priority computations, making them to appear +//! to take significantly longer time. +//! +//! ```not_rust +//! [med] Starting long computation +//! [med] done in 992 ms +//! [high] tick! +//! [low] Starting long computation +//! [med] Starting long computation +//! [high] tick! +//! [high] tick! +//! [med] done in 993 ms +//! [med] Starting long computation +//! [high] tick! +//! [high] tick! +//! [med] done in 993 ms +//! [low] done in 3972 ms +//! [med] Starting long computation +//! [high] tick! +//! [high] tick! +//! [med] done in 993 ms +//! ``` +//! +//! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor. +//! You will get an output like the following. Note that no computation is ever interrupted. +//! +//! ```not_rust +//! [high] tick! +//! [med] Starting long computation +//! [med] done in 496 ms +//! [low] Starting long computation +//! [low] done in 992 ms +//! [med] Starting long computation +//! [med] done in 496 ms +//! [high] tick! +//! [low] Starting long computation +//! [low] done in 992 ms +//! [high] tick! +//! [med] Starting long computation +//! [med] done in 496 ms +//! [high] tick! +//! ``` +//! + +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use defmt::*; +use embassy_executor::{Executor, InterruptExecutor}; +use embassy_stm32::interrupt; +use embassy_stm32::interrupt::{InterruptExt, Priority}; +use embassy_time::{Instant, Timer}; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task] +async fn run_high() { + loop { + info!(" [high] tick!"); + Timer::after_ticks(27374).await; + } +} + +#[embassy_executor::task] +async fn run_med() { + loop { + let start = Instant::now(); + info!(" [med] Starting long computation"); + + // Spin-wait to simulate a long CPU computation + cortex_m::asm::delay(128_000_000); // ~1 second + + let end = Instant::now(); + let ms = end.duration_since(start).as_ticks() / 33; + info!(" [med] done in {} ms", ms); + + Timer::after_ticks(23421).await; + } +} + +#[embassy_executor::task] +async fn run_low() { + loop { + let start = Instant::now(); + info!("[low] Starting long computation"); + + // Spin-wait to simulate a long CPU computation + cortex_m::asm::delay(256_000_000); // ~2 seconds + + let end = Instant::now(); + let ms = end.duration_since(start).as_ticks() / 33; + info!("[low] done in {} ms", ms); + + Timer::after_ticks(32983).await; + } +} + +static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new(); +static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); +static EXECUTOR_LOW: StaticCell = StaticCell::new(); + +#[interrupt] +unsafe fn UART4() { + EXECUTOR_HIGH.on_interrupt() +} + +#[interrupt] +unsafe fn UART5() { + EXECUTOR_MED.on_interrupt() +} + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let _p = embassy_stm32::init(Default::default()); + + // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as + // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application. + // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt + // vector would work exactly the same. + + // High-priority executor: UART4, priority level 6 + interrupt::UART4.set_priority(Priority::P6); + let spawner = EXECUTOR_HIGH.start(interrupt::UART4); + unwrap!(spawner.spawn(run_high())); + + // Medium-priority executor: UART5, priority level 7 + interrupt::UART5.set_priority(Priority::P7); + let spawner = EXECUTOR_MED.start(interrupt::UART5); + unwrap!(spawner.spawn(run_med())); + + // Low priority executor: runs in thread mode, using WFE/SEV + let executor = EXECUTOR_LOW.init(Executor::new()); + executor.run(|spawner| { + unwrap!(spawner.spawn(run_low())); + }); +} diff --git a/examples/stm32h7rs/src/bin/rng.rs b/examples/stm32h7rs/src/bin/rng.rs new file mode 100644 index 000000000..a9ef7200d --- /dev/null +++ b/examples/stm32h7rs/src/bin/rng.rs @@ -0,0 +1,26 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::rng::Rng; +use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + RNG => rng::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.rcc.hsi48 = Some(Default::default()); // needed for RNG + let p = embassy_stm32::init(config); + info!("Hello World!"); + + let mut rng = Rng::new(p.RNG, Irqs); + + let mut buf = [0u8; 16]; + unwrap!(rng.async_fill_bytes(&mut buf).await); + info!("random bytes: {:02x}", buf); +} diff --git a/examples/stm32h7rs/src/bin/rtc.rs b/examples/stm32h7rs/src/bin/rtc.rs new file mode 100644 index 000000000..0adb48877 --- /dev/null +++ b/examples/stm32h7rs/src/bin/rtc.rs @@ -0,0 +1,36 @@ +#![no_std] +#![no_main] + +use chrono::{NaiveDate, NaiveDateTime}; +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::rcc::LsConfig; +use embassy_stm32::rtc::{Rtc, RtcConfig}; +use embassy_stm32::Config; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.rcc.ls = LsConfig::default_lse(); + + let p = embassy_stm32::init(config); + info!("Hello World!"); + + let now = NaiveDate::from_ymd_opt(2020, 5, 15) + .unwrap() + .and_hms_opt(10, 30, 15) + .unwrap(); + + let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + info!("Got RTC! {:?}", now.and_utc().timestamp()); + + rtc.set_datetime(now.into()).expect("datetime not set"); + + // In reality the delay would be much longer + Timer::after_millis(20000).await; + + let then: NaiveDateTime = rtc.now().unwrap().into(); + info!("Got RTC! {:?}", then.and_utc().timestamp()); +} diff --git a/examples/stm32h7rs/src/bin/signal.rs b/examples/stm32h7rs/src/bin/signal.rs new file mode 100644 index 000000000..b73360f32 --- /dev/null +++ b/examples/stm32h7rs/src/bin/signal.rs @@ -0,0 +1,36 @@ +#![no_std] +#![no_main] + +use defmt::{info, unwrap}; +use embassy_executor::Spawner; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::signal::Signal; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +static SIGNAL: Signal = Signal::new(); + +#[embassy_executor::task] +async fn my_sending_task() { + let mut counter: u32 = 0; + + loop { + Timer::after_secs(1).await; + + SIGNAL.signal(counter); + + counter = counter.wrapping_add(1); + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let _p = embassy_stm32::init(Default::default()); + unwrap!(spawner.spawn(my_sending_task())); + + loop { + let received_counter = SIGNAL.wait().await; + + info!("signalled, counter: {}", received_counter); + } +} diff --git a/examples/stm32h7rs/src/bin/spi.rs b/examples/stm32h7rs/src/bin/spi.rs new file mode 100644 index 000000000..a7767876d --- /dev/null +++ b/examples/stm32h7rs/src/bin/spi.rs @@ -0,0 +1,50 @@ +#![no_std] +#![no_main] + +use core::fmt::Write; +use core::str::from_utf8; + +use cortex_m_rt::entry; +use defmt::*; +use embassy_executor::Executor; +use embassy_stm32::mode::Blocking; +use embassy_stm32::peripherals::SPI3; +use embassy_stm32::spi; +use embassy_stm32::time::mhz; +use heapless::String; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task] +async fn main_task(mut spi: spi::Spi<'static, SPI3, Blocking>) { + for n in 0u32.. { + let mut write: String<128> = String::new(); + core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); + unsafe { + let result = spi.blocking_transfer_in_place(write.as_bytes_mut()); + if let Err(_) = result { + defmt::panic!("crap"); + } + } + info!("read via spi: {}", from_utf8(write.as_bytes()).unwrap()); + } +} + +static EXECUTOR: StaticCell = StaticCell::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + let p = embassy_stm32::init(Default::default()); + + let mut spi_config = spi::Config::default(); + spi_config.frequency = mhz(1); + + let spi = spi::Spi::new_blocking(p.SPI3, p.PB3, p.PB5, p.PB4, spi_config); + + let executor = EXECUTOR.init(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task(spi))); + }) +} diff --git a/examples/stm32h7rs/src/bin/spi_dma.rs b/examples/stm32h7rs/src/bin/spi_dma.rs new file mode 100644 index 000000000..26b5d6751 --- /dev/null +++ b/examples/stm32h7rs/src/bin/spi_dma.rs @@ -0,0 +1,46 @@ +#![no_std] +#![no_main] + +use core::fmt::Write; +use core::str::from_utf8; + +use cortex_m_rt::entry; +use defmt::*; +use embassy_executor::Executor; +use embassy_stm32::mode::Async; +use embassy_stm32::time::mhz; +use embassy_stm32::{peripherals, spi}; +use heapless::String; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task] +async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI3, Async>) { + for n in 0u32.. { + let mut write: String<128> = String::new(); + let mut read = [0; 128]; + core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); + // transfer will slice the &mut read down to &write's actual length. + spi.transfer(&mut read, write.as_bytes()).await.ok(); + info!("read via spi+dma: {}", from_utf8(&read).unwrap()); + } +} + +static EXECUTOR: StaticCell = StaticCell::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + let p = embassy_stm32::init(Default::default()); + + let mut spi_config = spi::Config::default(); + spi_config.frequency = mhz(1); + + let spi = spi::Spi::new(p.SPI3, p.PB3, p.PB5, p.PB4, p.GPDMA1_CH0, p.GPDMA1_CH1, spi_config); + + let executor = EXECUTOR.init(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task(spi))); + }) +} diff --git a/examples/stm32h7rs/src/bin/usart.rs b/examples/stm32h7rs/src/bin/usart.rs new file mode 100644 index 000000000..cc49c2fdb --- /dev/null +++ b/examples/stm32h7rs/src/bin/usart.rs @@ -0,0 +1,39 @@ +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use defmt::*; +use embassy_executor::Executor; +use embassy_stm32::usart::{Config, Uart}; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task] +async fn main_task() { + let p = embassy_stm32::init(Default::default()); + + let config = Config::default(); + let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap(); + + unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); + info!("wrote Hello, starting echo"); + + let mut buf = [0u8; 1]; + loop { + unwrap!(usart.blocking_read(&mut buf)); + unwrap!(usart.blocking_write(&buf)); + } +} + +static EXECUTOR: StaticCell = StaticCell::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let executor = EXECUTOR.init(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task())); + }) +} diff --git a/examples/stm32h7rs/src/bin/usart_dma.rs b/examples/stm32h7rs/src/bin/usart_dma.rs new file mode 100644 index 000000000..c644e84bd --- /dev/null +++ b/examples/stm32h7rs/src/bin/usart_dma.rs @@ -0,0 +1,47 @@ +#![no_std] +#![no_main] + +use core::fmt::Write; + +use cortex_m_rt::entry; +use defmt::*; +use embassy_executor::Executor; +use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; +use heapless::String; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + UART7 => usart::InterruptHandler; +}); + +#[embassy_executor::task] +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, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap(); + + for n in 0u32.. { + let mut s: String<128> = String::new(); + core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap(); + + usart.write(s.as_bytes()).await.ok(); + + info!("wrote DMA"); + } +} + +static EXECUTOR: StaticCell = StaticCell::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let executor = EXECUTOR.init(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task())); + }) +} diff --git a/examples/stm32h7rs/src/bin/usart_split.rs b/examples/stm32h7rs/src/bin/usart_split.rs new file mode 100644 index 000000000..77b4caa9e --- /dev/null +++ b/examples/stm32h7rs/src/bin/usart_split.rs @@ -0,0 +1,48 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::mode::Async; +use embassy_stm32::peripherals::UART7; +use embassy_stm32::usart::{Config, Uart, UartRx}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; +use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; +use embassy_sync::channel::Channel; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + UART7 => usart::InterruptHandler; +}); + +static CHANNEL: Channel = Channel::new(); + +#[embassy_executor::main] +async fn main(spawner: Spawner) -> ! { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let config = Config::default(); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap(); + unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); + + let (mut tx, rx) = usart.split(); + + unwrap!(spawner.spawn(reader(rx))); + + loop { + let buf = CHANNEL.receive().await; + info!("writing..."); + unwrap!(tx.write(&buf).await); + } +} + +#[embassy_executor::task] +async fn reader(mut rx: UartRx<'static, UART7, Async>) { + let mut buf = [0; 8]; + loop { + info!("reading..."); + unwrap!(rx.read(&mut buf).await); + CHANNEL.send(buf).await; + } +} diff --git a/tests/stm32/.cargo/config.toml b/tests/stm32/.cargo/config.toml index 528bd3451..8752da59b 100644 --- a/tests/stm32/.cargo/config.toml +++ b/tests/stm32/.cargo/config.toml @@ -4,7 +4,7 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] runner = "teleprobe client run" -#runner = "teleprobe local run --chip STM32F103C8 --elf" +#runner = "teleprobe local run --chip STM32H7S3L8Hx --elf" rustflags = [ # Code-size optimizations. diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 30669b88c..6afa2a68e 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -32,6 +32,7 @@ stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"] stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"] stm32h503rb = ["embassy-stm32/stm32h503rb", "rng", "stop"] +stm32h7s3l8 = ["embassy-stm32/stm32h7s3l8", "rng", "cordic", "hash"] # TODO: fdcan crashes, cryp dma hangs. cryp = [] hash = [] diff --git a/tests/stm32/src/bin/cordic.rs b/tests/stm32/src/bin/cordic.rs index 400e10207..e09226de8 100644 --- a/tests/stm32/src/bin/cordic.rs +++ b/tests/stm32/src/bin/cordic.rs @@ -67,7 +67,12 @@ async fn main(_spawner: Spawner) { #[cfg(feature = "stm32g491re")] let (mut write_dma, mut read_dma) = (dp.DMA1_CH4, dp.DMA1_CH5); - #[cfg(any(feature = "stm32h563zi", feature = "stm32u585ai", feature = "stm32u5a5zj"))] + #[cfg(any( + feature = "stm32h563zi", + feature = "stm32u585ai", + feature = "stm32u5a5zj", + feature = "stm32h7s3l8" + ))] let (mut write_dma, mut read_dma) = (dp.GPDMA1_CH0, dp.GPDMA1_CH1); // calculate first result using blocking mode diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index b0c0cd82e..20bd3f7e3 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs @@ -74,6 +74,20 @@ fn options() -> (Config, TestOptions) { ) } +#[cfg(any(feature = "stm32h7s3l8"))] +fn options() -> (Config, TestOptions) { + use embassy_stm32::rcc; + let mut c = config(); + c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; + ( + c, + TestOptions { + max_latency: Duration::from_micros(1200), + max_buffered: 3, + }, + ) +} + #[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))] fn options() -> (Config, TestOptions) { info!("G4 config"); diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs index c4e2fe161..dfa299ab5 100644 --- a/tests/stm32/src/bin/gpio.rs +++ b/tests/stm32/src/bin/gpio.rs @@ -216,7 +216,12 @@ async fn main(_spawner: Spawner) { } fn delay() { - #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h7a3zi"))] + #[cfg(any( + feature = "stm32h755zi", + feature = "stm32h753zi", + feature = "stm32h7a3zi", + feature = "stm32h7s3l8" + ))] cortex_m::asm::delay(9000); cortex_m::asm::delay(1000); } diff --git a/tests/stm32/src/bin/hash.rs b/tests/stm32/src/bin/hash.rs index 8cc5d593f..5f54ea435 100644 --- a/tests/stm32/src/bin/hash.rs +++ b/tests/stm32/src/bin/hash.rs @@ -26,7 +26,8 @@ bind_interrupts!(struct Irqs { feature = "stm32h563zi", feature = "stm32h503rb", feature = "stm32u5a5zj", - feature = "stm32u585ai" + feature = "stm32u585ai", + feature = "stm32h7s3l8" ))] bind_interrupts!(struct Irqs { HASH => hash::InterruptHandler; diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 24d33dc3b..07c61956f 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -60,6 +60,8 @@ teleprobe_meta::target!(b"nucleo-stm32wba52cg"); teleprobe_meta::target!(b"nucleo-stm32f091rc"); #[cfg(feature = "stm32h503rb")] teleprobe_meta::target!(b"nucleo-stm32h503rb"); +#[cfg(feature = "stm32h7s3l8")] +teleprobe_meta::target!(b"nucleo-stm32h7s3l8"); macro_rules! define_peris { ($($name:ident = $peri:ident,)* $(@irq $irq_name:ident = $irq_code:tt,)*) => { @@ -249,6 +251,13 @@ define_peris!( SPI = SPI1, SPI_SCK = PB4, SPI_MOSI = PA15, SPI_MISO = PB3, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1, @irq UART = {LPUART1 => embassy_stm32::usart::InterruptHandler;}, ); +#[cfg(feature = "stm32h7s3l8")] +define_peris!( + CRYP_IN_DMA = GPDMA1_CH0, CRYP_OUT_DMA = GPDMA1_CH1, + UART = USART1, UART_TX = PB14, UART_RX = PA10, UART_TX_DMA = GPDMA1_CH0, UART_RX_DMA = GPDMA1_CH1, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PB5, SPI_MISO = PA6, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1, + @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, +); pub fn config() -> Config { #[allow(unused_mut)] @@ -641,6 +650,28 @@ pub fn config() -> Config { }); config.rcc.sys = Sysclk::PLL1_R; } - + #[cfg(any(feature = "stm32h7s3l8"))] + { + config.rcc.hse = Some(Hse { + freq: Hertz(24_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll1 = Some(Pll { + source: PllSource::HSE, + prediv: PllPreDiv::DIV3, + mul: PllMul::MUL150, + divp: Some(PllDiv::DIV2), // 600Mhz + divq: Some(PllDiv::DIV25), // 48Mhz + divr: None, + }); + config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.voltage_scale = VoltageScale::HIGH; + config.rcc.mux.spi1sel = mux::Spi123sel::PLL1_Q; + } config }