From c4b0e3a2bfc2c4b60f70f862a893b90b91954baa Mon Sep 17 00:00:00 2001 From: everdrone Date: Sat, 20 Sep 2025 12:39:15 +0200 Subject: Add feature, disable flash for N6 family --- embassy-stm32/Cargo.toml | 10 ++- embassy-stm32/build.rs | 226 +++++++++++++++++++++++++---------------------- embassy-stm32/src/lib.rs | 1 + 3 files changed, 127 insertions(+), 110 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 6cd8ed262..fb4bc70b7 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -95,6 +95,7 @@ build = [ {target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "low-power", "stm32wba65ri", "time", "time-driver-any"]}, {target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "stm32u5f9zj", "time", "time-driver-any"]}, {target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "stm32u5g9nj", "time", "time-driver-any"]}, + {target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "stm32n657x0", "time", "time-driver-any"]}, {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32wb35ce", "time", "time-driver-any"]}, {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "low-power", "stm32wb55rg", "time", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "exti", "stm32u031r8", "time", "time-driver-any"]}, @@ -173,8 +174,8 @@ cortex-m = "0.7.6" futures-util = { version = "0.3.30", default-features = false } sdio-host = "0.9.0" critical-section = "1.1" -#stm32-metapac = { version = "18" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7" } +stm32-metapac = { path = "../../stm32-data/build/stm32-metapac" } +# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7" } vcell = "0.1.3" nb = "1.0.0" @@ -203,8 +204,8 @@ proptest-state-machine = "0.3.0" proc-macro2 = "1.0.36" quote = "1.0.15" -#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7", default-features = false, features = ["metadata"] } +stm32-metapac = { path = "../../stm32-data/build/stm32-metapac", default-features = false, features = ["metadata"]} +# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7", default-features = false, features = ["metadata"] } [features] default = ["rt"] @@ -1629,6 +1630,7 @@ stm32l562qe = [ "stm32-metapac/stm32l562qe" ] stm32l562re = [ "stm32-metapac/stm32l562re" ] stm32l562ve = [ "stm32-metapac/stm32l562ve" ] stm32l562ze = [ "stm32-metapac/stm32l562ze" ] +stm32n657x0 = [ "stm32-metapac/stm32n657x0" ] stm32u031c6 = [ "stm32-metapac/stm32u031c6" ] stm32u031c8 = [ "stm32-metapac/stm32u031c8" ] stm32u031f4 = [ "stm32-metapac/stm32u031f4" ] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index b5f1261fe..861f3fcee 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -352,101 +352,108 @@ fn main() { // ======== // Generate FLASH regions - let mut flash_regions = TokenStream::new(); - let flash_memory_regions: Vec<_> = memory - .iter() - .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some()) - .collect(); - for region in flash_memory_regions.iter() { - let region_name = format_ident!("{}", get_flash_region_name(region.name)); - let bank_variant = format_ident!( - "{}", - if region.name.starts_with("BANK_1") { - "Bank1" - } else if region.name.starts_with("BANK_2") { - "Bank2" - } else if region.name == "OTP" { - "Otp" - } else { - continue; - } - ); - let base = region.address; - let size = region.size; - let settings = region.settings.as_ref().unwrap(); - let erase_size = settings.erase_size; - let write_size = settings.write_size; - let erase_value = settings.erase_value; - - flash_regions.extend(quote! { - pub const #region_name: crate::flash::FlashRegion = crate::flash::FlashRegion { - bank: crate::flash::FlashBank::#bank_variant, - base: #base, - size: #size, - erase_size: #erase_size, - write_size: #write_size, - erase_value: #erase_value, - _ensure_internal: (), - }; - }); + cfgs.declare("flash"); + let mut has_flash = false; + if !chip_name.starts_with("stm32n6") { + cfgs.enable("flash"); + has_flash = true; + + let mut flash_regions = TokenStream::new(); + let flash_memory_regions: Vec<_> = memory + .iter() + .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some()) + .collect(); + for region in flash_memory_regions.iter() { + let region_name = format_ident!("{}", get_flash_region_name(region.name)); + let bank_variant = format_ident!( + "{}", + if region.name.starts_with("BANK_1") { + "Bank1" + } else if region.name.starts_with("BANK_2") { + "Bank2" + } else if region.name == "OTP" { + "Otp" + } else { + continue; + } + ); + let base = region.address; + let size = region.size; + let settings = region.settings.as_ref().unwrap(); + let erase_size = settings.erase_size; + let write_size = settings.write_size; + let erase_value = settings.erase_value; + + flash_regions.extend(quote! { + pub const #region_name: crate::flash::FlashRegion = crate::flash::FlashRegion { + bank: crate::flash::FlashBank::#bank_variant, + base: #base, + size: #size, + erase_size: #erase_size, + write_size: #write_size, + erase_value: #erase_value, + _ensure_internal: (), + }; + }); - let region_type = format_ident!("{}", get_flash_region_type_name(region.name)); - flash_regions.extend(quote! { + let region_type = format_ident!("{}", get_flash_region_type_name(region.name)); + flash_regions.extend(quote! { #[cfg(flash)] pub struct #region_type<'d, MODE = crate::flash::Async>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_internal::Peri<'d, crate::peripherals::FLASH>, pub(crate) core::marker::PhantomData); }); - } + } - let (fields, (inits, region_names)): (Vec, (Vec, Vec)) = flash_memory_regions - .iter() - .map(|f| { - let region_name = get_flash_region_name(f.name); - let field_name = format_ident!("{}", region_name.to_lowercase()); - let field_type = format_ident!("{}", get_flash_region_type_name(f.name)); - let field = quote! { - pub #field_name: #field_type<'d, MODE> - }; - let region_name = format_ident!("{}", region_name); - let init = quote! { - #field_name: #field_type(&#region_name, unsafe { p.clone_unchecked()}, core::marker::PhantomData) - }; + let (fields, (inits, region_names)): (Vec, (Vec, Vec)) = flash_memory_regions + .iter() + .map(|f| { + let region_name = get_flash_region_name(f.name); + let field_name = format_ident!("{}", region_name.to_lowercase()); + let field_type = format_ident!("{}", get_flash_region_type_name(f.name)); + let field = quote! { + pub #field_name: #field_type<'d, MODE> + }; + let region_name = format_ident!("{}", region_name); + let init = quote! { + #field_name: #field_type(&#region_name, unsafe { p.clone_unchecked()}, core::marker::PhantomData) + }; - (field, (init, region_name)) - }) - .unzip(); - - let regions_len = flash_memory_regions.len(); - flash_regions.extend(quote! { - #[cfg(flash)] - pub struct FlashLayout<'d, MODE = crate::flash::Async> { - #(#fields),*, - _mode: core::marker::PhantomData, - } + (field, (init, region_name)) + }) + .unzip(); - #[cfg(flash)] - impl<'d, MODE> FlashLayout<'d, MODE> { - pub(crate) fn new(p: embassy_hal_internal::Peri<'d, crate::peripherals::FLASH>) -> Self { - Self { - #(#inits),*, - _mode: core::marker::PhantomData, + let regions_len = flash_memory_regions.len(); + flash_regions.extend(quote! { + #[cfg(flash)] + pub struct FlashLayout<'d, MODE = crate::flash::Async> { + #(#fields),*, + _mode: core::marker::PhantomData, + } + + #[cfg(flash)] + impl<'d, MODE> FlashLayout<'d, MODE> { + pub(crate) fn new(p: embassy_hal_internal::Peri<'d, crate::peripherals::FLASH>) -> Self { + Self { + #(#inits),*, + _mode: core::marker::PhantomData, + } } } - } - pub const FLASH_REGIONS: [&crate::flash::FlashRegion; #regions_len] = [ - #(&#region_names),* - ]; - }); + pub const FLASH_REGIONS: [&crate::flash::FlashRegion; #regions_len] = [ + #(&#region_names),* + ]; + }); - let max_erase_size = flash_memory_regions - .iter() - .map(|region| region.settings.as_ref().unwrap().erase_size) - .max() - .unwrap(); + let max_erase_size = flash_memory_regions + .iter() + .map(|region| region.settings.as_ref().unwrap().erase_size) + .max() + .unwrap(); - g.extend(quote! { pub const MAX_ERASE_SIZE: usize = #max_erase_size as usize; }); + g.extend(quote! { pub const MAX_ERASE_SIZE: usize = #max_erase_size as usize; }); - g.extend(quote! { pub mod flash_regions { #flash_regions } }); + g.extend(quote! { pub mod flash_regions { #flash_regions } }); + } // ======== // Extract the rcc registers @@ -1844,7 +1851,12 @@ fn main() { if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" || r.kind == "lpdma" { for irq in p.interrupts { let ch_name = format!("{}_{}", p.name, irq.signal); - let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name).unwrap(); + let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name); + + if ch.is_none() { + continue; + } + let ch = ch.unwrap(); // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it. if has_dmamux && ch.dmamux.is_none() { @@ -1985,31 +1997,33 @@ fn main() { // ======== // Generate flash constants - let flash_regions: Vec<&MemoryRegion> = memory - .iter() - .filter(|x| x.kind == MemoryRegionKind::Flash && x.name.starts_with("BANK_")) - .collect(); - let first_flash = flash_regions.first().unwrap(); - let total_flash_size = flash_regions - .iter() - .map(|x| x.size) - .reduce(|acc, item| acc + item) - .unwrap(); - let write_sizes: HashSet<_> = flash_regions - .iter() - .map(|r| r.settings.as_ref().unwrap().write_size) - .collect(); - assert_eq!(1, write_sizes.len()); + if has_flash { + let flash_regions: Vec<&MemoryRegion> = memory + .iter() + .filter(|x| x.kind == MemoryRegionKind::Flash && x.name.starts_with("BANK_")) + .collect(); + let first_flash = flash_regions.first().unwrap(); + let total_flash_size = flash_regions + .iter() + .map(|x| x.size) + .reduce(|acc, item| acc + item) + .unwrap(); + let write_sizes: HashSet<_> = flash_regions + .iter() + .map(|r| r.settings.as_ref().unwrap().write_size) + .collect(); + assert_eq!(1, write_sizes.len()); - let flash_base = first_flash.address as usize; - let total_flash_size = total_flash_size as usize; - let write_size = (*write_sizes.iter().next().unwrap()) as usize; + let flash_base = first_flash.address as usize; + let total_flash_size = total_flash_size as usize; + let write_size = (*write_sizes.iter().next().unwrap()) as usize; - g.extend(quote!( - pub const FLASH_BASE: usize = #flash_base; - pub const FLASH_SIZE: usize = #total_flash_size; - pub const WRITE_SIZE: usize = #write_size; - )); + g.extend(quote!( + pub const FLASH_BASE: usize = #flash_base; + pub const FLASH_SIZE: usize = #total_flash_size; + pub const WRITE_SIZE: usize = #write_size; + )); + } // ======== // Generate EEPROM constants diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 7e0f7884e..292586ee4 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -74,6 +74,7 @@ pub mod dts; pub mod eth; #[cfg(feature = "exti")] pub mod exti; +#[cfg(flash)] pub mod flash; #[cfg(fmc)] pub mod fmc; -- cgit From 5f4a411978b97fbb55475eb7dafafdedb452eb6a Mon Sep 17 00:00:00 2001 From: everdrone Date: Sat, 20 Sep 2025 12:39:33 +0200 Subject: Add N6 family RCC config --- embassy-stm32/src/rcc/mco.rs | 6 ++++-- embassy-stm32/src/rcc/mod.rs | 1 + embassy-stm32/src/rcc/n6.rs | 20 ++++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 embassy-stm32/src/rcc/n6.rs diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index 59ccc8cb5..3d0f510c0 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs @@ -15,7 +15,8 @@ pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; rcc_h7ab, rcc_h7rm0433, rcc_h7, - rcc_h7rs + rcc_h7rs, + rcc_n6 )))] pub use crate::pac::rcc::vals::Mcosel as McoSource; #[cfg(any( @@ -28,7 +29,8 @@ pub use crate::pac::rcc::vals::Mcosel as McoSource; rcc_h7ab, rcc_h7rm0433, rcc_h7, - rcc_h7rs + rcc_h7rs, + rcc_n6 ))] pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; use crate::pac::RCC; diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index c41f81816..1cd80c17f 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -28,6 +28,7 @@ pub use hsi48::*; #[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")] +#[cfg_attr(stm32n6, path = "n6.rs")] mod _version; pub use _version::*; diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs new file mode 100644 index 000000000..68627edfd --- /dev/null +++ b/embassy-stm32/src/rcc/n6.rs @@ -0,0 +1,20 @@ +/// Configuration of the core clocks +#[non_exhaustive] +#[derive(Clone, Copy)] +pub struct Config {} + +impl Config { + pub const fn new() -> Self { + Self {} + } +} + +impl Default for Config { + fn default() -> Self { + Self::new() + } +} + +pub(crate) unsafe fn init(config: Config) { + todo!() +} -- cgit From e6e42001a65e2c77cdb6995b7f689fbb4d10d045 Mon Sep 17 00:00:00 2001 From: everdrone Date: Sun, 21 Sep 2025 14:50:54 +0200 Subject: Use N6 registers for MCOxSEL and MCOxPRE --- embassy-stm32/src/rcc/mco.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index 3d0f510c0..a8f8cfcff 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs @@ -61,10 +61,12 @@ macro_rules! impl_peri { type Source = $source; unsafe fn _apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) { - #[cfg(not(any(stm32u5, stm32wba)))] + #[cfg(not(any(stm32u5, stm32wba, stm32n6)))] let r = RCC.cfgr(); #[cfg(any(stm32u5, stm32wba))] let r = RCC.cfgr1(); + #[cfg(any(stm32n6))] + let r = RCC.ccipr5(); r.modify(|w| { w.$set_source(source); -- cgit From 500ffc0acb4014e334d9d1f23a45a1f65c02aa17 Mon Sep 17 00:00:00 2001 From: everdrone Date: Sun, 21 Sep 2025 14:52:11 +0200 Subject: Fix EXTI, DTS and FLASH for N6 family --- embassy-stm32/src/dts/tsel.rs | 17 +++++++++++++++++ embassy-stm32/src/exti.rs | 16 ++++++++-------- embassy-stm32/src/lib.rs | 2 +- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/dts/tsel.rs b/embassy-stm32/src/dts/tsel.rs index 99eab6dd8..79c697c8d 100644 --- a/embassy-stm32/src/dts/tsel.rs +++ b/embassy-stm32/src/dts/tsel.rs @@ -49,3 +49,20 @@ pub enum TriggerSel { /// EXTI13 Exti13 = 4, } + +/// Trigger selection for N6 +#[cfg(stm32n6)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum TriggerSel { + /// Software triggering. Performs continuous measurements. + Software = 0, + /// LPTIM4 OUT + Lptim4 = 1, + /// LPTIM2 CH1 + Lptim2 = 2, + /// LPTIM3 CH1 + Lptim3 = 3, + /// EXTI13 + Exti13 = 4, +} diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 9fce78f95..376fdccb8 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -31,11 +31,11 @@ fn cpu_regs() -> pac::exti::Exti { EXTI } -#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))] +#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50, exti_n6)))] fn exticr_regs() -> pac::syscfg::Syscfg { pac::SYSCFG } -#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] +#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))] fn exticr_regs() -> pac::exti::Exti { EXTI } @@ -45,9 +45,9 @@ fn exticr_regs() -> pac::afio::Afio { } unsafe fn on_irq() { - #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] + #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))] let bits = EXTI.pr(0).read().0; - #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] + #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))] let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0; // We don't handle or change any EXTI lines above 16. @@ -62,9 +62,9 @@ unsafe fn on_irq() { } // Clear pending - #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] + #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))] EXTI.pr(0).write_value(Lines(bits)); - #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] + #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))] { EXTI.rpr(0).write_value(Lines(bits)); EXTI.fpr(0).write_value(Lines(bits)); @@ -239,9 +239,9 @@ impl<'a> ExtiInputFuture<'a> { EXTI.ftsr(0).modify(|w| w.set_line(pin, falling)); // clear pending bit - #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] + #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))] EXTI.pr(0).write(|w| w.set_line(pin, true)); - #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] + #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))] { EXTI.rpr(0).write(|w| w.set_line(pin, true)); EXTI.fpr(0).write(|w| w.set_line(pin, true)); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 292586ee4..6abd60eb0 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -531,7 +531,7 @@ fn init_hw(config: Config) -> Peripherals { rcc::enable_and_reset_with_cs::(cs); #[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))] rcc::enable_and_reset_with_cs::(cs); - #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs)))] + #[cfg(all(flash, not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs))))] rcc::enable_and_reset_with_cs::(cs); // Enable the VDDIO2 power supply on chips that have it. -- cgit From 7b9116957a439a5e8488aa9d6f47bbb7b8a306a1 Mon Sep 17 00:00:00 2001 From: everdrone Date: Sun, 21 Sep 2025 14:52:54 +0200 Subject: Add `cfg`s for N6 family in BD --- embassy-stm32/src/rcc/bd.rs | 102 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 82 insertions(+), 20 deletions(-) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index e2c704405..e5f52c3c7 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -66,9 +66,11 @@ fn unlock() {} fn unlock() { #[cfg(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1))] let cr = crate::pac::PWR.cr(); - #[cfg(not(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba)))] + #[cfg(not(any( + stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba, stm32n6 + )))] let cr = crate::pac::PWR.cr1(); - #[cfg(any(stm32u5, stm32h5, stm32wba))] + #[cfg(any(stm32u5, stm32h5, stm32wba, stm32n6))] let cr = crate::pac::PWR.dbpcr(); cr.modify(|w| w.set_dbp(true)); @@ -175,14 +177,19 @@ impl LsConfig { if self.lsi { #[cfg(any(stm32u5, stm32h5, stm32wba))] let csr = crate::pac::RCC.bdcr(); - #[cfg(not(any(stm32u5, stm32h5, stm32wba, stm32c0)))] + #[cfg(stm32n6)] + let csr = crate::pac::RCC.sr(); + #[cfg(not(any(stm32u5, stm32h5, stm32wba, stm32c0, stm32n6)))] let csr = crate::pac::RCC.csr(); - #[cfg(any(stm32c0))] + #[cfg(stm32c0)] let csr = crate::pac::RCC.csr2(); - #[cfg(not(any(rcc_wb, rcc_wba)))] + #[cfg(not(any(rcc_wb, rcc_wba, rcc_n6)))] csr.modify(|w| w.set_lsion(true)); + #[cfg(rcc_n6)] + crate::pac::RCC.cr().modify(|w| w.set_lsion(true)); + #[cfg(any(rcc_wb, rcc_wba))] csr.modify(|w| w.set_lsi1on(true)); @@ -196,25 +203,58 @@ impl LsConfig { // 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. + // N6 has all the fields spread across multiple registers under RCC. // check if it's already enabled and in the source we want. + #[cfg(not(rcc_n6))] let reg = bdcr().read(); + #[cfg(rcc_n6)] + let reg = crate::pac::RCC.cr().read(); + #[cfg(rcc_n6)] + let apb4lenr = crate::pac::RCC.apb4lenr().read(); + #[cfg(rcc_n6)] + let ccipr7 = crate::pac::RCC.ccipr7().read(); + #[cfg(rcc_n6)] + let lsecfgr = crate::pac::RCC.lsecfgr().read(); + let mut ok = true; - ok &= reg.rtcsel() == self.rtc; - #[cfg(not(rcc_wba))] + #[cfg(not(rcc_n6))] + { + ok &= reg.rtcsel() == self.rtc; + } + #[cfg(rcc_n6)] + { + ok &= ccipr7.rtcsel() == self.rtc; + } + #[cfg(not(any(rcc_wba, rcc_n6)))] { ok &= reg.rtcen() == (self.rtc != RtcClockSource::DISABLE); } + #[cfg(rcc_n6)] + { + ok &= apb4lenr.rtcen() == (self.rtc != RtcClockSource::DISABLE); + } ok &= reg.lseon() == lse_en; - ok &= reg.lsebyp() == lse_byp; + #[cfg(not(rcc_n6))] + { + ok &= reg.lsebyp() == lse_byp; + } + #[cfg(rcc_n6)] + { + ok &= lsecfgr.lsebyp() == lse_byp; + } #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))] if let Some(lse_sysen) = lse_sysen { ok &= reg.lsesysen() == lse_sysen; } - #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))] + #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1, rcc_n6)))] if let Some(lse_drv) = lse_drv { ok &= reg.lsedrv() == lse_drv.into(); } + #[cfg(rcc_n6)] + if let Some(lse_drv) = lse_drv { + ok &= lsecfgr.lsedrv() == lse_drv.into(); + } // if configuration is OK, we're done. if ok { @@ -223,7 +263,7 @@ impl LsConfig { } // If not OK, reset backup domain and configure it. - #[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32h7rs, stm32c0)))] + #[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32h7rs, stm32c0, stm32n6)))] { bdcr().modify(|w| w.set_bdrst(true)); bdcr().modify(|w| w.set_bdrst(false)); @@ -236,7 +276,7 @@ impl LsConfig { // 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, stm32h7rs))] - #[cfg(any(stm32h7rs))] + #[cfg(any(stm32h7rs, stm32n6))] { bdcr().modify(|w| w.set_vswrst(true)); bdcr().modify(|w| w.set_vswrst(false)); @@ -248,16 +288,31 @@ impl LsConfig { } if lse_en { - bdcr().modify(|w| { - #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))] - if let Some(lse_drv) = lse_drv { - w.set_lsedrv(lse_drv.into()); - } - w.set_lsebyp(lse_byp); - w.set_lseon(true); - }); + #[cfg(not(rcc_n6))] + { + bdcr().modify(|w| { + #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))] + if let Some(lse_drv) = lse_drv { + w.set_lsedrv(lse_drv.into()); + } + w.set_lsebyp(lse_byp); + w.set_lseon(true); + }); - while !bdcr().read().lserdy() {} + while !bdcr().read().lserdy() {} + } + #[cfg(rcc_n6)] + { + crate::pac::RCC.lsecfgr().modify(|w| { + if let Some(lse_drv) = lse_drv { + w.set_lsedrv(lse_drv.into()); + } + w.set_lsebyp(lse_byp); + }); + crate::pac::RCC.cr().modify(|w| w.set_lseon(true)); + + while !crate::pac::RCC.sr().read().lserdy() {} + } #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))] if let Some(lse_sysen) = lse_sysen { @@ -272,6 +327,7 @@ impl LsConfig { } if self.rtc != RtcClockSource::DISABLE { + #[cfg(not(rcc_n6))] bdcr().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."); @@ -280,6 +336,12 @@ impl LsConfig { w.set_rtcen(true); w.set_rtcsel(self.rtc); }); + + #[cfg(rcc_n6)] + { + crate::pac::RCC.ccipr7().modify(|w| w.set_rtcsel(self.rtc)); + crate::pac::RCC.apb4lenr().modify(|w| w.set_rtcen(true)) + } } trace!("BDCR configured: {:08x}", bdcr().read().0); -- cgit From ea4e7bc3d23c3deb44fa6029f70ddcd72dfa4d35 Mon Sep 17 00:00:00 2001 From: everdrone Date: Sun, 21 Sep 2025 17:23:39 +0200 Subject: Use `PinNumber` to accomodate chips with more than 256 pins --- embassy-stm32/src/exti.rs | 16 ++++++++-------- embassy-stm32/src/gpio.rs | 37 +++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 376fdccb8..bc4ecd1cc 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -8,7 +8,7 @@ use core::task::{Context, Poll}; use embassy_hal_internal::{impl_peripheral, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; -use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, Pull}; +use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, PinNumber, Pull}; use crate::pac::exti::regs::Lines; use crate::pac::EXTI; use crate::{interrupt, pac, peripherals, Peri}; @@ -226,12 +226,12 @@ impl<'d> embedded_hal_async::digital::Wait for ExtiInput<'d> { #[must_use = "futures do nothing unless you `.await` or poll them"] struct ExtiInputFuture<'a> { - pin: u8, + pin: PinNumber, phantom: PhantomData<&'a mut AnyPin>, } impl<'a> ExtiInputFuture<'a> { - fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self { + fn new(pin: PinNumber, port: PinNumber, rising: bool, falling: bool) -> Self { critical_section::with(|_| { let pin = pin as usize; exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port)); @@ -334,20 +334,20 @@ trait SealedChannel {} #[allow(private_bounds)] pub trait Channel: PeripheralType + SealedChannel + Sized { /// Get the EXTI channel number. - fn number(&self) -> u8; + fn number(&self) -> PinNumber; } /// Type-erased EXTI channel. /// /// This represents ownership over any EXTI channel, known at runtime. pub struct AnyChannel { - number: u8, + number: PinNumber, } impl_peripheral!(AnyChannel); impl SealedChannel for AnyChannel {} impl Channel for AnyChannel { - fn number(&self) -> u8 { + fn number(&self) -> PinNumber { self.number } } @@ -356,7 +356,7 @@ macro_rules! impl_exti { ($type:ident, $number:expr) => { impl SealedChannel for peripherals::$type {} impl Channel for peripherals::$type { - fn number(&self) -> u8 { + fn number(&self) -> PinNumber { $number } } @@ -364,7 +364,7 @@ macro_rules! impl_exti { impl From for AnyChannel { fn from(val: peripherals::$type) -> Self { Self { - number: val.number() as u8, + number: val.number() as PinNumber, } } } diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 5a8d23183..ba5cf24c6 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -592,7 +592,7 @@ impl AfType { #[inline(never)] #[cfg(gpio_v1)] -fn set_as_af(pin_port: u8, af_type: AfType) { +fn set_as_af(pin_port: PinNumber, af_type: AfType) { let pin = unsafe { AnyPin::steal(pin_port) }; let r = pin.block(); let n = pin._pin() as usize; @@ -649,12 +649,12 @@ impl AfType { #[inline(never)] #[cfg(gpio_v2)] -fn set_as_af(pin_port: u8, af_num: u8, af_type: AfType) { +fn set_as_af(pin_port: PinNumber, af_num: u8, af_type: AfType) { let pin = unsafe { AnyPin::steal(pin_port) }; let r = pin.block(); let n = pin._pin() as usize; - r.afr(n / 8).modify(|w| w.set_afr(n % 8, af_num)); + r.afr(n / 8).modify(|w| w.set_afr(n % 8, af_num as u8)); r.pupdr().modify(|w| w.set_pupdr(n, af_type.pupdr)); r.otyper().modify(|w| w.set_ot(n, af_type.ot)); r.ospeedr().modify(|w| w.set_ospeedr(n, af_type.ospeedr)); @@ -663,7 +663,7 @@ fn set_as_af(pin_port: u8, af_num: u8, af_type: AfType) { #[inline(never)] #[cfg(gpio_v2)] -fn set_speed(pin_port: u8, speed: Speed) { +fn set_speed(pin_port: PinNumber, speed: Speed) { let pin = unsafe { AnyPin::steal(pin_port) }; let r = pin.block(); let n = pin._pin() as usize; @@ -672,7 +672,7 @@ fn set_speed(pin_port: u8, speed: Speed) { } #[inline(never)] -fn set_as_analog(pin_port: u8) { +fn set_as_analog(pin_port: PinNumber) { let pin = unsafe { AnyPin::steal(pin_port) }; let r = pin.block(); let n = pin._pin() as usize; @@ -688,7 +688,7 @@ fn set_as_analog(pin_port: u8) { } #[inline(never)] -fn get_pull(pin_port: u8) -> Pull { +fn get_pull(pin_port: PinNumber) -> Pull { let pin = unsafe { AnyPin::steal(pin_port) }; let r = pin.block(); let n = pin._pin() as usize; @@ -727,15 +727,15 @@ pub struct AfioRemapBool; pub struct AfioRemapNotApplicable; pub(crate) trait SealedPin { - fn pin_port(&self) -> u8; + fn pin_port(&self) -> PinNumber; #[inline] - fn _pin(&self) -> u8 { + fn _pin(&self) -> PinNumber { self.pin_port() % 16 } #[inline] - fn _port(&self) -> u8 { + fn _port(&self) -> PinNumber { self.pin_port() / 16 } @@ -798,6 +798,11 @@ pub(crate) trait SealedPin { } } +#[cfg(not(stm32n6))] +pub type PinNumber = u8; +#[cfg(stm32n6)] +pub type PinNumber = u16; + /// GPIO pin trait. #[allow(private_bounds)] pub trait Pin: PeripheralType + Into + SealedPin + Sized + 'static { @@ -809,20 +814,20 @@ pub trait Pin: PeripheralType + Into + SealedPin + Sized + 'static { /// Number of the pin within the port (0..31) #[inline] - fn pin(&self) -> u8 { + fn pin(&self) -> PinNumber { self._pin() } /// Port of the pin #[inline] - fn port(&self) -> u8 { + fn port(&self) -> PinNumber { self._port() } } /// Type-erased GPIO pin pub struct AnyPin { - pin_port: u8, + pin_port: PinNumber, } impl AnyPin { @@ -830,12 +835,12 @@ impl AnyPin { /// /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc... #[inline] - pub unsafe fn steal(pin_port: u8) -> Peri<'static, Self> { + pub unsafe fn steal(pin_port: PinNumber) -> Peri<'static, Self> { Peri::new_unchecked(Self { pin_port }) } #[inline] - fn _port(&self) -> u8 { + fn _port(&self) -> PinNumber { self.pin_port / 16 } @@ -854,7 +859,7 @@ impl Pin for AnyPin { } impl SealedPin for AnyPin { #[inline] - fn pin_port(&self) -> u8 { + fn pin_port(&self) -> PinNumber { self.pin_port } } @@ -869,7 +874,7 @@ foreach_pin!( } impl SealedPin for peripherals::$pin_name { #[inline] - fn pin_port(&self) -> u8 { + fn pin_port(&self) -> PinNumber { $port_num * 16 + $pin_num } } -- cgit From 5f5f71efd09266eccb0ab7e4048994f244eed5ae Mon Sep 17 00:00:00 2001 From: matteo Date: Sun, 21 Sep 2025 17:52:14 +0200 Subject: Add support for changing hid protocol mode --- embassy-usb/CHANGELOG.md | 4 ++++ embassy-usb/Cargo.toml | 2 +- embassy-usb/src/class/hid.rs | 39 ++++++++++++++++++++++++++++++++------- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/embassy-usb/CHANGELOG.md b/embassy-usb/CHANGELOG.md index 0a30bc24b..891388122 100644 --- a/embassy-usb/CHANGELOG.md +++ b/embassy-usb/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +## 0.5.2 - Unreleased + +- `hid`: Add USB HID Boot Protocol Mode support + ## 0.5.1 - 2025-08-26 ## 0.5.0 - 2025-07-16 diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index e309eec93..fde603df0 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-usb" -version = "0.5.1" +version = "0.5.2" edition = "2021" license = "MIT OR Apache-2.0" description = "Async USB device stack for embedded devices in Rust." diff --git a/embassy-usb/src/class/hid.rs b/embassy-usb/src/class/hid.rs index 182e1f83f..8df23b384 100644 --- a/embassy-usb/src/class/hid.rs +++ b/embassy-usb/src/class/hid.rs @@ -8,6 +8,7 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use ssmarshal::serialize; #[cfg(feature = "usbd-hid")] use usbd_hid::descriptor::AsInputReport; +use usbd_hid::hid_class::HidProtocolMode; use crate::control::{InResponse, OutResponse, Recipient, Request, RequestType}; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; @@ -389,6 +390,23 @@ pub trait RequestHandler { OutResponse::Rejected } + /// Gets the current hid protocol. + /// + /// Returns `Report` protocol by default. + fn get_protocol(&self) -> HidProtocolMode { + HidProtocolMode::Report + } + + /// Sets the current hid protocol to `protocol`. + /// + /// Accepts only `Report` protocol by default. + fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse { + match protocol { + HidProtocolMode::Report => OutResponse::Accepted, + HidProtocolMode::Boot => OutResponse::Rejected, + } + } + /// Get the idle rate for `id`. /// /// If `id` is `None`, get the idle rate for all reports. Returning `None` @@ -482,11 +500,14 @@ impl<'d> Handler for Control<'d> { _ => Some(OutResponse::Rejected), }, HID_REQ_SET_PROTOCOL => { - if req.value == 1 { - Some(OutResponse::Accepted) - } else { - warn!("HID Boot Protocol is unsupported."); - Some(OutResponse::Rejected) // UNSUPPORTED: Boot Protocol + let hid_protocol = HidProtocolMode::from(req.value as u8); + match (self.request_handler.as_mut(), hid_protocol) { + (Some(request_handler), hid_protocol) => Some(request_handler.set_protocol(hid_protocol)), + (None, HidProtocolMode::Report) => Some(OutResponse::Accepted), + (None, HidProtocolMode::Boot) => { + warn!("HID Boot Protocol is unsupported."); + Some(OutResponse::Rejected) // UNSUPPORTED: Boot Protocol + } } } _ => Some(OutResponse::Rejected), @@ -539,8 +560,12 @@ impl<'d> Handler for Control<'d> { } } HID_REQ_GET_PROTOCOL => { - // UNSUPPORTED: Boot Protocol - buf[0] = 1; + if let Some(request_handler) = self.request_handler.as_mut() { + buf[0] = request_handler.get_protocol() as u8; + } else { + // Return `Report` protocol by default + buf[0] = HidProtocolMode::Report as u8; + } Some(InResponse::Accepted(&buf[0..1])) } _ => Some(InResponse::Rejected), -- cgit From 2cf7cc4c92fe0f7897513286e4bce944870e1bad Mon Sep 17 00:00:00 2001 From: matteo Date: Sun, 21 Sep 2025 18:00:32 +0200 Subject: fix compilation with usbd-hid feature off --- embassy-usb/src/class/hid.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/embassy-usb/src/class/hid.rs b/embassy-usb/src/class/hid.rs index 8df23b384..f97bcdfac 100644 --- a/embassy-usb/src/class/hid.rs +++ b/embassy-usb/src/class/hid.rs @@ -8,6 +8,7 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use ssmarshal::serialize; #[cfg(feature = "usbd-hid")] use usbd_hid::descriptor::AsInputReport; +#[cfg(feature = "usbd-hid")] use usbd_hid::hid_class::HidProtocolMode; use crate::control::{InResponse, OutResponse, Recipient, Request, RequestType}; @@ -32,6 +33,30 @@ const HID_REQ_SET_REPORT: u8 = 0x09; const HID_REQ_GET_PROTOCOL: u8 = 0x03; const HID_REQ_SET_PROTOCOL: u8 = 0x0b; +/// Get/Set Protocol mapping +/// See (7.2.5 and 7.2.6): +#[cfg(not(feature = "usbd-hid"))] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum HidProtocolMode { + /// Hid Boot Protocol Mode + Boot = 0, + /// Hid Report Protocol Mode + Report = 1, +} + +#[cfg(not(feature = "usbd-hid"))] +impl From for HidProtocolMode { + fn from(mode: u8) -> HidProtocolMode { + if mode == HidProtocolMode::Boot as u8 { + HidProtocolMode::Boot + } else { + HidProtocolMode::Report + } + } +} + /// Configuration for the HID class. pub struct Config<'d> { /// HID report descriptor. -- cgit From 1688a3c393375790b223da70d41106fd59431878 Mon Sep 17 00:00:00 2001 From: matteo Date: Sun, 21 Sep 2025 18:08:42 +0200 Subject: update comments --- embassy-usb/src/class/hid.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-usb/src/class/hid.rs b/embassy-usb/src/class/hid.rs index f97bcdfac..c8875435f 100644 --- a/embassy-usb/src/class/hid.rs +++ b/embassy-usb/src/class/hid.rs @@ -530,8 +530,8 @@ impl<'d> Handler for Control<'d> { (Some(request_handler), hid_protocol) => Some(request_handler.set_protocol(hid_protocol)), (None, HidProtocolMode::Report) => Some(OutResponse::Accepted), (None, HidProtocolMode::Boot) => { - warn!("HID Boot Protocol is unsupported."); - Some(OutResponse::Rejected) // UNSUPPORTED: Boot Protocol + info!("Received request to switch to Boot protocol mode, but it is disabled by default."); + Some(OutResponse::Rejected) } } } @@ -588,7 +588,7 @@ impl<'d> Handler for Control<'d> { if let Some(request_handler) = self.request_handler.as_mut() { buf[0] = request_handler.get_protocol() as u8; } else { - // Return `Report` protocol by default + // Return `Report` protocol mode by default buf[0] = HidProtocolMode::Report as u8; } Some(InResponse::Accepted(&buf[0..1])) -- cgit From 10397e9f3c4a224c38caa81f1f1d72c0aa96fcdf Mon Sep 17 00:00:00 2001 From: matteo Date: Sun, 21 Sep 2025 18:26:26 +0200 Subject: fix changelog --- embassy-usb/CHANGELOG.md | 4 +--- embassy-usb/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/embassy-usb/CHANGELOG.md b/embassy-usb/CHANGELOG.md index 891388122..cfb1bf021 100644 --- a/embassy-usb/CHANGELOG.md +++ b/embassy-usb/CHANGELOG.md @@ -8,9 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate -## 0.5.2 - Unreleased - -- `hid`: Add USB HID Boot Protocol Mode support +- Add support for USB HID Boot Protocol Mode ## 0.5.1 - 2025-08-26 diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index fde603df0..e309eec93 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-usb" -version = "0.5.2" +version = "0.5.1" edition = "2021" license = "MIT OR Apache-2.0" description = "Async USB device stack for embedded devices in Rust." -- cgit From d72e8d9af921bfd5ddc25a17933e16b2132386b8 Mon Sep 17 00:00:00 2001 From: matteo Date: Tue, 23 Sep 2025 20:08:11 +0200 Subject: add usb subclass boot and usb protocol mouse and keyboard --- embassy-usb/src/class/hid.rs | 95 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 90 insertions(+), 5 deletions(-) diff --git a/embassy-usb/src/class/hid.rs b/embassy-usb/src/class/hid.rs index c8875435f..b9830baeb 100644 --- a/embassy-usb/src/class/hid.rs +++ b/embassy-usb/src/class/hid.rs @@ -17,8 +17,13 @@ use crate::types::InterfaceNumber; use crate::{Builder, Handler}; const USB_CLASS_HID: u8 = 0x03; -const USB_SUBCLASS_NONE: u8 = 0x00; + +const USB_SUBCLASS_REPORT_ONLY: u8 = 0x00; +const USB_SUBCLASS_BOOT_OR_REPORT: u8 = 0x01; + const USB_PROTOCOL_NONE: u8 = 0x00; +const USB_PROTOCOL_KEYBOARD: u8 = 0x01; +const USB_PROTOCOL_MOUSE: u8 = 0x02; // HID const HID_DESC_DESCTYPE_HID: u8 = 0x21; @@ -132,13 +137,15 @@ fn build<'d, D: Driver<'d>>( state: &'d mut State<'d>, config: Config<'d>, with_out_endpoint: bool, + usb_subclass: u8, + usb_protocol: u8, ) -> (Option, D::EndpointIn, &'d AtomicUsize) { let len = config.report_descriptor.len(); - let mut func = builder.function(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE); + let mut func = builder.function(USB_CLASS_HID, usb_subclass, usb_protocol); let mut iface = func.interface(); let if_num = iface.interface_number(); - let mut alt = iface.alt_setting(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE, None); + let mut alt = iface.alt_setting(USB_CLASS_HID, usb_subclass, usb_protocol, None); // HID descriptor alt.descriptor( @@ -186,7 +193,42 @@ impl<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N: usize> HidReaderWrit /// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only. /// pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { - let (ep_out, ep_in, offset) = build(builder, state, config, true); + HidReaderWriter::_new(builder, state, config, USB_SUBCLASS_REPORT_ONLY, USB_PROTOCOL_NONE) + } + + /// Creates a new `HidReaderWriter` for a HID Mouse, with support for the BOOT protocol mode. + /// + /// This will allocate one IN and one OUT endpoints. If you only need writing (sending) + /// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only. + /// + pub fn new_mouse(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { + HidReaderWriter::_new(builder, state, config, USB_SUBCLASS_BOOT_OR_REPORT, USB_PROTOCOL_MOUSE) + } + + /// Creates a new `HidReaderWriter` for a HID Keyboard, with support for the BOOT protocol mode. + /// + /// This will allocate one IN and one OUT endpoints. If you only need writing (sending) + /// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only. + /// + pub fn new_keyboard(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { + HidReaderWriter::_new( + builder, + state, + config, + USB_SUBCLASS_BOOT_OR_REPORT, + USB_PROTOCOL_KEYBOARD, + ) + } + + /// Private helper function to create a new `HidReaderWriter`. + fn _new( + builder: &mut Builder<'d, D>, + state: &'d mut State<'d>, + config: Config<'d>, + usb_subclass: u8, + usb_protocol: u8, + ) -> Self { + let (ep_out, ep_in, offset) = build(builder, state, config, true, usb_subclass, usb_protocol); Self { reader: HidReader { @@ -275,7 +317,50 @@ impl<'d, D: Driver<'d>, const N: usize> HidWriter<'d, D, N> { /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for /// high performance uses, and a value of 255 is good for best-effort usecases. pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { - let (ep_out, ep_in, _offset) = build(builder, state, config, false); + HidWriter::_new(builder, state, config, USB_SUBCLASS_REPORT_ONLY, USB_PROTOCOL_NONE) + } + + /// Creates a new `HidWriter` for a HID Mouse, with support for the BOOT protocol mode. + /// + /// This will allocate one IN endpoint only, so the host won't be able to send + /// reports to us. If you need that, consider using [`HidReaderWriter::new`] instead. + /// + /// poll_ms configures how frequently the host should poll for reading/writing + /// HID reports. A lower value means better throughput & latency, at the expense + /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for + /// high performance uses, and a value of 255 is good for best-effort usecases. + pub fn new_mouse(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { + HidWriter::_new(builder, state, config, USB_SUBCLASS_BOOT_OR_REPORT, USB_PROTOCOL_MOUSE) + } + + /// Creates a new `HidWriter` for a HID Keyboard, with support for the BOOT protocol mode. + /// + /// This will allocate one IN endpoint only, so the host won't be able to send + /// reports to us. If you need that, consider using [`HidReaderWriter::new`] instead. + /// + /// poll_ms configures how frequently the host should poll for reading/writing + /// HID reports. A lower value means better throughput & latency, at the expense + /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for + /// high performance uses, and a value of 255 is good for best-effort usecases. + pub fn new_keyboard(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { + HidWriter::_new( + builder, + state, + config, + USB_SUBCLASS_BOOT_OR_REPORT, + USB_PROTOCOL_KEYBOARD, + ) + } + + /// Private helper function to create a new `HidWriter`. + pub fn _new( + builder: &mut Builder<'d, D>, + state: &'d mut State<'d>, + config: Config<'d>, + usb_subclass: u8, + usb_protocol: u8, + ) -> Self { + let (ep_out, ep_in, _offset) = build(builder, state, config, false, usb_subclass, usb_protocol); assert!(ep_out.is_none()); -- cgit From 2e303c995c53a97a1c2eaecf77827f02567b8417 Mon Sep 17 00:00:00 2001 From: matteo Date: Tue, 23 Sep 2025 20:20:43 +0200 Subject: update hid examples --- examples/nrf52840/src/bin/usb_hid_keyboard.rs | 6 +++++- examples/nrf52840/src/bin/usb_hid_mouse.rs | 6 +++++- examples/rp/src/bin/usb_hid_keyboard.rs | 6 +++++- examples/rp/src/bin/usb_hid_mouse.rs | 6 +++++- examples/rp235x/src/bin/usb_hid_keyboard.rs | 6 +++++- examples/stm32f4/src/bin/usb_hid_keyboard.rs | 6 +++++- examples/stm32f4/src/bin/usb_hid_mouse.rs | 6 +++++- examples/stm32l5/src/bin/usb_hid_mouse.rs | 6 +++++- 8 files changed, 40 insertions(+), 8 deletions(-) diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index 5a9dc90a2..0f0d830c6 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs @@ -45,6 +45,10 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; config.supports_remote_wakeup = true; + config.composite_with_iads = false; + config.device_class = 0; + config.device_sub_class = 0; + config.device_protocol = 0; // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. @@ -75,7 +79,7 @@ async fn main(_spawner: Spawner) { poll_ms: 60, max_packet_size: 64, }; - let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); + let hid = HidReaderWriter::<_, 1, 8>::new_keyboard(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index 80cda70e3..b3d90354b 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs @@ -37,6 +37,10 @@ async fn main(_spawner: Spawner) { config.serial_number = Some("12345678"); config.max_power = 100; config.max_packet_size_0 = 64; + config.composite_with_iads = false; + config.device_class = 0; + config.device_sub_class = 0; + config.device_protocol = 0; // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. @@ -65,7 +69,7 @@ async fn main(_spawner: Spawner) { max_packet_size: 8, }; - let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); + let mut writer = HidWriter::<_, 5>::new_mouse(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs index a7cb322d8..8658da6b5 100644 --- a/examples/rp/src/bin/usb_hid_keyboard.rs +++ b/examples/rp/src/bin/usb_hid_keyboard.rs @@ -33,6 +33,10 @@ async fn main(_spawner: Spawner) { config.serial_number = Some("12345678"); config.max_power = 100; config.max_packet_size_0 = 64; + config.composite_with_iads = false; + config.device_class = 0; + config.device_sub_class = 0; + config.device_protocol = 0; // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. @@ -64,7 +68,7 @@ async fn main(_spawner: Spawner) { poll_ms: 60, max_packet_size: 64, }; - let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); + let hid = HidReaderWriter::<_, 1, 8>::new_keyboard(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs index 4454c593c..4d8fc354e 100755 --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -35,6 +35,10 @@ async fn main(_spawner: Spawner) { config.serial_number = Some("12345678"); config.max_power = 100; config.max_packet_size_0 = 64; + config.composite_with_iads = false; + config.device_class = 0; + config.device_sub_class = 0; + config.device_protocol = 0; // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. @@ -66,7 +70,7 @@ async fn main(_spawner: Spawner) { poll_ms: 60, max_packet_size: 64, }; - let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); + let hid = HidReaderWriter::<_, 1, 8>::new_keyboard(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); diff --git a/examples/rp235x/src/bin/usb_hid_keyboard.rs b/examples/rp235x/src/bin/usb_hid_keyboard.rs index 6f496e23a..fa9eaa863 100644 --- a/examples/rp235x/src/bin/usb_hid_keyboard.rs +++ b/examples/rp235x/src/bin/usb_hid_keyboard.rs @@ -33,6 +33,10 @@ async fn main(_spawner: Spawner) { config.serial_number = Some("12345678"); config.max_power = 100; config.max_packet_size_0 = 64; + config.composite_with_iads = false; + config.device_class = 0; + config.device_sub_class = 0; + config.device_protocol = 0; // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. @@ -64,7 +68,7 @@ async fn main(_spawner: Spawner) { poll_ms: 60, max_packet_size: 64, }; - let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); + let hid = HidReaderWriter::<_, 1, 8>::new_keyboard(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index d6b4a9bc9..6ddfba83a 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -70,6 +70,10 @@ async fn main(_spawner: Spawner) { config.serial_number = Some("12345678"); config.max_power = 100; config.max_packet_size_0 = 64; + config.composite_with_iads = false; + config.device_class = 0; + config.device_sub_class = 0; + config.device_protocol = 0; // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. @@ -103,7 +107,7 @@ async fn main(_spawner: Spawner) { max_packet_size: 8, }; - let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); + let hid = HidReaderWriter::<_, 1, 8>::new_keyboard(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index badb65e98..8d035d0d5 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -65,6 +65,10 @@ async fn main(_spawner: Spawner) { config.manufacturer = Some("Embassy"); config.product = Some("HID mouse example"); config.serial_number = Some("12345678"); + config.composite_with_iads = false; + config.device_class = 0; + config.device_sub_class = 0; + config.device_protocol = 0; // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. @@ -93,7 +97,7 @@ async fn main(_spawner: Spawner) { max_packet_size: 8, }; - let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); + let mut writer = HidWriter::<_, 5>::new_mouse(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index 3f8c52b82..6f9200548 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs @@ -48,6 +48,10 @@ async fn main(_spawner: Spawner) { config.serial_number = Some("12345678"); config.max_power = 100; config.max_packet_size_0 = 64; + config.composite_with_iads = false; + config.device_class = 0; + config.device_sub_class = 0; + config.device_protocol = 0; // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. @@ -75,7 +79,7 @@ async fn main(_spawner: Spawner) { max_packet_size: 8, }; - let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); + let mut writer = HidWriter::<_, 5>::new_mouse(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); -- cgit From 8eebeceb16fc5ef15285c62d21b8ea65b9baf6ee Mon Sep 17 00:00:00 2001 From: matteo Date: Tue, 23 Sep 2025 20:51:58 +0200 Subject: working nrf52840 examples --- examples/nrf52840/Cargo.toml | 2 +- examples/nrf52840/src/bin/usb_hid_keyboard.rs | 49 +++++++++++++++++++++------ examples/nrf52840/src/bin/usb_hid_mouse.rs | 47 +++++++++++++++++++------ 3 files changed, 76 insertions(+), 22 deletions(-) diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 452e83b7e..9a1fc080e 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -28,7 +28,7 @@ cortex-m-rt = "0.7.0" panic-probe = { version = "1.0.0", features = ["print-defmt"] } rand = { version = "0.9.0", default-features = false } embedded-storage = "0.3.1" -usbd-hid = "0.8.1" +usbd-hid = { version = "0.8.1", features = ["defmt"] } serde = { version = "1.0.136", default-features = false } embedded-hal = { version = "1.0" } embedded-hal-async = { version = "1.0" } diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index 0f0d830c6..a4931099a 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -use core::sync::atomic::{AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use defmt::*; use embassy_executor::Spawner; @@ -17,6 +17,7 @@ use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Config, Handler}; use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; +use usbd_hid::hid_class::HidProtocolMode; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -26,6 +27,8 @@ bind_interrupts!(struct Irqs { static SUSPENDED: AtomicBool = AtomicBool::new(false); +static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); @@ -110,6 +113,11 @@ async fn main(_spawner: Spawner) { if SUSPENDED.load(Ordering::Acquire) { info!("Triggering remote wakeup"); remote_wakeup.signal(()); + } else if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { + match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await { + Ok(()) => {} + Err(e) => warn!("Failed to send boot report: {:?}", e), + }; } else { let report = KeyboardReport { keycodes: [4, 0, 0, 0, 0, 0], @@ -125,16 +133,23 @@ async fn main(_spawner: Spawner) { button.wait_for_high().await; info!("RELEASED"); - let report = KeyboardReport { - keycodes: [0, 0, 0, 0, 0, 0], - leds: 0, - modifier: 0, - reserved: 0, - }; - match writer.write_serialize(&report).await { - Ok(()) => {} - Err(e) => warn!("Failed to send report: {:?}", e), - }; + if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { + match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await { + Ok(()) => {} + Err(e) => warn!("Failed to send boot report: {:?}", e), + }; + } else { + let report = KeyboardReport { + keycodes: [0, 0, 0, 0, 0, 0], + leds: 0, + modifier: 0, + reserved: 0, + }; + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + }; + } } }; @@ -160,6 +175,18 @@ impl RequestHandler for MyRequestHandler { OutResponse::Accepted } + fn get_protocol(&self) -> HidProtocolMode { + let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed)); + info!("The current HID protocol mode is: {}", protocol); + protocol + } + + fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse { + info!("Switching to HID protocol mode: {}", protocol); + HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed); + OutResponse::Accepted + } + fn set_idle_ms(&mut self, id: Option, dur: u32) { info!("Set idle rate for {:?} to {:?}", id, dur); } diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index b3d90354b..6ec8a2d33 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs @@ -1,6 +1,8 @@ #![no_std] #![no_main] +use core::sync::atomic::{AtomicU8, Ordering}; + use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; @@ -12,6 +14,7 @@ use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Config}; use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; +use usbd_hid::hid_class::HidProtocolMode; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -19,6 +22,8 @@ bind_interrupts!(struct Irqs { CLOCK_POWER => usb::vbus_detect::InterruptHandler; }); +static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); @@ -84,16 +89,26 @@ async fn main(_spawner: Spawner) { Timer::after_millis(500).await; y = -y; - let report = MouseReport { - buttons: 0, - x: 0, - y, - wheel: 0, - pan: 0, - }; - match writer.write_serialize(&report).await { - Ok(()) => {} - Err(e) => warn!("Failed to send report: {:?}", e), + + if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { + let buttons = 0u8; + let x = 0i8; + match writer.write(&[buttons, x as u8, y as u8]).await { + Ok(()) => {} + Err(e) => warn!("Failed to send boot report: {:?}", e), + } + } else { + let report = MouseReport { + buttons: 0, + x: 0, + y, + wheel: 0, + pan: 0, + }; + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + } } } }; @@ -116,6 +131,18 @@ impl RequestHandler for MyRequestHandler { OutResponse::Accepted } + fn get_protocol(&self) -> HidProtocolMode { + let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed)); + info!("The current HID protocol mode is: {}", protocol); + protocol + } + + fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse { + info!("Switching to HID protocol mode: {}", protocol); + HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed); + OutResponse::Accepted + } + fn set_idle_ms(&mut self, id: Option, dur: u32) { info!("Set idle rate for {:?} to {:?}", id, dur); } -- cgit From bbb2a1ca5359f4a31c91aed9fe5fa347bef4d3f1 Mon Sep 17 00:00:00 2001 From: everdrone Date: Wed, 24 Sep 2025 14:02:34 +0200 Subject: Add clock initialization to N6 --- embassy-stm32/src/rcc/n6.rs | 222 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 219 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs index 68627edfd..c8dae6303 100644 --- a/embassy-stm32/src/rcc/n6.rs +++ b/embassy-stm32/src/rcc/n6.rs @@ -1,11 +1,61 @@ +use stm32_metapac::rcc::vals::{Cpusws, Hseext, Hsitrim, Pllsel, Syssws}; +pub use stm32_metapac::rcc::vals::{Hsidiv as HsiPrescaler, Hsitrim as HsiCalibration, Syssw as Sysclk}; + +use crate::pac::{PWR, RCC, SYSCFG}; +use crate::time::Hertz; + +pub const HSI_FREQ: Hertz = Hertz(64_000_000); + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum HseMode { + /// crystal/ceramic oscillator + Oscillator, + /// oscillator bypassed with external clock (analog) + Bypass, + /// oscillator bypassed with external digital clock + BypassDigital, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Hse { + /// HSE frequency. + pub freq: Hertz, + /// HSE oscillator mode. + pub mode: HseMode, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Hsi { + pub pre: HsiPrescaler, + pub calib: Hsitrim, +} + +#[derive(Clone, Copy, PartialEq)] +pub enum SupplyConfig { + Smps, + External, +} + /// Configuration of the core clocks #[non_exhaustive] #[derive(Clone, Copy)] -pub struct Config {} +pub struct Config { + pub hsi: Option, + pub hse: Option, + pub sys: Sysclk, + + pub supply_config: SupplyConfig, +} impl Config { pub const fn new() -> Self { - Self {} + Self { + hsi: None, + hse: None, + sys: Sysclk::HSI, + + supply_config: SupplyConfig::Smps, + } } } @@ -15,6 +65,172 @@ impl Default for Config { } } +fn power_supply_config(supply_config: SupplyConfig) { + // power supply config + PWR.cr1().modify(|w| { + w.set_sden(match supply_config { + SupplyConfig::External => false, + SupplyConfig::Smps => true, + }); + }); + + // Validate supply configuration + while !PWR.voscr().read().actvosrdy() {} +} + +fn osc_config(config: Config) -> (Option, Option) { + let (cpu_clk_src, sys_clk_src) = { + let cfgr = RCC.cfgr().read(); + (cfgr.cpusws(), cfgr.syssws()) + }; + let pll1_clk_src = RCC.pll1cfgr1().read().pllsel(); + let pll2_clk_src = RCC.pll2cfgr1().read().pllsel(); + let pll3_clk_src = RCC.pll3cfgr1().read().pllsel(); + let pll4_clk_src = RCC.pll4cfgr1().read().pllsel(); + let sr = RCC.sr().read(); + + let hsi = match config.hsi { + None => { + if (cpu_clk_src == Cpusws::HSI || sys_clk_src == Syssws::HSI) + || (pll1_clk_src == Pllsel::HSI && sr.pllrdy(0)) + || (pll2_clk_src == Pllsel::HSI && sr.pllrdy(1)) + || (pll3_clk_src == Pllsel::HSI && sr.pllrdy(2)) + || (pll4_clk_src == Pllsel::HSI && sr.pllrdy(3)) + { + if config.hse.is_none() { + panic!("When the HSI is used as CPU or system bus clock source, it is not allowed to be disabled"); + } + } else { + // disable the HSI + RCC.ccr().write(|w| w.set_hsionc(true)); + // wait until HSI is disabled + while RCC.sr().read().hsirdy() {} + } + + None + } + Some(hsi_config) => { + RCC.hsicfgr().modify(|w| { + w.set_hsidiv(hsi_config.pre); + w.set_hsitrim(hsi_config.calib); + }); + Some(HSI_FREQ / hsi_config.pre) + } + }; + + let hse = match config.hse { + None => { + if ((cpu_clk_src == Cpusws::HSE || sys_clk_src == Syssws::HSE) + || (pll1_clk_src == Pllsel::HSE && sr.pllrdy(0)) + || (pll2_clk_src == Pllsel::HSE && sr.pllrdy(1)) + || (pll3_clk_src == Pllsel::HSE && sr.pllrdy(2)) + || (pll4_clk_src == Pllsel::HSE && sr.pllrdy(3))) + && config.hse.is_none() + { + panic!("When the HSE is used as CPU or system bus clock source, it is not allowed to be disabled"); + } + + // hse off + RCC.csr().modify(|w| w.set_hseons(false)); + RCC.hsecfgr().modify(|w| { + w.set_hseext(Hseext::ANALOG); + w.set_hsebyp(false); + }); + + // wait until hse is off + while RCC.sr().read().hserdy() {} + + None + } + Some(hse_config) => { + match hse_config.mode { + HseMode::Oscillator => RCC.csr().modify(|w| w.set_hseons(true)), + HseMode::Bypass => { + RCC.hsecfgr().modify(|w| { + w.set_hsebyp(true); + w.set_hseext(Hseext::ANALOG); + }); + RCC.csr().modify(|w| w.set_hseons(true)); + } + HseMode::BypassDigital => { + RCC.hsecfgr().modify(|w| { + w.set_hsebyp(true); + w.set_hseext(Hseext::DIGITAL) + }); + } + }; + + // wait until the hse is ready + while !RCC.sr().read().hserdy() {} + + Some(hse_config.freq) + } + }; + + (hsi, hse) +} + pub(crate) unsafe fn init(config: Config) { - todo!() + // system configuration setup + RCC.apb4hensr().write(|w| w.set_syscfgens(true)); + // delay after RCC peripheral clock enabling + core::ptr::read_volatile(RCC.apb4hensr().as_ptr()); + + let vtor = unsafe { + let p = cortex_m::Peripherals::steal(); + p.SCB.vtor.read() + }; + + // set default vector table location after reset or standby + SYSCFG.initsvtorcr().write(|w| w.set_svtor_addr(vtor)); + // read back the value to ensure it is written before deactivating SYSCFG + core::ptr::read_volatile(SYSCFG.initsvtorcr().as_ptr()); + + // deactivate SYSCFG + RCC.apb4hensr().write(|w| w.set_syscfgens(false)); + + // enable fpu + unsafe { + let p = cortex_m::Peripherals::steal(); + p.SCB.cpacr.modify(|w| w | (3 << 20) | (3 << 22)); + } + + power_supply_config(config.supply_config); + + let (hsi, hse) = osc_config(config); + + let sys = match config.sys { + Sysclk::HSE => unwrap!(hse), + Sysclk::HSI => unwrap!(hsi), + Sysclk::MSI => todo!(), + Sysclk::IC2 => todo!(), + }; + + // TODO: sysb, sysc, sysd must have the same clock source + + set_clocks!( + sys: Some(sys), + hsi: hsi, + hsi_div: None, + hse: hse, + hclk1: None, + hclk2: None, + hclk3: None, + hclk4: None, + hclk5: None, + pclk1: None, + pclk2: None, + pclk2_tim: None, + pclk4: None, + pclk5: None, + per: None, + rtc: None, + msi: None, + i2s_ckin: None, + ic8: None, + ic9: None, + ic14: None, + ic17: None, + ic20: None, + ); } -- cgit From 81cc2f1e9fe76ad6584b6ecc8bc855946bd131b0 Mon Sep 17 00:00:00 2001 From: everdrone Date: Wed, 24 Sep 2025 14:03:41 +0200 Subject: Add helix cargo settings overrides --- .helix/languages.toml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .helix/languages.toml diff --git a/.helix/languages.toml b/.helix/languages.toml new file mode 100644 index 000000000..d34df4b24 --- /dev/null +++ b/.helix/languages.toml @@ -0,0 +1,11 @@ +[language-server.rust-analyzer.config.cargo] +allTargets = false +noDefaultFeatures = true +target = "thumbv8m.main-none-eabihf" +features = ["stm32n657x0", "time-driver-any", "unstable-pac", "exti"] + +[language-server.rust-analyzer.config.check] +allTargets = false +noDefaultFeatures = true +target = "thumbv8m.main-none-eabihf" +features = ["stm32n657x0", "time-driver-any", "unstable-pac", "exti"] -- cgit From 791ce77dba0a9302ebb1ec0aaca0b121b6cf554e Mon Sep 17 00:00:00 2001 From: everdrone Date: Sat, 27 Sep 2025 15:47:48 +0200 Subject: Port RCC initialization from CMSIS HAL --- embassy-stm32/src/rcc/n6.rs | 640 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 550 insertions(+), 90 deletions(-) diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs index c8dae6303..08ea2fc4e 100644 --- a/embassy-stm32/src/rcc/n6.rs +++ b/embassy-stm32/src/rcc/n6.rs @@ -1,10 +1,15 @@ -use stm32_metapac::rcc::vals::{Cpusws, Hseext, Hsitrim, Pllsel, Syssws}; -pub use stm32_metapac::rcc::vals::{Hsidiv as HsiPrescaler, Hsitrim as HsiCalibration, Syssw as Sysclk}; +use stm32_metapac::rcc::vals::{ + Cpusw, Cpusws, Hseext, Hsitrim, Icint, Icsel, Msifreqsel, Plldivm, Pllmodssdis, Pllpdiv, Pllsel, Syssw, Syssws, +}; +pub use stm32_metapac::rcc::vals::{ + Hpre as AhbPrescaler, Hsidiv as HsiPrescaler, Hsitrim as HsiCalibration, Ppre as ApbPrescaler, +}; use crate::pac::{PWR, RCC, SYSCFG}; use crate::time::Hertz; pub const HSI_FREQ: Hertz = Hertz(64_000_000); +pub const LSE_FREQ: Hertz = Hertz(32_768); #[derive(Clone, Copy, Eq, PartialEq)] pub enum HseMode { @@ -27,7 +32,7 @@ pub struct Hse { #[derive(Clone, Copy, Eq, PartialEq)] pub struct Hsi { pub pre: HsiPrescaler, - pub calib: Hsitrim, + pub trim: Hsitrim, } #[derive(Clone, Copy, PartialEq)] @@ -36,13 +41,108 @@ pub enum SupplyConfig { External, } +#[derive(Clone, Copy, PartialEq)] +pub enum CpuClk { + Hse, + Pll { source: Icsel, divider: Icint }, + Msi, + Hsi, +} + +impl CpuClk { + const fn to_bits(self) -> u8 { + match self { + Self::Hsi => 0x0, + Self::Msi => 0x1, + Self::Hse => 0x2, + Self::Pll { .. } => 0x3, + } + } +} + +#[derive(Clone, Copy, PartialEq)] +pub struct IcConfig { + source: Icsel, + divider: Icint, +} + +#[derive(Clone, Copy, PartialEq)] +pub enum SysClk { + Hse, + Pll { + ic2: IcConfig, + ic6: IcConfig, + ic11: IcConfig, + }, + Msi, + Hsi, +} + +impl SysClk { + const fn to_bits(self) -> u8 { + match self { + Self::Hsi => 0x0, + Self::Msi => 0x1, + Self::Hse => 0x2, + Self::Pll { .. } => 0x3, + } + } +} + +#[derive(Clone, Copy, PartialEq)] +pub struct Msi { + pub freq: Msifreqsel, + pub trim: u8, +} + +#[derive(Clone, Copy, PartialEq)] +pub struct PllOscillator { + pub source: Pllsel, + pub divm: Plldivm, + pub fractional: u32, + pub divn: u16, + pub divp1: Pllpdiv, + pub divp2: Pllpdiv, +} + +#[derive(Clone, Copy, PartialEq)] +pub enum Pll { + Oscillator { + source: Pllsel, + m: Plldivm, + fractional: u32, + n: u16, + p1: Pllpdiv, + p2: Pllpdiv, + }, + Bypass { + source: Pllsel, + }, +} + /// Configuration of the core clocks #[non_exhaustive] #[derive(Clone, Copy)] pub struct Config { pub hsi: Option, pub hse: Option, - pub sys: Sysclk, + pub msi: Option, + pub lsi: bool, + pub lse: bool, + + pub sys: SysClk, + pub cpu: CpuClk, + + pub pll1: Option, + pub pll2: Option, + pub pll3: Option, + pub pll4: Option, + + pub ahb: AhbPrescaler, + pub apb1: ApbPrescaler, + pub apb2: ApbPrescaler, + pub apb4: ApbPrescaler, + pub apb5: ApbPrescaler, pub supply_config: SupplyConfig, } @@ -52,13 +152,160 @@ impl Config { Self { hsi: None, hse: None, - sys: Sysclk::HSI, + msi: None, + lsi: true, + lse: false, + sys: SysClk::Hsi, + cpu: CpuClk::Hsi, + pll1: None, + pll2: None, + pll3: None, + pll4: None, + + ahb: AhbPrescaler::DIV1, + apb1: ApbPrescaler::DIV1, + apb2: ApbPrescaler::DIV1, + apb4: ApbPrescaler::DIV1, + apb5: ApbPrescaler::DIV1, supply_config: SupplyConfig::Smps, } } } +fn HAL_RCC_ClockConfig(config: Config) { + // handle increasing dividers + debug!("configuring increasing pclk dividers"); + RCC.cfgr2().modify(|w| { + if config.apb1 > w.ppre1() { + debug!(" - APB1"); + w.set_ppre1(config.apb1); + } + if config.apb2 > w.ppre2() { + debug!(" - APB2"); + w.set_ppre2(config.apb2); + } + if config.apb4 > w.ppre4() { + debug!(" - APB4"); + w.set_ppre4(config.apb4); + } + if config.apb5 > w.ppre5() { + debug!(" - APB5"); + w.set_ppre5(config.apb5); + } + if config.ahb > w.hpre() { + debug!(" - AHB"); + w.set_hpre(config.ahb); + } + }); + // cpuclk + debug!("configuring cpuclk"); + match config.cpu { + CpuClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"), + CpuClk::Pll { source, divider } => { + if !RCC_IC_CheckPLLSources(RCC.iccfgr(0).read().icsel().to_bits(), source.to_bits()) { + panic!("ICx clock switch requires both origin and destination clock source to be active") + } + + RCC.iccfgr(0).write(|w| { + w.set_icsel(source); + w.set_icint(divider); + }); + RCC.divensr().modify(|w| w.set_ic1ens(true)); + } + CpuClk::Msi if !RCC.sr().read().msirdy() => panic!("MSI is not ready to be selected as CPU clock source"), + CpuClk::Hsi if !RCC.sr().read().hsirdy() => panic!("HSI is not ready to be selected as CPU clock source"), + _ => {} + } + // set source + let cpusw = Cpusw::from_bits(config.cpu.to_bits()); + RCC.cfgr().modify(|w| w.set_cpusw(cpusw)); + // wait for changes to take effect + while RCC.cfgr().read().cpusws() != Cpusws::from_bits(config.cpu.to_bits()) {} + + // sysclk + debug!("configuring sysclk"); + match config.sys { + SysClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"), + SysClk::Pll { ic2, ic6, ic11 } => { + if !RCC_IC_CheckPLLSources(RCC.iccfgr(1).read().icsel().to_bits(), ic2.source.to_bits()) { + panic!("IC2 clock switch requires both origin and destination clock source to be active") + } + if !RCC_IC_CheckPLLSources(RCC.iccfgr(5).read().icsel().to_bits(), ic6.source.to_bits()) { + panic!("IC6 clock switch requires both origin and destination clock source to be active") + } + if !RCC_IC_CheckPLLSources(RCC.iccfgr(10).read().icsel().to_bits(), ic11.source.to_bits()) { + panic!("IC11 clock switch requires both origin and destination clock source to be active") + } + + RCC.iccfgr(1).write(|w| { + w.set_icsel(ic2.source); + w.set_icint(ic2.divider); + }); + RCC.iccfgr(5).write(|w| { + w.set_icsel(ic6.source); + w.set_icint(ic6.divider); + }); + RCC.iccfgr(10).write(|w| { + w.set_icsel(ic11.source); + w.set_icint(ic11.divider); + }); + RCC.divensr().modify(|w| { + w.set_ic2ens(true); + w.set_ic6ens(true); + w.set_ic11ens(true); + }); + } + SysClk::Msi if !RCC.sr().read().msirdy() => panic!("MSI is not ready to be selected as CPU clock source"), + SysClk::Hsi if !RCC.sr().read().hsirdy() => panic!("HSI is not ready to be selected as CPU clock source"), + _ => {} + } + // switch the system bus clock + let syssw = Syssw::from_bits(config.sys.to_bits()); + RCC.cfgr().modify(|w| w.set_syssw(syssw)); + // wait for changes to be applied + while RCC.cfgr().read().syssws() != Syssws::from_bits(config.sys.to_bits()) {} + + // decreasing dividers + debug!("configuring decreasing pclk dividers"); + RCC.cfgr2().modify(|w| { + if config.ahb < w.hpre() { + debug!(" - AHB"); + w.set_hpre(config.ahb); + } + if config.apb1 < w.ppre1() { + debug!(" - APB1"); + w.set_ppre1(config.apb1); + } + if config.apb2 < w.ppre2() { + debug!(" - APB2"); + w.set_ppre2(config.apb2); + } + if config.apb4 < w.ppre4() { + debug!(" - APB4"); + w.set_ppre4(config.apb4); + } + if config.apb5 < w.ppre5() { + debug!(" - APB5"); + w.set_ppre5(config.apb5); + } + }); +} + +fn RCC_PLL_Source_IsReady(source: u8) -> bool { + match source { + 0x0 if !RCC.sr().read().pllrdy(0) && !RCC.pllcfgr1(0).read().pllbyp() => false, + 0x1 if !RCC.sr().read().pllrdy(1) && !RCC.pllcfgr1(1).read().pllbyp() => false, + 0x2 if !RCC.sr().read().pllrdy(2) && !RCC.pllcfgr1(2).read().pllbyp() => false, + 0x3 if !RCC.sr().read().pllrdy(3) && !RCC.pllcfgr1(3).read().pllbyp() => false, + _ => true, + } +} + +fn RCC_IC_CheckPLLSources(source1: u8, source2: u8) -> bool { + RCC_PLL_Source_IsReady(source1) && RCC_PLL_Source_IsReady(source2) +} + impl Default for Config { fn default() -> Self { Self::new() @@ -78,104 +325,310 @@ fn power_supply_config(supply_config: SupplyConfig) { while !PWR.voscr().read().actvosrdy() {} } -fn osc_config(config: Config) -> (Option, Option) { - let (cpu_clk_src, sys_clk_src) = { - let cfgr = RCC.cfgr().read(); - (cfgr.cpusws(), cfgr.syssws()) - }; - let pll1_clk_src = RCC.pll1cfgr1().read().pllsel(); - let pll2_clk_src = RCC.pll2cfgr1().read().pllsel(); - let pll3_clk_src = RCC.pll3cfgr1().read().pllsel(); - let pll4_clk_src = RCC.pll4cfgr1().read().pllsel(); - let sr = RCC.sr().read(); +fn pll_config(pll_config: Option, pll_index: usize) { + let cfgr1 = RCC.pllcfgr1(pll_index); + let cfgr2 = RCC.pllcfgr2(pll_index); + let cfgr3 = RCC.pllcfgr3(pll_index); + + match pll_config { + Some(Pll::Oscillator { + source, + m, + fractional, + n, + p1, + p2, + }) => { + // ensure pll is disabled + RCC.ccr().write(|w| w.set_pllonc(pll_index, true)); + while RCC.sr().read().pllrdy(pll_index) {} + + // ensure PLLxMODSSDIS=1 + cfgr3.modify(|w| w.set_pllmodssdis(Pllmodssdis::FRACTIONAL_DIVIDE)); + // clear bypass mode + cfgr1.modify(|w| w.set_pllbyp(false)); + // configure the pll clock source, mul and div factors + cfgr1.modify(|w| { + w.set_pllsel(source); + w.set_plldivm(m); + w.set_plldivn(n); + }); + cfgr3.modify(|w| { + w.set_pllpdiv1(p1); + w.set_pllpdiv2(p2); + }); + // configure pll divnfrac + cfgr2.modify(|w| w.set_plldivnfrac(fractional)); + // clear pllxmoddsen + cfgr3.modify(|w| w.set_pllmoddsen(false)); + // fractional mode + if fractional != 0 { + cfgr3.modify(|w| { + w.set_pllmoddsen(true); + w.set_plldacen(true); + }) + } + // enable pll post divider output + cfgr3.modify(|w| { + w.set_pllmodssrst(true); + w.set_pllpdiven(true); + }); + // enable the pll + RCC.csr().write(|w| w.pllons(pll_index)); + // wait until ready + while RCC.sr().read().pllrdy(pll_index) {} + } + Some(Pll::Bypass { source }) => { + // check if source is ready + if !RCC_PLL_Source_IsReady(source.to_bits()) { + panic!("PLL source is not ready") + } - let hsi = match config.hsi { + // ensure pll is disabled + RCC.ccr().write(|w| w.set_pllonc(pll_index, true)); + while RCC.sr().read().pllrdy(pll_index) {} + + cfgr1.modify(|w| { + w.set_pllbyp(true); + w.set_pllsel(source); + }) + } None => { - if (cpu_clk_src == Cpusws::HSI || sys_clk_src == Syssws::HSI) - || (pll1_clk_src == Pllsel::HSI && sr.pllrdy(0)) - || (pll2_clk_src == Pllsel::HSI && sr.pllrdy(1)) - || (pll3_clk_src == Pllsel::HSI && sr.pllrdy(2)) - || (pll4_clk_src == Pllsel::HSI && sr.pllrdy(3)) - { - if config.hse.is_none() { - panic!("When the HSI is used as CPU or system bus clock source, it is not allowed to be disabled"); - } - } else { - // disable the HSI - RCC.ccr().write(|w| w.set_hsionc(true)); - // wait until HSI is disabled - while RCC.sr().read().hsirdy() {} - } + cfgr3.modify(|w| w.set_pllpdiven(false)); + RCC.ccr().write(|w| w.set_pllonc(pll_index, true)); + // wait till disabled + while RCC.sr().read().pllrdy(pll_index) {} - None + // clear bypass mode + cfgr1.modify(|w| w.set_pllbyp(false)); } - Some(hsi_config) => { - RCC.hsicfgr().modify(|w| { - w.set_hsidiv(hsi_config.pre); - w.set_hsitrim(hsi_config.calib); - }); - Some(HSI_FREQ / hsi_config.pre) + } +} + +fn HAL_RCC_OscConfig(config: Config) { + let (cpu_src, sys_src) = { + let reg = RCC.cfgr().read(); + (reg.cpusws(), reg.syssws()) + }; + let pll1_src = RCC.pllcfgr1(0).read().pllsel(); + let pll2_src = RCC.pllcfgr1(1).read().pllsel(); + let pll3_src = RCC.pllcfgr1(2).read().pllsel(); + let pll4_src = RCC.pllcfgr1(3).read().pllsel(); + let rcc_sr = RCC.sr().read(); + + debug!("configuring HSE"); + + // hse configuration + let hse = if let Some(hse) = config.hse { + match hse.mode { + HseMode::Oscillator => { + debug!("HSE in oscillator mode"); + } + HseMode::Bypass => { + debug!("HSE in bypass mode"); + RCC.hsecfgr().modify(|w| { + w.set_hsebyp(true); + w.set_hseext(Hseext::ANALOG); + }); + } + HseMode::BypassDigital => { + debug!("HSE in bypass digital mode"); + RCC.hsecfgr().modify(|w| { + w.set_hsebyp(true); + w.set_hseext(Hseext::DIGITAL); + }); + } } + RCC.csr().write(|w| w.set_hseons(true)); + + // wait until the hse is ready + while !RCC.sr().read().hserdy() {} + + Some(hse.freq) + } else if cpu_src == Cpusws::HSE + || sys_src == Syssws::HSE + || (pll1_src == Pllsel::HSE && rcc_sr.pllrdy(0)) + || (pll2_src == Pllsel::HSE && rcc_sr.pllrdy(1)) + || (pll3_src == Pllsel::HSE && rcc_sr.pllrdy(2)) + || (pll4_src == Pllsel::HSE && rcc_sr.pllrdy(3)) + { + panic!("When the HSE is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"); + } else { + debug!("HSE off"); + + RCC.ccr().write(|w| w.set_hseonc(true)); + RCC.hsecfgr().modify(|w| { + w.set_hseext(Hseext::ANALOG); + w.set_hsebyp(false); + }); + + // wait until the hse is disabled + while RCC.sr().read().hserdy() {} + + None }; - let hse = match config.hse { - None => { - if ((cpu_clk_src == Cpusws::HSE || sys_clk_src == Syssws::HSE) - || (pll1_clk_src == Pllsel::HSE && sr.pllrdy(0)) - || (pll2_clk_src == Pllsel::HSE && sr.pllrdy(1)) - || (pll3_clk_src == Pllsel::HSE && sr.pllrdy(2)) - || (pll4_clk_src == Pllsel::HSE && sr.pllrdy(3))) - && config.hse.is_none() - { - panic!("When the HSE is used as CPU or system bus clock source, it is not allowed to be disabled"); + // hsi configuration + debug!("configuring HSI"); + let hsi = if let Some(hsi) = config.hsi { + RCC.csr().write(|w| w.set_hsions(true)); + while !RCC.sr().read().hsirdy() {} + + // set divider and calibration + RCC.hsicfgr().modify(|w| { + w.set_hsidiv(hsi.pre); + w.set_hsitrim(hsi.trim); + }); + + Some(HSI_FREQ / hsi.pre) + } else if cpu_src == Cpusws::HSI + || sys_src == Syssws::HSI + || (pll1_src == Pllsel::HSI && rcc_sr.pllrdy(0)) + || (pll2_src == Pllsel::HSI && rcc_sr.pllrdy(1)) + || (pll3_src == Pllsel::HSI && rcc_sr.pllrdy(2)) + || (pll4_src == Pllsel::HSI && rcc_sr.pllrdy(3)) + { + panic!("When the HSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"); + } else { + debug!("HSI off"); + + RCC.ccr().write(|w| w.set_hsionc(true)); + while RCC.sr().read().hsirdy() {} + + None + }; + + // msi configuration + debug!("configuring MSI"); + let msi = if let Some(msi) = config.msi { + RCC.msicfgr().modify(|w| w.set_msifreqsel(msi.freq)); + RCC.csr().write(|w| w.set_msions(true)); + while !RCC.sr().read().msirdy() {} + RCC.msicfgr().modify(|w| w.set_msitrim(msi.trim)); + + Some(match msi.freq { + Msifreqsel::_4MHZ => Hertz::mhz(4), + Msifreqsel::_16MHZ => Hertz::mhz(16), + }) + } else if cpu_src == Cpusws::MSI + || sys_src == Syssws::MSI + || (pll1_src == Pllsel::MSI && rcc_sr.pllrdy(0)) + || (pll2_src == Pllsel::MSI && rcc_sr.pllrdy(1)) + || (pll3_src == Pllsel::MSI && rcc_sr.pllrdy(2)) + || (pll4_src == Pllsel::MSI && rcc_sr.pllrdy(3)) + { + panic!("When the MSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"); + } else { + RCC.ccr().write(|w| w.set_msionc(true)); + while RCC.sr().read().msirdy() {} + + None + }; + + // lsi configuration + debug!("configuring LSI"); + let lsi = if config.lsi { + RCC.csr().write(|w| w.set_lsions(true)); + while !RCC.sr().read().lsirdy() {} + Some(super::LSI_FREQ) + } else { + RCC.ccr().write(|w| w.set_lsionc(true)); + while RCC.sr().read().lsirdy() {} + None + }; + + // lse configuration + debug!("configuring LSE"); + let lse = if config.lse { + RCC.csr().write(|w| w.set_lseons(true)); + while !RCC.sr().read().lserdy() {} + Some(LSE_FREQ) + } else { + RCC.ccr().write(|w| w.set_lseonc(true)); + while RCC.sr().read().lserdy() {} + None + }; + + // pll1,2,3,4 config + let pll_configs = [config.pll1, config.pll2, config.pll3, config.pll4]; + for (n, &pll) in pll_configs.iter().enumerate() { + debug!("configuring PLL{}", n + 1); + let pll_ready = RCC.sr().read().pllrdy(n); + + if RCC_PLL_IsNewConfig(pll, 0) { + let ic1_src = RCC.iccfgr(0).read().icsel(); + let ic2_src = RCC.iccfgr(1).read().icsel(); + let ic6_src = RCC.iccfgr(5).read().icsel(); + let ic11_src = RCC.iccfgr(10).read().icsel(); + + let this_pll = Icsel::from_bits(n as u8); + + if cpu_src == Cpusws::IC1 && ic1_src == this_pll { + panic!("PLL should not be disabled / reconfigured if used for IC1 (cpuclksrc)") } - // hse off - RCC.csr().modify(|w| w.set_hseons(false)); - RCC.hsecfgr().modify(|w| { - w.set_hseext(Hseext::ANALOG); - w.set_hsebyp(false); - }); + if sys_src == Syssws::IC2 && (ic2_src == this_pll || ic6_src == this_pll || ic11_src == this_pll) { + panic!("PLL should not be disabled / reconfigured if used for IC2, IC6 or IC11 (sysclksrc)") + } - // wait until hse is off - while RCC.sr().read().hserdy() {} - - None - } - Some(hse_config) => { - match hse_config.mode { - HseMode::Oscillator => RCC.csr().modify(|w| w.set_hseons(true)), - HseMode::Bypass => { - RCC.hsecfgr().modify(|w| { - w.set_hsebyp(true); - w.set_hseext(Hseext::ANALOG); - }); - RCC.csr().modify(|w| w.set_hseons(true)); - } - HseMode::BypassDigital => { - RCC.hsecfgr().modify(|w| { - w.set_hsebyp(true); - w.set_hseext(Hseext::DIGITAL) - }); - } - }; - - // wait until the hse is ready - while !RCC.sr().read().hserdy() {} - - Some(hse_config.freq) + pll_config(pll, 0); + } else if pll.is_some() && !pll_ready { + debug!("PLL{} off", n + 1); + RCC.csr().write(|w| w.pllons(n)); + while !RCC.sr().read().pllrdy(n) {} } - }; + } +} + +fn RCC_PLL_IsNewConfig(pll: Option, pll_index: usize) -> bool { + let cfgr1 = RCC.pllcfgr1(pll_index).read(); + let cfgr2 = RCC.pllcfgr2(pll_index).read(); + let cfgr3 = RCC.pllcfgr3(pll_index).read(); + + let ready = RCC.sr().read().pllrdy(pll_index); + let bypass = cfgr1.pllbyp(); + + match (pll, ready, bypass) { + (None, true, _) => return true, + (Some(_), false, _) => return true, + (Some(conf), true, bypass) => match (conf, bypass) { + (Pll::Bypass { .. }, false) => return true, + (Pll::Oscillator { .. }, true) => return true, + _ => {} + }, + _ => {} + } - (hsi, hse) + match pll { + Some(Pll::Bypass { source }) => cfgr1.pllsel() != source, + Some(Pll::Oscillator { + source, + m, + fractional, + n, + p1, + p2, + }) => { + cfgr1.pllsel() != source + || cfgr1.plldivm() != m + || cfgr1.plldivn() != n + || cfgr2.plldivnfrac() != fractional + || cfgr3.pllpdiv1() != p1 + || cfgr3.pllpdiv2() != p2 + } + None => false, + } } pub(crate) unsafe fn init(config: Config) { + debug!("enabling SYSCFG"); // system configuration setup RCC.apb4hensr().write(|w| w.set_syscfgens(true)); // delay after RCC peripheral clock enabling core::ptr::read_volatile(RCC.apb4hensr().as_ptr()); + debug!("setting VTOR"); + let vtor = unsafe { let p = cortex_m::Peripherals::steal(); p.SCB.vtor.read() @@ -186,33 +639,40 @@ pub(crate) unsafe fn init(config: Config) { // read back the value to ensure it is written before deactivating SYSCFG core::ptr::read_volatile(SYSCFG.initsvtorcr().as_ptr()); + debug!("deactivating SYSCFG"); + // deactivate SYSCFG RCC.apb4hensr().write(|w| w.set_syscfgens(false)); + debug!("enabling FPU"); + // enable fpu unsafe { let p = cortex_m::Peripherals::steal(); p.SCB.cpacr.modify(|w| w | (3 << 20) | (3 << 22)); } + debug!("setting power supply config"); + power_supply_config(config.supply_config); - let (hsi, hse) = osc_config(config); + HAL_RCC_OscConfig(config); + HAL_RCC_ClockConfig(config); let sys = match config.sys { - Sysclk::HSE => unwrap!(hse), - Sysclk::HSI => unwrap!(hsi), - Sysclk::MSI => todo!(), - Sysclk::IC2 => todo!(), + SysClk::Hse => todo!(), + SysClk::Hsi => Hertz(64_000_000), + SysClk::Msi => todo!(), + SysClk::Pll { .. } => todo!(), }; // TODO: sysb, sysc, sysd must have the same clock source set_clocks!( sys: Some(sys), - hsi: hsi, + hsi: None, hsi_div: None, - hse: hse, + hse: None, hclk1: None, hclk2: None, hclk3: None, -- cgit From 2674462a4d21b4901fceb32f6534160a44d1a564 Mon Sep 17 00:00:00 2001 From: everdrone Date: Sat, 27 Sep 2025 16:00:39 +0200 Subject: Use nicer names in N6 RCC --- embassy-stm32/src/rcc/n6.rs | 81 +++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs index 08ea2fc4e..51fc8cdc8 100644 --- a/embassy-stm32/src/rcc/n6.rs +++ b/embassy-stm32/src/rcc/n6.rs @@ -95,25 +95,15 @@ pub struct Msi { pub trim: u8, } -#[derive(Clone, Copy, PartialEq)] -pub struct PllOscillator { - pub source: Pllsel, - pub divm: Plldivm, - pub fractional: u32, - pub divn: u16, - pub divp1: Pllpdiv, - pub divp2: Pllpdiv, -} - #[derive(Clone, Copy, PartialEq)] pub enum Pll { Oscillator { source: Pllsel, - m: Plldivm, + divm: Plldivm, fractional: u32, - n: u16, - p1: Pllpdiv, - p2: Pllpdiv, + divn: u16, + divp1: Pllpdiv, + divp2: Pllpdiv, }, Bypass { source: Pllsel, @@ -150,7 +140,10 @@ pub struct Config { impl Config { pub const fn new() -> Self { Self { - hsi: None, + hsi: Some(Hsi { + pre: HsiPrescaler::DIV1, + trim: HsiCalibration::from_bits(32), + }), hse: None, msi: None, lsi: true, @@ -173,7 +166,7 @@ impl Config { } } -fn HAL_RCC_ClockConfig(config: Config) { +fn init_clocks(config: Config) { // handle increasing dividers debug!("configuring increasing pclk dividers"); RCC.cfgr2().modify(|w| { @@ -203,7 +196,7 @@ fn HAL_RCC_ClockConfig(config: Config) { match config.cpu { CpuClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"), CpuClk::Pll { source, divider } => { - if !RCC_IC_CheckPLLSources(RCC.iccfgr(0).read().icsel().to_bits(), source.to_bits()) { + if !pll_sources_ready(RCC.iccfgr(0).read().icsel().to_bits(), source.to_bits()) { panic!("ICx clock switch requires both origin and destination clock source to be active") } @@ -228,13 +221,13 @@ fn HAL_RCC_ClockConfig(config: Config) { match config.sys { SysClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"), SysClk::Pll { ic2, ic6, ic11 } => { - if !RCC_IC_CheckPLLSources(RCC.iccfgr(1).read().icsel().to_bits(), ic2.source.to_bits()) { + if !pll_sources_ready(RCC.iccfgr(1).read().icsel().to_bits(), ic2.source.to_bits()) { panic!("IC2 clock switch requires both origin and destination clock source to be active") } - if !RCC_IC_CheckPLLSources(RCC.iccfgr(5).read().icsel().to_bits(), ic6.source.to_bits()) { + if !pll_sources_ready(RCC.iccfgr(5).read().icsel().to_bits(), ic6.source.to_bits()) { panic!("IC6 clock switch requires both origin and destination clock source to be active") } - if !RCC_IC_CheckPLLSources(RCC.iccfgr(10).read().icsel().to_bits(), ic11.source.to_bits()) { + if !pll_sources_ready(RCC.iccfgr(10).read().icsel().to_bits(), ic11.source.to_bits()) { panic!("IC11 clock switch requires both origin and destination clock source to be active") } @@ -292,7 +285,7 @@ fn HAL_RCC_ClockConfig(config: Config) { }); } -fn RCC_PLL_Source_IsReady(source: u8) -> bool { +fn pll_source_ready(source: u8) -> bool { match source { 0x0 if !RCC.sr().read().pllrdy(0) && !RCC.pllcfgr1(0).read().pllbyp() => false, 0x1 if !RCC.sr().read().pllrdy(1) && !RCC.pllcfgr1(1).read().pllbyp() => false, @@ -302,8 +295,8 @@ fn RCC_PLL_Source_IsReady(source: u8) -> bool { } } -fn RCC_IC_CheckPLLSources(source1: u8, source2: u8) -> bool { - RCC_PLL_Source_IsReady(source1) && RCC_PLL_Source_IsReady(source2) +fn pll_sources_ready(source1: u8, source2: u8) -> bool { + pll_source_ready(source1) && pll_source_ready(source2) } impl Default for Config { @@ -325,7 +318,7 @@ fn power_supply_config(supply_config: SupplyConfig) { while !PWR.voscr().read().actvosrdy() {} } -fn pll_config(pll_config: Option, pll_index: usize) { +fn init_pll(pll_config: Option, pll_index: usize) { let cfgr1 = RCC.pllcfgr1(pll_index); let cfgr2 = RCC.pllcfgr2(pll_index); let cfgr3 = RCC.pllcfgr3(pll_index); @@ -333,11 +326,11 @@ fn pll_config(pll_config: Option, pll_index: usize) { match pll_config { Some(Pll::Oscillator { source, - m, + divm, fractional, - n, - p1, - p2, + divn, + divp1, + divp2, }) => { // ensure pll is disabled RCC.ccr().write(|w| w.set_pllonc(pll_index, true)); @@ -350,12 +343,12 @@ fn pll_config(pll_config: Option, pll_index: usize) { // configure the pll clock source, mul and div factors cfgr1.modify(|w| { w.set_pllsel(source); - w.set_plldivm(m); - w.set_plldivn(n); + w.set_plldivm(divm); + w.set_plldivn(divn); }); cfgr3.modify(|w| { - w.set_pllpdiv1(p1); - w.set_pllpdiv2(p2); + w.set_pllpdiv1(divp1); + w.set_pllpdiv2(divp2); }); // configure pll divnfrac cfgr2.modify(|w| w.set_plldivnfrac(fractional)); @@ -380,7 +373,7 @@ fn pll_config(pll_config: Option, pll_index: usize) { } Some(Pll::Bypass { source }) => { // check if source is ready - if !RCC_PLL_Source_IsReady(source.to_bits()) { + if !pll_source_ready(source.to_bits()) { panic!("PLL source is not ready") } @@ -405,7 +398,7 @@ fn pll_config(pll_config: Option, pll_index: usize) { } } -fn HAL_RCC_OscConfig(config: Config) { +fn init_osc(config: Config) { let (cpu_src, sys_src) = { let reg = RCC.cfgr().read(); (reg.cpusws(), reg.syssws()) @@ -555,7 +548,7 @@ fn HAL_RCC_OscConfig(config: Config) { debug!("configuring PLL{}", n + 1); let pll_ready = RCC.sr().read().pllrdy(n); - if RCC_PLL_IsNewConfig(pll, 0) { + if is_new_pll_config(pll, 0) { let ic1_src = RCC.iccfgr(0).read().icsel(); let ic2_src = RCC.iccfgr(1).read().icsel(); let ic6_src = RCC.iccfgr(5).read().icsel(); @@ -571,7 +564,7 @@ fn HAL_RCC_OscConfig(config: Config) { panic!("PLL should not be disabled / reconfigured if used for IC2, IC6 or IC11 (sysclksrc)") } - pll_config(pll, 0); + init_pll(pll, 0); } else if pll.is_some() && !pll_ready { debug!("PLL{} off", n + 1); RCC.csr().write(|w| w.pllons(n)); @@ -580,7 +573,7 @@ fn HAL_RCC_OscConfig(config: Config) { } } -fn RCC_PLL_IsNewConfig(pll: Option, pll_index: usize) -> bool { +fn is_new_pll_config(pll: Option, pll_index: usize) -> bool { let cfgr1 = RCC.pllcfgr1(pll_index).read(); let cfgr2 = RCC.pllcfgr2(pll_index).read(); let cfgr3 = RCC.pllcfgr3(pll_index).read(); @@ -603,11 +596,11 @@ fn RCC_PLL_IsNewConfig(pll: Option, pll_index: usize) -> bool { Some(Pll::Bypass { source }) => cfgr1.pllsel() != source, Some(Pll::Oscillator { source, - m, + divm: m, fractional, - n, - p1, - p2, + divn: n, + divp1: p1, + divp2: p2, }) => { cfgr1.pllsel() != source || cfgr1.plldivm() != m @@ -656,8 +649,8 @@ pub(crate) unsafe fn init(config: Config) { power_supply_config(config.supply_config); - HAL_RCC_OscConfig(config); - HAL_RCC_ClockConfig(config); + init_osc(config); + init_clocks(config); let sys = match config.sys { SysClk::Hse => todo!(), @@ -680,7 +673,7 @@ pub(crate) unsafe fn init(config: Config) { hclk5: None, pclk1: None, pclk2: None, - pclk2_tim: None, + pclk2_tim: Some(Hertz(1_000_000)), // FIXME: what is this?? pclk4: None, pclk5: None, per: None, -- cgit From 97b0afb8d000bcc72582a09e3b9c2d7c33b66e7a Mon Sep 17 00:00:00 2001 From: everdrone Date: Sun, 28 Sep 2025 01:18:40 +0200 Subject: Calculate RCC frequencies --- embassy-stm32/src/gpio.rs | 6 +- embassy-stm32/src/rcc/n6.rs | 259 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 216 insertions(+), 49 deletions(-) diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index ba5cf24c6..5645f71cb 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -654,7 +654,7 @@ fn set_as_af(pin_port: PinNumber, af_num: u8, af_type: AfType) { let r = pin.block(); let n = pin._pin() as usize; - r.afr(n / 8).modify(|w| w.set_afr(n % 8, af_num as u8)); + r.afr(n / 8).modify(|w| w.set_afr(n % 8, af_num)); r.pupdr().modify(|w| w.set_pupdr(n, af_type.pupdr)); r.otyper().modify(|w| w.set_ot(n, af_type.ot)); r.ospeedr().modify(|w| w.set_ospeedr(n, af_type.ospeedr)); @@ -798,6 +798,10 @@ pub(crate) trait SealedPin { } } +/// GPIO pin number type. +/// +/// Some chips have a total number of ports that exceeds 8, a larger integer +/// is needed to hold the total pin number `(ports * number)`. #[cfg(not(stm32n6))] pub type PinNumber = u8; #[cfg(stm32n6)] diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs index 51fc8cdc8..5d2003325 100644 --- a/embassy-stm32/src/rcc/n6.rs +++ b/embassy-stm32/src/rcc/n6.rs @@ -1,5 +1,6 @@ use stm32_metapac::rcc::vals::{ Cpusw, Cpusws, Hseext, Hsitrim, Icint, Icsel, Msifreqsel, Plldivm, Pllmodssdis, Pllpdiv, Pllsel, Syssw, Syssws, + Timpre, }; pub use stm32_metapac::rcc::vals::{ Hpre as AhbPrescaler, Hsidiv as HsiPrescaler, Hsitrim as HsiCalibration, Ppre as ApbPrescaler, @@ -44,7 +45,7 @@ pub enum SupplyConfig { #[derive(Clone, Copy, PartialEq)] pub enum CpuClk { Hse, - Pll { source: Icsel, divider: Icint }, + Ic1 { source: Icsel, divider: Icint }, Msi, Hsi, } @@ -55,7 +56,7 @@ impl CpuClk { Self::Hsi => 0x0, Self::Msi => 0x1, Self::Hse => 0x2, - Self::Pll { .. } => 0x3, + Self::Ic1 { .. } => 0x3, } } } @@ -69,7 +70,7 @@ pub struct IcConfig { #[derive(Clone, Copy, PartialEq)] pub enum SysClk { Hse, - Pll { + Ic2 { ic2: IcConfig, ic6: IcConfig, ic11: IcConfig, @@ -84,7 +85,7 @@ impl SysClk { Self::Hsi => 0x0, Self::Msi => 0x1, Self::Hse => 0x2, - Self::Pll { .. } => 0x3, + Self::Ic2 { .. } => 0x3, } } } @@ -150,12 +151,12 @@ impl Config { lse: false, sys: SysClk::Hsi, cpu: CpuClk::Hsi, - pll1: None, - pll2: None, - pll3: None, - pll4: None, + pll1: Some(Pll::Bypass { source: Pllsel::HSI }), + pll2: Some(Pll::Bypass { source: Pllsel::HSI }), + pll3: Some(Pll::Bypass { source: Pllsel::HSI }), + pll4: Some(Pll::Bypass { source: Pllsel::HSI }), - ahb: AhbPrescaler::DIV1, + ahb: AhbPrescaler::DIV2, apb1: ApbPrescaler::DIV1, apb2: ApbPrescaler::DIV1, apb4: ApbPrescaler::DIV1, @@ -166,7 +167,24 @@ impl Config { } } -fn init_clocks(config: Config) { +struct ClocksOutput { + cpuclk: Hertz, + sysclk: Hertz, + pclk_tim: Hertz, + ahb: Hertz, + apb1: Hertz, + apb2: Hertz, + apb4: Hertz, + apb5: Hertz, +} + +struct ClocksInput { + hsi: Option, + msi: Option, + hse: Option, +} + +fn init_clocks(config: Config, input: &ClocksInput) -> ClocksOutput { // handle increasing dividers debug!("configuring increasing pclk dividers"); RCC.cfgr2().modify(|w| { @@ -195,7 +213,7 @@ fn init_clocks(config: Config) { debug!("configuring cpuclk"); match config.cpu { CpuClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"), - CpuClk::Pll { source, divider } => { + CpuClk::Ic1 { source, divider } => { if !pll_sources_ready(RCC.iccfgr(0).read().icsel().to_bits(), source.to_bits()) { panic!("ICx clock switch requires both origin and destination clock source to be active") } @@ -220,7 +238,7 @@ fn init_clocks(config: Config) { debug!("configuring sysclk"); match config.sys { SysClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"), - SysClk::Pll { ic2, ic6, ic11 } => { + SysClk::Ic2 { ic2, ic6, ic11 } => { if !pll_sources_ready(RCC.iccfgr(1).read().icsel().to_bits(), ic2.source.to_bits()) { panic!("IC2 clock switch requires both origin and destination clock source to be active") } @@ -283,6 +301,57 @@ fn init_clocks(config: Config) { w.set_ppre5(config.apb5); } }); + + let cpuclk = match config.cpu { + CpuClk::Hsi => unwrap!(input.hsi), + CpuClk::Msi => unwrap!(input.msi), + CpuClk::Hse => unwrap!(input.hse), + CpuClk::Ic1 { .. } => todo!(), + }; + + let sysclk = match config.sys { + SysClk::Hsi => unwrap!(input.hsi), + SysClk::Msi => unwrap!(input.msi), + SysClk::Hse => unwrap!(input.hse), + SysClk::Ic2 { .. } => todo!(), + }; + + let timpre: u32 = match RCC.cfgr2().read().timpre() { + Timpre::DIV1 => 1, + Timpre::DIV2 => 2, + Timpre::DIV4 => 4, + Timpre::_RESERVED_3 => 8, + }; + + let hpre = periph_prescaler_to_value(config.ahb.to_bits()); + let ppre1 = periph_prescaler_to_value(config.apb1.to_bits()); + let ppre2 = periph_prescaler_to_value(config.apb2.to_bits()); + let ppre4 = periph_prescaler_to_value(config.apb4.to_bits()); + let ppre5 = periph_prescaler_to_value(config.apb5.to_bits()); + + ClocksOutput { + sysclk, + cpuclk, + pclk_tim: sysclk / timpre, + ahb: Hertz(sysclk.0 / hpre as u32), + apb1: sysclk / hpre / ppre1, + apb2: sysclk / hpre / ppre2, + apb4: sysclk / hpre / ppre4, + apb5: sysclk / hpre / ppre5, + } +} + +const fn periph_prescaler_to_value(bits: u8) -> u8 { + match bits { + 0 => 1, + 1 => 2, + 2 => 4, + 3 => 8, + 4 => 16, + 5 => 32, + 6 => 64, + 7.. => 128, + } } fn pll_source_ready(source: u8) -> bool { @@ -318,7 +387,23 @@ fn power_supply_config(supply_config: SupplyConfig) { while !PWR.voscr().read().actvosrdy() {} } -fn init_pll(pll_config: Option, pll_index: usize) { +struct PllInput { + hsi: Option, + msi: Option, + hse: Option, + i2s_ckin: Option, +} + +#[derive(Clone, Copy, Default)] +struct PllOutput { + divm: Option, + divn: Option, + divp1: Option, + divp2: Option, + output: Option, +} + +fn init_pll(pll_config: Option, pll_index: usize, input: &PllInput) -> PllOutput { let cfgr1 = RCC.pllcfgr1(pll_index); let cfgr2 = RCC.pllcfgr2(pll_index); let cfgr3 = RCC.pllcfgr3(pll_index); @@ -336,7 +421,7 @@ fn init_pll(pll_config: Option, pll_index: usize) { RCC.ccr().write(|w| w.set_pllonc(pll_index, true)); while RCC.sr().read().pllrdy(pll_index) {} - // ensure PLLxMODSSDIS=1 + // ensure PLLxMODSSDIS=1 to work in fractional mode cfgr3.modify(|w| w.set_pllmodssdis(Pllmodssdis::FRACTIONAL_DIVIDE)); // clear bypass mode cfgr1.modify(|w| w.set_pllbyp(false)); @@ -346,10 +431,26 @@ fn init_pll(pll_config: Option, pll_index: usize) { w.set_plldivm(divm); w.set_plldivn(divn); }); + + let in_clk = match source { + Pllsel::HSI => unwrap!(input.hsi), + Pllsel::MSI => unwrap!(input.msi), + Pllsel::HSE => unwrap!(input.hse), + Pllsel::I2S_CKIN => unwrap!(input.i2s_ckin), + _ => panic!("reserved PLL source not allowed"), + }; + + let m = divm.to_bits() as u32; + let n = divn as u32; + cfgr3.modify(|w| { w.set_pllpdiv1(divp1); w.set_pllpdiv2(divp2); }); + + let p1 = divp1.to_bits() as u32; + let p2 = divp2.to_bits() as u32; + // configure pll divnfrac cfgr2.modify(|w| w.set_plldivnfrac(fractional)); // clear pllxmoddsen @@ -370,6 +471,14 @@ fn init_pll(pll_config: Option, pll_index: usize) { RCC.csr().write(|w| w.pllons(pll_index)); // wait until ready while RCC.sr().read().pllrdy(pll_index) {} + + PllOutput { + divm: Some(Hertz(m)), + divn: Some(Hertz(n)), + divp1: Some(Hertz(p1)), + divp2: Some(Hertz(p2)), + output: Some(Hertz(in_clk.0 / m / n / p1 / p2)), + } } Some(Pll::Bypass { source }) => { // check if source is ready @@ -384,7 +493,20 @@ fn init_pll(pll_config: Option, pll_index: usize) { cfgr1.modify(|w| { w.set_pllbyp(true); w.set_pllsel(source); - }) + }); + + let in_clk = match source { + Pllsel::HSI => unwrap!(input.hsi), + Pllsel::MSI => unwrap!(input.msi), + Pllsel::HSE => unwrap!(input.hse), + Pllsel::I2S_CKIN => unwrap!(input.i2s_ckin), + _ => panic!("reserved PLL source not allowed"), + }; + + PllOutput { + output: Some(in_clk), + ..Default::default() + } } None => { cfgr3.modify(|w| w.set_pllpdiven(false)); @@ -394,11 +516,29 @@ fn init_pll(pll_config: Option, pll_index: usize) { // clear bypass mode cfgr1.modify(|w| w.set_pllbyp(false)); + + PllOutput::default() } } } -fn init_osc(config: Config) { +struct OscOutput { + hsi: Option, + hse: Option, + msi: Option, + lsi: Option, + lse: Option, + pll1: Option, + pll2: Option, + pll3: Option, + pll4: Option, + ic1sel: Icsel, + ic2sel: Icsel, + ic6sel: Icsel, + ic11sel: Icsel, +} + +fn init_osc(config: Config) -> OscOutput { let (cpu_src, sys_src) = { let reg = RCC.cfgr().read(); (reg.cpusws(), reg.syssws()) @@ -542,18 +682,27 @@ fn init_osc(config: Config) { None }; + let pll_input = PllInput { + hse, + msi, + hsi, + i2s_ckin: None, + }; + // pll1,2,3,4 config let pll_configs = [config.pll1, config.pll2, config.pll3, config.pll4]; - for (n, &pll) in pll_configs.iter().enumerate() { + let mut pll_outputs: [PllOutput; 4] = [PllOutput::default(); 4]; + + let ic1_src = RCC.iccfgr(0).read().icsel(); + let ic2_src = RCC.iccfgr(1).read().icsel(); + let ic6_src = RCC.iccfgr(5).read().icsel(); + let ic11_src = RCC.iccfgr(10).read().icsel(); + + for (n, (&pll, out)) in pll_configs.iter().zip(pll_outputs.iter_mut()).enumerate() { debug!("configuring PLL{}", n + 1); let pll_ready = RCC.sr().read().pllrdy(n); if is_new_pll_config(pll, 0) { - let ic1_src = RCC.iccfgr(0).read().icsel(); - let ic2_src = RCC.iccfgr(1).read().icsel(); - let ic6_src = RCC.iccfgr(5).read().icsel(); - let ic11_src = RCC.iccfgr(10).read().icsel(); - let this_pll = Icsel::from_bits(n as u8); if cpu_src == Cpusws::IC1 && ic1_src == this_pll { @@ -564,13 +713,28 @@ fn init_osc(config: Config) { panic!("PLL should not be disabled / reconfigured if used for IC2, IC6 or IC11 (sysclksrc)") } - init_pll(pll, 0); + *out = init_pll(pll, 0, &pll_input); } else if pll.is_some() && !pll_ready { - debug!("PLL{} off", n + 1); RCC.csr().write(|w| w.pllons(n)); while !RCC.sr().read().pllrdy(n) {} } } + + OscOutput { + hsi, + hse, + msi, + lsi, + lse, + pll1: pll_outputs[0].output, + pll2: pll_outputs[1].output, + pll3: pll_outputs[2].output, + pll4: pll_outputs[3].output, + ic1sel: ic1_src, + ic2sel: ic2_src, + ic6sel: ic6_src, + ic11sel: ic11_src, + } } fn is_new_pll_config(pll: Option, pll_index: usize) -> bool { @@ -618,7 +782,7 @@ pub(crate) unsafe fn init(config: Config) { // system configuration setup RCC.apb4hensr().write(|w| w.set_syscfgens(true)); // delay after RCC peripheral clock enabling - core::ptr::read_volatile(RCC.apb4hensr().as_ptr()); + RCC.apb4hensr().read(); debug!("setting VTOR"); @@ -630,7 +794,7 @@ pub(crate) unsafe fn init(config: Config) { // set default vector table location after reset or standby SYSCFG.initsvtorcr().write(|w| w.set_svtor_addr(vtor)); // read back the value to ensure it is written before deactivating SYSCFG - core::ptr::read_volatile(SYSCFG.initsvtorcr().as_ptr()); + SYSCFG.initsvtorcr().read(); debug!("deactivating SYSCFG"); @@ -649,36 +813,35 @@ pub(crate) unsafe fn init(config: Config) { power_supply_config(config.supply_config); - init_osc(config); - init_clocks(config); - - let sys = match config.sys { - SysClk::Hse => todo!(), - SysClk::Hsi => Hertz(64_000_000), - SysClk::Msi => todo!(), - SysClk::Pll { .. } => todo!(), + let osc = init_osc(config); + let clock_inputs = ClocksInput { + hsi: osc.hsi, + msi: osc.msi, + hse: osc.hse, }; + let clocks = init_clocks(config, &clock_inputs); // TODO: sysb, sysc, sysd must have the same clock source set_clocks!( - sys: Some(sys), - hsi: None, + sys: Some(clocks.sysclk), + hsi: osc.hsi, hsi_div: None, - hse: None, - hclk1: None, - hclk2: None, - hclk3: None, - hclk4: None, - hclk5: None, - pclk1: None, - pclk2: None, - pclk2_tim: Some(Hertz(1_000_000)), // FIXME: what is this?? - pclk4: None, - pclk5: None, + hse: osc.hse, + msi: osc.msi, + hclk1: Some(clocks.ahb), + hclk2: Some(clocks.ahb), + hclk3: Some(clocks.ahb), + hclk4: Some(clocks.ahb), + hclk5: Some(clocks.ahb), + pclk1: Some(clocks.apb1), + pclk2: Some(clocks.apb2), + pclk1_tim: Some(clocks.pclk_tim), + pclk2_tim: Some(clocks.pclk_tim), + pclk4: Some(clocks.apb4), + pclk5: Some(clocks.apb5), per: None, rtc: None, - msi: None, i2s_ckin: None, ic8: None, ic9: None, -- cgit From 36d368d70e56181554b690687ef2c88a84704b0c Mon Sep 17 00:00:00 2001 From: pkj Date: Sun, 28 Sep 2025 21:13:17 +0800 Subject: stm32/timer: Support 32-bit timers in SimplePwm waveform_up method Add TimerBits matching following waveform method pattern to handle both 16-bit and 32-bit timer DMA transfers with appropriate pointer types. --- embassy-stm32/src/timer/simple_pwm.rs | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index e6165e42b..19c1610f7 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -339,14 +339,33 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { ..Default::default() }; - Transfer::new_write( - dma, - req, - duty, - self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, - dma_transfer_option, - ) - .await + match self.inner.bits() { + TimerBits::Bits16 => { + Transfer::new_write( + dma, + req, + duty, + self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16, + dma_transfer_option, + ) + .await + } + #[cfg(not(any(stm32l0)))] + TimerBits::Bits32 => { + #[cfg(not(any(bdma, gpdma)))] + panic!("unsupported timer bits"); + + #[cfg(any(bdma, gpdma))] + Transfer::new_write( + dma, + req, + duty, + self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32, + dma_transfer_option, + ) + .await + } + }; }; // restore output compare state -- cgit From 04171d903d3676d87aa0fd85719878d3087028f3 Mon Sep 17 00:00:00 2001 From: pkj Date: Sun, 28 Sep 2025 21:21:09 +0800 Subject: fix: correct register access for SimplePwm 32-bit timer support - Replace `regs_gp16().ccr()` with `regs_1ch().ccr()` for proper register access - Fix variable name from `cc_channel` to `channel` - Ensure PWM waveform generation works correctly with 32-bit timer mode --- embassy-stm32/src/timer/simple_pwm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 19c1610f7..e60bb5b06 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -345,7 +345,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { dma, req, duty, - self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16, + self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, dma_transfer_option, ) .await @@ -360,7 +360,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { dma, req, duty, - self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32, + self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32, dma_transfer_option, ) .await -- cgit From 5c8218b8750bed3f4bef7973e250aa830d8c2fe3 Mon Sep 17 00:00:00 2001 From: matteo Date: Tue, 30 Sep 2025 18:38:43 +0200 Subject: review comments --- embassy-usb/src/class/hid.rs | 134 ++++++++------------------ examples/nrf52840/Cargo.toml | 2 +- examples/nrf52840/src/bin/usb_hid_keyboard.rs | 9 +- examples/nrf52840/src/bin/usb_hid_mouse.rs | 9 +- examples/rp/src/bin/usb_hid_keyboard.rs | 6 +- examples/rp/src/bin/usb_hid_mouse.rs | 6 +- examples/rp235x/src/bin/usb_hid_keyboard.rs | 8 +- examples/stm32f4/src/bin/usb_hid_keyboard.rs | 6 +- examples/stm32f4/src/bin/usb_hid_mouse.rs | 6 +- examples/stm32l5/src/bin/usb_hid_mouse.rs | 6 +- 10 files changed, 78 insertions(+), 114 deletions(-) diff --git a/embassy-usb/src/class/hid.rs b/embassy-usb/src/class/hid.rs index b9830baeb..6723afbbc 100644 --- a/embassy-usb/src/class/hid.rs +++ b/embassy-usb/src/class/hid.rs @@ -8,8 +8,6 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use ssmarshal::serialize; #[cfg(feature = "usbd-hid")] use usbd_hid::descriptor::AsInputReport; -#[cfg(feature = "usbd-hid")] -use usbd_hid::hid_class::HidProtocolMode; use crate::control::{InResponse, OutResponse, Recipient, Request, RequestType}; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; @@ -18,13 +16,6 @@ use crate::{Builder, Handler}; const USB_CLASS_HID: u8 = 0x03; -const USB_SUBCLASS_REPORT_ONLY: u8 = 0x00; -const USB_SUBCLASS_BOOT_OR_REPORT: u8 = 0x01; - -const USB_PROTOCOL_NONE: u8 = 0x00; -const USB_PROTOCOL_KEYBOARD: u8 = 0x01; -const USB_PROTOCOL_MOUSE: u8 = 0x02; - // HID const HID_DESC_DESCTYPE_HID: u8 = 0x21; const HID_DESC_DESCTYPE_HID_REPORT: u8 = 0x22; @@ -40,7 +31,6 @@ const HID_REQ_SET_PROTOCOL: u8 = 0x0b; /// Get/Set Protocol mapping /// See (7.2.5 and 7.2.6): -#[cfg(not(feature = "usbd-hid"))] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] @@ -51,7 +41,6 @@ pub enum HidProtocolMode { Report = 1, } -#[cfg(not(feature = "usbd-hid"))] impl From for HidProtocolMode { fn from(mode: u8) -> HidProtocolMode { if mode == HidProtocolMode::Boot as u8 { @@ -62,6 +51,30 @@ impl From for HidProtocolMode { } } +/// USB HID interface subclass values. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum HidSubclass { + /// Only report mode is supported. + ReportOnly = 0, + /// Both boot and report mode are supported. + ReportOrBoot = 1, +} + +/// USB HID protocol values. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum HidBootProtocol { + /// No specific boot protocol. + None = 0, + /// Boot protocol keyboard. + Keyboard = 1, + /// Boot protocol mouse. + Mouse = 2, +} + /// Configuration for the HID class. pub struct Config<'d> { /// HID report descriptor. @@ -79,6 +92,12 @@ pub struct Config<'d> { /// Max packet size for both the IN and OUT endpoints. pub max_packet_size: u16, + + /// The HID subclass of this interface + pub hid_subclass: HidSubclass, + + /// The HID boot protocol of this interface + pub hid_boot_protocol: HidBootProtocol, } /// Report ID @@ -137,15 +156,18 @@ fn build<'d, D: Driver<'d>>( state: &'d mut State<'d>, config: Config<'d>, with_out_endpoint: bool, - usb_subclass: u8, - usb_protocol: u8, ) -> (Option, D::EndpointIn, &'d AtomicUsize) { let len = config.report_descriptor.len(); - let mut func = builder.function(USB_CLASS_HID, usb_subclass, usb_protocol); + let mut func = builder.function(USB_CLASS_HID, config.hid_subclass as u8, config.hid_boot_protocol as u8); let mut iface = func.interface(); let if_num = iface.interface_number(); - let mut alt = iface.alt_setting(USB_CLASS_HID, usb_subclass, usb_protocol, None); + let mut alt = iface.alt_setting( + USB_CLASS_HID, + config.hid_subclass as u8, + config.hid_boot_protocol as u8, + None, + ); // HID descriptor alt.descriptor( @@ -193,42 +215,7 @@ impl<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N: usize> HidReaderWrit /// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only. /// pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { - HidReaderWriter::_new(builder, state, config, USB_SUBCLASS_REPORT_ONLY, USB_PROTOCOL_NONE) - } - - /// Creates a new `HidReaderWriter` for a HID Mouse, with support for the BOOT protocol mode. - /// - /// This will allocate one IN and one OUT endpoints. If you only need writing (sending) - /// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only. - /// - pub fn new_mouse(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { - HidReaderWriter::_new(builder, state, config, USB_SUBCLASS_BOOT_OR_REPORT, USB_PROTOCOL_MOUSE) - } - - /// Creates a new `HidReaderWriter` for a HID Keyboard, with support for the BOOT protocol mode. - /// - /// This will allocate one IN and one OUT endpoints. If you only need writing (sending) - /// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only. - /// - pub fn new_keyboard(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { - HidReaderWriter::_new( - builder, - state, - config, - USB_SUBCLASS_BOOT_OR_REPORT, - USB_PROTOCOL_KEYBOARD, - ) - } - - /// Private helper function to create a new `HidReaderWriter`. - fn _new( - builder: &mut Builder<'d, D>, - state: &'d mut State<'d>, - config: Config<'d>, - usb_subclass: u8, - usb_protocol: u8, - ) -> Self { - let (ep_out, ep_in, offset) = build(builder, state, config, true, usb_subclass, usb_protocol); + let (ep_out, ep_in, offset) = build(builder, state, config, true); Self { reader: HidReader { @@ -317,50 +304,7 @@ impl<'d, D: Driver<'d>, const N: usize> HidWriter<'d, D, N> { /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for /// high performance uses, and a value of 255 is good for best-effort usecases. pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { - HidWriter::_new(builder, state, config, USB_SUBCLASS_REPORT_ONLY, USB_PROTOCOL_NONE) - } - - /// Creates a new `HidWriter` for a HID Mouse, with support for the BOOT protocol mode. - /// - /// This will allocate one IN endpoint only, so the host won't be able to send - /// reports to us. If you need that, consider using [`HidReaderWriter::new`] instead. - /// - /// poll_ms configures how frequently the host should poll for reading/writing - /// HID reports. A lower value means better throughput & latency, at the expense - /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for - /// high performance uses, and a value of 255 is good for best-effort usecases. - pub fn new_mouse(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { - HidWriter::_new(builder, state, config, USB_SUBCLASS_BOOT_OR_REPORT, USB_PROTOCOL_MOUSE) - } - - /// Creates a new `HidWriter` for a HID Keyboard, with support for the BOOT protocol mode. - /// - /// This will allocate one IN endpoint only, so the host won't be able to send - /// reports to us. If you need that, consider using [`HidReaderWriter::new`] instead. - /// - /// poll_ms configures how frequently the host should poll for reading/writing - /// HID reports. A lower value means better throughput & latency, at the expense - /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for - /// high performance uses, and a value of 255 is good for best-effort usecases. - pub fn new_keyboard(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { - HidWriter::_new( - builder, - state, - config, - USB_SUBCLASS_BOOT_OR_REPORT, - USB_PROTOCOL_KEYBOARD, - ) - } - - /// Private helper function to create a new `HidWriter`. - pub fn _new( - builder: &mut Builder<'d, D>, - state: &'d mut State<'d>, - config: Config<'d>, - usb_subclass: u8, - usb_protocol: u8, - ) -> Self { - let (ep_out, ep_in, _offset) = build(builder, state, config, false, usb_subclass, usb_protocol); + let (ep_out, ep_in, _offset) = build(builder, state, config, false); assert!(ep_out.is_none()); diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 9a1fc080e..452e83b7e 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -28,7 +28,7 @@ cortex-m-rt = "0.7.0" panic-probe = { version = "1.0.0", features = ["print-defmt"] } rand = { version = "0.9.0", default-features = false } embedded-storage = "0.3.1" -usbd-hid = { version = "0.8.1", features = ["defmt"] } +usbd-hid = "0.8.1" serde = { version = "1.0.136", default-features = false } embedded-hal = { version = "1.0" } embedded-hal-async = { version = "1.0" } diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index a4931099a..8649d5667 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs @@ -13,11 +13,12 @@ use embassy_nrf::usb::Driver; use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::signal::Signal; -use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; +use embassy_usb::class::hid::{ + HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State, +}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Config, Handler}; use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; -use usbd_hid::hid_class::HidProtocolMode; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -81,8 +82,10 @@ async fn main(_spawner: Spawner) { request_handler: None, poll_ms: 60, max_packet_size: 64, + hid_subclass: HidSubclass::ReportOrBoot, + hid_boot_protocol: HidBootProtocol::Keyboard, }; - let hid = HidReaderWriter::<_, 1, 8>::new_keyboard(&mut builder, &mut state, config); + let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index 6ec8a2d33..4baf2e814 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs @@ -10,11 +10,12 @@ use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::usb::Driver; use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; use embassy_time::Timer; -use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; +use embassy_usb::class::hid::{ + HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State, +}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Config}; use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; -use usbd_hid::hid_class::HidProtocolMode; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -72,9 +73,11 @@ async fn main(_spawner: Spawner) { request_handler: Some(&mut request_handler), poll_ms: 60, max_packet_size: 8, + hid_subclass: HidSubclass::ReportOrBoot, + hid_boot_protocol: HidBootProtocol::Mouse, }; - let mut writer = HidWriter::<_, 5>::new_mouse(&mut builder, &mut state, config); + let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs index 8658da6b5..fa78d0c2e 100644 --- a/examples/rp/src/bin/usb_hid_keyboard.rs +++ b/examples/rp/src/bin/usb_hid_keyboard.rs @@ -10,7 +10,7 @@ use embassy_rp::bind_interrupts; use embassy_rp::gpio::{Input, Pull}; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, InterruptHandler}; -use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; +use embassy_usb::class::hid::{HidBootProtocol, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Config, Handler}; use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; @@ -67,8 +67,10 @@ async fn main(_spawner: Spawner) { request_handler: None, poll_ms: 60, max_packet_size: 64, + hid_subclass: HidSubclass::ReportOrBoot, + hid_boot_protocol: HidBootProtocol::Keyboard, }; - let hid = HidReaderWriter::<_, 1, 8>::new_keyboard(&mut builder, &mut state, config); + let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs index 4d8fc354e..100e6048a 100755 --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -11,7 +11,7 @@ use embassy_rp::clocks::RoscRng; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, InterruptHandler}; use embassy_time::Timer; -use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; +use embassy_usb::class::hid::{HidBootProtocol, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Config, Handler}; use rand::Rng; @@ -69,8 +69,10 @@ async fn main(_spawner: Spawner) { request_handler: None, poll_ms: 60, max_packet_size: 64, + hid_subclass: HidSubclass::ReportOrBoot, + hid_boot_protocol: HidBootProtocol::Mouse, }; - let hid = HidReaderWriter::<_, 1, 8>::new_keyboard(&mut builder, &mut state, config); + let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); diff --git a/examples/rp235x/src/bin/usb_hid_keyboard.rs b/examples/rp235x/src/bin/usb_hid_keyboard.rs index fa9eaa863..3203176cb 100644 --- a/examples/rp235x/src/bin/usb_hid_keyboard.rs +++ b/examples/rp235x/src/bin/usb_hid_keyboard.rs @@ -10,7 +10,9 @@ use embassy_rp::bind_interrupts; use embassy_rp::gpio::{Input, Pull}; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; -use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State as HidState}; +use embassy_usb::class::hid::{ + HidBootProtocol, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State as HidState, +}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Config, Handler}; use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; @@ -67,8 +69,10 @@ async fn main(_spawner: Spawner) { request_handler: None, poll_ms: 60, max_packet_size: 64, + hid_subclass: HidSubclass::ReportOrBoot, + hid_boot_protocol: HidBootProtocol::Keyboard, }; - let hid = HidReaderWriter::<_, 1, 8>::new_keyboard(&mut builder, &mut state, config); + let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index 6ddfba83a..740fbcaef 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -11,7 +11,7 @@ use embassy_stm32::gpio::Pull; use embassy_stm32::time::Hertz; use embassy_stm32::usb::Driver; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; -use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; +use embassy_usb::class::hid::{HidBootProtocol, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Handler}; use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; @@ -105,9 +105,11 @@ async fn main(_spawner: Spawner) { request_handler: None, poll_ms: 60, max_packet_size: 8, + hid_subclass: HidSubclass::ReportOrBoot, + hid_boot_protocol: HidBootProtocol::Keyboard, }; - let hid = HidReaderWriter::<_, 1, 8>::new_keyboard(&mut builder, &mut state, config); + let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index 8d035d0d5..09af204c4 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -8,7 +8,7 @@ use embassy_stm32::time::Hertz; use embassy_stm32::usb::Driver; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_time::Timer; -use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; +use embassy_usb::class::hid::{HidBootProtocol, HidSubclass, HidWriter, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; use embassy_usb::Builder; use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; @@ -95,9 +95,11 @@ async fn main(_spawner: Spawner) { request_handler: Some(&mut request_handler), poll_ms: 60, max_packet_size: 8, + hid_subclass: HidSubclass::ReportOrBoot, + hid_boot_protocol: HidBootProtocol::Mouse, }; - let mut writer = HidWriter::<_, 5>::new_mouse(&mut builder, &mut state, config); + let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index 6f9200548..30dbd2698 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs @@ -7,7 +7,7 @@ use embassy_futures::join::join; use embassy_stm32::usb::Driver; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_time::Timer; -use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; +use embassy_usb::class::hid::{HidBootProtocol, HidSubclass, HidWriter, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; use embassy_usb::Builder; use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; @@ -77,9 +77,11 @@ async fn main(_spawner: Spawner) { request_handler: Some(&mut request_handler), poll_ms: 60, max_packet_size: 8, + hid_subclass: HidSubclass::ReportOrBoot, + hid_boot_protocol: HidBootProtocol::Mouse, }; - let mut writer = HidWriter::<_, 5>::new_mouse(&mut builder, &mut state, config); + let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); // Build the builder. let mut usb = builder.build(); -- cgit From d79d433d02ab154e5f8570392fd0ca1ffdf9cac1 Mon Sep 17 00:00:00 2001 From: matteo Date: Wed, 1 Oct 2025 18:30:15 +0200 Subject: rename HidSubclass to match hid spec --- embassy-usb/src/class/hid.rs | 14 +++++++------- examples/nrf52840/src/bin/usb_hid_keyboard.rs | 2 +- examples/nrf52840/src/bin/usb_hid_mouse.rs | 2 +- examples/rp/src/bin/usb_hid_keyboard.rs | 2 +- examples/rp/src/bin/usb_hid_mouse.rs | 2 +- examples/rp235x/src/bin/usb_hid_keyboard.rs | 2 +- examples/stm32f4/src/bin/usb_hid_keyboard.rs | 2 +- examples/stm32f4/src/bin/usb_hid_mouse.rs | 2 +- examples/stm32l5/src/bin/usb_hid_mouse.rs | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/embassy-usb/src/class/hid.rs b/embassy-usb/src/class/hid.rs index 6723afbbc..64e8fd59f 100644 --- a/embassy-usb/src/class/hid.rs +++ b/embassy-usb/src/class/hid.rs @@ -56,10 +56,10 @@ impl From for HidProtocolMode { #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] pub enum HidSubclass { - /// Only report mode is supported. - ReportOnly = 0, - /// Both boot and report mode are supported. - ReportOrBoot = 1, + /// No subclass, standard HID device. + No = 0, + /// Boot interface subclass, supports BIOS boot protocol. + Boot = 1, } /// USB HID protocol values. @@ -67,11 +67,11 @@ pub enum HidSubclass { #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] pub enum HidBootProtocol { - /// No specific boot protocol. + /// No boot protocol. None = 0, - /// Boot protocol keyboard. + /// Keyboard boot protocol. Keyboard = 1, - /// Boot protocol mouse. + /// Mouse boot protocol. Mouse = 2, } diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index 8649d5667..540580c31 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs @@ -82,7 +82,7 @@ async fn main(_spawner: Spawner) { request_handler: None, poll_ms: 60, max_packet_size: 64, - hid_subclass: HidSubclass::ReportOrBoot, + hid_subclass: HidSubclass::Boot, hid_boot_protocol: HidBootProtocol::Keyboard, }; let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index 4baf2e814..efc28203c 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs @@ -73,7 +73,7 @@ async fn main(_spawner: Spawner) { request_handler: Some(&mut request_handler), poll_ms: 60, max_packet_size: 8, - hid_subclass: HidSubclass::ReportOrBoot, + hid_subclass: HidSubclass::Boot, hid_boot_protocol: HidBootProtocol::Mouse, }; diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs index fa78d0c2e..adf91439e 100644 --- a/examples/rp/src/bin/usb_hid_keyboard.rs +++ b/examples/rp/src/bin/usb_hid_keyboard.rs @@ -67,7 +67,7 @@ async fn main(_spawner: Spawner) { request_handler: None, poll_ms: 60, max_packet_size: 64, - hid_subclass: HidSubclass::ReportOrBoot, + hid_subclass: HidSubclass::Boot, hid_boot_protocol: HidBootProtocol::Keyboard, }; let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs index 100e6048a..3e62e8891 100755 --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -69,7 +69,7 @@ async fn main(_spawner: Spawner) { request_handler: None, poll_ms: 60, max_packet_size: 64, - hid_subclass: HidSubclass::ReportOrBoot, + hid_subclass: HidSubclass::Boot, hid_boot_protocol: HidBootProtocol::Mouse, }; let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); diff --git a/examples/rp235x/src/bin/usb_hid_keyboard.rs b/examples/rp235x/src/bin/usb_hid_keyboard.rs index 3203176cb..b740a07b3 100644 --- a/examples/rp235x/src/bin/usb_hid_keyboard.rs +++ b/examples/rp235x/src/bin/usb_hid_keyboard.rs @@ -69,7 +69,7 @@ async fn main(_spawner: Spawner) { request_handler: None, poll_ms: 60, max_packet_size: 64, - hid_subclass: HidSubclass::ReportOrBoot, + hid_subclass: HidSubclass::Boot, hid_boot_protocol: HidBootProtocol::Keyboard, }; let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index 740fbcaef..5521a8240 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -105,7 +105,7 @@ async fn main(_spawner: Spawner) { request_handler: None, poll_ms: 60, max_packet_size: 8, - hid_subclass: HidSubclass::ReportOrBoot, + hid_subclass: HidSubclass::Boot, hid_boot_protocol: HidBootProtocol::Keyboard, }; diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index 09af204c4..5cfa0aec4 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -95,7 +95,7 @@ async fn main(_spawner: Spawner) { request_handler: Some(&mut request_handler), poll_ms: 60, max_packet_size: 8, - hid_subclass: HidSubclass::ReportOrBoot, + hid_subclass: HidSubclass::Boot, hid_boot_protocol: HidBootProtocol::Mouse, }; diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index 30dbd2698..f64fde3cb 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs @@ -77,7 +77,7 @@ async fn main(_spawner: Spawner) { request_handler: Some(&mut request_handler), poll_ms: 60, max_packet_size: 8, - hid_subclass: HidSubclass::ReportOrBoot, + hid_subclass: HidSubclass::Boot, hid_boot_protocol: HidBootProtocol::Mouse, }; -- cgit From 176649e71ad442ca9856af6c11989b0b2f228c4b Mon Sep 17 00:00:00 2001 From: matteo Date: Wed, 1 Oct 2025 18:56:38 +0200 Subject: update hid mouse and keyboard examples --- examples/rp/src/bin/usb_hid_keyboard.rs | 80 +++++++++++++++++++--------- examples/rp/src/bin/usb_hid_mouse.rs | 54 ++++++++++++++----- examples/rp235x/src/bin/usb_hid_keyboard.rs | 77 +++++++++++++++++--------- examples/stm32f4/src/bin/usb_hid_keyboard.rs | 78 ++++++++++++++++++--------- examples/stm32f4/src/bin/usb_hid_mouse.rs | 50 +++++++++++++---- examples/stm32l5/src/bin/usb_hid_mouse.rs | 50 +++++++++++++---- 6 files changed, 282 insertions(+), 107 deletions(-) diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs index adf91439e..2f6d169bf 100644 --- a/examples/rp/src/bin/usb_hid_keyboard.rs +++ b/examples/rp/src/bin/usb_hid_keyboard.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -use core::sync::atomic::{AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use defmt::*; use embassy_executor::Spawner; @@ -10,7 +10,9 @@ use embassy_rp::bind_interrupts; use embassy_rp::gpio::{Input, Pull}; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, InterruptHandler}; -use embassy_usb::class::hid::{HidBootProtocol, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State}; +use embassy_usb::class::hid::{ + HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State, +}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Config, Handler}; use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; @@ -20,6 +22,8 @@ bind_interrupts!(struct Irqs { USBCTRL_IRQ => InterruptHandler; }); +static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); @@ -92,30 +96,46 @@ async fn main(_spawner: Spawner) { info!("Waiting for HIGH on pin 16"); signal_pin.wait_for_high().await; info!("HIGH DETECTED"); - // Create a report with the A key pressed. (no shift modifier) - let report = KeyboardReport { - keycodes: [4, 0, 0, 0, 0, 0], - leds: 0, - modifier: 0, - reserved: 0, - }; - // Send the report. - match writer.write_serialize(&report).await { - Ok(()) => {} - Err(e) => warn!("Failed to send report: {:?}", e), - }; + + if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { + match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await { + Ok(()) => {} + Err(e) => warn!("Failed to send boot report: {:?}", e), + }; + } else { + // Create a report with the A key pressed. (no shift modifier) + let report = KeyboardReport { + keycodes: [4, 0, 0, 0, 0, 0], + leds: 0, + modifier: 0, + reserved: 0, + }; + // Send the report. + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + }; + } + signal_pin.wait_for_low().await; info!("LOW DETECTED"); - let report = KeyboardReport { - keycodes: [0, 0, 0, 0, 0, 0], - leds: 0, - modifier: 0, - reserved: 0, - }; - match writer.write_serialize(&report).await { - Ok(()) => {} - Err(e) => warn!("Failed to send report: {:?}", e), - }; + if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { + match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await { + Ok(()) => {} + Err(e) => warn!("Failed to send boot report: {:?}", e), + }; + } else { + let report = KeyboardReport { + keycodes: [0, 0, 0, 0, 0, 0], + leds: 0, + modifier: 0, + reserved: 0, + }; + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + }; + } } }; @@ -141,6 +161,18 @@ impl RequestHandler for MyRequestHandler { OutResponse::Accepted } + fn get_protocol(&self) -> HidProtocolMode { + let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed)); + info!("The current HID protocol mode is: {}", protocol); + protocol + } + + fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse { + info!("Switching to HID protocol mode: {}", protocol); + HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed); + OutResponse::Accepted + } + fn set_idle_ms(&mut self, id: Option, dur: u32) { info!("Set idle rate for {:?} to {:?}", id, dur); } diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs index 3e62e8891..dc331cbdd 100755 --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -use core::sync::atomic::{AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use defmt::*; use embassy_executor::Spawner; @@ -11,7 +11,9 @@ use embassy_rp::clocks::RoscRng; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, InterruptHandler}; use embassy_time::Timer; -use embassy_usb::class::hid::{HidBootProtocol, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State}; +use embassy_usb::class::hid::{ + HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State, +}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Config, Handler}; use rand::Rng; @@ -22,6 +24,8 @@ bind_interrupts!(struct Irqs { USBCTRL_IRQ => InterruptHandler; }); +static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); @@ -89,17 +93,29 @@ async fn main(_spawner: Spawner) { loop { // every 1 second _ = Timer::after_secs(1).await; - let report = MouseReport { - buttons: 0, - x: rng.random_range(-100..100), // random small x movement - y: rng.random_range(-100..100), // random small y movement - wheel: 0, - pan: 0, - }; - // Send the report. - match writer.write_serialize(&report).await { - Ok(()) => {} - Err(e) => warn!("Failed to send report: {:?}", e), + + let x = rng.random_range(-100..100); // random small x movement + let y = rng.random_range(-100..100); // random small y movement + + if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { + let buttons = 0u8; + match writer.write(&[buttons, x as u8, y as u8]).await { + Ok(()) => {} + Err(e) => warn!("Failed to send boot report: {:?}", e), + } + } else { + let report = MouseReport { + buttons: 0, + x, + y, + wheel: 0, + pan: 0, + }; + // Send the report. + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + } } } }; @@ -126,6 +142,18 @@ impl RequestHandler for MyRequestHandler { OutResponse::Accepted } + fn get_protocol(&self) -> HidProtocolMode { + let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed)); + info!("The current HID protocol mode is: {}", protocol); + protocol + } + + fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse { + info!("Switching to HID protocol mode: {}", protocol); + HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed); + OutResponse::Accepted + } + fn set_idle_ms(&mut self, id: Option, dur: u32) { info!("Set idle rate for {:?} to {:?}", id, dur); } diff --git a/examples/rp235x/src/bin/usb_hid_keyboard.rs b/examples/rp235x/src/bin/usb_hid_keyboard.rs index b740a07b3..d8f64c470 100644 --- a/examples/rp235x/src/bin/usb_hid_keyboard.rs +++ b/examples/rp235x/src/bin/usb_hid_keyboard.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -use core::sync::atomic::{AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use defmt::*; use embassy_executor::Spawner; @@ -11,7 +11,7 @@ use embassy_rp::gpio::{Input, Pull}; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; use embassy_usb::class::hid::{ - HidBootProtocol, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State as HidState, + HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State as HidState, }; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Config, Handler}; @@ -22,6 +22,8 @@ bind_interrupts!(struct Irqs { USBCTRL_IRQ => InterruptHandler; }); +static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); @@ -94,30 +96,45 @@ async fn main(_spawner: Spawner) { info!("Waiting for HIGH on pin 16"); signal_pin.wait_for_high().await; info!("HIGH DETECTED"); - // Create a report with the A key pressed. (no shift modifier) - let report = KeyboardReport { - keycodes: [4, 0, 0, 0, 0, 0], - leds: 0, - modifier: 0, - reserved: 0, - }; - // Send the report. - match writer.write_serialize(&report).await { - Ok(()) => {} - Err(e) => warn!("Failed to send report: {:?}", e), - }; + + if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { + match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await { + Ok(()) => {} + Err(e) => warn!("Failed to send boot report: {:?}", e), + }; + } else { + // Create a report with the A key pressed. (no shift modifier) + let report = KeyboardReport { + keycodes: [4, 0, 0, 0, 0, 0], + leds: 0, + modifier: 0, + reserved: 0, + }; + // Send the report. + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + }; + } signal_pin.wait_for_low().await; info!("LOW DETECTED"); - let report = KeyboardReport { - keycodes: [0, 0, 0, 0, 0, 0], - leds: 0, - modifier: 0, - reserved: 0, - }; - match writer.write_serialize(&report).await { - Ok(()) => {} - Err(e) => warn!("Failed to send report: {:?}", e), - }; + if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { + match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await { + Ok(()) => {} + Err(e) => warn!("Failed to send boot report: {:?}", e), + }; + } else { + let report = KeyboardReport { + keycodes: [0, 0, 0, 0, 0, 0], + leds: 0, + modifier: 0, + reserved: 0, + }; + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + }; + } } }; @@ -143,6 +160,18 @@ impl RequestHandler for MyRequestHandler { OutResponse::Accepted } + fn get_protocol(&self) -> HidProtocolMode { + let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed)); + info!("The current HID protocol mode is: {}", protocol); + protocol + } + + fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse { + info!("Switching to HID protocol mode: {}", protocol); + HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed); + OutResponse::Accepted + } + fn set_idle_ms(&mut self, id: Option, dur: u32) { info!("Set idle rate for {:?} to {:?}", id, dur); } diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index 5521a8240..86b6fa95f 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -use core::sync::atomic::{AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use defmt::*; use embassy_executor::Spawner; @@ -11,7 +11,9 @@ use embassy_stm32::gpio::Pull; use embassy_stm32::time::Hertz; use embassy_stm32::usb::Driver; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; -use embassy_usb::class::hid::{HidBootProtocol, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State}; +use embassy_usb::class::hid::{ + HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State, +}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Handler}; use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; @@ -21,6 +23,8 @@ bind_interrupts!(struct Irqs { OTG_FS => usb::InterruptHandler; }); +static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); + // If you are trying this and your USB device doesn't connect, the most // common issues are the RCC config and vbus_detection // @@ -127,32 +131,46 @@ async fn main(_spawner: Spawner) { button.wait_for_rising_edge().await; // signal_pin.wait_for_high().await; info!("Button pressed!"); - // Create a report with the A key pressed. (no shift modifier) - let report = KeyboardReport { - keycodes: [4, 0, 0, 0, 0, 0], - leds: 0, - modifier: 0, - reserved: 0, - }; - // Send the report. - match writer.write_serialize(&report).await { - Ok(()) => {} - Err(e) => warn!("Failed to send report: {:?}", e), - }; + if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { + match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await { + Ok(()) => {} + Err(e) => warn!("Failed to send boot report: {:?}", e), + }; + } else { + // Create a report with the A key pressed. (no shift modifier) + let report = KeyboardReport { + keycodes: [4, 0, 0, 0, 0, 0], + leds: 0, + modifier: 0, + reserved: 0, + }; + // Send the report. + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + }; + } button.wait_for_falling_edge().await; // signal_pin.wait_for_low().await; info!("Button released!"); - let report = KeyboardReport { - keycodes: [0, 0, 0, 0, 0, 0], - leds: 0, - modifier: 0, - reserved: 0, - }; - match writer.write_serialize(&report).await { - Ok(()) => {} - Err(e) => warn!("Failed to send report: {:?}", e), - }; + if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { + match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await { + Ok(()) => {} + Err(e) => warn!("Failed to send boot report: {:?}", e), + }; + } else { + let report = KeyboardReport { + keycodes: [0, 0, 0, 0, 0, 0], + leds: 0, + modifier: 0, + reserved: 0, + }; + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + }; + } } }; @@ -178,6 +196,18 @@ impl RequestHandler for MyRequestHandler { OutResponse::Accepted } + fn get_protocol(&self) -> HidProtocolMode { + let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed)); + info!("The current HID protocol mode is: {}", protocol); + protocol + } + + fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse { + info!("Switching to HID protocol mode: {}", protocol); + HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed); + OutResponse::Accepted + } + fn set_idle_ms(&mut self, id: Option, dur: u32) { info!("Set idle rate for {:?} to {:?}", id, dur); } diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index 5cfa0aec4..977db4c15 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -1,6 +1,8 @@ #![no_std] #![no_main] +use core::sync::atomic::{AtomicU8, Ordering}; + use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; @@ -8,7 +10,9 @@ use embassy_stm32::time::Hertz; use embassy_stm32::usb::Driver; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_time::Timer; -use embassy_usb::class::hid::{HidBootProtocol, HidSubclass, HidWriter, ReportId, RequestHandler, State}; +use embassy_usb::class::hid::{ + HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State, +}; use embassy_usb::control::OutResponse; use embassy_usb::Builder; use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; @@ -18,6 +22,8 @@ bind_interrupts!(struct Irqs { OTG_FS => usb::InterruptHandler; }); +static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); + // If you are trying this and your USB device doesn't connect, the most // common issues are the RCC config and vbus_detection // @@ -114,16 +120,26 @@ async fn main(_spawner: Spawner) { Timer::after_millis(500).await; y = -y; - let report = MouseReport { - buttons: 0, - x: 0, - y, - wheel: 0, - pan: 0, - }; - match writer.write_serialize(&report).await { - Ok(()) => {} - Err(e) => warn!("Failed to send report: {:?}", e), + + if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { + let buttons = 0u8; + let x = 0i8; + match writer.write(&[buttons, x as u8, y as u8]).await { + Ok(()) => {} + Err(e) => warn!("Failed to send boot report: {:?}", e), + } + } else { + let report = MouseReport { + buttons: 0, + x: 0, + y, + wheel: 0, + pan: 0, + }; + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + } } } }; @@ -146,6 +162,18 @@ impl RequestHandler for MyRequestHandler { OutResponse::Accepted } + fn get_protocol(&self) -> HidProtocolMode { + let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed)); + info!("The current HID protocol mode is: {}", protocol); + protocol + } + + fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse { + info!("Switching to HID protocol mode: {}", protocol); + HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed); + OutResponse::Accepted + } + fn set_idle_ms(&mut self, id: Option, dur: u32) { info!("Set idle rate for {:?} to {:?}", id, dur); } diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index f64fde3cb..8c7cdbef5 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs @@ -1,13 +1,17 @@ #![no_std] #![no_main] +use core::sync::atomic::{AtomicU8, Ordering}; + use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::Driver; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_time::Timer; -use embassy_usb::class::hid::{HidBootProtocol, HidSubclass, HidWriter, ReportId, RequestHandler, State}; +use embassy_usb::class::hid::{ + HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State, +}; use embassy_usb::control::OutResponse; use embassy_usb::Builder; use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; @@ -17,6 +21,8 @@ bind_interrupts!(struct Irqs { USB_FS => usb::InterruptHandler; }); +static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); @@ -96,16 +102,26 @@ async fn main(_spawner: Spawner) { Timer::after_millis(500).await; y = -y; - let report = MouseReport { - buttons: 0, - x: 0, - y, - wheel: 0, - pan: 0, - }; - match writer.write_serialize(&report).await { - Ok(()) => {} - Err(e) => warn!("Failed to send report: {:?}", e), + + if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { + let buttons = 0u8; + let x = 0i8; + match writer.write(&[buttons, x as u8, y as u8]).await { + Ok(()) => {} + Err(e) => warn!("Failed to send boot report: {:?}", e), + } + } else { + let report = MouseReport { + buttons: 0, + x: 0, + y, + wheel: 0, + pan: 0, + }; + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + } } } }; @@ -128,6 +144,18 @@ impl RequestHandler for MyRequestHandler { OutResponse::Accepted } + fn get_protocol(&self) -> HidProtocolMode { + let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed)); + info!("The current HID protocol mode is: {}", protocol); + protocol + } + + fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse { + info!("Switching to HID protocol mode: {}", protocol); + HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed); + OutResponse::Accepted + } + fn set_idle_ms(&mut self, id: Option, dur: u32) { info!("Set idle rate for {:?} to {:?}", id, dur); } -- cgit From 647c6f5f6969ab291130a50384cd2f26b167e008 Mon Sep 17 00:00:00 2001 From: everdrone Date: Thu, 23 Oct 2025 12:22:31 +0200 Subject: add dbgmcu --- embassy-stm32/src/lib.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 6abd60eb0..4ea38b414 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -175,7 +175,6 @@ pub use crate::_generated::interrupt; /// } /// ); /// ``` - // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. #[macro_export] macro_rules! bind_interrupts { @@ -496,6 +495,16 @@ fn init_hw(config: Config) -> Peripherals { critical_section::with(|cs| { let p = Peripherals::take_with_cs(cs); + #[cfg(dbgmcu_n6)] + { + crate::pac::RCC.miscensr().write(|w| w.set_dbgens(true)); + crate::pac::RCC.miscenr().read(); // volatile read + crate::pac::DBGMCU + .cr() + .modify(|w| w.set_dbgclken(stm32_metapac::dbgmcu::vals::Dbgclken::B_0X1)); + crate::pac::DBGMCU.cr().read(); + } + #[cfg(dbgmcu)] crate::pac::DBGMCU.cr().modify(|cr| { #[cfg(dbgmcu_h5)] @@ -510,7 +519,7 @@ fn init_hw(config: Config) -> Peripherals { } #[cfg(any( dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, - dbgmcu_l4, dbgmcu_wb, dbgmcu_wl + dbgmcu_l4, dbgmcu_wb, dbgmcu_wl, dbgmcu_n6 ))] { cr.set_dbg_sleep(config.enable_debug_during_sleep); -- cgit From 7976f950b0de72c521f92efa350c67ccd197fab9 Mon Sep 17 00:00:00 2001 From: Matteo Meluzzi Date: Fri, 24 Oct 2025 15:48:34 +0200 Subject: Merge branch 'main' into 17-add-support-for-boot-protocol --- .github/ci/build-nightly.sh | 2 +- .github/ci/build-xtensa.sh | 2 +- .github/ci/build.sh | 2 +- .github/ci/doc.sh | 2 +- .github/ci/janitor.sh | 2 +- .github/ci/rustfmt.sh | 2 +- cyw43-pio/Cargo.toml | 2 +- cyw43-pio/src/lib.rs | 4 +- cyw43/Cargo.toml | 2 +- cyw43/src/bluetooth.rs | 2 +- cyw43/src/bus.rs | 6 +- cyw43/src/control.rs | 2 +- cyw43/src/ioctl.rs | 2 +- cyw43/src/lib.rs | 1 + cyw43/src/runner.rs | 6 +- .../layer-by-layer/blinky-async/Cargo.toml | 2 +- docs/examples/layer-by-layer/blinky-hal/Cargo.toml | 2 +- docs/examples/layer-by-layer/blinky-irq/Cargo.toml | 2 +- docs/examples/layer-by-layer/blinky-pac/Cargo.toml | 2 +- docs/pages/embassy_in_the_wild.adoc | 7 +- embassy-boot-nrf/Cargo.toml | 2 +- embassy-boot-nrf/src/lib.rs | 3 +- embassy-boot-rp/Cargo.toml | 2 +- embassy-boot-rp/src/lib.rs | 5 +- embassy-boot-stm32/Cargo.toml | 2 +- embassy-boot-stm32/src/lib.rs | 1 + embassy-boot/Cargo.toml | 2 +- embassy-boot/src/boot_loader.rs | 6 +- embassy-boot/src/firmware_updater/asynch.rs | 4 +- embassy-boot/src/firmware_updater/blocking.rs | 6 +- embassy-boot/src/lib.rs | 15 +- embassy-boot/src/test_flash/blocking.rs | 2 +- embassy-embedded-hal/Cargo.toml | 2 +- .../src/flash/partition/blocking.rs | 2 +- embassy-embedded-hal/src/shared_bus/asynch/i2c.rs | 2 +- embassy-embedded-hal/src/shared_bus/asynch/spi.rs | 2 +- .../src/shared_bus/blocking/i2c.rs | 4 +- .../src/shared_bus/blocking/spi.rs | 4 +- embassy-executor-macros/Cargo.toml | 2 +- embassy-executor-macros/src/macros/main.rs | 4 +- embassy-executor-macros/src/macros/task.rs | 8 +- embassy-executor-macros/src/util.rs | 2 +- embassy-executor-timer-queue/Cargo.toml | 2 +- embassy-executor/CHANGELOG.md | 1 + embassy-executor/Cargo.toml | 6 +- embassy-executor/src/arch/avr.rs | 4 +- embassy-executor/src/arch/cortex_ar.rs | 4 +- embassy-executor/src/arch/cortex_m.rs | 4 +- embassy-executor/src/arch/riscv32.rs | 4 +- embassy-executor/src/arch/spin.rs | 4 +- embassy-executor/src/arch/std.rs | 4 +- embassy-executor/src/arch/wasm.rs | 4 +- embassy-executor/src/lib.rs | 1 + embassy-executor/src/metadata.rs | 2 +- embassy-executor/src/raw/mod.rs | 6 +- embassy-executor/src/raw/run_queue.rs | 4 +- embassy-executor/src/raw/state_atomics_arm.rs | 2 +- embassy-executor/src/raw/state_critical_section.rs | 2 +- embassy-executor/src/raw/trace.rs | 6 +- embassy-executor/src/raw/waker.rs | 6 +- embassy-executor/src/raw/waker_turbo.rs | 4 +- embassy-executor/src/spawner.rs | 12 +- embassy-executor/tests/test.rs | 6 +- .../tests/ui/nonstatic_struct_elided.stderr | 12 +- embassy-executor/tests/ui/task_safety_attribute.rs | 2 +- embassy-futures/Cargo.toml | 2 +- embassy-hal-internal/Cargo.toml | 2 +- embassy-hal-internal/src/interrupt.rs | 2 +- embassy-hal-internal/src/lib.rs | 1 + embassy-hal-internal/src/macros.rs | 2 +- embassy-imxrt/Cargo.toml | 2 +- embassy-imxrt/src/clocks.rs | 2 +- embassy-imxrt/src/crc.rs | 4 +- embassy-imxrt/src/dma.rs | 6 +- embassy-imxrt/src/flexcomm/mod.rs | 18 +- embassy-imxrt/src/flexcomm/uart.rs | 4 +- embassy-imxrt/src/gpio.rs | 2 +- embassy-imxrt/src/iopctl.rs | 2 +- embassy-imxrt/src/lib.rs | 5 +- embassy-imxrt/src/rng.rs | 4 +- embassy-imxrt/src/time_driver.rs | 4 +- embassy-mspm0/CHANGELOG.md | 4 + embassy-mspm0/Cargo.toml | 20 +- embassy-mspm0/build.rs | 52 ++- embassy-mspm0/src/adc.rs | 6 +- embassy-mspm0/src/dma.rs | 8 +- embassy-mspm0/src/gpio.rs | 32 +- embassy-mspm0/src/i2c.rs | 21 +- embassy-mspm0/src/i2c_target.rs | 509 +++++++++++++++++++++ embassy-mspm0/src/lib.rs | 6 +- embassy-mspm0/src/time_driver.rs | 2 +- embassy-mspm0/src/uart/buffered.rs | 4 +- embassy-mspm0/src/uart/mod.rs | 13 +- embassy-mspm0/src/wwdt.rs | 4 +- embassy-net-adin1110/Cargo.toml | 2 +- embassy-net-adin1110/src/crc8.rs | 2 +- embassy-net-adin1110/src/lib.rs | 4 +- embassy-net-driver-channel/Cargo.toml | 2 +- embassy-net-driver-channel/src/lib.rs | 2 +- embassy-net-driver/Cargo.toml | 2 +- embassy-net-driver/src/lib.rs | 1 + embassy-net-enc28j60/Cargo.toml | 2 +- embassy-net-esp-hosted/Cargo.toml | 2 +- embassy-net-esp-hosted/src/control.rs | 3 +- embassy-net-esp-hosted/src/ioctl.rs | 2 +- embassy-net-esp-hosted/src/lib.rs | 2 +- embassy-net-nrf91/Cargo.toml | 2 +- embassy-net-nrf91/src/lib.rs | 12 +- embassy-net-ppp/Cargo.toml | 2 +- embassy-net-ppp/src/lib.rs | 2 +- embassy-net-tuntap/Cargo.toml | 2 +- embassy-net-wiznet/Cargo.toml | 2 +- embassy-net-wiznet/src/chip/mod.rs | 2 +- embassy-net-wiznet/src/lib.rs | 2 +- embassy-net/Cargo.toml | 2 +- embassy-net/src/icmp.rs | 2 +- embassy-net/src/lib.rs | 3 +- embassy-net/src/raw.rs | 2 +- embassy-net/src/tcp.rs | 4 +- embassy-net/src/udp.rs | 2 +- embassy-nrf/CHANGELOG.md | 6 + embassy-nrf/Cargo.toml | 4 +- embassy-nrf/src/buffered_uarte.rs | 32 +- embassy-nrf/src/chips/nrf54l15_app.rs | 43 ++ embassy-nrf/src/egu.rs | 2 +- embassy-nrf/src/embassy_net_802154_driver.rs | 4 +- embassy-nrf/src/gpio.rs | 4 +- embassy-nrf/src/gpiote.rs | 12 +- embassy-nrf/src/i2s.rs | 4 +- embassy-nrf/src/lib.rs | 70 ++- embassy-nrf/src/nfct.rs | 6 +- embassy-nrf/src/nvmc.rs | 2 +- embassy-nrf/src/pdm.rs | 4 +- embassy-nrf/src/ppi/dppi.rs | 2 +- embassy-nrf/src/ppi/mod.rs | 4 +- embassy-nrf/src/ppi/ppi.rs | 2 +- embassy-nrf/src/pwm.rs | 4 +- embassy-nrf/src/qspi.rs | 2 +- embassy-nrf/src/radio/ieee802154.rs | 21 +- embassy-nrf/src/rramc.rs | 2 +- embassy-nrf/src/saadc.rs | 4 +- embassy-nrf/src/spim.rs | 6 +- embassy-nrf/src/spis.rs | 6 +- embassy-nrf/src/temp.rs | 2 +- embassy-nrf/src/time_driver.rs | 4 +- embassy-nrf/src/twim.rs | 2 +- embassy-nrf/src/twis.rs | 4 +- embassy-nrf/src/uarte.rs | 4 +- embassy-nrf/src/usb/mod.rs | 10 +- embassy-nrf/src/usb/vbus_detect.rs | 2 +- embassy-nrf/src/util.rs | 6 +- embassy-nrf/src/wdt.rs | 2 +- embassy-nxp/CHANGELOG.md | 2 + embassy-nxp/Cargo.toml | 2 +- embassy-nxp/src/dma/lpc55.rs | 6 +- embassy-nxp/src/gpio/lpc55.rs | 70 +-- embassy-nxp/src/gpio/rt1xxx.rs | 4 +- embassy-nxp/src/lib.rs | 5 +- embassy-nxp/src/pint.rs | 4 +- embassy-nxp/src/time_driver/rtc.rs | 4 +- embassy-nxp/src/usart/lpc55.rs | 177 ++++--- embassy-rp/Cargo.toml | 6 +- embassy-rp/src/adc.rs | 8 +- embassy-rp/src/bootsel.rs | 4 +- embassy-rp/src/clocks.rs | 4 +- embassy-rp/src/dma.rs | 4 +- embassy-rp/src/flash.rs | 10 +- embassy-rp/src/float/cmp.rs | 12 +- embassy-rp/src/float/functions.rs | 12 +- embassy-rp/src/gpio.rs | 6 +- embassy-rp/src/i2c_slave.rs | 4 +- embassy-rp/src/intrinsics.rs | 6 +- embassy-rp/src/lib.rs | 14 +- embassy-rp/src/multicore.rs | 9 +- embassy-rp/src/pio/mod.rs | 14 +- embassy-rp/src/pio_programs/hd44780.rs | 2 +- embassy-rp/src/pio_programs/i2s.rs | 2 +- embassy-rp/src/pio_programs/onewire.rs | 8 +- embassy-rp/src/pio_programs/pwm.rs | 2 +- embassy-rp/src/pio_programs/rotary_encoder.rs | 2 +- embassy-rp/src/pio_programs/stepper.rs | 2 +- embassy-rp/src/pio_programs/uart.rs | 2 +- embassy-rp/src/pio_programs/ws2812.rs | 2 +- embassy-rp/src/psram.rs | 10 +- embassy-rp/src/pwm.rs | 4 +- embassy-rp/src/rtc/mod.rs | 2 +- embassy-rp/src/time_driver.rs | 2 +- embassy-rp/src/uart/mod.rs | 16 +- embassy-rp/src/usb.rs | 16 +- embassy-rp/src/watchdog.rs | 2 +- embassy-stm32-wpan/Cargo.toml | 2 +- embassy-stm32-wpan/src/cmd.rs | 2 +- embassy-stm32-wpan/src/consts.rs | 2 +- embassy-stm32-wpan/src/lhci.rs | 4 +- embassy-stm32-wpan/src/lib.rs | 5 +- embassy-stm32-wpan/src/mac/driver.rs | 2 +- embassy-stm32-wpan/src/mac/runner.rs | 2 +- embassy-stm32-wpan/src/sub/ble.rs | 4 +- embassy-stm32-wpan/src/sub/mm.rs | 4 +- embassy-stm32-wpan/src/sub/sys.rs | 12 +- embassy-stm32-wpan/src/tables.rs | 52 +-- embassy-stm32/CHANGELOG.md | 4 + embassy-stm32/Cargo.toml | 2 +- embassy-stm32/build.rs | 8 +- embassy-stm32/src/adc/adc4.rs | 9 +- embassy-stm32/src/adc/c0.rs | 9 +- embassy-stm32/src/adc/f1.rs | 2 +- embassy-stm32/src/adc/f3.rs | 2 +- embassy-stm32/src/adc/f3_v1_1.rs | 2 +- embassy-stm32/src/adc/g4.rs | 9 +- embassy-stm32/src/adc/mod.rs | 2 +- embassy-stm32/src/adc/ringbuffered_v2.rs | 4 +- embassy-stm32/src/adc/v1.rs | 8 +- embassy-stm32/src/adc/v2.rs | 2 +- embassy-stm32/src/adc/v3.rs | 4 +- embassy-stm32/src/adc/v4.rs | 9 +- embassy-stm32/src/can/bxcan/mod.rs | 12 +- embassy-stm32/src/can/fd/config.rs | 2 +- embassy-stm32/src/can/fdcan.rs | 12 +- embassy-stm32/src/can/util.rs | 2 +- embassy-stm32/src/crc/v1.rs | 2 +- embassy-stm32/src/crc/v2v3.rs | 4 +- embassy-stm32/src/cryp/mod.rs | 10 +- embassy-stm32/src/dac/mod.rs | 2 +- embassy-stm32/src/dcmi.rs | 2 +- embassy-stm32/src/dma/dma_bdma.rs | 4 +- embassy-stm32/src/dma/gpdma/mod.rs | 2 +- embassy-stm32/src/dma/gpdma/ringbuffered.rs | 4 +- embassy-stm32/src/dma/mod.rs | 2 +- .../src/dma/ringbuffer/tests/prop_test/mod.rs | 2 +- embassy-stm32/src/dsihost.rs | 2 +- embassy-stm32/src/dts/mod.rs | 2 +- embassy-stm32/src/eth/v1/mod.rs | 8 +- embassy-stm32/src/eth/v1/rx_desc.rs | 2 +- embassy-stm32/src/eth/v1/tx_desc.rs | 2 +- embassy-stm32/src/eth/v2/descriptors.rs | 2 +- embassy-stm32/src/eth/v2/mod.rs | 6 +- embassy-stm32/src/exti.rs | 6 +- embassy-stm32/src/flash/asynch.rs | 8 +- embassy-stm32/src/flash/common.rs | 8 +- embassy-stm32/src/flash/eeprom.rs | 2 +- embassy-stm32/src/flash/f0.rs | 2 +- embassy-stm32/src/flash/f1f3.rs | 2 +- embassy-stm32/src/flash/f2.rs | 4 +- embassy-stm32/src/flash/f4.rs | 24 +- embassy-stm32/src/flash/f7.rs | 12 +- embassy-stm32/src/flash/g.rs | 18 +- embassy-stm32/src/flash/h5.rs | 2 +- embassy-stm32/src/flash/h50.rs | 2 +- embassy-stm32/src/flash/h7.rs | 4 +- embassy-stm32/src/flash/l.rs | 30 +- embassy-stm32/src/flash/u0.rs | 2 +- embassy-stm32/src/flash/u5.rs | 2 +- embassy-stm32/src/fmc.rs | 2 +- embassy-stm32/src/gpio.rs | 2 +- embassy-stm32/src/hash/mod.rs | 8 +- embassy-stm32/src/hsem/mod.rs | 4 +- embassy-stm32/src/hspi/mod.rs | 2 +- embassy-stm32/src/i2c/mod.rs | 4 +- embassy-stm32/src/i2c/v1.rs | 8 +- embassy-stm32/src/i2c/v2.rs | 2 +- embassy-stm32/src/i2s.rs | 4 +- embassy-stm32/src/ipcc.rs | 2 +- embassy-stm32/src/lib.rs | 5 +- embassy-stm32/src/low_power.rs | 4 +- embassy-stm32/src/lptim/pwm.rs | 6 +- embassy-stm32/src/ltdc.rs | 2 +- embassy-stm32/src/opamp.rs | 2 +- embassy-stm32/src/ospi/mod.rs | 6 +- embassy-stm32/src/qspi/mod.rs | 2 +- embassy-stm32/src/rcc/bd.rs | 4 +- embassy-stm32/src/rcc/f247.rs | 4 +- embassy-stm32/src/rcc/h.rs | 5 +- embassy-stm32/src/rcc/l.rs | 8 +- embassy-stm32/src/rcc/mco.rs | 4 +- embassy-stm32/src/rcc/mod.rs | 2 +- embassy-stm32/src/rcc/u5.rs | 9 +- embassy-stm32/src/rcc/wba.rs | 9 +- embassy-stm32/src/rng.rs | 2 +- embassy-stm32/src/rtc/low_power.rs | 2 +- embassy-stm32/src/rtc/mod.rs | 8 +- embassy-stm32/src/rtc/v3.rs | 2 +- embassy-stm32/src/sai/mod.rs | 6 +- embassy-stm32/src/sdmmc/mod.rs | 6 +- embassy-stm32/src/spdifrx/mod.rs | 2 +- embassy-stm32/src/spi/mod.rs | 8 +- embassy-stm32/src/time_driver.rs | 6 +- embassy-stm32/src/timer/complementary_pwm.rs | 6 +- embassy-stm32/src/timer/input_capture.rs | 2 +- embassy-stm32/src/timer/one_pulse.rs | 2 +- embassy-stm32/src/timer/pwm_input.rs | 2 +- embassy-stm32/src/timer/qei.rs | 2 +- embassy-stm32/src/timer/simple_pwm.rs | 2 +- embassy-stm32/src/tsc/acquisition_banks.rs | 4 +- embassy-stm32/src/tsc/pin_groups.rs | 4 +- embassy-stm32/src/ucpd.rs | 4 +- embassy-stm32/src/uid.rs | 4 +- embassy-stm32/src/usart/buffered.rs | 6 +- embassy-stm32/src/usart/mod.rs | 8 +- embassy-stm32/src/usart/ringbuffered.rs | 8 +- embassy-stm32/src/usb/otg.rs | 10 +- embassy-stm32/src/usb/usb.rs | 4 +- embassy-stm32/src/vrefbuf/mod.rs | 3 +- embassy-stm32/src/wdg/mod.rs | 2 +- embassy-stm32/src/xspi/mod.rs | 6 +- embassy-sync/Cargo.toml | 2 +- embassy-sync/src/channel.rs | 30 +- embassy-sync/src/lib.rs | 1 + embassy-sync/src/mutex.rs | 4 +- embassy-sync/src/once_lock.rs | 2 +- embassy-sync/src/pipe.rs | 2 +- embassy-sync/src/priority_channel.rs | 32 +- embassy-sync/src/pubsub/mod.rs | 2 +- embassy-sync/src/ring_buffer.rs | 6 +- embassy-sync/src/rwlock.rs | 4 +- embassy-sync/src/semaphore.rs | 4 +- embassy-sync/src/signal.rs | 4 +- embassy-sync/src/waitqueue/atomic_waker.rs | 2 +- embassy-sync/src/watch.rs | 4 +- embassy-sync/src/zerocopy_channel.rs | 10 +- embassy-time-driver/Cargo.toml | 2 +- embassy-time-driver/src/lib.rs | 8 +- embassy-time-queue-utils/Cargo.toml | 2 +- embassy-time-queue-utils/src/queue_generic.rs | 2 +- embassy-time/Cargo.toml | 2 +- embassy-time/src/duration.rs | 8 +- embassy-time/src/lib.rs | 11 +- embassy-time/src/timer.rs | 4 +- embassy-usb-dfu/Cargo.toml | 2 +- embassy-usb-dfu/src/application.rs | 4 +- embassy-usb-dfu/src/dfu.rs | 4 +- embassy-usb-driver/Cargo.toml | 2 +- embassy-usb-driver/src/lib.rs | 1 + embassy-usb-logger/Cargo.toml | 2 +- embassy-usb-synopsys-otg/Cargo.toml | 2 +- embassy-usb-synopsys-otg/src/lib.rs | 17 +- embassy-usb/Cargo.toml | 2 +- embassy-usb/src/builder.rs | 9 +- embassy-usb/src/class/cdc_acm.rs | 2 +- embassy-usb/src/class/cdc_ncm/embassy_net.rs | 2 +- embassy-usb/src/class/cdc_ncm/mod.rs | 2 +- embassy-usb/src/class/cmsis_dap_v2.rs | 2 +- embassy-usb/src/class/midi.rs | 2 +- embassy-usb/src/class/uac1/speaker.rs | 4 +- embassy-usb/src/descriptor.rs | 2 +- embassy-usb/src/lib.rs | 3 +- embassy-usb/src/msos.rs | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/src/main.rs | 4 +- examples/boot/application/stm32wba-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wba-dfu/src/main.rs | 4 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/boot/application/stm32wl/src/bin/a.rs | 2 +- examples/boot/application/stm32wl/src/bin/b.rs | 2 +- examples/boot/bootloader/nrf/Cargo.toml | 2 +- examples/boot/bootloader/nrf/src/main.rs | 6 +- examples/boot/bootloader/rp/Cargo.toml | 2 +- examples/boot/bootloader/rp/src/main.rs | 6 +- .../boot/bootloader/stm32-dual-bank/Cargo.toml | 2 +- .../boot/bootloader/stm32-dual-bank/src/main.rs | 8 +- examples/boot/bootloader/stm32/Cargo.toml | 2 +- examples/boot/bootloader/stm32/src/main.rs | 8 +- examples/boot/bootloader/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/bootloader/stm32wb-dfu/src/main.rs | 12 +- examples/boot/bootloader/stm32wba-dfu/Cargo.toml | 2 +- examples/boot/bootloader/stm32wba-dfu/src/main.rs | 14 +- examples/lpc55s69/Cargo.toml | 2 +- examples/mimxrt1011/Cargo.toml | 2 +- examples/mimxrt1011/src/lib.rs | 2 +- examples/mimxrt1062-evk/Cargo.toml | 2 +- examples/mimxrt1062-evk/src/lib.rs | 4 +- examples/mimxrt6/Cargo.toml | 2 +- examples/mimxrt6/src/bin/button.rs | 2 +- examples/mspm0c1104/Cargo.toml | 2 +- examples/mspm0c1104/src/bin/blinky.rs | 2 +- examples/mspm0c1104/src/bin/button.rs | 2 +- examples/mspm0g3507/Cargo.toml | 2 +- examples/mspm0g3507/src/bin/adc.rs | 2 +- examples/mspm0g3507/src/bin/blinky.rs | 2 +- examples/mspm0g3507/src/bin/button.rs | 2 +- examples/mspm0g3507/src/bin/i2c_target.rs | 63 +++ examples/mspm0g3519/Cargo.toml | 2 +- examples/mspm0g3519/src/bin/blinky.rs | 2 +- examples/mspm0g3519/src/bin/button.rs | 2 +- examples/mspm0l1306/Cargo.toml | 2 +- examples/mspm0l1306/src/bin/adc.rs | 2 +- examples/mspm0l1306/src/bin/blinky.rs | 2 +- examples/mspm0l1306/src/bin/button.rs | 2 +- examples/mspm0l1306/src/bin/i2c_target.rs | 63 +++ examples/mspm0l2228/Cargo.toml | 2 +- examples/mspm0l2228/src/bin/blinky.rs | 2 +- examples/mspm0l2228/src/bin/button.rs | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf51/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840-edf/Cargo.toml | 2 +- examples/nrf52840-edf/src/bin/basic.rs | 2 +- examples/nrf52840-rtic/Cargo.toml | 2 +- examples/nrf52840-rtic/src/bin/blinky.rs | 2 +- examples/nrf52840/Cargo.toml | 2 +- .../nrf52840/src/bin/channel_sender_receiver.rs | 2 +- examples/nrf52840/src/bin/ethernet_enc28j60.rs | 2 +- examples/nrf52840/src/bin/i2s_effect.rs | 8 +- examples/nrf52840/src/bin/i2s_monitor.rs | 2 +- examples/nrf52840/src/bin/i2s_waveform.rs | 8 +- examples/nrf52840/src/bin/multiprio.rs | 4 +- examples/nrf52840/src/bin/raw_spawn.rs | 4 +- examples/nrf52840/src/bin/rtc.rs | 2 +- examples/nrf52840/src/bin/usb_ethernet.rs | 4 +- examples/nrf52840/src/bin/usb_hid_keyboard.rs | 8 +- examples/nrf52840/src/bin/usb_hid_mouse.rs | 2 +- examples/nrf52840/src/bin/usb_serial.rs | 2 +- examples/nrf52840/src/bin/usb_serial_multitask.rs | 2 +- examples/nrf52840/src/bin/usb_serial_winusb.rs | 2 +- examples/nrf52840/src/bin/wifi_esp_hosted.rs | 2 +- examples/nrf5340/Cargo.toml | 2 +- .../nrf5340/src/bin/nrf5340dk_internal_caps.rs | 30 ++ examples/nrf54l15/Cargo.toml | 4 +- examples/nrf54l15/src/bin/rtc.rs | 56 +++ examples/nrf9151/ns/Cargo.toml | 2 +- examples/nrf9151/s/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- examples/nrf9160/src/bin/modem_tcp_client.rs | 6 +- examples/rp/Cargo.toml | 2 +- examples/rp/src/bin/assign_resources.rs | 2 +- examples/rp/src/bin/debounce.rs | 2 +- examples/rp/src/bin/ethernet_w5500_icmp_ping.rs | 4 +- examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs | 2 +- examples/rp/src/bin/interrupt.rs | 2 +- examples/rp/src/bin/multicore.rs | 2 +- examples/rp/src/bin/multiprio.rs | 6 +- examples/rp/src/bin/orchestrate_tasks.rs | 4 +- examples/rp/src/bin/overclock.rs | 2 +- examples/rp/src/bin/overclock_manual.rs | 2 +- examples/rp/src/bin/pio_async.rs | 2 +- examples/rp/src/bin/pio_stepper.rs | 2 +- examples/rp/src/bin/pwm.rs | 4 +- examples/rp/src/bin/rtc_alarm.rs | 2 +- examples/rp/src/bin/sharing.rs | 2 +- examples/rp/src/bin/spi_display.rs | 12 +- examples/rp/src/bin/spi_gc9a01.rs | 4 +- examples/rp/src/bin/uart_r503.rs | 2 +- examples/rp/src/bin/usb_ethernet.rs | 2 +- examples/rp/src/bin/usb_serial.rs | 2 +- examples/rp/src/bin/wifi_ap_tcp_server.rs | 2 +- examples/rp/src/bin/wifi_blinky.rs | 2 +- examples/rp/src/bin/wifi_scan.rs | 2 +- examples/rp/src/bin/wifi_tcp_server.rs | 2 +- examples/rp/src/bin/wifi_webrequest.rs | 2 +- examples/rp/src/bin/zerocopy.rs | 2 +- examples/rp235x/Cargo.toml | 2 +- examples/rp235x/src/bin/assign_resources.rs | 2 +- examples/rp235x/src/bin/debounce.rs | 2 +- .../rp235x/src/bin/ethernet_w5500_icmp_ping.rs | 4 +- examples/rp235x/src/bin/interrupt.rs | 2 +- examples/rp235x/src/bin/multicore.rs | 2 +- .../rp235x/src/bin/multicore_stack_overflow.rs | 2 +- examples/rp235x/src/bin/multiprio.rs | 6 +- examples/rp235x/src/bin/overclock.rs | 2 +- examples/rp235x/src/bin/pio_async.rs | 2 +- examples/rp235x/src/bin/pio_i2s_rx.rs | 2 +- examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs | 2 +- examples/rp235x/src/bin/pio_stepper.rs | 2 +- examples/rp235x/src/bin/pwm.rs | 4 +- .../rp235x/src/bin/pwm_tb6612fng_motor_driver.rs | 2 +- examples/rp235x/src/bin/sharing.rs | 2 +- examples/rp235x/src/bin/spi_display.rs | 12 +- examples/rp235x/src/bin/uart_r503.rs | 2 +- examples/rp235x/src/bin/zerocopy.rs | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32c0/Cargo.toml | 2 +- examples/stm32c0/src/bin/rtc.rs | 2 +- examples/stm32f0/Cargo.toml | 2 +- .../stm32f0/src/bin/button_controlled_blink.rs | 2 +- examples/stm32f0/src/bin/multiprio.rs | 4 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f1/src/bin/can.rs | 6 +- examples/stm32f1/src/bin/input_capture.rs | 2 +- examples/stm32f1/src/bin/pwm_input.rs | 2 +- examples/stm32f1/src/bin/usb_serial.rs | 4 +- examples/stm32f2/Cargo.toml | 2 +- examples/stm32f2/src/bin/pll.rs | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f3/src/bin/button_events.rs | 2 +- examples/stm32f3/src/bin/multiprio.rs | 4 +- examples/stm32f3/src/bin/usb_serial.rs | 4 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f334/src/bin/adc.rs | 2 +- examples/stm32f334/src/bin/opamp.rs | 2 +- examples/stm32f334/src/bin/pwm.rs | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f4/src/bin/adc_dma.rs | 2 +- examples/stm32f4/src/bin/eth.rs | 2 +- examples/stm32f4/src/bin/eth_compliance_test.rs | 2 +- examples/stm32f4/src/bin/eth_w5500.rs | 2 +- examples/stm32f4/src/bin/flash_async.rs | 2 +- examples/stm32f4/src/bin/input_capture.rs | 2 +- examples/stm32f4/src/bin/multiprio.rs | 4 +- examples/stm32f4/src/bin/pwm_complementary.rs | 2 +- examples/stm32f4/src/bin/pwm_input.rs | 2 +- examples/stm32f4/src/bin/rtc.rs | 2 +- examples/stm32f4/src/bin/sdmmc.rs | 4 +- examples/stm32f4/src/bin/usb_ethernet.rs | 4 +- examples/stm32f4/src/bin/usb_hid_keyboard.rs | 2 +- examples/stm32f4/src/bin/usb_hid_mouse.rs | 4 +- examples/stm32f4/src/bin/usb_raw.rs | 2 +- examples/stm32f4/src/bin/usb_serial.rs | 4 +- examples/stm32f4/src/bin/usb_uac_speaker.rs | 4 +- examples/stm32f4/src/bin/ws2812_pwm.rs | 2 +- examples/stm32f469/Cargo.toml | 2 +- examples/stm32f469/src/bin/dsi_bsp.rs | 6 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32f7/src/bin/can.rs | 2 +- examples/stm32f7/src/bin/cryp.rs | 4 +- examples/stm32f7/src/bin/eth.rs | 2 +- examples/stm32f7/src/bin/hash.rs | 2 +- examples/stm32f7/src/bin/qspi.rs | 2 +- examples/stm32f7/src/bin/sdmmc.rs | 4 +- examples/stm32f7/src/bin/usb_serial.rs | 4 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g0/src/bin/hf_timer.rs | 4 +- examples/stm32g0/src/bin/input_capture.rs | 4 +- examples/stm32g0/src/bin/pwm_complementary.rs | 2 +- examples/stm32g0/src/bin/pwm_input.rs | 2 +- examples/stm32g0/src/bin/rtc.rs | 2 +- examples/stm32g0/src/bin/usb_serial.rs | 4 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32g4/src/bin/adc.rs | 2 +- examples/stm32g4/src/bin/adc_differential.rs | 2 +- examples/stm32g4/src/bin/adc_dma.rs | 2 +- examples/stm32g4/src/bin/adc_oversampling.rs | 2 +- examples/stm32g4/src/bin/can.rs | 2 +- examples/stm32g4/src/bin/usb_c_pd.rs | 6 +- examples/stm32g4/src/bin/usb_serial.rs | 4 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h5/src/bin/adc.rs | 2 +- examples/stm32h5/src/bin/can.rs | 2 +- examples/stm32h5/src/bin/dts.rs | 2 +- examples/stm32h5/src/bin/eth.rs | 2 +- examples/stm32h5/src/bin/sai.rs | 2 +- examples/stm32h5/src/bin/usb_c_pd.rs | 6 +- examples/stm32h5/src/bin/usb_serial.rs | 4 +- examples/stm32h5/src/bin/usb_uac_speaker.rs | 4 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h7/src/bin/adc.rs | 2 +- examples/stm32h7/src/bin/adc_dma.rs | 2 +- examples/stm32h7/src/bin/camera.rs | 2 +- examples/stm32h7/src/bin/can.rs | 2 +- examples/stm32h7/src/bin/dac.rs | 2 +- examples/stm32h7/src/bin/dac_dma.rs | 2 +- examples/stm32h7/src/bin/eth.rs | 2 +- examples/stm32h7/src/bin/eth_client.rs | 4 +- examples/stm32h7/src/bin/eth_client_mii.rs | 4 +- examples/stm32h7/src/bin/fmc.rs | 2 +- examples/stm32h7/src/bin/i2c_shared.rs | 2 +- examples/stm32h7/src/bin/low_level_timer_api.rs | 2 +- examples/stm32h7/src/bin/multiprio.rs | 4 +- examples/stm32h7/src/bin/pwm.rs | 2 +- examples/stm32h7/src/bin/rng.rs | 2 +- examples/stm32h7/src/bin/rtc.rs | 2 +- examples/stm32h7/src/bin/sdmmc.rs | 2 +- examples/stm32h7/src/bin/spi.rs | 2 +- examples/stm32h7/src/bin/spi_bdma.rs | 2 +- examples/stm32h7/src/bin/spi_dma.rs | 2 +- examples/stm32h7/src/bin/usb_serial.rs | 4 +- examples/stm32h723/Cargo.toml | 2 +- examples/stm32h723/src/bin/spdifrx.rs | 4 +- examples/stm32h735/Cargo.toml | 2 +- examples/stm32h735/src/bin/ltdc.rs | 4 +- examples/stm32h742/Cargo.toml | 2 +- examples/stm32h742/src/bin/qspi.rs | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm4/src/bin/blinky.rs | 2 +- examples/stm32h755cm4/src/bin/intercore.rs | 6 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h755cm7/src/bin/blinky.rs | 2 +- examples/stm32h755cm7/src/bin/intercore.rs | 4 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32h7b0/src/bin/ospi_memory_mapped.rs | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32h7rs/src/bin/blinky.rs | 2 +- examples/stm32h7rs/src/bin/can.rs | 2 +- examples/stm32h7rs/src/bin/eth.rs | 2 +- examples/stm32h7rs/src/bin/multiprio.rs | 4 +- examples/stm32h7rs/src/bin/rng.rs | 2 +- examples/stm32h7rs/src/bin/rtc.rs | 2 +- examples/stm32h7rs/src/bin/usb_serial.rs | 4 +- examples/stm32h7rs/src/bin/xspi_memory_mapped.rs | 2 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l0/src/bin/button_exti.rs | 2 +- examples/stm32l0/src/bin/dds.rs | 2 +- examples/stm32l0/src/bin/eeprom.rs | 2 +- examples/stm32l0/src/bin/raw_spawn.rs | 4 +- examples/stm32l0/src/bin/usb_serial.rs | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l1/src/bin/eeprom.rs | 2 +- examples/stm32l1/src/bin/usb_serial.rs | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l4/src/bin/adc.rs | 2 +- examples/stm32l4/src/bin/can.rs | 2 +- examples/stm32l4/src/bin/dac_dma.rs | 2 +- examples/stm32l4/src/bin/rng.rs | 2 +- examples/stm32l4/src/bin/rtc.rs | 2 +- .../stm32l4/src/bin/spe_adin1110_http_server.rs | 10 +- examples/stm32l4/src/bin/usb_serial.rs | 4 +- examples/stm32l432/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32l5/src/bin/rng.rs | 2 +- examples/stm32l5/src/bin/usb_ethernet.rs | 4 +- examples/stm32l5/src/bin/usb_hid_mouse.rs | 4 +- examples/stm32l5/src/bin/usb_serial.rs | 4 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u0/src/bin/adc.rs | 2 +- examples/stm32u0/src/bin/rng.rs | 2 +- examples/stm32u0/src/bin/rtc.rs | 2 +- examples/stm32u0/src/bin/usb_serial.rs | 4 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32u5/src/bin/adc.rs | 2 +- examples/stm32u5/src/bin/ltdc.rs | 6 +- examples/stm32u5/src/bin/usb_hs_serial.rs | 4 +- examples/stm32u5/src/bin/usb_serial.rs | 4 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wb/src/bin/eddystone_beacon.rs | 4 +- examples/stm32wb/src/bin/gatt_server.rs | 2 +- examples/stm32wb/src/bin/mac_ffd.rs | 2 +- examples/stm32wb/src/bin/mac_ffd_net.rs | 2 +- examples/stm32wb/src/bin/mac_rfd.rs | 2 +- examples/stm32wb/src/bin/tl_mbox_mac.rs | 2 +- examples/stm32wba/Cargo.toml | 2 +- examples/stm32wba/src/bin/adc.rs | 2 +- examples/stm32wba/src/bin/pwm.rs | 2 +- examples/stm32wba6/Cargo.toml | 2 +- examples/stm32wba6/src/bin/adc.rs | 2 +- examples/stm32wba6/src/bin/pwm.rs | 2 +- examples/stm32wba6/src/bin/usb_hs_serial.rs | 4 +- examples/stm32wl/Cargo.toml | 2 +- examples/stm32wl/src/bin/adc.rs | 2 +- examples/stm32wl/src/bin/blinky.rs | 2 +- examples/stm32wl/src/bin/button.rs | 2 +- examples/stm32wl/src/bin/button_exti.rs | 2 +- examples/stm32wl/src/bin/flash.rs | 2 +- examples/stm32wl/src/bin/random.rs | 2 +- examples/stm32wl/src/bin/uart_async.rs | 2 +- examples/wasm/Cargo.toml | 2 +- rustfmt.toml | 2 +- tests/mspm0/Cargo.toml | 2 +- tests/mspm0/src/bin/dma.rs | 2 +- tests/nrf/Cargo.toml | 2 +- tests/perf-client/Cargo.toml | 2 +- tests/perf-client/src/lib.rs | 2 +- tests/perf-server/Cargo.toml | 2 +- tests/riscv32/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/rp/src/bin/cyw43-perf.rs | 2 +- tests/rp/src/bin/gpio_multicore.rs | 4 +- tests/rp/src/bin/multicore.rs | 2 +- tests/rp/src/bin/overclock.rs | 2 +- tests/rp/src/bin/pio_multi_load.rs | 4 +- tests/rp/src/bin/rtc.rs | 2 +- tests/rp/src/bin/spinlock_mutex_multicore.rs | 2 +- tests/stm32/Cargo.toml | 2 +- tests/stm32/src/bin/afio.rs | 2 +- tests/stm32/src/bin/cryp.rs | 2 +- tests/stm32/src/bin/fdcan.rs | 2 +- tests/stm32/src/bin/stop.rs | 4 +- tests/stm32/src/bin/ucpd.rs | 2 +- tests/stm32/src/bin/usart.rs | 2 +- tests/stm32/src/bin/wpan_ble.rs | 4 +- tests/stm32/src/bin/wpan_mac.rs | 2 +- tests/stm32/src/common.rs | 2 +- tests/utils/Cargo.toml | 2 +- tests/utils/src/bin/saturate_serial.rs | 2 +- 680 files changed, 2326 insertions(+), 1395 deletions(-) create mode 100644 embassy-mspm0/src/i2c_target.rs create mode 100644 examples/mspm0g3507/src/bin/i2c_target.rs create mode 100644 examples/mspm0l1306/src/bin/i2c_target.rs create mode 100644 examples/nrf5340/src/bin/nrf5340dk_internal_caps.rs create mode 100644 examples/nrf54l15/src/bin/rtc.rs diff --git a/.github/ci/build-nightly.sh b/.github/ci/build-nightly.sh index 8cca1b445..82e9436f3 100755 --- a/.github/ci/build-nightly.sh +++ b/.github/ci/build-nightly.sh @@ -23,7 +23,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev d015fd5e972a3e550ebef0da6748099b88a93ba6 ./ci-nightly.sh diff --git a/.github/ci/build-xtensa.sh b/.github/ci/build-xtensa.sh index dbd2f7ffc..3f74b4a5a 100755 --- a/.github/ci/build-xtensa.sh +++ b/.github/ci/build-xtensa.sh @@ -25,7 +25,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev d015fd5e972a3e550ebef0da6748099b88a93ba6 ./ci-xtensa.sh diff --git a/.github/ci/build.sh b/.github/ci/build.sh index d5e0e0bd2..3c196f72b 100755 --- a/.github/ci/build.sh +++ b/.github/ci/build.sh @@ -28,7 +28,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev d015fd5e972a3e550ebef0da6748099b88a93ba6 ./ci.sh diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index dab47e86d..535fc5262 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -12,7 +12,7 @@ export CARGO_TARGET_DIR=/ci/cache/target export PATH=$CARGO_HOME/bin:$PATH mv rust-toolchain-nightly.toml rust-toolchain.toml -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev d015fd5e972a3e550ebef0da6748099b88a93ba6 cargo embassy-devtool doc -o webroot diff --git a/.github/ci/janitor.sh b/.github/ci/janitor.sh index 305c6b227..bc43075bd 100755 --- a/.github/ci/janitor.sh +++ b/.github/ci/janitor.sh @@ -9,7 +9,7 @@ export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target export PATH=$CARGO_HOME/bin:$PATH -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev d015fd5e972a3e550ebef0da6748099b88a93ba6 cargo embassy-devtool check-crlf cargo embassy-devtool check-manifest diff --git a/.github/ci/rustfmt.sh b/.github/ci/rustfmt.sh index 369239cfe..7aaf93234 100755 --- a/.github/ci/rustfmt.sh +++ b/.github/ci/rustfmt.sh @@ -9,4 +9,4 @@ export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target mv rust-toolchain-nightly.toml rust-toolchain.toml -find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2021 +find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2024 diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 6ab5c453e..a10a091e9 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cyw43-pio" version = "0.8.0" -edition = "2021" +edition = "2024" description = "RP2040 PIO SPI implementation for cyw43" keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index b0be19358..41ac6816d 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -6,13 +6,13 @@ use core::slice; use cyw43::SpiBusCyw43; +use embassy_rp::Peri; use embassy_rp::dma::Channel; use embassy_rp::gpio::{Drive, Level, Output, Pull, SlewRate}; use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; -use embassy_rp::Peri; -use fixed::types::extra::U8; use fixed::FixedU32; +use fixed::types::extra::U8; /// SPI comms driven by PIO. pub struct PioSpi<'d, PIO: Instance, const SM: usize, DMA: Channel> { diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index c59c15a71..314427611 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cyw43" version = "0.5.0" -edition = "2021" +edition = "2024" description = "Rust driver for the CYW43439 WiFi chip, used in the Raspberry Pi Pico W." keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] diff --git a/cyw43/src/bluetooth.rs b/cyw43/src/bluetooth.rs index d176c4b09..332b7048d 100644 --- a/cyw43/src/bluetooth.rs +++ b/cyw43/src/bluetooth.rs @@ -15,7 +15,7 @@ use crate::bus::Bus; pub use crate::bus::SpiBusCyw43; use crate::consts::*; use crate::util::round_up; -use crate::{util, CHIP}; +use crate::{CHIP, util}; pub(crate) struct BtState { rx: [BtPacketBuf; 4], diff --git a/cyw43/src/bus.rs b/cyw43/src/bus.rs index 8a53484d5..aa2b66a40 100644 --- a/cyw43/src/bus.rs +++ b/cyw43/src/bus.rs @@ -340,11 +340,7 @@ where self.status = self.spi.cmd_read(cmd, &mut buf[..len]).await; // if we read from the backplane, the result is in the second word, after the response delay - if func == FUNC_BACKPLANE { - buf[1] - } else { - buf[0] - } + if func == FUNC_BACKPLANE { buf[1] } else { buf[0] } } async fn writen(&mut self, func: u32, addr: u32, val: u32, len: u32) { diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index fd0d4d532..49e3faee4 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -10,7 +10,7 @@ use crate::events::{Event, EventSubscriber, Events}; use crate::fmt::Bytes; use crate::ioctl::{IoctlState, IoctlType}; use crate::structs::*; -use crate::{countries, events, PowerManagementMode}; +use crate::{PowerManagementMode, countries, events}; /// Control errors. #[derive(Debug)] diff --git a/cyw43/src/ioctl.rs b/cyw43/src/ioctl.rs index 35135e296..deccc945d 100644 --- a/cyw43/src/ioctl.rs +++ b/cyw43/src/ioctl.rs @@ -1,5 +1,5 @@ use core::cell::{Cell, RefCell}; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::task::{Poll, Waker}; use embassy_sync::waitqueue::WakerRegistration; diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs index 16b436e66..82c636346 100644 --- a/cyw43/src/lib.rs +++ b/cyw43/src/lib.rs @@ -1,6 +1,7 @@ #![no_std] #![no_main] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![deny(unused_must_use)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs index 77910b281..7c38be24a 100644 --- a/cyw43/src/runner.rs +++ b/cyw43/src/runner.rs @@ -1,6 +1,6 @@ -use embassy_futures::select::{select4, Either4}; +use embassy_futures::select::{Either4, select4}; use embassy_net_driver_channel as ch; -use embassy_time::{block_for, Duration, Timer}; +use embassy_time::{Duration, Timer, block_for}; use embedded_hal_1::digital::OutputPin; use crate::bus::Bus; @@ -12,7 +12,7 @@ use crate::ioctl::{IoctlState, IoctlType, PendingIoctl}; use crate::nvram::NVRAM; use crate::structs::*; use crate::util::slice8_mut; -use crate::{events, Core, CHIP, MTU}; +use crate::{CHIP, Core, MTU, events}; #[cfg(feature = "firmware-logs")] struct LogState { diff --git a/docs/examples/layer-by-layer/blinky-async/Cargo.toml b/docs/examples/layer-by-layer/blinky-async/Cargo.toml index ec718022c..797ae3097 100644 --- a/docs/examples/layer-by-layer/blinky-async/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-async/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "blinky-async" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/docs/examples/layer-by-layer/blinky-hal/Cargo.toml b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml index 4a0b03a83..802b8b32e 100644 --- a/docs/examples/layer-by-layer/blinky-hal/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "blinky-hal" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/docs/examples/layer-by-layer/blinky-irq/Cargo.toml b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml index 3c4bf8446..d1b893a1e 100644 --- a/docs/examples/layer-by-layer/blinky-irq/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "blinky-irq" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/docs/examples/layer-by-layer/blinky-pac/Cargo.toml b/docs/examples/layer-by-layer/blinky-pac/Cargo.toml index 0d4711da2..fa093a3af 100644 --- a/docs/examples/layer-by-layer/blinky-pac/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-pac/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "blinky-pac" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/docs/pages/embassy_in_the_wild.adoc b/docs/pages/embassy_in_the_wild.adoc index cedbedada..3b58bb9b4 100644 --- a/docs/pages/embassy_in_the_wild.adoc +++ b/docs/pages/embassy_in_the_wild.adoc @@ -4,6 +4,8 @@ Here are known examples of real-world projects which make use of Embassy. Feel f _newer entries at the top_ +* link:https://github.com/1-rafael-1/air-quality-monitor[Air Quality Monitor] +** Air Quality Monitor based on rp2350 board, ens160 and aht21 sensors and ssd1306 display. Code and 3D printable enclosure included. * link:https://github.com/CarlKCarlK/clock[Embassy Clock: Layered, modular bare-metal clock with emulation] ** A `no_std` Raspberry Pi Pico clock demonstrating layered Embassy tasks (Display->Blinker->Clock) for clean separation of multiplexing, blinking, and UI logic. Features single-button HH:MM/MM:SS time-set UI, heapless data structures, and a Renode emulator for hardware-free testing. See link:https://medium.com/@carlmkadie/how-rust-embassy-shine-on-embedded-devices-part-2-aad1adfccf72[this article] for details. * link:https://github.com/1-rafael-1/simple-robot[A simple tracked robot based on Raspberry Pi Pico 2] @@ -11,7 +13,7 @@ _newer entries at the top_ * link:https://github.com/1-rafael-1/pi-pico-alarmclock-rust[A Raspberry Pi Pico W Alarmclock] ** A hobbyist project building an alarm clock around a Pi Pico W complete with code, components list and enclosure design files. * link:https://github.com/haobogu/rmk/[RMK: A feature-rich Rust keyboard firmware] -** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more! +** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more! ** Targets STM32, RP2040, nRF52 and ESP32 MCUs * link:https://github.com/cbruiz/printhor/[Printhor: The highly reliable but not necessarily functional 3D printer firmware] ** Targets some STM32 MCUs @@ -21,10 +23,9 @@ _newer entries at the top_ * link:https://github.com/matoushybl/air-force-one[Air force one: A simple air quality monitoring system] ** Targets nRF52 and uses nrf-softdevice -* link:https://github.com/schmettow/ylab-edge-go[YLab Edge Go] and link:https://github.com/schmettow/ylab-edge-pro[YLab Edge Pro] projects develop +* link:https://github.com/schmettow/ylab-edge-go[YLab Edge Go] and link:https://github.com/schmettow/ylab-edge-pro[YLab Edge Pro] projects develop firmware (RP2040, STM32) for capturing physiological data in behavioural science research. Included so far are: ** biopotentials (analog ports) ** motion capture (6-axis accelerometers) ** air quality (CO2, Temp, Humidity) ** comes with an app for capturing and visualizing data [link:https://github.com/schmettow/ystudio-zero[Ystudio]] - diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index 466f18631..787a28d70 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-nrf" version = "0.9.0" description = "Bootloader lib for nRF chips" diff --git a/embassy-boot-nrf/src/lib.rs b/embassy-boot-nrf/src/lib.rs index f1c9da080..b4c3c1151 100644 --- a/embassy-boot-nrf/src/lib.rs +++ b/embassy-boot-nrf/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] mod fmt; @@ -8,7 +9,7 @@ pub use embassy_boot::{ FirmwareUpdater, FirmwareUpdaterConfig, }; use embassy_nrf::nvmc::PAGE_SIZE; -use embassy_nrf::{wdt, Peri}; +use embassy_nrf::{Peri, wdt}; use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; /// A bootloader for nRF devices. diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index 894b77595..e80c79374 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-rp" version = "0.8.0" description = "Bootloader lib for RP2040 chips" diff --git a/embassy-boot-rp/src/lib.rs b/embassy-boot-rp/src/lib.rs index f704380ef..d090aee49 100644 --- a/embassy-boot-rp/src/lib.rs +++ b/embassy-boot-rp/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] mod fmt; @@ -7,10 +8,10 @@ pub use embassy_boot::{ AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootError, BootLoaderConfig, FirmwareState, FirmwareUpdater, FirmwareUpdaterConfig, State, }; -use embassy_rp::flash::{Blocking, Flash, ERASE_SIZE}; +use embassy_rp::Peri; +use embassy_rp::flash::{Blocking, ERASE_SIZE, Flash}; use embassy_rp::peripherals::{FLASH, WATCHDOG}; use embassy_rp::watchdog::Watchdog; -use embassy_rp::Peri; use embassy_time::Duration; use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml index 24eafcdbf..c8c7f4409 100644 --- a/embassy-boot-stm32/Cargo.toml +++ b/embassy-boot-stm32/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32" version = "0.6.0" description = "Bootloader lib for STM32 chips" diff --git a/embassy-boot-stm32/src/lib.rs b/embassy-boot-stm32/src/lib.rs index 387cc0ce5..ee6ae41b7 100644 --- a/embassy-boot-stm32/src/lib.rs +++ b/embassy-boot-stm32/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] mod fmt; diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index a18438c81..8c5c1f633 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot" version = "0.6.1" description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks." diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs index 5bffdc5ea..c38940d6e 100644 --- a/embassy-boot/src/boot_loader.rs +++ b/embassy-boot/src/boot_loader.rs @@ -1,11 +1,11 @@ use core::cell::RefCell; use embassy_embedded_hal::flash::partition::BlockingPartition; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; -use crate::{State, DFU_DETACH_MAGIC, REVERT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; +use crate::{DFU_DETACH_MAGIC, REVERT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC, State}; /// Errors returned by bootloader #[derive(PartialEq, Eq, Debug)] @@ -94,7 +94,7 @@ impl<'a, ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> dfu_flash: &'a Mutex>, state_flash: &'a Mutex>, ) -> Self { - extern "C" { + unsafe extern "C" { static __bootloader_state_start: u32; static __bootloader_state_end: u32; static __bootloader_active_start: u32; diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index 66e311e38..26d4d39bd 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embedded_storage_async::nor_flash::NorFlash; use super::FirmwareUpdaterConfig; -use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; +use crate::{BOOT_MAGIC, DFU_DETACH_MAGIC, FirmwareUpdaterError, STATE_ERASE_VALUE, SWAP_MAGIC, State}; /// FirmwareUpdater is an application API for interacting with the BootLoader without the ability to /// 'mess up' the internal bootloader state @@ -25,7 +25,7 @@ impl<'a, DFU: NorFlash, STATE: NorFlash> dfu_flash: &'a embassy_sync::mutex::Mutex, state_flash: &'a embassy_sync::mutex::Mutex, ) -> Self { - extern "C" { + unsafe extern "C" { static __bootloader_state_start: u32; static __bootloader_state_end: u32; static __bootloader_dfu_start: u32; diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index 0fedac1ea..5554025fc 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embedded_storage::nor_flash::NorFlash; use super::FirmwareUpdaterConfig; -use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; +use crate::{BOOT_MAGIC, DFU_DETACH_MAGIC, FirmwareUpdaterError, STATE_ERASE_VALUE, SWAP_MAGIC, State}; /// Blocking FirmwareUpdater is an application API for interacting with the BootLoader without the ability to /// 'mess up' the internal bootloader state @@ -55,7 +55,7 @@ impl<'a, DFU: NorFlash, STATE: NorFlash> dfu_flash: &'a embassy_sync::blocking_mutex::Mutex>, state_flash: &'a embassy_sync::blocking_mutex::Mutex>, ) -> Self { - extern "C" { + unsafe extern "C" { static __bootloader_state_start: u32; static __bootloader_state_end: u32; static __bootloader_dfu_start: u32; @@ -399,8 +399,8 @@ mod tests { use core::cell::RefCell; use embassy_embedded_hal::flash::partition::BlockingPartition; - use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; + use embassy_sync::blocking_mutex::raw::NoopRawMutex; use sha1::{Digest, Sha1}; use super::*; diff --git a/embassy-boot/src/lib.rs b/embassy-boot/src/lib.rs index e2c4cf771..7dc811f66 100644 --- a/embassy-boot/src/lib.rs +++ b/embassy-boot/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] mod fmt; @@ -341,11 +342,13 @@ mod tests { &mut aligned, ); - assert!(block_on(updater.verify_and_mark_updated( - &public_key.to_bytes(), - &signature.to_bytes(), - firmware_len as u32, - )) - .is_ok()); + assert!( + block_on(updater.verify_and_mark_updated( + &public_key.to_bytes(), + &signature.to_bytes(), + firmware_len as u32, + )) + .is_ok() + ); } } diff --git a/embassy-boot/src/test_flash/blocking.rs b/embassy-boot/src/test_flash/blocking.rs index 5ec476c65..7334346fd 100644 --- a/embassy-boot/src/test_flash/blocking.rs +++ b/embassy-boot/src/test_flash/blocking.rs @@ -1,8 +1,8 @@ use core::cell::RefCell; use embassy_embedded_hal::flash::partition::BlockingPartition; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embedded_storage::nor_flash::NorFlash; use crate::BootLoaderConfig; diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index 8b8122567..c9551257a 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-embedded-hal" version = "0.5.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Collection of utilities to use `embedded-hal` and `embedded-storage` traits with Embassy." repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-embedded-hal/src/flash/partition/blocking.rs b/embassy-embedded-hal/src/flash/partition/blocking.rs index cb30290a8..bd9329e2d 100644 --- a/embassy-embedded-hal/src/flash/partition/blocking.rs +++ b/embassy-embedded-hal/src/flash/partition/blocking.rs @@ -1,7 +1,7 @@ use core::cell::RefCell; -use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::RawMutex; use embedded_storage::nor_flash::{ErrorType, MultiwriteNorFlash, NorFlash, ReadNorFlash}; use super::Error; diff --git a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs index 48246270e..9c7d3ee71 100644 --- a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs @@ -26,8 +26,8 @@ use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::mutex::Mutex; use embedded_hal_async::i2c; -use crate::shared_bus::I2cDeviceError; use crate::SetConfig; +use crate::shared_bus::I2cDeviceError; /// I2C device on a shared bus. pub struct I2cDevice<'a, M: RawMutex, BUS> { diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs index 0faefbc1e..869a78164 100644 --- a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs @@ -32,8 +32,8 @@ use embedded_hal_1::digital::OutputPin; use embedded_hal_1::spi::Operation; use embedded_hal_async::spi; -use crate::shared_bus::SpiDeviceError; use crate::SetConfig; +use crate::shared_bus::SpiDeviceError; /// SPI device on a shared bus. pub struct SpiDevice<'a, M: RawMutex, BUS, CS> { diff --git a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs index dc634a209..49b50f8c1 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs @@ -17,12 +17,12 @@ use core::cell::RefCell; -use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::RawMutex; use embedded_hal_1::i2c::{ErrorType, I2c, Operation}; -use crate::shared_bus::I2cDeviceError; use crate::SetConfig; +use crate::shared_bus::I2cDeviceError; /// I2C device on a shared bus. pub struct I2cDevice<'a, M: RawMutex, BUS> { diff --git a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs index ffe2aa1c6..48fe2f4c4 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs @@ -19,13 +19,13 @@ use core::cell::RefCell; -use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::RawMutex; use embedded_hal_1::digital::OutputPin; use embedded_hal_1::spi::{self, Operation, SpiBus}; -use crate::shared_bus::SpiDeviceError; use crate::SetConfig; +use crate::shared_bus::SpiDeviceError; /// SPI device on a shared bus. pub struct SpiDevice<'a, M: RawMutex, BUS, CS> { diff --git a/embassy-executor-macros/Cargo.toml b/embassy-executor-macros/Cargo.toml index 9c2b40d03..3eeed5e4d 100644 --- a/embassy-executor-macros/Cargo.toml +++ b/embassy-executor-macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-executor-macros" version = "0.7.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "macros for creating the entry point and tasks for embassy-executor" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs index dc470e51c..c259c003f 100644 --- a/embassy-executor-macros/src/macros/main.rs +++ b/embassy-executor-macros/src/macros/main.rs @@ -1,7 +1,7 @@ use std::str::FromStr; -use darling::export::NestedMeta; use darling::FromMeta; +use darling::export::NestedMeta; use proc_macro2::TokenStream; use quote::quote; use syn::{ReturnType, Type}; @@ -183,7 +183,7 @@ For example: `#[embassy_executor::main(entry = ..., executor = \"some_crate::Exe quote!(!), quote! { unsafe fn __make_static(t: &mut T) -> &'static mut T { - ::core::mem::transmute(t) + unsafe { ::core::mem::transmute(t) } } let mut executor = #executor::new(); diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs index 755948882..8ce8d6726 100644 --- a/embassy-executor-macros/src/macros/task.rs +++ b/embassy-executor-macros/src/macros/task.rs @@ -1,7 +1,7 @@ use std::str::FromStr; -use darling::export::NestedMeta; use darling::FromMeta; +use darling::export::NestedMeta; use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote}; use syn::visit::{self, Visit}; @@ -287,7 +287,11 @@ fn check_arg_ty(errors: &mut TokenStream, ty: &Type) { } fn visit_type_impl_trait(&mut self, i: &'ast syn::TypeImplTrait) { - error(self.errors, i, "`impl Trait` is not allowed in task arguments. It is syntax sugar for generics, and tasks can't be generic."); + error( + self.errors, + i, + "`impl Trait` is not allowed in task arguments. It is syntax sugar for generics, and tasks can't be generic.", + ); } } diff --git a/embassy-executor-macros/src/util.rs b/embassy-executor-macros/src/util.rs index ebd032a62..5a13f2121 100644 --- a/embassy-executor-macros/src/util.rs +++ b/embassy-executor-macros/src/util.rs @@ -3,7 +3,7 @@ use std::fmt::Display; use proc_macro2::{TokenStream, TokenTree}; use quote::{ToTokens, TokenStreamExt}; use syn::parse::{Parse, ParseStream}; -use syn::{braced, bracketed, token, AttrStyle, Attribute, Signature, Token, Visibility}; +use syn::{AttrStyle, Attribute, Signature, Token, Visibility, braced, bracketed, token}; pub fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream { tokens.extend(error.into_compile_error()); diff --git a/embassy-executor-timer-queue/Cargo.toml b/embassy-executor-timer-queue/Cargo.toml index a0ac44420..6770ab26e 100644 --- a/embassy-executor-timer-queue/Cargo.toml +++ b/embassy-executor-timer-queue/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-executor-timer-queue" version = "0.1.0" -edition = "2021" +edition = "2024" description = "Timer queue item and interface between embassy-executor and timer queues" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-executor-timer-queue" diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index 6f079a11a..47a8ae995 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Upgraded rtos-trace - Added optional "highest priority" scheduling - Added optional "earliest deadline first" EDF scheduling +- Bump `cortex-ar` to v0.3 ## 0.9.1 - 2025-08-31 diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 61d060630..ecc4b6338 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-executor" version = "0.9.1" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "async/await executor designed for embedded usage" repository = "https://github.com/embassy-rs/embassy" @@ -30,6 +30,8 @@ build = [ {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "embassy-time-driver", "scheduler-deadline"]}, {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "scheduler-priority", "scheduler-deadline"]}, {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "scheduler-deadline"]}, + {target = "thumbv7em-none-eabi", features = ["arch-spin"]}, + {target = "thumbv7em-none-eabi", features = ["arch-spin", "scheduler-deadline"]}, {target = "armv7a-none-eabi", features = ["arch-cortex-ar", "executor-thread"]}, {target = "armv7r-none-eabi", features = ["arch-cortex-ar", "executor-thread"]}, {target = "armv7r-none-eabihf", features = ["arch-cortex-ar", "executor-thread"]}, @@ -98,7 +100,7 @@ portable-atomic = { version = "1.5", optional = true } cortex-m = { version = "0.7.6", optional = true } # arch-cortex-ar dependencies -cortex-ar = { version = "0.2", optional = true } +cortex-ar = { version = "0.3", optional = true } # arch-wasm dependencies wasm-bindgen = { version = "0.2.82", optional = true } diff --git a/embassy-executor/src/arch/avr.rs b/embassy-executor/src/arch/avr.rs index 70085d04d..a841afe15 100644 --- a/embassy-executor/src/arch/avr.rs +++ b/embassy-executor/src/arch/avr.rs @@ -10,11 +10,11 @@ mod thread { pub use embassy_executor_macros::main_avr as main; use portable_atomic::{AtomicBool, Ordering}; - use crate::{raw, Spawner}; + use crate::{Spawner, raw}; static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); - #[export_name = "__pender"] + #[unsafe(export_name = "__pender")] fn __pender(_context: *mut ()) { SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); } diff --git a/embassy-executor/src/arch/cortex_ar.rs b/embassy-executor/src/arch/cortex_ar.rs index f9e2f3f7c..a9be3d323 100644 --- a/embassy-executor/src/arch/cortex_ar.rs +++ b/embassy-executor/src/arch/cortex_ar.rs @@ -1,7 +1,7 @@ #[cfg(feature = "executor-interrupt")] compile_error!("`executor-interrupt` is not supported with `arch-cortex-ar`."); -#[export_name = "__pender"] +#[unsafe(export_name = "__pender")] #[cfg(any(feature = "executor-thread", feature = "executor-interrupt"))] fn __pender(context: *mut ()) { // `context` is always `usize::MAX` created by `Executor::run`. @@ -26,7 +26,7 @@ mod thread { use cortex_ar::asm::wfe; pub use embassy_executor_macros::main_cortex_ar as main; - use crate::{raw, Spawner}; + use crate::{Spawner, raw}; /// Thread mode executor, using WFE/SEV. /// diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs index 1c9ddd8a0..1ce96d1d5 100644 --- a/embassy-executor/src/arch/cortex_m.rs +++ b/embassy-executor/src/arch/cortex_m.rs @@ -1,4 +1,4 @@ -#[export_name = "__pender"] +#[unsafe(export_name = "__pender")] #[cfg(any(feature = "executor-thread", feature = "executor-interrupt"))] fn __pender(context: *mut ()) { unsafe { @@ -53,7 +53,7 @@ mod thread { pub use embassy_executor_macros::main_cortex_m as main; - use crate::{raw, Spawner}; + use crate::{Spawner, raw}; /// Thread mode executor, using WFE/SEV. /// diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs index 01e63a9fd..c70c1344a 100644 --- a/embassy-executor/src/arch/riscv32.rs +++ b/embassy-executor/src/arch/riscv32.rs @@ -10,12 +10,12 @@ mod thread { pub use embassy_executor_macros::main_riscv as main; - use crate::{raw, Spawner}; + use crate::{Spawner, raw}; /// global atomic used to keep track of whether there is work to do since sev() is not available on RISCV static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); - #[export_name = "__pender"] + #[unsafe(export_name = "__pender")] fn __pender(_context: *mut ()) { SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); } diff --git a/embassy-executor/src/arch/spin.rs b/embassy-executor/src/arch/spin.rs index 340023620..49f3356a6 100644 --- a/embassy-executor/src/arch/spin.rs +++ b/embassy-executor/src/arch/spin.rs @@ -9,9 +9,9 @@ mod thread { pub use embassy_executor_macros::main_spin as main; - use crate::{raw, Spawner}; + use crate::{Spawner, raw}; - #[export_name = "__pender"] + #[unsafe(export_name = "__pender")] fn __pender(_context: *mut ()) {} /// Spin Executor diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs index b02b15988..c62ab723b 100644 --- a/embassy-executor/src/arch/std.rs +++ b/embassy-executor/src/arch/std.rs @@ -10,9 +10,9 @@ mod thread { pub use embassy_executor_macros::main_std as main; - use crate::{raw, Spawner}; + use crate::{Spawner, raw}; - #[export_name = "__pender"] + #[unsafe(export_name = "__pender")] fn __pender(context: *mut ()) { let signaler: &'static Signaler = unsafe { std::mem::transmute(context) }; signaler.signal() diff --git a/embassy-executor/src/arch/wasm.rs b/embassy-executor/src/arch/wasm.rs index f9d0f935c..d2ff2fe51 100644 --- a/embassy-executor/src/arch/wasm.rs +++ b/embassy-executor/src/arch/wasm.rs @@ -13,9 +13,9 @@ mod thread { use wasm_bindgen::prelude::*; use crate::raw::util::UninitCell; - use crate::{raw, Spawner}; + use crate::{Spawner, raw}; - #[export_name = "__pender"] + #[unsafe(export_name = "__pender")] fn __pender(context: *mut ()) { let signaler: &'static WasmContext = unsafe { std::mem::transmute(context) }; let _ = signaler.promise.then(unsafe { signaler.closure.as_mut() }); diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index e47b8eb9f..cffc76699 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(any(feature = "arch-std", feature = "arch-wasm")), no_std)] #![allow(clippy::new_without_default)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/embassy-executor/src/metadata.rs b/embassy-executor/src/metadata.rs index bc0df0f83..76504ab0b 100644 --- a/embassy-executor/src/metadata.rs +++ b/embassy-executor/src/metadata.rs @@ -1,6 +1,6 @@ #[cfg(feature = "metadata-name")] use core::cell::Cell; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; #[cfg(feature = "scheduler-priority")] use core::sync::atomic::{AtomicU8, Ordering}; use core::task::Poll; diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index dbd70cbf4..ab845ed3b 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -52,7 +52,7 @@ pub use self::waker::task_from_waker; use super::SpawnToken; use crate::{Metadata, SpawnError}; -#[no_mangle] +#[unsafe(no_mangle)] extern "Rust" fn __embassy_time_queue_item_from_waker(waker: &Waker) -> &'static mut TimerQueueItem { unsafe { task_from_waker(waker).timer_queue_item() } } @@ -407,7 +407,7 @@ unsafe impl Sync for Pender {} impl Pender { pub(crate) fn pend(self) { - extern "Rust" { + unsafe extern "Rust" { fn __pender(context: *mut ()); } unsafe { __pender(self.0) }; @@ -507,7 +507,7 @@ impl SyncExecutor { /// The pender function must be exported with the name `__pender` and have the following signature: /// /// ```rust -/// #[export_name = "__pender"] +/// #[unsafe(export_name = "__pender")] /// fn pender(context: *mut ()) { /// // schedule `poll()` to be called /// } diff --git a/embassy-executor/src/raw/run_queue.rs b/embassy-executor/src/raw/run_queue.rs index b8b052310..6f2abdbd0 100644 --- a/embassy-executor/src/raw/run_queue.rs +++ b/embassy-executor/src/raw/run_queue.rs @@ -1,9 +1,9 @@ -use core::ptr::{addr_of_mut, NonNull}; +use core::ptr::{NonNull, addr_of_mut}; -use cordyceps::sorted_list::Links; use cordyceps::Linked; #[cfg(any(feature = "scheduler-priority", feature = "scheduler-deadline"))] use cordyceps::SortedList; +use cordyceps::sorted_list::Links; #[cfg(target_has_atomic = "ptr")] type TransferStack = cordyceps::TransferStack; diff --git a/embassy-executor/src/raw/state_atomics_arm.rs b/embassy-executor/src/raw/state_atomics_arm.rs index b743dcc2c..f68de955f 100644 --- a/embassy-executor/src/raw/state_atomics_arm.rs +++ b/embassy-executor/src/raw/state_atomics_arm.rs @@ -1,4 +1,4 @@ -use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicU32, Ordering, compiler_fence}; #[derive(Clone, Copy)] pub(crate) struct Token(()); diff --git a/embassy-executor/src/raw/state_critical_section.rs b/embassy-executor/src/raw/state_critical_section.rs index b69a6ac66..8d7ef2892 100644 --- a/embassy-executor/src/raw/state_critical_section.rs +++ b/embassy-executor/src/raw/state_critical_section.rs @@ -1,7 +1,7 @@ use core::cell::Cell; -pub(crate) use critical_section::{with as locked, CriticalSection as Token}; use critical_section::{CriticalSection, Mutex}; +pub(crate) use critical_section::{CriticalSection as Token, with as locked}; #[cfg(target_arch = "avr")] type StateBits = u8; diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index b3086948c..74519b927 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -368,11 +368,7 @@ impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { } fn time() -> u64 { const fn gcd(a: u64, b: u64) -> u64 { - if b == 0 { - a - } else { - gcd(b, a % b) - } + if b == 0 { a } else { gcd(b, a % b) } } const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000); diff --git a/embassy-executor/src/raw/waker.rs b/embassy-executor/src/raw/waker.rs index d0d7b003d..2706f0fdf 100644 --- a/embassy-executor/src/raw/waker.rs +++ b/embassy-executor/src/raw/waker.rs @@ -1,6 +1,6 @@ use core::task::{RawWaker, RawWakerVTable, Waker}; -use super::{wake_task, TaskHeader, TaskRef}; +use super::{TaskHeader, TaskRef, wake_task}; static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake, drop); @@ -35,7 +35,9 @@ pub fn task_from_waker(waker: &Waker) -> TaskRef { // make sure to compare vtable addresses. Doing `==` on the references // will compare the contents, which is slower. if waker.vtable() as *const _ != &VTABLE as *const _ { - panic!("Found waker not created by the Embassy executor. `embassy_time::Timer` only works with the Embassy executor.") + panic!( + "Found waker not created by the Embassy executor. `embassy_time::Timer` only works with the Embassy executor." + ) } // safety: our wakers are always created with `TaskRef::as_ptr` unsafe { TaskRef::from_ptr(waker.data() as *const TaskHeader) } diff --git a/embassy-executor/src/raw/waker_turbo.rs b/embassy-executor/src/raw/waker_turbo.rs index 435a0ff7e..919bcc61a 100644 --- a/embassy-executor/src/raw/waker_turbo.rs +++ b/embassy-executor/src/raw/waker_turbo.rs @@ -1,7 +1,7 @@ use core::ptr::NonNull; use core::task::Waker; -use super::{wake_task, TaskHeader, TaskRef}; +use super::{TaskHeader, TaskRef, wake_task}; pub(crate) unsafe fn from_task(p: TaskRef) -> Waker { Waker::from_turbo_ptr(NonNull::new_unchecked(p.as_ptr() as _)) @@ -26,7 +26,7 @@ pub fn task_from_waker(waker: &Waker) -> TaskRef { } #[inline(never)] -#[no_mangle] +#[unsafe(no_mangle)] fn _turbo_wake(ptr: NonNull<()>) { // safety: our wakers are always created with `TaskRef::as_ptr` let task = unsafe { TaskRef::from_ptr(ptr.as_ptr() as *const TaskHeader) }; diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index 83d896b76..b73a1e7c6 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -1,4 +1,4 @@ -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::mem; use core::sync::atomic::Ordering; @@ -75,7 +75,10 @@ impl core::fmt::Debug for SpawnError { impl core::fmt::Display for SpawnError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - SpawnError::Busy => write!(f, "Busy - Too many instances of this task are already running. Check the `pool_size` attribute of the task."), + SpawnError::Busy => write!( + f, + "Busy - Too many instances of this task are already running. Check the `pool_size` attribute of the task." + ), } } } @@ -84,7 +87,10 @@ impl core::fmt::Display for SpawnError { impl defmt::Format for SpawnError { fn format(&self, f: defmt::Formatter) { match self { - SpawnError::Busy => defmt::write!(f, "Busy - Too many instances of this task are already running. Check the `pool_size` attribute of the task."), + SpawnError::Busy => defmt::write!( + f, + "Busy - Too many instances of this task are already running. Check the `pool_size` attribute of the task." + ), } } } diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs index 6baf3dc21..a99976168 100644 --- a/embassy-executor/tests/test.rs +++ b/embassy-executor/tests/test.rs @@ -2,14 +2,14 @@ #![cfg_attr(feature = "nightly", feature(never_type))] use std::boxed::Box; -use std::future::{poll_fn, Future}; +use std::future::{Future, poll_fn}; use std::sync::{Arc, Mutex}; use std::task::Poll; use embassy_executor::raw::Executor; -use embassy_executor::{task, Spawner}; +use embassy_executor::{Spawner, task}; -#[export_name = "__pender"] +#[unsafe(export_name = "__pender")] fn __pender(context: *mut ()) { unsafe { let trace = &*(context as *const Trace); diff --git a/embassy-executor/tests/ui/nonstatic_struct_elided.stderr b/embassy-executor/tests/ui/nonstatic_struct_elided.stderr index 0ee1bfe0c..e6829bf5d 100644 --- a/embassy-executor/tests/ui/nonstatic_struct_elided.stderr +++ b/embassy-executor/tests/ui/nonstatic_struct_elided.stderr @@ -9,16 +9,16 @@ help: indicate the anonymous lifetime 6 | async fn task(_x: Foo<'_>) {} | ++++ -error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds +error: lifetime may not live long enough --> tests/ui/nonstatic_struct_elided.rs:5:1 | 5 | #[embassy_executor::task] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type defined here + | ^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` 6 | async fn task(_x: Foo) {} - | --- hidden type `impl Sized` captures the anonymous lifetime defined here + | -- has type `Foo<'1>` | = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info) -help: add a `use<...>` bound to explicitly capture `'_` +help: to declare that `impl Sized` captures data from argument `_x`, you can add an explicit `'_` lifetime bound | -5 | #[embassy_executor::task] + use<'_> - | +++++++++ +5 | #[embassy_executor::task] + '_ + | ++++ diff --git a/embassy-executor/tests/ui/task_safety_attribute.rs b/embassy-executor/tests/ui/task_safety_attribute.rs index ab5a2f99f..46a5c665f 100644 --- a/embassy-executor/tests/ui/task_safety_attribute.rs +++ b/embassy-executor/tests/ui/task_safety_attribute.rs @@ -9,7 +9,7 @@ async fn safe() {} #[embassy_executor::task] async unsafe fn not_safe() {} -#[export_name = "__pender"] +#[unsafe(export_name = "__pender")] fn pender(_: *mut ()) { // The test doesn't link if we don't include this. // We never call this anyway. diff --git a/embassy-futures/Cargo.toml b/embassy-futures/Cargo.toml index 07d5219cf..d344e5c4b 100644 --- a/embassy-futures/Cargo.toml +++ b/embassy-futures/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-futures" version = "0.1.2" -edition = "2021" +edition = "2024" description = "no-std, no-alloc utilities for working with futures" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-futures" diff --git a/embassy-hal-internal/Cargo.toml b/embassy-hal-internal/Cargo.toml index 11dcc2466..c2e0bd30f 100644 --- a/embassy-hal-internal/Cargo.toml +++ b/embassy-hal-internal/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-hal-internal" version = "0.3.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Internal implementation details for Embassy HALs. DO NOT USE DIRECTLY." repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-hal-internal/src/interrupt.rs b/embassy-hal-internal/src/interrupt.rs index 5e64dce9d..ce6057e2d 100644 --- a/embassy-hal-internal/src/interrupt.rs +++ b/embassy-hal-internal/src/interrupt.rs @@ -1,6 +1,6 @@ //! Interrupt handling for cortex-m devices. use core::mem; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use cortex_m::interrupt::InterruptNumber; use cortex_m::peripheral::NVIC; diff --git a/embassy-hal-internal/src/lib.rs b/embassy-hal-internal/src/lib.rs index 7addb71e2..729f97f0c 100644 --- a/embassy-hal-internal/src/lib.rs +++ b/embassy-hal-internal/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![allow(clippy::new_without_default)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/embassy-hal-internal/src/macros.rs b/embassy-hal-internal/src/macros.rs index ce72ded5c..0fcca2baf 100644 --- a/embassy-hal-internal/src/macros.rs +++ b/embassy-hal-internal/src/macros.rs @@ -58,7 +58,7 @@ macro_rules! peripherals_struct { ///Returns all the peripherals *once* #[inline] pub(crate) fn take_with_cs(_cs: critical_section::CriticalSection) -> Self { - #[no_mangle] + #[unsafe(no_mangle)] static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false; // safety: OK because we're inside a CS. diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml index 7561640dd..c47756f10 100644 --- a/embassy-imxrt/Cargo.toml +++ b/embassy-imxrt/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-imxrt" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for the IMXRT microcontroller" keywords = ["embedded", "async", "imxrt", "rt600", "embedded-hal"] diff --git a/embassy-imxrt/src/clocks.rs b/embassy-imxrt/src/clocks.rs index 39c3e6238..22df2686f 100644 --- a/embassy-imxrt/src/clocks.rs +++ b/embassy-imxrt/src/clocks.rs @@ -1,5 +1,5 @@ //! Clock configuration for the `RT6xx` -use core::sync::atomic::{AtomicU32, AtomicU8, Ordering}; +use core::sync::atomic::{AtomicU8, AtomicU32, Ordering}; use paste::paste; diff --git a/embassy-imxrt/src/crc.rs b/embassy-imxrt/src/crc.rs index 24d6ba5bd..d6f0419d0 100644 --- a/embassy-imxrt/src/crc.rs +++ b/embassy-imxrt/src/crc.rs @@ -2,9 +2,9 @@ use core::marker::PhantomData; -use crate::clocks::{enable_and_reset, SysconPeripheral}; +use crate::clocks::{SysconPeripheral, enable_and_reset}; pub use crate::pac::crc_engine::mode::CrcPolynomial as Polynomial; -use crate::{peripherals, Peri, PeripheralType}; +use crate::{Peri, PeripheralType, peripherals}; /// CRC driver. pub struct Crc<'d> { diff --git a/embassy-imxrt/src/dma.rs b/embassy-imxrt/src/dma.rs index e141447f3..e71a27e0e 100644 --- a/embassy-imxrt/src/dma.rs +++ b/embassy-imxrt/src/dma.rs @@ -2,10 +2,10 @@ use core::future::Future; use core::pin::Pin; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use pac::dma0::channel::cfg::Periphreqen; use pac::dma0::channel::xfercfg::{Dstinc, Srcinc, Width}; @@ -14,7 +14,7 @@ use crate::clocks::enable_and_reset; use crate::interrupt::InterruptExt; use crate::peripherals::DMA0; use crate::sealed::Sealed; -use crate::{interrupt, pac, peripherals, BitIter}; +use crate::{BitIter, interrupt, pac, peripherals}; #[cfg(feature = "rt")] #[interrupt] diff --git a/embassy-imxrt/src/flexcomm/mod.rs b/embassy-imxrt/src/flexcomm/mod.rs index 4473c9a77..27794042b 100644 --- a/embassy-imxrt/src/flexcomm/mod.rs +++ b/embassy-imxrt/src/flexcomm/mod.rs @@ -4,11 +4,11 @@ pub mod uart; use paste::paste; -use crate::clocks::{enable_and_reset, SysconPeripheral}; +use crate::clocks::{SysconPeripheral, enable_and_reset}; use crate::peripherals::{ - FLEXCOMM0, FLEXCOMM1, FLEXCOMM14, FLEXCOMM15, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, + FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM14, FLEXCOMM15, }; -use crate::{pac, PeripheralType}; +use crate::{PeripheralType, pac}; /// clock selection option #[derive(Copy, Clone, Debug)] @@ -223,9 +223,15 @@ macro_rules! into_mode { } } -into_mode!(usart, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7); -into_mode!(spi, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM14); -into_mode!(i2c, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM15); +into_mode!( + usart, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7 +); +into_mode!( + spi, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM14 +); +into_mode!( + i2c, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM15 +); into_mode!( i2s_transmit, diff --git a/embassy-imxrt/src/flexcomm/uart.rs b/embassy-imxrt/src/flexcomm/uart.rs index 230b30d43..2b759ba84 100644 --- a/embassy-imxrt/src/flexcomm/uart.rs +++ b/embassy-imxrt/src/flexcomm/uart.rs @@ -2,10 +2,10 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, AtomicU8, Ordering}; +use core::sync::atomic::{AtomicU8, Ordering, compiler_fence}; use core::task::Poll; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; diff --git a/embassy-imxrt/src/gpio.rs b/embassy-imxrt/src/gpio.rs index e62fde8b1..4a0608e76 100644 --- a/embassy-imxrt/src/gpio.rs +++ b/embassy-imxrt/src/gpio.rs @@ -13,7 +13,7 @@ use crate::clocks::enable_and_reset; use crate::iopctl::IopctlPin; pub use crate::iopctl::{AnyPin, DriveMode, DriveStrength, Function, Inverter, Pull, SlewRate}; use crate::sealed::Sealed; -use crate::{interrupt, peripherals, BitIter, Peri, PeripheralType}; +use crate::{BitIter, Peri, PeripheralType, interrupt, peripherals}; // This should be unique per IMXRT package const PORT_COUNT: usize = 8; diff --git a/embassy-imxrt/src/iopctl.rs b/embassy-imxrt/src/iopctl.rs index a3b8b14d6..805bf2f1b 100644 --- a/embassy-imxrt/src/iopctl.rs +++ b/embassy-imxrt/src/iopctl.rs @@ -2,7 +2,7 @@ //! //! Also known as IO Pin Configuration (IOCON) -use crate::pac::{iopctl, Iopctl}; +use crate::pac::{Iopctl, iopctl}; // A generic pin of any type. // diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs index a3437c655..643dd0c8a 100644 --- a/embassy-imxrt/src/lib.rs +++ b/embassy-imxrt/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] @@ -39,7 +40,7 @@ pub use chip::interrupts::*; pub use chip::pac; #[cfg(not(feature = "unstable-pac"))] pub(crate) use chip::pac; -pub use chip::{peripherals, Peripherals}; +pub use chip::{Peripherals, peripherals}; pub use embassy_hal_internal::{Peri, PeripheralType}; #[cfg(feature = "rt")] @@ -74,7 +75,7 @@ macro_rules! bind_interrupts { $( #[allow(non_snake_case)] - #[no_mangle] + #[unsafe(no_mangle)] unsafe extern "C" fn $irq() { unsafe { $( diff --git a/embassy-imxrt/src/rng.rs b/embassy-imxrt/src/rng.rs index 75f243df9..094418e41 100644 --- a/embassy-imxrt/src/rng.rs +++ b/embassy-imxrt/src/rng.rs @@ -7,9 +7,9 @@ use core::task::Poll; use embassy_futures::block_on; use embassy_sync::waitqueue::AtomicWaker; -use crate::clocks::{enable_and_reset, SysconPeripheral}; +use crate::clocks::{SysconPeripheral, enable_and_reset}; use crate::interrupt::typelevel::Interrupt; -use crate::{interrupt, peripherals, Peri, PeripheralType}; +use crate::{Peri, PeripheralType, interrupt, peripherals}; static RNG_WAKER: AtomicWaker = AtomicWaker::new(); diff --git a/embassy-imxrt/src/time_driver.rs b/embassy-imxrt/src/time_driver.rs index f127609c8..fbd935b70 100644 --- a/embassy-imxrt/src/time_driver.rs +++ b/embassy-imxrt/src/time_driver.rs @@ -1,11 +1,11 @@ //! Time Driver. use core::cell::{Cell, RefCell}; #[cfg(feature = "time-driver-rtc")] -use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; use critical_section::CriticalSection; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_time_driver::Driver; use embassy_time_queue_utils::Queue; diff --git a/embassy-mspm0/CHANGELOG.md b/embassy-mspm0/CHANGELOG.md index b846f21b1..fcb0f9dbd 100644 --- a/embassy-mspm0/CHANGELOG.md +++ b/embassy-mspm0/CHANGELOG.md @@ -13,3 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - feat: Add window watchdog implementation based on WWDT0, WWDT1 peripherals (#4574) - feat: Add MSPM0C1105/C1106 support - feat: Add adc implementation (#4646) +- fix: gpio OutputOpenDrain config (#4735) +- fix: add MSPM0C1106 to build test matrix +- feat: add MSPM0H3216 support +- feat: Add i2c target implementation (#4605) diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml index 1b32c4d43..df6176ff6 100644 --- a/embassy-mspm0/Cargo.toml +++ b/embassy-mspm0/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-mspm0" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for Texas Instruments MSPM0 series microcontrollers" keywords = ["embedded", "async", "mspm0", "hal", "embedded-hal"] @@ -15,17 +15,19 @@ publish = false [package.metadata.embassy] build = [ {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0c1104dgs20", "time-driver-any"]}, + {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0c1106rgz", "time-driver-any"]}, + {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g1107ycj", "time-driver-any"]}, + {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g1505pt", "time-driver-any"]}, + {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g1519rhb", "time-driver-any"]}, + {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g3105rhb", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g3507pm", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g3519pz", "time-driver-any"]}, + {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0h3216pt", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0l1306rhb", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0l2228pn", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0l1345dgs28", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0l1106dgs28", "time-driver-any"]}, - {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0l1228pm", "time-driver-any"]}, - {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g1107ycj", "time-driver-any"]}, - {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g3105rhb", "time-driver-any"]}, - {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g1505pt", "time-driver-any"]}, - {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g1519rhb", "time-driver-any"]}, + {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0l1228pt", "time-driver-any"]}, ] [package.metadata.embassy_docs] @@ -37,6 +39,7 @@ flavors = [ { regex_feature = "mspm0c.*", target = "thumbv6m-none-eabi" }, { regex_feature = "mspm0l.*", target = "thumbv6m-none-eabi" }, { regex_feature = "mspm0g.*", target = "thumbv6m-none-eabi" }, + { regex_feature = "mspm0h.*", target = "thumbv6m-none-eabi" }, ] [package.metadata.docs.rs] @@ -69,7 +72,7 @@ cortex-m = "0.7.6" critical-section = "1.2.0" # mspm0-metapac = { version = "" } -mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-d7bf3d01ac0780e716a45b0474234d39443dc5cf" } +mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-e7de4103a0713772695ffcad52c3c2f07414dc29" } [build-dependencies] proc-macro2 = "1.0.94" @@ -77,7 +80,7 @@ quote = "1.0.40" cfg_aliases = "0.2.1" # mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } -mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-d7bf3d01ac0780e716a45b0474234d39443dc5cf", default-features = false, features = ["metadata"] } +mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-e7de4103a0713772695ffcad52c3c2f07414dc29", default-features = false, features = ["metadata"] } [features] default = ["rt"] @@ -243,6 +246,7 @@ mspm0g3519pn = ["mspm0-metapac/mspm0g3519pn"] mspm0g3519pz = ["mspm0-metapac/mspm0g3519pz"] mspm0g3519rgz = ["mspm0-metapac/mspm0g3519rgz"] mspm0g3519rhb = ["mspm0-metapac/mspm0g3519rhb"] +mspm0h3216pt = ["mspm0-metapac/mspm0h3216pt"] mspm0l1105dgs20 = ["mspm0-metapac/mspm0l1105dgs20"] mspm0l1105dgs28 = ["mspm0-metapac/mspm0l1105dgs28"] mspm0l1105dyy = ["mspm0-metapac/mspm0l1105dyy"] diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs index d294bc422..1d118ad66 100644 --- a/embassy-mspm0/build.rs +++ b/embassy-mspm0/build.rs @@ -16,14 +16,15 @@ use quote::{format_ident, quote}; mod common; fn main() { - generate_code(); - interrupt_group_linker_magic(); -} - -fn generate_code() { let mut cfgs = common::CfgSet::new(); common::set_target_cfgs(&mut cfgs); + generate_code(&mut cfgs); + select_gpio_features(&mut cfgs); + interrupt_group_linker_magic(); +} + +fn generate_code(cfgs: &mut CfgSet) { #[cfg(any(feature = "rt"))] println!( "cargo:rustc-link-search={}", @@ -53,9 +54,9 @@ fn generate_code() { cfgs.declare_all(&get_chip_cfgs(&chip)); } - let mut singletons = get_singletons(&mut cfgs); + let mut singletons = get_singletons(cfgs); - time_driver(&mut singletons, &mut cfgs); + time_driver(&mut singletons, cfgs); let mut g = TokenStream::new(); @@ -68,7 +69,7 @@ fn generate_code() { g.extend(generate_pin_trait_impls()); g.extend(generate_groups()); g.extend(generate_dma_channel_count()); - g.extend(generate_adc_constants(&mut cfgs)); + g.extend(generate_adc_constants(cfgs)); let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string(); @@ -115,6 +116,10 @@ fn get_chip_cfgs(chip_name: &str) -> Vec { cfgs.push("mspm0g351x".to_string()); } + if chip_name.starts_with("mspm0h321") { + cfgs.push("mspm0h321x".to_string()); + } + if chip_name.starts_with("mspm0l110") { cfgs.push("mspm0l110x".to_string()); } @@ -208,7 +213,7 @@ fn generate_groups() -> TokenStream { #[cfg(feature = "rt")] mod group_vectors { - extern "Rust" { + unsafe extern "Rust" { #(#group_vectors)* } } @@ -646,6 +651,35 @@ fn generate_pin_trait_impls() -> TokenStream { } } +fn select_gpio_features(cfgs: &mut CfgSet) { + cfgs.declare_all(&[ + "gpioa_interrupt", + "gpioa_group", + "gpiob_interrupt", + "gpiob_group", + "gpioc_group", + ]); + + for interrupt in METADATA.interrupts.iter() { + match interrupt.name { + "GPIOA" => cfgs.enable("gpioa_interrupt"), + "GPIOB" => cfgs.enable("gpiob_interrupt"), + _ => (), + } + } + + for group in METADATA.interrupt_groups.iter() { + for interrupt in group.interrupts { + match interrupt.name { + "GPIOA" => cfgs.enable("gpioa_group"), + "GPIOB" => cfgs.enable("gpiob_group"), + "GPIOC" => cfgs.enable("gpioc_group"), + _ => (), + } + } + } +} + /// rustfmt a given path. /// Failures are logged to stderr and ignored. fn rustfmt(path: impl AsRef) { diff --git a/embassy-mspm0/src/adc.rs b/embassy-mspm0/src/adc.rs index 5b93e9a6e..948801679 100644 --- a/embassy-mspm0/src/adc.rs +++ b/embassy-mspm0/src/adc.rs @@ -4,13 +4,13 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_hal_internal::{PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use crate::interrupt::{Interrupt, InterruptExt}; use crate::mode::{Async, Blocking, Mode}; -use crate::pac::adc::{vals, Adc as Regs}; -use crate::{interrupt, Peri}; +use crate::pac::adc::{Adc as Regs, vals}; +use crate::{Peri, interrupt}; /// Interrupt handler. pub struct InterruptHandler { diff --git a/embassy-mspm0/src/dma.rs b/embassy-mspm0/src/dma.rs index 66b79709c..58b087761 100644 --- a/embassy-mspm0/src/dma.rs +++ b/embassy-mspm0/src/dma.rs @@ -5,18 +5,18 @@ use core::future::Future; use core::mem; use core::pin::Pin; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::{Context, Poll}; use critical_section::CriticalSection; use embassy_hal_internal::interrupt::InterruptExt; -use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_hal_internal::{PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; -use mspm0_metapac::common::{Reg, RW}; +use mspm0_metapac::common::{RW, Reg}; use mspm0_metapac::dma::regs; use mspm0_metapac::dma::vals::{self, Autoen, Em, Incr, Preirq, Wdth}; -use crate::{interrupt, pac, Peri}; +use crate::{Peri, interrupt, pac}; /// The burst size of a DMA transfer. #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs index d5fd36dbf..d8eb42dc2 100644 --- a/embassy-mspm0/src/gpio.rs +++ b/embassy-mspm0/src/gpio.rs @@ -5,12 +5,12 @@ use core::future::Future; use core::pin::Pin as FuturePin; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use crate::pac::gpio::vals::*; use crate::pac::gpio::{self}; -#[cfg(all(feature = "rt", any(mspm0c110x, mspm0c1105_c1106, mspm0l110x)))] +#[cfg(all(feature = "rt", any(gpioa_interrupt, gpiob_interrupt)))] use crate::pac::interrupt; use crate::pac::{self}; @@ -156,7 +156,12 @@ impl<'d> Flex<'d> { w.set_pf(GPIO_PF); w.set_hiz1(true); w.set_pc(true); - w.set_inena(false); + w.set_inena(true); + }); + + // Enable output driver (DOE) - required for open-drain to drive low + self.pin.block().doeset31_0().write(|w| { + w.set_dio(self.pin.bit_index(), true); }); self.set_pull(Pull::None); @@ -1105,16 +1110,21 @@ fn irq_handler(gpio: gpio::Gpio, wakers: &[AtomicWaker; 32]) { } } +#[cfg(all(gpioa_interrupt, gpioa_group))] +compile_error!("gpioa_interrupt and gpioa_group are mutually exclusive cfgs"); +#[cfg(all(gpiob_interrupt, gpiob_group))] +compile_error!("gpiob_interrupt and gpiob_group are mutually exclusive cfgs"); + // C110x and L110x have a dedicated interrupts just for GPIOA. // // These chips do not have a GROUP1 interrupt. -#[cfg(all(feature = "rt", any(mspm0c110x, mspm0c1105_c1106, mspm0l110x)))] +#[cfg(all(feature = "rt", gpioa_interrupt))] #[interrupt] fn GPIOA() { irq_handler(pac::GPIOA, &PORTA_WAKERS); } -#[cfg(all(feature = "rt", mspm0c1105_c1106))] +#[cfg(all(feature = "rt", gpiob_interrupt))] #[interrupt] fn GPIOB() { irq_handler(pac::GPIOB, &PORTB_WAKERS); @@ -1124,23 +1134,23 @@ fn GPIOB() { // // Defining these as no_mangle is required so that the linker will pick these over the default handler. -#[cfg(all(feature = "rt", not(any(mspm0c110x, mspm0c1105_c1106, mspm0l110x))))] -#[no_mangle] +#[cfg(all(feature = "rt", gpioa_group))] +#[unsafe(no_mangle)] #[allow(non_snake_case)] fn GPIOA() { irq_handler(pac::GPIOA, &PORTA_WAKERS); } -#[cfg(all(feature = "rt", gpio_pb, not(mspm0c1105_c1106)))] -#[no_mangle] +#[cfg(all(feature = "rt", gpiob_group))] +#[unsafe(no_mangle)] #[allow(non_snake_case)] fn GPIOB() { irq_handler(pac::GPIOB, &PORTB_WAKERS); } -#[cfg(all(feature = "rt", gpio_pc))] +#[cfg(all(feature = "rt", gpioc_group))] #[allow(non_snake_case)] -#[no_mangle] +#[unsafe(no_mangle)] fn GPIOC() { irq_handler(pac::GPIOC, &PORTC_WAKERS); } diff --git a/embassy-mspm0/src/i2c.rs b/embassy-mspm0/src/i2c.rs index 1906e37ba..3067f4833 100644 --- a/embassy-mspm0/src/i2c.rs +++ b/embassy-mspm0/src/i2c.rs @@ -10,13 +10,13 @@ use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; use mspm0_metapac::i2c; +use crate::Peri; use crate::gpio::{AnyPin, PfType, Pull, SealedPin}; use crate::interrupt::typelevel::Binding; use crate::interrupt::{Interrupt, InterruptExt}; use crate::mode::{Async, Blocking, Mode}; -use crate::pac::i2c::{vals, I2c as Regs}; +use crate::pac::i2c::{I2c as Regs, vals}; use crate::pac::{self}; -use crate::Peri; /// The clock source for the I2C. #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -56,7 +56,7 @@ pub enum ClockDiv { } impl ClockDiv { - fn into(self) -> vals::Ratio { + pub(crate) fn into(self) -> vals::Ratio { match self { Self::DivBy1 => vals::Ratio::DIV_BY_1, Self::DivBy2 => vals::Ratio::DIV_BY_2, @@ -133,6 +133,11 @@ pub enum ConfigError { /// /// The clock soure is not enabled is SYSCTL. ClockSourceNotEnabled, + + /// Invalid target address. + /// + /// The target address is not 7-bit. + InvalidTargetAddress, } #[non_exhaustive] @@ -140,7 +145,7 @@ pub enum ConfigError { /// Config pub struct Config { /// I2C clock source. - clock_source: ClockSel, + pub(crate) clock_source: ClockSel, /// I2C clock divider. pub clock_div: ClockDiv, @@ -196,7 +201,7 @@ impl Config { } #[cfg(any(mspm0c110x, mspm0c1105_c1106))] - fn calculate_clock_source(&self) -> u32 { + pub(crate) fn calculate_clock_source(&self) -> u32 { // Assume that BusClk has default value. // TODO: calculate BusClk more precisely. match self.clock_source { @@ -206,10 +211,10 @@ impl Config { } #[cfg(any( - mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0l110x, mspm0l122x, mspm0l130x, - mspm0l134x, mspm0l222x + mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0h321x, mspm0l110x, mspm0l122x, + mspm0l130x, mspm0l134x, mspm0l222x ))] - fn calculate_clock_source(&self) -> u32 { + pub(crate) fn calculate_clock_source(&self) -> u32 { // Assume that BusClk has default value. // TODO: calculate BusClk more precisely. match self.clock_source { diff --git a/embassy-mspm0/src/i2c_target.rs b/embassy-mspm0/src/i2c_target.rs new file mode 100644 index 000000000..86be91415 --- /dev/null +++ b/embassy-mspm0/src/i2c_target.rs @@ -0,0 +1,509 @@ +//! Inter-Integrated-Circuit (I2C) Target +// The following code is modified from embassy-stm32 and embassy-rp +// https://github.com/embassy-rs/embassy/tree/main/embassy-stm32 +// https://github.com/embassy-rs/embassy/tree/main/embassy-rp + +use core::future::poll_fn; +use core::marker::PhantomData; +use core::sync::atomic::Ordering; +use core::task::Poll; + +use embassy_embedded_hal::SetConfig; +use mspm0_metapac::i2c::vals::CpuIntIidxStat; + +use crate::gpio::{AnyPin, SealedPin}; +use crate::interrupt::InterruptExt; +use crate::mode::{Async, Blocking, Mode}; +use crate::pac::{self, i2c::vals}; +use crate::{i2c, i2c_target, interrupt, Peri}; +// Re-use I2c controller types +use crate::i2c::{ClockSel, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State}; + +#[non_exhaustive] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +/// Config +pub struct Config { + /// 7-bit Target Address + pub target_addr: u8, + + /// Control if the target should ack to and report general calls. + pub general_call: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { + target_addr: 0x48, + general_call: false, + } + } +} + +/// I2C error +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + /// User passed in a response buffer that was 0 length + InvalidResponseBufferLength, + /// The response buffer length was too short to contain the message + /// + /// The length parameter will always be the length of the buffer, and is + /// provided as a convenience for matching alongside `Command::Write`. + PartialWrite(usize), + /// The response buffer length was too short to contain the message + /// + /// The length parameter will always be the length of the buffer, and is + /// provided as a convenience for matching alongside `Command::GeneralCall`. + PartialGeneralCall(usize), +} + +/// Received command from the controller. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Command { + /// General Call Write: Controller sent the General Call address (0x00) followed by data. + /// Contains the number of bytes written by the controller. + GeneralCall(usize), + /// Read: Controller wants to read data from the target. + Read, + /// Write: Controller sent the target's address followed by data. + /// Contains the number of bytes written by the controller. + Write(usize), + /// Write followed by Read (Repeated Start): Controller wrote data, then issued a repeated + /// start and wants to read data. Contains the number of bytes written before the read. + WriteRead(usize), +} + +/// Status after responding to a controller read request. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ReadStatus { + /// Transaction completed successfully. The controller either NACKed the last byte + /// or sent a STOP condition. + Done, + /// Transaction incomplete, controller trying to read more bytes than were provided + NeedMoreBytes, + /// Transaction complete, but controller stopped reading bytes before we ran out + LeftoverBytes(u16), +} + +/// I2C Target driver. +// Use the same Instance, SclPin, SdaPin traits as the controller +pub struct I2cTarget<'d, M: Mode> { + info: &'static Info, + state: &'static State, + scl: Option>, + sda: Option>, + config: i2c::Config, + target_config: i2c_target::Config, + _phantom: PhantomData, +} + +impl<'d> SetConfig for I2cTarget<'d, Async> { + type Config = (i2c::Config, i2c_target::Config); + type ConfigError = ConfigError; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + self.info.interrupt.disable(); + + if let Some(ref sda) = self.sda { + sda.update_pf(config.0.sda_pf()); + } + + if let Some(ref scl) = self.scl { + scl.update_pf(config.0.scl_pf()); + } + + self.config = config.0.clone(); + self.target_config = config.1.clone(); + + self.reset() + } +} + +impl<'d> SetConfig for I2cTarget<'d, Blocking> { + type Config = (i2c::Config, i2c_target::Config); + type ConfigError = ConfigError; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + if let Some(ref sda) = self.sda { + sda.update_pf(config.0.sda_pf()); + } + + if let Some(ref scl) = self.scl { + scl.update_pf(config.0.scl_pf()); + } + + self.config = config.0.clone(); + self.target_config = config.1.clone(); + + self.reset() + } +} + +impl<'d> I2cTarget<'d, Async> { + /// Create a new asynchronous I2C target driver using interrupts + /// The `config` reuses the i2c controller config to setup the clock while `target_config` + /// configures i2c target specific parameters. + pub fn new( + peri: Peri<'d, T>, + scl: Peri<'d, impl SclPin>, + sda: Peri<'d, impl SdaPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, + config: i2c::Config, + target_config: i2c_target::Config, + ) -> Result { + let mut this = Self::new_inner( + peri, + new_pin!(scl, config.scl_pf()), + new_pin!(sda, config.sda_pf()), + config, + target_config, + ); + this.reset()?; + Ok(this) + } + + /// Reset the i2c peripheral. If you cancel a respond_to_read, you may stall the bus. + /// You can recover the bus by calling this function, but doing so will almost certainly cause + /// an i/o error in the controller. + pub fn reset(&mut self) -> Result<(), ConfigError> { + self.init()?; + unsafe { self.info.interrupt.enable() }; + Ok(()) + } +} + +impl<'d> I2cTarget<'d, Blocking> { + /// Create a new blocking I2C target driver. + /// The `config` reuses the i2c controller config to setup the clock while `target_config` + /// configures i2c target specific parameters. + pub fn new_blocking( + peri: Peri<'d, T>, + scl: Peri<'d, impl SclPin>, + sda: Peri<'d, impl SdaPin>, + config: i2c::Config, + target_config: i2c_target::Config, + ) -> Result { + let mut this = Self::new_inner( + peri, + new_pin!(scl, config.scl_pf()), + new_pin!(sda, config.sda_pf()), + config, + target_config, + ); + this.reset()?; + Ok(this) + } + + /// Reset the i2c peripheral. If you cancel a respond_to_read, you may stall the bus. + /// You can recover the bus by calling this function, but doing so will almost certainly cause + /// an i/o error in the controller. + pub fn reset(&mut self) -> Result<(), ConfigError> { + self.init()?; + Ok(()) + } +} + +impl<'d, M: Mode> I2cTarget<'d, M> { + fn new_inner( + _peri: Peri<'d, T>, + scl: Option>, + sda: Option>, + config: i2c::Config, + target_config: i2c_target::Config, + ) -> Self { + if let Some(ref scl) = scl { + let pincm = pac::IOMUX.pincm(scl._pin_cm() as usize); + pincm.modify(|w| { + w.set_hiz1(true); + }); + } + if let Some(ref sda) = sda { + let pincm = pac::IOMUX.pincm(sda._pin_cm() as usize); + pincm.modify(|w| { + w.set_hiz1(true); + }); + } + + Self { + info: T::info(), + state: T::state(), + scl, + sda, + config, + target_config, + _phantom: PhantomData, + } + } + + fn init(&mut self) -> Result<(), ConfigError> { + let mut config = self.config; + let target_config = self.target_config; + let regs = self.info.regs; + + config.check_config()?; + // Target address must be 7-bit + if !(target_config.target_addr < 0x80) { + return Err(ConfigError::InvalidTargetAddress); + } + + regs.target(0).tctr().modify(|w| { + w.set_active(false); + }); + + // Init power for I2C + regs.gprcm(0).rstctl().write(|w| { + w.set_resetstkyclr(true); + w.set_resetassert(true); + w.set_key(vals::ResetKey::KEY); + }); + + regs.gprcm(0).pwren().write(|w| { + w.set_enable(true); + w.set_key(vals::PwrenKey::KEY); + }); + + self.info.interrupt.disable(); + + // Init delay from the M0 examples by TI in CCStudio (16 cycles) + cortex_m::asm::delay(16); + + // Select and configure the I2C clock using the CLKSEL and CLKDIV registers + regs.clksel().write(|w| match config.clock_source { + ClockSel::BusClk => { + w.set_mfclk_sel(false); + w.set_busclk_sel(true); + } + ClockSel::MfClk => { + w.set_mfclk_sel(true); + w.set_busclk_sel(false); + } + }); + regs.clkdiv().write(|w| w.set_ratio(config.clock_div.into())); + + // Configure at least one target address by writing the 7-bit address to I2Cx.SOAR register. The additional + // target address can be enabled and configured by using I2Cx.TOAR2 register. + regs.target(0).toar().modify(|w| { + w.set_oaren(true); + w.set_oar(target_config.target_addr as u16); + }); + + self.state + .clock + .store(config.calculate_clock_source(), Ordering::Relaxed); + + regs.target(0).tctr().modify(|w| { + w.set_gencall(target_config.general_call); + w.set_tclkstretch(true); + // Disable target wakeup, follow TI example. (TI note: Workaround for errata I2C_ERR_04.) + w.set_twuen(false); + w.set_txempty_on_treq(true); + }); + + // Enable the I2C target mode by setting the ACTIVE bit in I2Cx.TCTR register. + regs.target(0).tctr().modify(|w| { + w.set_active(true); + }); + + Ok(()) + } + + #[inline(always)] + fn drain_fifo(&mut self, buffer: &mut [u8], offset: &mut usize) { + let regs = self.info.regs; + + for b in &mut buffer[*offset..] { + if regs.target(0).tfifosr().read().rxfifocnt() == 0 { + break; + } + + *b = regs.target(0).trxdata().read().value(); + *offset += 1; + } + } + + /// Blocking function to empty the tx fifo + /// + /// This function can be used to empty the transmit FIFO if data remains after handling a 'read' command (LeftoverBytes). + pub fn flush_tx_fifo(&mut self) { + self.info.regs.target(0).tfifoctl().modify(|w| { + w.set_txflush(true); + }); + while self.info.regs.target(0).tfifosr().read().txfifocnt() as usize != self.info.fifo_size {} + self.info.regs.target(0).tfifoctl().modify(|w| { + w.set_txflush(false); + }); + } +} + +impl<'d> I2cTarget<'d, Async> { + /// Wait asynchronously for commands from an I2C controller. + /// `buffer` is provided in case controller does a 'write', 'write read', or 'general call' and is unused for 'read'. + pub async fn listen(&mut self, buffer: &mut [u8]) -> Result { + let regs = self.info.regs; + + let mut len = 0; + + // Set the rx fifo interrupt to avoid a fifo overflow + regs.target(0).tfifoctl().modify(|r| { + r.set_rxtrig(vals::TfifoctlRxtrig::LEVEL_6); + }); + + self.wait_on( + |me| { + // Check if address matches the General Call address (0x00) + let is_gencall = regs.target(0).tsr().read().addrmatch() == 0; + + if regs.target(0).tfifosr().read().rxfifocnt() > 0 { + me.drain_fifo(buffer, &mut len); + } + + if buffer.len() == len && regs.target(0).tfifosr().read().rxfifocnt() > 0 { + if is_gencall { + return Poll::Ready(Err(Error::PartialGeneralCall(buffer.len()))); + } else { + return Poll::Ready(Err(Error::PartialWrite(buffer.len()))); + } + } + + let iidx = regs.cpu_int(0).iidx().read().stat(); + trace!("ls:{} len:{}", iidx as u8, len); + let result = match iidx { + CpuIntIidxStat::TTXEMPTY => match len { + 0 => Poll::Ready(Ok(Command::Read)), + w => Poll::Ready(Ok(Command::WriteRead(w))), + }, + CpuIntIidxStat::TSTOPFG => match (is_gencall, len) { + (_, 0) => Poll::Pending, + (true, w) => Poll::Ready(Ok(Command::GeneralCall(w))), + (false, w) => Poll::Ready(Ok(Command::Write(w))), + }, + _ => Poll::Pending, + }; + if !result.is_pending() { + regs.cpu_int(0).imask().write(|_| {}); + } + result + }, + |_me| { + regs.cpu_int(0).imask().write(|_| {}); + regs.cpu_int(0).imask().modify(|w| { + w.set_tgencall(true); + w.set_trxfifotrg(true); + w.set_tstop(true); + w.set_ttxempty(true); + }); + }, + ) + .await + } + + /// Respond to an I2C controller 'read' command, asynchronously. + pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result { + if buffer.is_empty() { + return Err(Error::InvalidResponseBufferLength); + } + + let regs = self.info.regs; + let fifo_size = self.info.fifo_size; + let mut chunks = buffer.chunks(self.info.fifo_size); + + self.wait_on( + |_me| { + if let Some(chunk) = chunks.next() { + for byte in chunk { + regs.target(0).ttxdata().write(|w| w.set_value(*byte)); + } + + return Poll::Pending; + } + + let iidx = regs.cpu_int(0).iidx().read().stat(); + let fifo_bytes = fifo_size - regs.target(0).tfifosr().read().txfifocnt() as usize; + trace!("rs:{}, fifo:{}", iidx as u8, fifo_bytes); + + let result = match iidx { + CpuIntIidxStat::TTXEMPTY => Poll::Ready(Ok(ReadStatus::NeedMoreBytes)), + CpuIntIidxStat::TSTOPFG => match fifo_bytes { + 0 => Poll::Ready(Ok(ReadStatus::Done)), + w => Poll::Ready(Ok(ReadStatus::LeftoverBytes(w as u16))), + }, + _ => Poll::Pending, + }; + if !result.is_pending() { + regs.cpu_int(0).imask().write(|_| {}); + } + result + }, + |_me| { + regs.cpu_int(0).imask().write(|_| {}); + regs.cpu_int(0).imask().modify(|w| { + w.set_ttxempty(true); + w.set_tstop(true); + }); + }, + ) + .await + } + + /// Respond to reads with the fill byte until the controller stops asking + pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> { + // The buffer size could be increased to reduce interrupt noise but has higher probability + // of LeftoverBytes + let buff = [fill]; + loop { + match self.respond_to_read(&buff).await { + Ok(ReadStatus::NeedMoreBytes) => (), + Ok(_) => break Ok(()), + Err(e) => break Err(e), + } + } + } + + /// Respond to a controller read, then fill any remaining read bytes with `fill` + pub async fn respond_and_fill(&mut self, buffer: &[u8], fill: u8) -> Result { + let resp_stat = self.respond_to_read(buffer).await?; + + if resp_stat == ReadStatus::NeedMoreBytes { + self.respond_till_stop(fill).await?; + Ok(ReadStatus::Done) + } else { + Ok(resp_stat) + } + } + + /// Calls `f` to check if we are ready or not. + /// If not, `g` is called once(to eg enable the required interrupts). + /// The waker will always be registered prior to calling `f`. + #[inline(always)] + async fn wait_on(&mut self, mut f: F, mut g: G) -> U + where + F: FnMut(&mut Self) -> Poll, + G: FnMut(&mut Self), + { + poll_fn(|cx| { + // Register prior to checking the condition + self.state.waker.register(cx.waker()); + let r = f(self); + + if r.is_pending() { + g(self); + } + + r + }) + .await + } +} + +impl<'d, M: Mode> Drop for I2cTarget<'d, M> { + fn drop(&mut self) { + // Ensure peripheral is disabled and pins are reset + self.info.regs.target(0).tctr().modify(|w| w.set_active(false)); + + self.scl.as_ref().map(|x| x.set_as_disconnected()); + self.sda.as_ref().map(|x| x.set_as_disconnected()); + } +} diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs index 13f0ce662..7135dd9f0 100644 --- a/embassy-mspm0/src/lib.rs +++ b/embassy-mspm0/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] // Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg_hide), doc(cfg_hide(doc, docsrs)))] #![cfg_attr( @@ -17,6 +18,7 @@ pub mod adc; pub mod dma; pub mod gpio; pub mod i2c; +pub mod i2c_target; pub mod timer; pub mod uart; pub mod wwdt; @@ -54,7 +56,7 @@ pub(crate) mod _generated { // Reexports pub(crate) use _generated::gpio_pincm; -pub use _generated::{peripherals, Peripherals}; +pub use _generated::{Peripherals, peripherals}; pub use embassy_hal_internal::Peri; #[cfg(feature = "unstable-pac")] pub use mspm0_metapac as pac; @@ -111,7 +113,7 @@ macro_rules! bind_interrupts { $( #[allow(non_snake_case)] - #[no_mangle] + #[unsafe(no_mangle)] $(#[cfg($cond_irq)])? unsafe extern "C" fn $irq() { unsafe { diff --git a/embassy-mspm0/src/time_driver.rs b/embassy-mspm0/src/time_driver.rs index e80e89e55..0743c667b 100644 --- a/embassy-mspm0/src/time_driver.rs +++ b/embassy-mspm0/src/time_driver.rs @@ -1,5 +1,5 @@ use core::cell::{Cell, RefCell}; -use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; use core::task::Waker; use critical_section::{CriticalSection, Mutex}; diff --git a/embassy-mspm0/src/uart/buffered.rs b/embassy-mspm0/src/uart/buffered.rs index cbc0b6c80..89e6bcc7b 100644 --- a/embassy-mspm0/src/uart/buffered.rs +++ b/embassy-mspm0/src/uart/buffered.rs @@ -1,4 +1,4 @@ -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::slice; use core::sync::atomic::{AtomicU8, Ordering}; @@ -14,7 +14,7 @@ use crate::gpio::{AnyPin, SealedPin}; use crate::interrupt::typelevel::Binding; use crate::pac::uart::Uart as Regs; use crate::uart::{Config, ConfigError, CtsPin, Error, Info, Instance, RtsPin, RxPin, State, TxPin}; -use crate::{interrupt, Peri}; +use crate::{Peri, interrupt}; /// Interrupt handler. pub struct BufferedInterruptHandler { diff --git a/embassy-mspm0/src/uart/mod.rs b/embassy-mspm0/src/uart/mod.rs index 6599cea06..03e68d297 100644 --- a/embassy-mspm0/src/uart/mod.rs +++ b/embassy-mspm0/src/uart/mod.rs @@ -3,17 +3,17 @@ mod buffered; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; pub use buffered::*; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::PeripheralType; +use crate::Peri; use crate::gpio::{AnyPin, PfType, Pull, SealedPin}; use crate::interrupt::{Interrupt, InterruptExt}; use crate::mode::{Blocking, Mode}; -use crate::pac::uart::{vals, Uart as Regs}; -use crate::Peri; +use crate::pac::uart::{Uart as Regs, vals}; /// The clock source for the UART. #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -931,8 +931,7 @@ fn set_baudrate_inner(regs: Regs, clock: u32, baudrate: u32) -> Result<(), Confi let Some(min_clock) = baudrate.checked_mul(oversampling as u32) else { trace!( "{}x oversampling would cause overflow for clock: {} Hz", - oversampling, - clock + oversampling, clock ); continue; }; @@ -945,9 +944,7 @@ fn set_baudrate_inner(regs: Regs, clock: u32, baudrate: u32) -> Result<(), Confi for &(div, div_value) in &DIVS { trace!( "Trying div: {}, oversampling {} for {} baud", - div, - oversampling, - baudrate + div, oversampling, baudrate ); let Some((ibrd, fbrd)) = calculate_brd(clock, div, baudrate, oversampling) else { diff --git a/embassy-mspm0/src/wwdt.rs b/embassy-mspm0/src/wwdt.rs index e5c62c660..92aeb8b40 100644 --- a/embassy-mspm0/src/wwdt.rs +++ b/embassy-mspm0/src/wwdt.rs @@ -6,9 +6,9 @@ use embassy_hal_internal::PeripheralType; -use crate::pac::wwdt::{vals, Wwdt as Regs}; -use crate::pac::{self}; use crate::Peri; +use crate::pac::wwdt::{Wwdt as Regs, vals}; +use crate::pac::{self}; /// Possible watchdog timeout values. #[derive(Clone, Copy, PartialEq, Eq, Debug)] diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index 587c69eb7..a5655870f 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -5,7 +5,7 @@ description = "embassy-net driver for the ADIN1110 ethernet chip" keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethernet"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" -edition = "2021" +edition = "2024" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-net-adin1110" diff --git a/embassy-net-adin1110/src/crc8.rs b/embassy-net-adin1110/src/crc8.rs index 321983e64..a51353aab 100644 --- a/embassy-net-adin1110/src/crc8.rs +++ b/embassy-net-adin1110/src/crc8.rs @@ -23,7 +23,7 @@ pub fn crc8(data: &[u8]) -> u8 { #[cfg(test)] mod tests { - use ::crc::{Crc, CRC_8_SMBUS}; + use ::crc::{CRC_8_SMBUS, Crc}; use super::crc8; diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 7f1c772e2..90ac242bd 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -17,9 +17,9 @@ mod phy; mod regs; use ch::driver::LinkState; -pub use crc32::ETH_FCS; use crc8::crc8; -use embassy_futures::select::{select, Either}; +pub use crc32::ETH_FCS; +use embassy_futures::select::{Either, select}; use embassy_net_driver_channel as ch; use embassy_time::Timer; use embedded_hal_1::digital::OutputPin; diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml index 1e40c2d87..116057d6e 100644 --- a/embassy-net-driver-channel/Cargo.toml +++ b/embassy-net-driver-channel/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-net-driver-channel" version = "0.3.2" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack." repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs index 600efd9e5..d0a14aa52 100644 --- a/embassy-net-driver-channel/src/lib.rs +++ b/embassy-net-driver-channel/src/lib.rs @@ -11,8 +11,8 @@ use core::task::{Context, Poll}; pub use embassy_net_driver as driver; use embassy_net_driver::{Capabilities, LinkState}; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::waitqueue::WakerRegistration; use embassy_sync::zerocopy_channel; diff --git a/embassy-net-driver/Cargo.toml b/embassy-net-driver/Cargo.toml index a36e412ad..948fb2667 100644 --- a/embassy-net-driver/Cargo.toml +++ b/embassy-net-driver/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-net-driver" version = "0.2.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Driver trait for the `embassy-net` async TCP/IP network stack." repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-net-driver/src/lib.rs b/embassy-net-driver/src/lib.rs index 4c847718d..47babe34a 100644 --- a/embassy-net-driver/src/lib.rs +++ b/embassy-net-driver/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml index e7bad118b..7c3e05922 100644 --- a/embassy-net-enc28j60/Cargo.toml +++ b/embassy-net-enc28j60/Cargo.toml @@ -5,7 +5,7 @@ description = "embassy-net driver for the ENC28J60 ethernet chip" keywords = ["embedded", "enc28j60", "embassy-net", "embedded-hal-async", "ethernet"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" -edition = "2021" +edition = "2024" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-net-enc28j60" diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index 149ff2bb2..f148f4762 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-net-esp-hosted" version = "0.2.1" -edition = "2021" +edition = "2024" description = "embassy-net driver for ESP-Hosted" keywords = ["embedded", "esp-hosted", "embassy-net", "embedded-hal-async", "wifi"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs index b1838a425..cbc194877 100644 --- a/embassy-net-esp-hosted/src/control.rs +++ b/embassy-net-esp-hosted/src/control.rs @@ -65,8 +65,7 @@ macro_rules! ioctl { }; $self.ioctl(&mut msg).await?; #[allow(unused_mut)] - let Some(proto::CtrlMsgPayload::$resp_variant(mut $resp)) = msg.payload - else { + let Some(proto::CtrlMsgPayload::$resp_variant(mut $resp)) = msg.payload else { warn!("unexpected response variant"); return Err(Error::Internal); }; diff --git a/embassy-net-esp-hosted/src/ioctl.rs b/embassy-net-esp-hosted/src/ioctl.rs index 512023206..a516f80c7 100644 --- a/embassy-net-esp-hosted/src/ioctl.rs +++ b/embassy-net-esp-hosted/src/ioctl.rs @@ -1,5 +1,5 @@ use core::cell::RefCell; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::task::Poll; use embassy_sync::waitqueue::WakerRegistration; diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs index f05e2a70a..4405d9f77 100644 --- a/embassy-net-esp-hosted/src/lib.rs +++ b/embassy-net-esp-hosted/src/lib.rs @@ -2,7 +2,7 @@ #![doc = include_str!("../README.md")] #![warn(missing_docs)] -use embassy_futures::select::{select4, Either4}; +use embassy_futures::select::{Either4, select4}; use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::LinkState; use embassy_time::{Duration, Instant, Timer}; diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index 35fbef3f6..ecb10246a 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-net-nrf91" version = "0.1.1" -edition = "2021" +edition = "2024" description = "embassy-net driver for Nordic nRF91-series cellular modems" keywords = ["embedded", "nrf91", "embassy-net", "cellular"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index 0bd9be0d9..dd4812aae 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] #![deny(unused_must_use)] @@ -9,12 +10,12 @@ mod fmt; pub mod context; use core::cell::RefCell; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::mem::{self, MaybeUninit}; use core::ptr::{self, addr_of, addr_of_mut, copy_nonoverlapping}; use core::slice; -use core::sync::atomic::{compiler_fence, fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence, fence}; use core::task::{Poll, Waker}; use cortex_m::peripheral::NVIC; @@ -139,9 +140,7 @@ async fn new_internal<'a>( debug!("Setting IPC RAM as nonsecure..."); trace!( " SPU_REGION_SIZE={}, shmem_ptr=0x{:08X}, shmem_len={}", - SPU_REGION_SIZE, - shmem_ptr as usize, - shmem_len + SPU_REGION_SIZE, shmem_ptr as usize, shmem_len ); let region_start = (shmem_ptr as usize - 0x2000_0000) / SPU_REGION_SIZE; let region_end = region_start + shmem_len / SPU_REGION_SIZE; @@ -165,8 +164,7 @@ async fn new_internal<'a>( }; trace!( " Allocator: start=0x{:08X}, end=0x{:08X}", - alloc.start as usize, - alloc.end as usize + alloc.start as usize, alloc.end as usize ); let cb: &mut ControlBlock = alloc.alloc().write(unsafe { mem::zeroed() }); diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml index 644f5b827..45ee2f6b5 100644 --- a/embassy-net-ppp/Cargo.toml +++ b/embassy-net-ppp/Cargo.toml @@ -5,7 +5,7 @@ description = "embassy-net driver for PPP over Serial" keywords = ["embedded", "ppp", "embassy-net", "embedded-hal-async", "async"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" -edition = "2021" +edition = "2024" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-net-ppp" diff --git a/embassy-net-ppp/src/lib.rs b/embassy-net-ppp/src/lib.rs index 54a98c95f..ab42ecd26 100644 --- a/embassy-net-ppp/src/lib.rs +++ b/embassy-net-ppp/src/lib.rs @@ -8,7 +8,7 @@ mod fmt; use core::convert::Infallible; use core::mem::MaybeUninit; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::LinkState; use embedded_io_async::{BufRead, Write}; diff --git a/embassy-net-tuntap/Cargo.toml b/embassy-net-tuntap/Cargo.toml index 2cd0c0f7e..77668b445 100644 --- a/embassy-net-tuntap/Cargo.toml +++ b/embassy-net-tuntap/Cargo.toml @@ -5,7 +5,7 @@ description = "embassy-net driver for Linux TUN/TAP interfaces." keywords = ["embedded", "tuntap", "embassy-net", "ethernet", "async"] categories = ["embedded", "hardware-support", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" -edition = "2021" +edition = "2024" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-net-tuntap" diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index 6e6dccebd..069f46fc3 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -5,7 +5,7 @@ description = "embassy-net driver for WIZnet SPI Ethernet chips" keywords = ["embedded", "embassy-net", "embedded-hal-async", "ethernet", "async"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" -edition = "2021" +edition = "2024" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-net-wiznet" diff --git a/embassy-net-wiznet/src/chip/mod.rs b/embassy-net-wiznet/src/chip/mod.rs index 47d7c5dc3..04346bb21 100644 --- a/embassy-net-wiznet/src/chip/mod.rs +++ b/embassy-net-wiznet/src/chip/mod.rs @@ -43,7 +43,7 @@ pub(crate) trait SealedChip { fn tx_addr(addr: u16) -> Self::Address; async fn bus_read(spi: &mut SPI, address: Self::Address, data: &mut [u8]) - -> Result<(), SPI::Error>; + -> Result<(), SPI::Error>; async fn bus_write(spi: &mut SPI, address: Self::Address, data: &[u8]) -> Result<(), SPI::Error>; } diff --git a/embassy-net-wiznet/src/lib.rs b/embassy-net-wiznet/src/lib.rs index 3fbd4c741..30a5db9f6 100644 --- a/embassy-net-wiznet/src/lib.rs +++ b/embassy-net-wiznet/src/lib.rs @@ -6,7 +6,7 @@ pub mod chip; mod device; -use embassy_futures::select::{select3, Either3}; +use embassy_futures::select::{Either3, select3}; use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::LinkState; use embassy_time::{Duration, Ticker, Timer}; diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 31ce7e9a6..4c8075c43 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-net" version = "0.7.1" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Async TCP/IP network stack for embedded systems" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-net/src/icmp.rs b/embassy-net/src/icmp.rs index 22c31a589..09e91a1ae 100644 --- a/embassy-net/src/icmp.rs +++ b/embassy-net/src/icmp.rs @@ -1,6 +1,6 @@ //! ICMP sockets. -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::mem; use core::task::{Context, Poll}; diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 3f0634849..a49955c96 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] @@ -26,7 +27,7 @@ mod time; pub mod udp; use core::cell::RefCell; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::mem::MaybeUninit; use core::pin::pin; use core::task::{Context, Poll}; diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs index c9f753f13..89d2dd350 100644 --- a/embassy-net/src/raw.rs +++ b/embassy-net/src/raw.rs @@ -1,6 +1,6 @@ //! Raw sockets. -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::mem; use core::task::{Context, Poll}; diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index d0230b581..6792c5526 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -8,7 +8,7 @@ //! Incoming connections when no socket is listening are rejected. To accept many incoming //! connections, create many sockets and put them all into listening mode. -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::mem; use core::task::{Context, Poll}; @@ -18,8 +18,8 @@ use smoltcp::socket::tcp; pub use smoltcp::socket::tcp::State; use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; -use crate::time::duration_to_smoltcp; use crate::Stack; +use crate::time::duration_to_smoltcp; /// Error returned by TcpSocket read/write functions. #[derive(PartialEq, Eq, Clone, Copy, Debug)] diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 482eb0e56..448c25ecc 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -1,6 +1,6 @@ //! UDP sockets. -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::mem; use core::task::{Context, Poll}; diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index b3d4045fa..0280e2730 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -8,6 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- added: Add basic RTC support for nRF54L +- changed: apply trimming values from FICR.TRIMCNF on nrf53/54l +- changed: do not panic on BufferedUarte overrun +- added: allow direct access to the input pin of `gpiote::InputChannel` +- bugfix: use DETECTMODE_SEC in GPIOTE in secure mode + ## 0.8.0 - 2025-09-30 - changed: Remove `T: Instance` generic params in all drivers. diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 362fabcf7..28f137d5c 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-nrf" version = "0.8.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers" keywords = ["embedded", "async", "nordic", "nrf", "embedded-hal"] @@ -80,6 +80,8 @@ unstable-pac = [] gpiote = [] ## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz +## +## Note: For nRF54L, it's actually RTC30 time-driver-rtc1 = ["_time-driver"] ## Enable embassy-net 802.15.4 driver diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 40c679190..b1eb5c81a 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -9,27 +9,27 @@ //! Please also see [crate::uarte] to understand when [BufferedUarte] should be used. use core::cmp::min; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::slice; -use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU8, AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering, compiler_fence}; use core::task::Poll; -use embassy_hal_internal::atomic_ring_buffer::RingBuffer; use embassy_hal_internal::Peri; +use embassy_hal_internal::atomic_ring_buffer::RingBuffer; use pac::uarte::vals; // Re-export SVD variants to allow user to directly set values pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity}; use crate::gpio::{AnyPin, Pin as GpioPin}; -use crate::interrupt::typelevel::Interrupt; use crate::interrupt::InterruptExt; +use crate::interrupt::typelevel::Interrupt; use crate::ppi::{ self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, }; use crate::timer::{Instance as TimerInstance, Timer}; -use crate::uarte::{configure, configure_rx_pins, configure_tx_pins, drop_tx_rx, Config, Instance as UarteInstance}; -use crate::{interrupt, pac, EASY_DMA_SIZE}; +use crate::uarte::{Config, Instance as UarteInstance, configure, configure_rx_pins, configure_tx_pins, drop_tx_rx}; +use crate::{EASY_DMA_SIZE, interrupt, pac}; pub(crate) struct State { tx_buf: RingBuffer, @@ -40,6 +40,7 @@ pub(crate) struct State { rx_started_count: AtomicU8, rx_ended_count: AtomicU8, rx_ppi_ch: AtomicU8, + rx_overrun: AtomicBool, } /// UART error. @@ -47,7 +48,8 @@ pub(crate) struct State { #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub enum Error { - // No errors for now + /// Buffer Overrun + Overrun, } impl State { @@ -61,6 +63,7 @@ impl State { rx_started_count: AtomicU8::new(0), rx_ended_count: AtomicU8::new(0), rx_ppi_ch: AtomicU8::new(0), + rx_overrun: AtomicBool::new(false), } } } @@ -87,7 +90,8 @@ impl interrupt::typelevel::Handler for Interrupt r.errorsrc().write_value(errs); if errs.overrun() { - panic!("BufferedUarte overrun"); + s.rx_overrun.store(true, Ordering::Release); + ss.rx_waker.wake(); } } @@ -689,6 +693,7 @@ impl<'d> BufferedUarteRx<'d> { buffered_state.rx_started_count.store(0, Ordering::Relaxed); buffered_state.rx_ended_count.store(0, Ordering::Relaxed); buffered_state.rx_started.store(false, Ordering::Relaxed); + buffered_state.rx_overrun.store(false, Ordering::Relaxed); let rx_len = rx_buffer.len().min(EASY_DMA_SIZE * 2); unsafe { buffered_state.rx_buf.init(rx_buffer.as_mut_ptr(), rx_len) }; @@ -762,6 +767,10 @@ impl<'d> BufferedUarteRx<'d> { compiler_fence(Ordering::SeqCst); //trace!("poll_read"); + if s.rx_overrun.swap(false, Ordering::Acquire) { + return Poll::Ready(Err(Error::Overrun)); + } + // Read the RXDRDY counter. timer.cc(0).capture(); let mut end = timer.cc(0).read() as usize; @@ -820,6 +829,9 @@ impl<'d> BufferedUarteRx<'d> { /// we are ready to read if there is data in the buffer fn read_ready(&self) -> Result { let state = self.buffered_state; + if state.rx_overrun.swap(false, Ordering::Acquire) { + return Err(Error::Overrun); + } Ok(!state.rx_buf.is_empty()) } } @@ -854,7 +866,9 @@ mod _embedded_io { impl embedded_io_async::Error for Error { fn kind(&self) -> embedded_io_async::ErrorKind { - match *self {} + match *self { + Error::Overrun => embedded_io_async::ErrorKind::OutOfMemory, + } } } diff --git a/embassy-nrf/src/chips/nrf54l15_app.rs b/embassy-nrf/src/chips/nrf54l15_app.rs index ff05bbec0..901c5e7fc 100644 --- a/embassy-nrf/src/chips/nrf54l15_app.rs +++ b/embassy-nrf/src/chips/nrf54l15_app.rs @@ -94,6 +94,7 @@ pub mod pac { #[cfg(feature = "_s")] #[doc(no_inline)] pub use nrf_pac::{ + FICR_NS as FICR, SICR_S as SICR, ICACHEDATA_S as ICACHEDATA, ICACHEINFO_S as ICACHEINFO, @@ -248,6 +249,45 @@ embassy_hal_internal::peripherals! { P2_09, P2_10, + // RTC + RTC10, + RTC30, + + // SERIAL + SERIAL00, + SERIAL20, + SERIAL21, + SERIAL22, + SERIAL30, + + // SAADC + SAADC, + + // RADIO + RADIO, + + // TIMER + TIMER00, + TIMER10, + TIMER20, + + // PPI BRIDGE + PPIB00, + PPIB01, + PPIB10, + PPIB11, + PPIB20, + PPIB21, + PPIB22, + PPIB30, + + // GPIOTE + GPIOTE20, + GPIOTE30, + + // CRACEN + CRACEN, + #[cfg(feature = "_s")] // RRAMC RRAMC, @@ -302,6 +342,9 @@ impl_pin!(P2_08, 2, 8); impl_pin!(P2_09, 2, 9); impl_pin!(P2_10, 2, 10); +impl_rtc!(RTC10, RTC10, RTC10); +impl_rtc!(RTC30, RTC30, RTC30); + #[cfg(feature = "_ns")] impl_wdt!(WDT, WDT31, WDT31, 0); #[cfg(feature = "_s")] diff --git a/embassy-nrf/src/egu.rs b/embassy-nrf/src/egu.rs index f7372fca1..666986115 100644 --- a/embassy-nrf/src/egu.rs +++ b/embassy-nrf/src/egu.rs @@ -10,7 +10,7 @@ use core::marker::PhantomData; use embassy_hal_internal::PeripheralType; use crate::ppi::{Event, Task}; -use crate::{interrupt, pac, Peri}; +use crate::{Peri, interrupt, pac}; /// An instance of the EGU. pub struct Egu<'d> { diff --git a/embassy-nrf/src/embassy_net_802154_driver.rs b/embassy-nrf/src/embassy_net_802154_driver.rs index b3fc5df2c..4c47b7cbd 100644 --- a/embassy-nrf/src/embassy_net_802154_driver.rs +++ b/embassy-nrf/src/embassy_net_802154_driver.rs @@ -1,12 +1,12 @@ //! embassy-net IEEE 802.15.4 driver -use embassy_futures::select::{select3, Either3}; +use embassy_futures::select::{Either3, select3}; use embassy_net_driver_channel::driver::LinkState; use embassy_net_driver_channel::{self as ch}; use embassy_time::{Duration, Ticker}; -use crate::radio::ieee802154::{Packet, Radio}; use crate::radio::InterruptHandler; +use crate::radio::ieee802154::{Packet, Radio}; use crate::{self as nrf, interrupt}; /// MTU for the nrf radio. diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index ab5e7ed4b..7ed3a7927 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -5,10 +5,10 @@ use core::convert::Infallible; use core::hint::unreachable_unchecked; use cfg_if::cfg_if; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use crate::pac; -use crate::pac::common::{Reg, RW}; +use crate::pac::common::{RW, Reg}; use crate::pac::gpio; use crate::pac::gpio::vals; #[cfg(not(feature = "_nrf51"))] diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 43e43f0bf..3658657c0 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -1,10 +1,10 @@ //! GPIO task/event (GPIOTE) driver. use core::convert::Infallible; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin, SealedPin as _}; @@ -77,6 +77,9 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { for &p in ports { // Enable latched detection + #[cfg(feature = "_s")] + p.detectmode_sec().write(|w| w.set_detectmode(Detectmode::LDETECT)); + #[cfg(not(feature = "_s"))] p.detectmode().write(|w| w.set_detectmode(Detectmode::LDETECT)); // Clear latch p.latch().write(|w| w.0 = 0xFFFFFFFF) @@ -259,6 +262,11 @@ impl<'d> InputChannel<'d> { .await; } + /// Get the associated input pin. + pub fn pin(&self) -> &Input<'_> { + &self.pin + } + /// Returns the IN event, for use with PPI. pub fn event_in(&self) -> Event<'d> { let g = regs(); diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs index 1bfa18491..9cce9f1e8 100644 --- a/embassy-nrf/src/i2s.rs +++ b/embassy-nrf/src/i2s.rs @@ -6,7 +6,7 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::mem::size_of; use core::ops::{Deref, DerefMut}; -use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; @@ -17,7 +17,7 @@ use crate::gpio::{AnyPin, Pin as GpioPin, PselBits}; use crate::interrupt::typelevel::Interrupt; use crate::pac::i2s::vals; use crate::util::slice_in_ram_or; -use crate::{interrupt, pac, EASY_DMA_SIZE}; +use crate::{EASY_DMA_SIZE, interrupt, pac}; /// Type alias for `MultiBuffering` with 2 buffers. pub type DoubleBuffering = MultiBuffering; diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 7c26a6184..705c77453 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![cfg_attr( docsrs, doc = "

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

The documentation here on `docs.rs` is built for a single chip only (nRF52840 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" @@ -154,7 +155,6 @@ pub mod reset; #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] pub mod rng; -#[cfg(not(feature = "_nrf54l"))] // TODO pub mod rtc; #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] @@ -252,7 +252,7 @@ macro_rules! bind_interrupts { $( #[allow(non_snake_case)] - #[no_mangle] + #[unsafe(no_mangle)] $(#[cfg($cond_irq)])? unsafe extern "C" fn $irq() { unsafe { @@ -284,7 +284,7 @@ macro_rules! bind_interrupts { pub use chip::pac; #[cfg(not(feature = "unstable-pac"))] pub(crate) use chip::pac; -pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE}; +pub use chip::{EASY_DMA_SIZE, Peripherals, peripherals}; pub use embassy_hal_internal::{Peri, PeripheralType}; pub use crate::chip::interrupt; @@ -406,9 +406,10 @@ pub mod config { /// Settings for the internal capacitors. #[cfg(feature = "nrf5340-app-s")] pub struct InternalCapacitors { - /// Config for the internal capacitors on pins XC1 and XC2. + /// Config for the internal capacitors on pins XC1 and XC2. Pass `None` to not touch it. pub hfxo: Option, - /// Config for the internal capacitors between pins XL1 and XL2. + /// Config for the internal capacitors between pins XL1 and XL2. Pass `None` to not touch + /// it. pub lfxo: Option, } @@ -416,6 +417,8 @@ pub mod config { #[cfg(feature = "nrf5340-app-s")] #[derive(Copy, Clone)] pub enum HfxoCapacitance { + /// Use external capacitors + External, /// 7.0 pF _7_0pF, /// 7.5 pF @@ -475,8 +478,9 @@ pub mod config { #[cfg(feature = "nrf5340-app-s")] impl HfxoCapacitance { /// The capacitance value times two. - pub(crate) const fn value2(self) -> i32 { + pub(crate) fn value2(self) -> i32 { match self { + HfxoCapacitance::External => unreachable!(), HfxoCapacitance::_7_0pF => 14, HfxoCapacitance::_7_5pF => 15, HfxoCapacitance::_8_0pF => 16, @@ -506,11 +510,17 @@ pub mod config { HfxoCapacitance::_20_0pF => 40, } } + + pub(crate) fn external(self) -> bool { + matches!(self, Self::External) + } } /// Internal capacitance value for the LFXO. #[cfg(feature = "nrf5340-app-s")] pub enum LfxoCapacitance { + /// Use external capacitors + External = 0, /// 6 pF _6pF = 1, /// 7 pF @@ -523,6 +533,7 @@ pub mod config { impl From for super::pac::oscillators::vals::Intcap { fn from(t: LfxoCapacitance) -> Self { match t { + LfxoCapacitance::External => Self::EXTERNAL, LfxoCapacitance::_6pF => Self::C6PF, LfxoCapacitance::_7pF => Self::C7PF, LfxoCapacitance::_9pF => Self::C9PF, @@ -720,6 +731,29 @@ pub fn init(config: config::Config) -> Peripherals { } } + // Apply trimming values from the FICR. + #[cfg(any( + all(feature = "_nrf5340-app", feature = "_s"), + all(feature = "_nrf54l", feature = "_s"), + feature = "_nrf5340-net", + ))] + { + #[cfg(feature = "_nrf5340")] + let n = 32; + #[cfg(feature = "_nrf54l")] + let n = 64; + for i in 0..n { + let info = pac::FICR.trimcnf(i); + let addr = info.addr().read(); + if addr == 0 || addr == 0xFFFF_FFFF { + break; + } + unsafe { + (addr as *mut u32).write_volatile(info.data().read()); + } + } + } + // GLITCHDET is only accessible for secure code #[cfg(all(feature = "_nrf54l", feature = "_s"))] { @@ -953,17 +987,21 @@ pub fn init(config: config::Config) -> Peripherals { #[cfg(feature = "nrf5340-app-s")] { if let Some(cap) = config.internal_capacitors.hfxo { - let mut slope = pac::FICR.xosc32mtrim().read().slope() as i32; - let offset = pac::FICR.xosc32mtrim().read().offset() as i32; - // slope is a signed 5-bit integer - if slope >= 16 { - slope -= 32; + if cap.external() { + pac::OSCILLATORS.xosc32mcaps().write(|w| w.set_enable(false)); + } else { + let mut slope = pac::FICR.xosc32mtrim().read().slope() as i32; + let offset = pac::FICR.xosc32mtrim().read().offset() as i32; + // slope is a signed 5-bit integer + if slope >= 16 { + slope -= 32; + } + let capvalue = (((slope + 56) * (cap.value2() - 14)) + ((offset - 8) << 4) + 32) >> 6; + pac::OSCILLATORS.xosc32mcaps().write(|w| { + w.set_capvalue(capvalue as u8); + w.set_enable(true); + }); } - let capvalue = (((slope + 56) * (cap.value2() - 14)) + ((offset - 8) << 4) + 32) >> 6; - pac::OSCILLATORS.xosc32mcaps().write(|w| { - w.set_capvalue(capvalue as u8); - w.set_enable(true); - }); } if let Some(cap) = config.internal_capacitors.lfxo { pac::OSCILLATORS.xosc32ki().intcap().write(|w| w.set_intcap(cap.into())); diff --git a/embassy-nrf/src/nfct.rs b/embassy-nrf/src/nfct.rs index 8d70ec954..bfbdc2906 100644 --- a/embassy-nrf/src/nfct.rs +++ b/embassy-nrf/src/nfct.rs @@ -10,18 +10,18 @@ #![macro_use] use core::future::poll_fn; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_sync::waitqueue::AtomicWaker; pub use vals::{Bitframesdd as SddPat, Discardmode as DiscardMode}; use crate::interrupt::InterruptExt; -use crate::pac::nfct::vals; use crate::pac::NFCT; +use crate::pac::nfct::vals; use crate::peripherals::NFCT; use crate::util::slice_in_ram; -use crate::{interrupt, pac, Peri}; +use crate::{Peri, interrupt, pac}; /// NFCID1 (aka UID) of different sizes. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] diff --git a/embassy-nrf/src/nvmc.rs b/embassy-nrf/src/nvmc.rs index c46af0b34..3f38cd0f5 100644 --- a/embassy-nrf/src/nvmc.rs +++ b/embassy-nrf/src/nvmc.rs @@ -8,7 +8,7 @@ use embedded_storage::nor_flash::{ use crate::pac::nvmc::vals; use crate::peripherals::NVMC; -use crate::{pac, Peri}; +use crate::{Peri, pac}; #[cfg(not(feature = "_nrf5340-net"))] /// Erase size of NVMC flash in bytes. diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs index b6ee52850..bc28f5c8a 100644 --- a/embassy-nrf/src/pdm.rs +++ b/embassy-nrf/src/pdm.rs @@ -4,7 +4,7 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; @@ -13,7 +13,7 @@ use embassy_sync::waitqueue::AtomicWaker; use fixed::types::I7F1; use crate::chip::EASY_DMA_SIZE; -use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin, DISCONNECTED}; +use crate::gpio::{AnyPin, DISCONNECTED, Pin as GpioPin, SealedPin}; use crate::interrupt::typelevel::Interrupt; use crate::pac::gpio::vals as gpiovals; use crate::pac::pdm::vals; diff --git a/embassy-nrf/src/ppi/dppi.rs b/embassy-nrf/src/ppi/dppi.rs index 078d2fd1c..168647be3 100644 --- a/embassy-nrf/src/ppi/dppi.rs +++ b/embassy-nrf/src/ppi/dppi.rs @@ -1,5 +1,5 @@ use super::{Channel, ConfigurableChannel, Event, Ppi, Task}; -use crate::{pac, Peri}; +use crate::{Peri, pac}; const DPPI_ENABLE_BIT: u32 = 0x8000_0000; const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF; diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs index 2bcf72e9c..f30c2218d 100644 --- a/embassy-nrf/src/ppi/mod.rs +++ b/embassy-nrf/src/ppi/mod.rs @@ -18,9 +18,9 @@ use core::marker::PhantomData; use core::ptr::NonNull; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; -use crate::pac::common::{Reg, RW, W}; +use crate::pac::common::{RW, Reg, W}; use crate::peripherals; #[cfg_attr(feature = "_dppi", path = "dppi.rs")] diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs index 531c25444..18bc8b8db 100644 --- a/embassy-nrf/src/ppi/ppi.rs +++ b/embassy-nrf/src/ppi/ppi.rs @@ -1,5 +1,5 @@ use super::{Channel, ConfigurableChannel, Event, Ppi, Task}; -use crate::{pac, Peri}; +use crate::{Peri, pac}; impl<'d> Task<'d> { fn reg_val(&self) -> u32 { diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index d67cb546b..e038f44b8 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -2,11 +2,11 @@ #![macro_use] -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use embassy_hal_internal::{Peri, PeripheralType}; -use crate::gpio::{convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, DISCONNECTED}; +use crate::gpio::{AnyPin, DISCONNECTED, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, convert_drive}; use crate::pac::gpio::vals as gpiovals; use crate::pac::pwm::vals; use crate::ppi::{Event, Task}; diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 6f4524716..6bb7c033e 100755 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -2,7 +2,7 @@ #![macro_use] -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::ptr; use core::task::Poll; diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index 62af03a5a..54b463343 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs @@ -1,18 +1,18 @@ //! IEEE 802.15.4 radio driver use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use super::{Error, InterruptHandler, TxPower}; +use crate::Peri; use crate::interrupt::typelevel::Interrupt; use crate::interrupt::{self}; use crate::pac::radio::vals; pub use crate::pac::radio::vals::State as RadioState; use crate::radio::Instance; -use crate::Peri; /// Default (IEEE compliant) Start of Frame Delimiter pub const DEFAULT_SFD: u8 = 0xA7; @@ -52,6 +52,7 @@ impl<'d> Radio<'d> { // Disable and enable to reset peripheral r.power().write(|w| w.set_power(false)); r.power().write(|w| w.set_power(true)); + errata::post_power(); // Enable 802.15.4 mode r.mode().write(|w| w.set_mode(vals::Mode::IEEE802154_250KBIT)); @@ -541,3 +542,19 @@ fn dma_start_fence() { fn dma_end_fence() { compiler_fence(Ordering::Acquire); } + +mod errata { + pub fn post_power() { + // Workaround for anomaly 158 + #[cfg(feature = "_nrf5340-net")] + for i in 0..32 { + let info = crate::pac::FICR.trimcnf(i); + let addr = info.addr().read(); + if addr & 0xFFFF_F000 == crate::pac::RADIO.as_ptr() as u32 { + unsafe { + (addr as *mut u32).write_volatile(info.data().read()); + } + } + } + } +} diff --git a/embassy-nrf/src/rramc.rs b/embassy-nrf/src/rramc.rs index 7cb5660cb..521ac4ee7 100644 --- a/embassy-nrf/src/rramc.rs +++ b/embassy-nrf/src/rramc.rs @@ -7,7 +7,7 @@ use embedded_storage::nor_flash::{ }; use crate::peripherals::RRAMC; -use crate::{pac, Peri}; +use crate::{Peri, pac}; // // Export Nvmc alias and page size for downstream compatibility diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index fd48faabb..a199c1c4d 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -4,11 +4,11 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{impl_peripheral, Peri}; +use embassy_hal_internal::{Peri, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; pub(crate) use vals::Psel as InputChannel; diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index c410e49fd..ce994dbc9 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -6,17 +6,17 @@ use core::future::poll_fn; use core::marker::PhantomData; #[cfg(feature = "_nrf52832_anomaly_109")] use core::sync::atomic::AtomicU8; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; -pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +pub use embedded_hal_02::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity}; pub use pac::spim::vals::{Frequency, Order as BitOrder}; use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; -use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _}; +use crate::gpio::{self, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, convert_drive}; use crate::interrupt::typelevel::Interrupt; use crate::pac::gpio::vals as gpiovals; use crate::pac::spim::vals; diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index 713163a55..885821146 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs @@ -3,17 +3,17 @@ #![macro_use] use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; -pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +pub use embedded_hal_02::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity}; pub use pac::spis::vals::Order as BitOrder; use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; -use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, SealedPin as _}; +use crate::gpio::{self, AnyPin, OutputDrive, Pin as GpioPin, SealedPin as _, convert_drive}; use crate::interrupt::typelevel::Interrupt; use crate::pac::gpio::vals as gpiovals; use crate::pac::spis::vals; diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs index 44be0f6d1..a20e300b7 100644 --- a/embassy-nrf/src/temp.rs +++ b/embassy-nrf/src/temp.rs @@ -9,7 +9,7 @@ use fixed::types::I30F2; use crate::interrupt::InterruptExt; use crate::peripherals::TEMP; -use crate::{interrupt, pac, Peri}; +use crate::{Peri, interrupt, pac}; /// Interrupt handler. pub struct InterruptHandler { diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index 03f4c2e2b..b723e2334 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -1,9 +1,9 @@ use core::cell::{Cell, RefCell}; -use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; use critical_section::CriticalSection; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_time_driver::Driver; use embassy_time_queue_utils::Queue; diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 943ea9d31..93255c832 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -4,8 +4,8 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::compiler_fence; use core::sync::atomic::Ordering::SeqCst; +use core::sync::atomic::compiler_fence; use core::task::Poll; use embassy_embedded_hal::SetConfig; diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs index dd4978b3e..2bc0a5c13 100644 --- a/embassy-nrf/src/twis.rs +++ b/embassy-nrf/src/twis.rs @@ -2,10 +2,10 @@ #![macro_use] -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; -use core::sync::atomic::compiler_fence; use core::sync::atomic::Ordering::SeqCst; +use core::sync::atomic::compiler_fence; use core::task::Poll; use embassy_hal_internal::{Peri, PeripheralType}; diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 66fb3b3f2..1ee452173 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -15,7 +15,7 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, AtomicU8, Ordering}; +use core::sync::atomic::{AtomicU8, Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; @@ -25,7 +25,7 @@ use embassy_sync::waitqueue::AtomicWaker; pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity}; use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; -use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits, SealedPin as _, DISCONNECTED}; +use crate::gpio::{self, AnyPin, DISCONNECTED, Pin as GpioPin, PselBits, SealedPin as _}; use crate::interrupt::typelevel::Interrupt; use crate::pac::gpio::vals as gpiovals; use crate::pac::uarte::vals; diff --git a/embassy-nrf/src/usb/mod.rs b/embassy-nrf/src/usb/mod.rs index 2a32fe922..07cf2578a 100644 --- a/embassy-nrf/src/usb/mod.rs +++ b/embassy-nrf/src/usb/mod.rs @@ -4,10 +4,10 @@ pub mod vbus_detect; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::mem::MaybeUninit; -use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; use core::task::Poll; use cortex_m::peripheral::NVIC; @@ -330,11 +330,7 @@ impl<'d, V: VbusDetect> driver::Bus for Bus<'d, V> { let mut was_enabled = false; regs.epinen().modify(|w| { was_enabled = (w.0 & mask) != 0; - if enabled { - w.0 |= mask - } else { - w.0 &= !mask - } + if enabled { w.0 |= mask } else { w.0 &= !mask } }); let ready_mask = In::mask(i); diff --git a/embassy-nrf/src/usb/vbus_detect.rs b/embassy-nrf/src/usb/vbus_detect.rs index 33cf91ee2..f24a7bff5 100644 --- a/embassy-nrf/src/usb/vbus_detect.rs +++ b/embassy-nrf/src/usb/vbus_detect.rs @@ -1,6 +1,6 @@ //! Trait and implementations for performing VBUS detection. -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; diff --git a/embassy-nrf/src/util.rs b/embassy-nrf/src/util.rs index 78f71719f..87118d347 100644 --- a/embassy-nrf/src/util.rs +++ b/embassy-nrf/src/util.rs @@ -15,9 +15,5 @@ pub(crate) fn slice_in_ram(slice: *const [T]) -> bool { /// Return an error if slice is not in RAM. Skips check if slice is zero-length. pub(crate) fn slice_in_ram_or(slice: *const [T], err: E) -> Result<(), E> { - if slice_in_ram(slice) { - Ok(()) - } else { - Err(err) - } + if slice_in_ram(slice) { Ok(()) } else { Err(err) } } diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs index dc99a16f5..6afd73431 100644 --- a/embassy-nrf/src/wdt.rs +++ b/embassy-nrf/src/wdt.rs @@ -11,7 +11,7 @@ use embassy_hal_internal::PeripheralType; use crate::pac::wdt::vals; pub use crate::pac::wdt::vals::{Halt as HaltConfig, Sleep as SleepConfig}; -use crate::{interrupt, pac, peripherals, Peri}; +use crate::{Peri, interrupt, pac, peripherals}; const MIN_TICKS: u32 = 15; diff --git a/embassy-nxp/CHANGELOG.md b/embassy-nxp/CHANGELOG.md index 0fb677cd8..ad8670854 100644 --- a/embassy-nxp/CHANGELOG.md +++ b/embassy-nxp/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- LPC55: Move ALT definitions for USART to TX/RX pin impls. +- LPC55: Remove internal match_iocon macro - LPC55: DMA Controller and asynchronous version of USART - Moved NXP LPC55S69 from `lpc55-pac` to `nxp-pac` - First release with changelog. diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml index f3c828313..33f0f2dff 100644 --- a/embassy-nxp/Cargo.toml +++ b/embassy-nxp/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-nxp" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/embassy-nxp/src/dma/lpc55.rs b/embassy-nxp/src/dma/lpc55.rs index 578d1fd88..5bd763f03 100644 --- a/embassy-nxp/src/dma/lpc55.rs +++ b/embassy-nxp/src/dma/lpc55.rs @@ -1,16 +1,16 @@ use core::cell::RefCell; use core::future::Future; use core::pin::Pin; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::{Context, Poll}; use critical_section::Mutex; use embassy_hal_internal::interrupt::InterruptExt; -use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_hal_internal::{PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use crate::pac::{DMA0, SYSCON, *}; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; #[interrupt] fn DMA0() { diff --git a/embassy-nxp/src/gpio/lpc55.rs b/embassy-nxp/src/gpio/lpc55.rs index 36ea99d21..6039d8ca8 100644 --- a/embassy-nxp/src/gpio/lpc55.rs +++ b/embassy-nxp/src/gpio/lpc55.rs @@ -1,8 +1,9 @@ -use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_hal_internal::{PeripheralType, impl_peripheral}; +use crate::pac::common::{RW, Reg}; use crate::pac::iocon::vals::{PioDigimode, PioMode}; -use crate::pac::{GPIO, IOCON, SYSCON}; -use crate::{peripherals, Peri}; +use crate::pac::{GPIO, IOCON, SYSCON, iocon}; +use crate::{Peri, peripherals}; pub(crate) fn init() { // Enable clocks for GPIO, PINT, and IOCON @@ -109,13 +110,7 @@ impl<'d> Input<'d> { /// Set the pull configuration for the pin. To disable the pull, use [Pull::None]. pub fn set_pull(&mut self, pull: Pull) { - match_iocon!(register, self.pin.pin_bank(), self.pin.pin_number(), { - register.modify(|w| match pull { - Pull::None => w.set_mode(PioMode::INACTIVE), - Pull::Up => w.set_mode(PioMode::PULL_UP), - Pull::Down => w.set_mode(PioMode::PULL_DOWN), - }); - }); + self.pin.set_pull(pull); } /// Get the current input level of the pin. @@ -193,11 +188,20 @@ impl<'d> Flex<'d> { 1 << self.pin.pin_number() } + /// Set the pull configuration for the pin. To disable the pull, use [Pull::None]. + pub fn set_pull(&mut self, pull: Pull) { + self.pin.pio().modify(|w| match pull { + Pull::None => w.set_mode(PioMode::INACTIVE), + Pull::Up => w.set_mode(PioMode::PULL_UP), + Pull::Down => w.set_mode(PioMode::PULL_DOWN), + }); + } + /// Set the pin to digital mode. This is required for using a pin as a GPIO pin. The default /// setting for pins is (usually) non-digital. fn set_as_digital(&mut self) { - match_iocon!(register, self.pin_bank(), self.pin_number(), { - register.modify(|w| w.set_digimode(PioDigimode::DIGITAL)); + self.pin.pio().modify(|w| { + w.set_digimode(PioDigimode::DIGITAL); }); } @@ -220,6 +224,14 @@ impl<'d> Flex<'d> { pub(crate) trait SealedPin: Sized { fn pin_bank(&self) -> Bank; fn pin_number(&self) -> u8; + + #[inline] + fn pio(&self) -> Reg { + match self.pin_bank() { + Bank::Bank0 => IOCON.pio0(self.pin_number() as usize), + Bank::Bank1 => IOCON.pio1(self.pin_number() as usize), + } + } } /// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an @@ -272,40 +284,6 @@ impl SealedPin for AnyPin { } } -/// Match the pin bank and number of a pin to the corresponding IOCON register. -/// -/// # Example -/// ``` -/// use embassy_nxp::gpio::Bank; -/// use embassy_nxp::pac_utils::{iocon_reg, match_iocon}; -/// -/// // Make pin PIO1_6 digital and set it to pull-down mode. -/// match_iocon!(register, Bank::Bank1, 6, { -/// register.modify(|w|{ -/// w.set_mode(PioMode::PULL_DOWN); -/// w.set_digimode(PioDigimode::DIGITAL); -/// -/// } -/// }); -/// ``` -macro_rules! match_iocon { - ($register:ident, $pin_bank:expr, $pin_number:expr, $action:expr) => { - match $pin_bank { - Bank::Bank0 => { - let $register = IOCON.pio0($pin_number as usize); - $action; - } - - Bank::Bank1 => { - let $register = IOCON.pio1($pin_number as usize); - $action; - } - } - }; -} - -pub(crate) use match_iocon; - macro_rules! impl_pin { ($name:ident, $bank:expr, $pin_num:expr) => { impl Pin for peripherals::$name {} diff --git a/embassy-nxp/src/gpio/rt1xxx.rs b/embassy-nxp/src/gpio/rt1xxx.rs index 1d60a0d51..c4dc110ff 100644 --- a/embassy-nxp/src/gpio/rt1xxx.rs +++ b/embassy-nxp/src/gpio/rt1xxx.rs @@ -5,13 +5,13 @@ use core::ops::Not; use core::pin::Pin as FuturePin; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use nxp_pac::gpio::vals::Icr; use nxp_pac::iomuxc::vals::Pus; use crate::chip::{mux_address, pad_address}; -use crate::pac::common::{Reg, RW}; +use crate::pac::common::{RW, Reg}; use crate::pac::gpio::Gpio; #[cfg(feature = "rt")] use crate::pac::interrupt; diff --git a/embassy-nxp/src/lib.rs b/embassy-nxp/src/lib.rs index f0f0afb6c..9576f02b1 100644 --- a/embassy-nxp/src/lib.rs +++ b/embassy-nxp/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; @@ -29,7 +30,7 @@ pub use chip::interrupt; pub use chip::pac; #[cfg(not(feature = "unstable-pac"))] pub(crate) use chip::pac; -pub use chip::{peripherals, Peripherals}; +pub use chip::{Peripherals, peripherals}; pub use embassy_hal_internal::{Peri, PeripheralType}; /// Macro to bind interrupts to handlers. @@ -67,7 +68,7 @@ macro_rules! bind_interrupts { $( #[allow(non_snake_case)] - #[no_mangle] + #[unsafe(no_mangle)] $(#[cfg($cond_irq)])? unsafe extern "C" fn $irq() { unsafe { diff --git a/embassy-nxp/src/pint.rs b/embassy-nxp/src/pint.rs index e594aaa6a..5b10b4540 100644 --- a/embassy-nxp/src/pint.rs +++ b/embassy-nxp/src/pint.rs @@ -8,9 +8,9 @@ use critical_section::Mutex; use embassy_hal_internal::interrupt::InterruptExt; use embassy_sync::waitqueue::AtomicWaker; -use crate::gpio::{self, AnyPin, Level, SealedPin}; -use crate::pac::{interrupt, INPUTMUX, PINT, SYSCON}; use crate::Peri; +use crate::gpio::{self, AnyPin, Level, SealedPin}; +use crate::pac::{INPUTMUX, PINT, SYSCON, interrupt}; struct PinInterrupt { assigned: bool, diff --git a/embassy-nxp/src/time_driver/rtc.rs b/embassy-nxp/src/time_driver/rtc.rs index fb6de6a5e..0883fa2e8 100644 --- a/embassy-nxp/src/time_driver/rtc.rs +++ b/embassy-nxp/src/time_driver/rtc.rs @@ -4,10 +4,10 @@ use core::task::Waker; use critical_section::CriticalSection; use embassy_hal_internal::interrupt::{InterruptExt, Priority}; use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; -use embassy_time_driver::{time_driver_impl, Driver}; +use embassy_time_driver::{Driver, time_driver_impl}; use embassy_time_queue_utils::Queue; -use crate::pac::{interrupt, pmc, rtc, PMC, RTC, SYSCON}; +use crate::pac::{PMC, RTC, SYSCON, interrupt, pmc, rtc}; struct AlarmState { timestamp: Cell, diff --git a/embassy-nxp/src/usart/lpc55.rs b/embassy-nxp/src/usart/lpc55.rs index 9034ed429..d54927b25 100644 --- a/embassy-nxp/src/usart/lpc55.rs +++ b/embassy-nxp/src/usart/lpc55.rs @@ -4,16 +4,16 @@ use core::marker::PhantomData; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_hal_internal::interrupt::InterruptExt; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use embedded_io::{self, ErrorKind}; use crate::dma::{AnyChannel, Channel}; -use crate::gpio::{match_iocon, AnyPin, Bank, SealedPin}; -use crate::interrupt::typelevel::{Binding, Interrupt as _}; +use crate::gpio::{AnyPin, SealedPin}; use crate::interrupt::Interrupt; +use crate::interrupt::typelevel::{Binding, Interrupt as _}; use crate::pac::flexcomm::Flexcomm as FlexcommReg; use crate::pac::iocon::vals::PioFunc; use crate::pac::usart::Usart as UsartReg; @@ -146,7 +146,8 @@ impl<'d, M: Mode> UsartTx<'d, M> { tx_dma: Peri<'d, impl Channel>, config: Config, ) -> Self { - Usart::::init::(Some(tx.into()), None, config); + let tx_func = tx.pin_func(); + Usart::::init::(Some((tx.into(), tx_func)), None, config); Self::new_inner(T::info(), Some(tx_dma.into())) } @@ -179,7 +180,8 @@ impl<'d, M: Mode> UsartTx<'d, M> { impl<'d> UsartTx<'d, Blocking> { pub fn new_blocking(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, config: Config) -> Self { - Usart::::init::(Some(tx.into()), None, config); + let tx_func = tx.pin_func(); + Usart::::init::(Some((tx.into(), tx_func)), None, config); Self::new_inner(T::info(), None) } } @@ -208,7 +210,8 @@ impl<'d, M: Mode> UsartRx<'d, M> { rx_dma: Peri<'d, impl Channel>, config: Config, ) -> Self { - Usart::::init::(None, Some(rx.into()), config); + let rx_func = rx.pin_func(); + Usart::::init::(None, Some((rx.into(), rx_func)), config); Self::new_inner(T::info(), T::dma_state(), has_irq, Some(rx_dma.into())) } @@ -280,7 +283,8 @@ impl<'d, M: Mode> UsartRx<'d, M> { impl<'d> UsartRx<'d, Blocking> { pub fn new_blocking(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin>, config: Config) -> Self { - Usart::::init::(None, Some(rx.into()), config); + let rx_func = rx.pin_func(); + Usart::::init::(None, Some((rx.into(), rx_func)), config); Self::new_inner(T::info(), T::dma_state(), false, None) } } @@ -405,7 +409,10 @@ impl<'d> Usart<'d, Blocking> { rx: Peri<'d, impl RxPin>, config: Config, ) -> Self { - Self::new_inner(usart, tx.into(), rx.into(), false, None, None, config) + let tx_func = tx.pin_func(); + let rx_func = rx.pin_func(); + + Self::new_inner(usart, tx.into(), tx_func, rx.into(), rx_func, false, None, None, config) } } @@ -419,10 +426,15 @@ impl<'d> Usart<'d, Async> { rx_dma: Peri<'d, impl RxChannel>, config: Config, ) -> Self { + let tx_func = tx.pin_func(); + let rx_func = rx.pin_func(); + Self::new_inner( uart, tx.into(), + tx_func, rx.into(), + rx_func, true, Some(tx_dma.into()), Some(rx_dma.into()), @@ -435,20 +447,26 @@ impl<'d, M: Mode> Usart<'d, M> { fn new_inner( _usart: Peri<'d, T>, mut tx: Peri<'d, AnyPin>, + tx_func: PioFunc, mut rx: Peri<'d, AnyPin>, + rx_func: PioFunc, has_irq: bool, tx_dma: Option>, rx_dma: Option>, config: Config, ) -> Self { - Self::init::(Some(tx.reborrow()), Some(rx.reborrow()), config); + Self::init::(Some((tx.reborrow(), tx_func)), Some((rx.reborrow(), rx_func)), config); Self { tx: UsartTx::new_inner(T::info(), tx_dma), rx: UsartRx::new_inner(T::info(), T::dma_state(), has_irq, rx_dma), } } - fn init(tx: Option>, rx: Option>, config: Config) { + fn init( + tx: Option<(Peri<'_, AnyPin>, PioFunc)>, + rx: Option<(Peri<'_, AnyPin>, PioFunc)>, + config: Config, + ) { Self::configure_flexcomm(T::info().fc_reg, T::instance_number()); Self::configure_clock::(&config); Self::pin_config::(tx, rx); @@ -553,31 +571,27 @@ impl<'d, M: Mode> Usart<'d, M> { .modify(|w| w.set_brgval((brg_value - 1) as u16)); } - fn pin_config(tx: Option>, rx: Option>) { - if let Some(tx_pin) = tx { - match_iocon!(register, tx_pin.pin_bank(), tx_pin.pin_number(), { - register.modify(|w| { - w.set_func(T::tx_pin_func()); - w.set_mode(iocon::vals::PioMode::INACTIVE); - w.set_slew(iocon::vals::PioSlew::STANDARD); - w.set_invert(false); - w.set_digimode(iocon::vals::PioDigimode::DIGITAL); - w.set_od(iocon::vals::PioOd::NORMAL); - }); - }) + fn pin_config(tx: Option<(Peri<'_, AnyPin>, PioFunc)>, rx: Option<(Peri<'_, AnyPin>, PioFunc)>) { + if let Some((tx_pin, func)) = tx { + tx_pin.pio().modify(|w| { + w.set_func(func); + w.set_mode(iocon::vals::PioMode::INACTIVE); + w.set_slew(iocon::vals::PioSlew::STANDARD); + w.set_invert(false); + w.set_digimode(iocon::vals::PioDigimode::DIGITAL); + w.set_od(iocon::vals::PioOd::NORMAL); + }); } - if let Some(rx_pin) = rx { - match_iocon!(register, rx_pin.pin_bank(), rx_pin.pin_number(), { - register.modify(|w| { - w.set_func(T::rx_pin_func()); - w.set_mode(iocon::vals::PioMode::INACTIVE); - w.set_slew(iocon::vals::PioSlew::STANDARD); - w.set_invert(false); - w.set_digimode(iocon::vals::PioDigimode::DIGITAL); - w.set_od(iocon::vals::PioOd::NORMAL); - }); - }) + if let Some((rx_pin, func)) = rx { + rx_pin.pio().modify(|w| { + w.set_func(func); + w.set_mode(iocon::vals::PioMode::INACTIVE); + w.set_slew(iocon::vals::PioSlew::STANDARD); + w.set_invert(false); + w.set_digimode(iocon::vals::PioDigimode::DIGITAL); + w.set_od(iocon::vals::PioOd::NORMAL); + }); }; } @@ -814,8 +828,6 @@ trait SealedInstance { fn info() -> &'static Info; fn dma_state() -> &'static DmaState; fn instance_number() -> usize; - fn tx_pin_func() -> PioFunc; - fn rx_pin_func() -> PioFunc; } /// UART instance. @@ -826,7 +838,7 @@ pub trait Instance: SealedInstance + PeripheralType { } macro_rules! impl_instance { - ($inst:ident, $fc:ident, $tx_pin:ident, $rx_pin:ident, $fc_num:expr) => { + ($inst:ident, $fc:ident, $fc_num:expr) => { impl $crate::usart::inner::SealedInstance for $crate::peripherals::$inst { fn info() -> &'static Info { static INFO: Info = Info { @@ -848,14 +860,6 @@ macro_rules! impl_instance { fn instance_number() -> usize { $fc_num } - #[inline] - fn tx_pin_func() -> PioFunc { - PioFunc::$tx_pin - } - #[inline] - fn rx_pin_func() -> PioFunc { - PioFunc::$rx_pin - } } impl $crate::usart::Instance for $crate::peripherals::$inst { type Interrupt = crate::interrupt::typelevel::$fc; @@ -863,45 +867,72 @@ macro_rules! impl_instance { }; } -impl_instance!(USART0, FLEXCOMM0, ALT1, ALT1, 0); -impl_instance!(USART1, FLEXCOMM1, ALT2, ALT2, 1); -impl_instance!(USART2, FLEXCOMM2, ALT1, ALT1, 2); -impl_instance!(USART3, FLEXCOMM3, ALT1, ALT1, 3); -impl_instance!(USART4, FLEXCOMM4, ALT1, ALT2, 4); -impl_instance!(USART5, FLEXCOMM5, ALT3, ALT3, 5); -impl_instance!(USART6, FLEXCOMM6, ALT2, ALT2, 6); -impl_instance!(USART7, FLEXCOMM7, ALT7, ALT7, 7); +impl_instance!(USART0, FLEXCOMM0, 0); +impl_instance!(USART1, FLEXCOMM1, 1); +impl_instance!(USART2, FLEXCOMM2, 2); +impl_instance!(USART3, FLEXCOMM3, 3); +impl_instance!(USART4, FLEXCOMM4, 4); +impl_instance!(USART5, FLEXCOMM5, 5); +impl_instance!(USART6, FLEXCOMM6, 6); +impl_instance!(USART7, FLEXCOMM7, 7); + +pub(crate) trait SealedTxPin: crate::gpio::Pin { + fn pin_func(&self) -> PioFunc; +} + +pub(crate) trait SealedRxPin: crate::gpio::Pin { + fn pin_func(&self) -> PioFunc; +} /// Trait for TX pins. -pub trait TxPin: crate::gpio::Pin {} +#[allow(private_bounds)] +pub trait TxPin: SealedTxPin + crate::gpio::Pin {} + /// Trait for RX pins. -pub trait RxPin: crate::gpio::Pin {} +#[allow(private_bounds)] +pub trait RxPin: SealedRxPin + crate::gpio::Pin {} + +macro_rules! impl_tx_pin { + ($pin:ident, $instance:ident, $func: ident) => { + impl SealedTxPin for crate::peripherals::$pin { + fn pin_func(&self) -> PioFunc { + PioFunc::$func + } + } -macro_rules! impl_pin { - ($pin:ident, $instance:ident, Tx) => { impl TxPin for crate::peripherals::$pin {} }; - ($pin:ident, $instance:ident, Rx) => { +} + +macro_rules! impl_rx_pin { + ($pin:ident, $instance:ident, $func: ident) => { + impl SealedRxPin for crate::peripherals::$pin { + fn pin_func(&self) -> PioFunc { + PioFunc::$func + } + } + impl RxPin for crate::peripherals::$pin {} }; } -impl_pin!(PIO1_6, USART0, Tx); -impl_pin!(PIO1_5, USART0, Rx); -impl_pin!(PIO1_11, USART1, Tx); -impl_pin!(PIO1_10, USART1, Rx); -impl_pin!(PIO0_27, USART2, Tx); -impl_pin!(PIO1_24, USART2, Rx); -impl_pin!(PIO0_2, USART3, Tx); -impl_pin!(PIO0_3, USART3, Rx); -impl_pin!(PIO0_16, USART4, Tx); -impl_pin!(PIO0_5, USART4, Rx); -impl_pin!(PIO0_9, USART5, Tx); -impl_pin!(PIO0_8, USART5, Rx); -impl_pin!(PIO1_16, USART6, Tx); -impl_pin!(PIO1_13, USART6, Rx); -impl_pin!(PIO0_19, USART7, Tx); -impl_pin!(PIO0_20, USART7, Rx); +impl_tx_pin!(PIO1_6, USART0, ALT1); +impl_tx_pin!(PIO1_11, USART1, ALT2); +impl_tx_pin!(PIO0_27, USART2, ALT1); +impl_tx_pin!(PIO0_2, USART3, ALT1); +impl_tx_pin!(PIO0_16, USART4, ALT1); +impl_tx_pin!(PIO0_9, USART5, ALT3); +impl_tx_pin!(PIO1_16, USART6, ALT2); +impl_tx_pin!(PIO0_19, USART7, ALT7); + +impl_rx_pin!(PIO1_5, USART0, ALT1); +impl_rx_pin!(PIO1_10, USART1, ALT2); +impl_rx_pin!(PIO1_24, USART2, ALT1); +impl_rx_pin!(PIO0_3, USART3, ALT1); +impl_rx_pin!(PIO0_5, USART4, ALT2); +impl_rx_pin!(PIO0_8, USART5, ALT3); +impl_rx_pin!(PIO1_13, USART6, ALT2); +impl_rx_pin!(PIO0_20, USART7, ALT7); /// Trait for TX DMA channels. pub trait TxChannel: crate::dma::Channel {} diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index f6b0900f2..9ad4b47a3 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-rp" version = "0.8.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 or RP235x microcontroller" keywords = ["embedded", "async", "rp235x", "rp2040", "embedded-hal"] @@ -104,7 +104,7 @@ boot2-w25x10cl = [] ## Have embassy-rp not provide the boot2 so you can use your own. ## Place your own in the ".boot2" section like: ## ``` -## #[link_section = ".boot2"] +## #[unsafe(link_section = ".boot2")] ## #[used] ## static BOOT2: [u8; 256] = [0; 256]; // Provide your own with e.g. include_bytes! ## ``` @@ -127,7 +127,7 @@ imagedef-nonsecure-exe = [] ## ```ignore ## use embassy_rp::block::ImageDef; ## -## #[link_section = ".start_block"] +## #[unsafe(link_section = ".start_block")] ## #[used] ## static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); // Update this with your own implementation. ## ``` diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index 2db8e63d7..d16779e01 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs @@ -1,18 +1,18 @@ //! ADC driver. -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::mem; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{self, AnyPin, Pull, SealedPin as GpioPin}; -use crate::interrupt::typelevel::Binding; use crate::interrupt::InterruptExt; +use crate::interrupt::typelevel::Binding; use crate::pac::dma::vals::TreqSel; use crate::peripherals::{ADC, ADC_TEMP_SENSOR}; -use crate::{dma, interrupt, pac, peripherals, Peri, RegExt}; +use crate::{Peri, RegExt, dma, interrupt, pac, peripherals}; static WAKER: AtomicWaker = AtomicWaker::new(); diff --git a/embassy-rp/src/bootsel.rs b/embassy-rp/src/bootsel.rs index 14f9e46aa..b24b98cd5 100644 --- a/embassy-rp/src/bootsel.rs +++ b/embassy-rp/src/bootsel.rs @@ -7,8 +7,8 @@ //! //! This module provides functionality to poll BOOTSEL from an embassy application. -use crate::flash::in_ram; use crate::Peri; +use crate::flash::in_ram; /// Reads the BOOTSEL button. Returns true if the button is pressed. /// @@ -36,7 +36,7 @@ mod ram_helpers { /// This function must live in ram. It uses inline asm to avoid any /// potential calls to ABI functions that might be in flash. #[inline(never)] - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[cfg(target_arch = "arm")] pub unsafe fn read_cs_status() -> GpioStatus { let result: u32; diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 2eddc0bcc..56892d7a2 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -72,8 +72,8 @@ use core::sync::atomic::{AtomicU32, Ordering}; use pac::clocks::vals::*; use crate::gpio::{AnyPin, SealedPin}; -use crate::pac::common::{Reg, RW}; -use crate::{pac, reset, Peri}; +use crate::pac::common::{RW, Reg}; +use crate::{Peri, pac, reset}; // NOTE: all gpin handling is commented out for future reference. // gpin is not usually safe to use during the boot init() call, so it won't diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index d31d1e159..18aec60a5 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs @@ -1,10 +1,10 @@ //! Direct Memory Access (DMA) use core::future::Future; use core::pin::Pin; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use pac::dma::vals::DataSize; diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 8c809090e..7cc8f0c1d 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -6,8 +6,8 @@ use core::task::{Context, Poll}; use embassy_hal_internal::{Peri, PeripheralType}; use embedded_storage::nor_flash::{ - check_erase, check_read, check_write, ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, - ReadNorFlash, + ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash, check_erase, check_read, + check_write, }; use crate::dma::{AnyChannel, Channel, Transfer}; @@ -627,7 +627,7 @@ mod ram_helpers { /// Length of data must be a multiple of 4096 /// addr must be aligned to 4096 #[inline(never)] - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[cfg(feature = "rp2040")] unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { #[cfg(target_arch = "arm")] @@ -692,7 +692,7 @@ mod ram_helpers { /// Length of data must be a multiple of 4096 /// addr must be aligned to 4096 #[inline(never)] - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[cfg(feature = "_rp235x")] unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { let data = data.map(|d| d.as_ptr()).unwrap_or(core::ptr::null()); @@ -811,7 +811,7 @@ mod ram_helpers { /// /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) #[inline(never)] - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[cfg(feature = "rp2040")] unsafe fn read_flash_inner(cmd: FlashCommand, ptrs: *const FlashFunctionPointers) { #[cfg(target_arch = "arm")] diff --git a/embassy-rp/src/float/cmp.rs b/embassy-rp/src/float/cmp.rs index e540e3918..f917eb9b3 100644 --- a/embassy-rp/src/float/cmp.rs +++ b/embassy-rp/src/float/cmp.rs @@ -21,19 +21,11 @@ impl ROMCmp for f64 { } fn le_abi(a: F, b: F) -> i32 { - if a.is_nan() || b.is_nan() { - 1 - } else { - a.rom_cmp(b) - } + if a.is_nan() || b.is_nan() { 1 } else { a.rom_cmp(b) } } fn ge_abi(a: F, b: F) -> i32 { - if a.is_nan() || b.is_nan() { - -1 - } else { - a.rom_cmp(b) - } + if a.is_nan() || b.is_nan() { -1 } else { a.rom_cmp(b) } } intrinsics! { diff --git a/embassy-rp/src/float/functions.rs b/embassy-rp/src/float/functions.rs index de29ce336..170168237 100644 --- a/embassy-rp/src/float/functions.rs +++ b/embassy-rp/src/float/functions.rs @@ -114,19 +114,11 @@ fn sqrt(f: F) -> F { } fn ln(f: F) -> F { - if is_negative_nonzero_or_nan(f) { - F::NAN - } else { - f.ln() - } + if is_negative_nonzero_or_nan(f) { F::NAN } else { f.ln() } } fn exp(f: F) -> F { - if f.is_nan() { - F::NAN - } else { - f.exp() - } + if f.is_nan() { F::NAN } else { f.exp() } } fn sin(f: F) -> F { diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index f79bf8948..c15e0e41b 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -5,13 +5,13 @@ use core::future::Future; use core::pin::Pin as FuturePin; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use crate::interrupt::InterruptExt; -use crate::pac::common::{Reg, RW}; use crate::pac::SIO; -use crate::{interrupt, pac, peripherals, RegExt}; +use crate::pac::common::{RW, Reg}; +use crate::{RegExt, interrupt, pac, peripherals}; #[cfg(any(feature = "rp2040", feature = "rp235xa"))] pub(crate) const BANK0_PIN_COUNT: usize = 30; diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index c263047ad..770087bc8 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs @@ -5,9 +5,9 @@ use core::task::Poll; use pac::i2c; -use crate::i2c::{set_up_i2c_pin, AbortReason, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE}; +use crate::i2c::{AbortReason, FIFO_SIZE, Instance, InterruptHandler, SclPin, SdaPin, set_up_i2c_pin}; use crate::interrupt::typelevel::{Binding, Interrupt}; -use crate::{pac, Peri}; +use crate::{Peri, pac}; /// I2C error #[derive(Debug, PartialEq, Eq, Clone, Copy)] diff --git a/embassy-rp/src/intrinsics.rs b/embassy-rp/src/intrinsics.rs index 69d5d92de..aed8a3227 100644 --- a/embassy-rp/src/intrinsics.rs +++ b/embassy-rp/src/intrinsics.rs @@ -223,7 +223,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", feature = "intrinsics"))] mod $name { - #[no_mangle] + #[unsafe(no_mangle)] $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { super::$name($($argname),*) @@ -257,7 +257,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", feature = "intrinsics"))] mod $name { - #[no_mangle] + #[unsafe(no_mangle)] $(#[$($attr)*])* pub unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret { super::$name($($argname),*) @@ -392,7 +392,7 @@ macro_rules! division_function { ); #[cfg(target_arch = "arm")] - extern "aapcs" { + unsafe extern "aapcs" { // Connect a local name to global symbol above through FFI. #[link_name = concat!("_erphal_", stringify!($name)) ] fn $name(n: $argty, d: $argty) -> u64; diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index d03ba1fef..4cb1a0912 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -1,5 +1,7 @@ #![no_std] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] +#![allow(unused_unsafe)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] @@ -190,7 +192,7 @@ macro_rules! bind_interrupts { $( #[allow(non_snake_case)] - #[no_mangle] + #[unsafe(no_mangle)] $(#[cfg($cond_irq)])? unsafe extern "C" fn $irq() { unsafe { @@ -446,13 +448,13 @@ macro_rules! select_bootloader { ( $( $feature:literal => $loader:ident, )+ default => $default:ident ) => { $( #[cfg(feature = $feature)] - #[link_section = ".boot2"] + #[unsafe(link_section = ".boot2")] #[used] static BOOT2: [u8; 256] = rp2040_boot2::$loader; )* #[cfg(not(any( $( feature = $feature),* )))] - #[link_section = ".boot2"] + #[unsafe(link_section = ".boot2")] #[used] static BOOT2: [u8; 256] = rp2040_boot2::$default; } @@ -475,13 +477,13 @@ macro_rules! select_imagedef { ( $( $feature:literal => $imagedef:ident, )+ default => $default:ident ) => { $( #[cfg(feature = $feature)] - #[link_section = ".start_block"] + #[unsafe(link_section = ".start_block")] #[used] static IMAGE_DEF: crate::block::ImageDef = crate::block::ImageDef::$imagedef(); )* #[cfg(not(any( $( feature = $feature),* )))] - #[link_section = ".start_block"] + #[unsafe(link_section = ".start_block")] #[used] static IMAGE_DEF: crate::block::ImageDef = crate::block::ImageDef::$default(); } @@ -528,7 +530,7 @@ select_imagedef! { /// } /// ``` pub fn install_core0_stack_guard() -> Result<(), ()> { - extern "C" { + unsafe extern "C" { static mut _stack_end: usize; } unsafe { install_stack_guard(core::ptr::addr_of_mut!(_stack_end)) } diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index adedc98ad..3b120e349 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -14,6 +14,7 @@ //! use embassy_rp::multicore::Stack; //! use static_cell::StaticCell; //! use embassy_executor::Executor; +//! use core::ptr::addr_of_mut; //! //! static mut CORE1_STACK: Stack<4096> = Stack::new(); //! static EXECUTOR0: StaticCell = StaticCell::new(); @@ -36,7 +37,7 @@ //! fn main() -> ! { //! let p = embassy_rp::init(Default::default()); //! -//! embassy_rp::multicore::spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { +//! embassy_rp::multicore::spawn_core1(p.CORE1, unsafe { &mut *addr_of_mut!(CORE1_STACK) }, move || { //! let executor1 = EXECUTOR1.init(Executor::new()); //! executor1.run(|spawner| spawner.spawn(core1_task().unwrap())); //! }); @@ -47,11 +48,11 @@ //! ``` use core::mem::ManuallyDrop; -use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, Ordering, compiler_fence}; use crate::interrupt::InterruptExt; use crate::peripherals::CORE1; -use crate::{gpio, install_stack_guard, interrupt, pac, Peri}; +use crate::{Peri, gpio, install_stack_guard, interrupt, pac}; const PAUSE_TOKEN: u32 = 0xDEADBEEF; const RESUME_TOKEN: u32 = !0xDEADBEEF; @@ -110,7 +111,6 @@ impl Stack { #[cfg(all(feature = "rt", feature = "rp2040"))] #[interrupt] -#[link_section = ".data.ram_func"] unsafe fn SIO_IRQ_PROC1() { let sio = pac::SIO; // Clear IRQ @@ -135,7 +135,6 @@ unsafe fn SIO_IRQ_PROC1() { #[cfg(all(feature = "rt", feature = "_rp235x"))] #[interrupt] -#[link_section = ".data.ram_func"] unsafe fn SIO_IRQ_FIFO() { let sio = pac::SIO; // Clear IRQ diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 5f554dfe3..38ee1f97c 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -2,21 +2,21 @@ use core::future::Future; use core::marker::PhantomData; use core::pin::Pin as FuturePin; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::{Context, Poll}; -use atomic_polyfill::{AtomicU64, AtomicU8}; +use atomic_polyfill::{AtomicU8, AtomicU64}; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; -use fixed::types::extra::U8; use fixed::FixedU32; +use fixed::types::extra::U8; use pio::{Program, SideSet, Wrap}; use crate::dma::{self, Channel, Transfer, Word}; use crate::gpio::{self, AnyPin, Drive, Level, Pull, SealedPin, SlewRate}; use crate::interrupt::typelevel::{Binding, Handler, Interrupt}; use crate::relocate::RelocatedProgram; -use crate::{pac, peripherals, RegExt}; +use crate::{RegExt, pac, peripherals}; mod instr; @@ -984,11 +984,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { #[cfg(feature = "_rp235x")] fn pin_base() -> u8 { - if PIO::PIO.gpiobase().read().gpiobase() { - 16 - } else { - 0 - } + if PIO::PIO.gpiobase().read().gpiobase() { 16 } else { 0 } } /// Sets pin directions. This pauses the current state machine to run `SET` commands diff --git a/embassy-rp/src/pio_programs/hd44780.rs b/embassy-rp/src/pio_programs/hd44780.rs index 546c85a89..78281ddd4 100644 --- a/embassy-rp/src/pio_programs/hd44780.rs +++ b/embassy-rp/src/pio_programs/hd44780.rs @@ -1,12 +1,12 @@ //! [HD44780 display driver](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) +use crate::Peri; use crate::dma::{AnyChannel, Channel}; use crate::pio::{ Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, }; use crate::pio_programs::clock_divider::calculate_pio_clock_divider; -use crate::Peri; /// This struct represents a HD44780 program that takes command words ( <0:4>) pub struct PioHD44780CommandWordProgram<'a, PIO: Instance> { diff --git a/embassy-rp/src/pio_programs/i2s.rs b/embassy-rp/src/pio_programs/i2s.rs index 2382a3f9f..7e5f68ad6 100644 --- a/embassy-rp/src/pio_programs/i2s.rs +++ b/embassy-rp/src/pio_programs/i2s.rs @@ -2,12 +2,12 @@ use fixed::traits::ToFixed; +use crate::Peri; use crate::dma::{AnyChannel, Channel, Transfer}; use crate::gpio::Pull; use crate::pio::{ Common, Config, Direction, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, }; -use crate::Peri; /// This struct represents an i2s receiver & controller driver program pub struct PioI2sInProgram<'d, PIO: Instance> { diff --git a/embassy-rp/src/pio_programs/onewire.rs b/embassy-rp/src/pio_programs/onewire.rs index 980d0fe5f..09babc229 100644 --- a/embassy-rp/src/pio_programs/onewire.rs +++ b/embassy-rp/src/pio_programs/onewire.rs @@ -1,11 +1,11 @@ //! OneWire pio driver +use crate::Peri; use crate::clocks::clk_sys_freq; use crate::gpio::Level; use crate::pio::{ Common, Config, Direction, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, }; -use crate::Peri; /// This struct represents a onewire driver program pub struct PioOneWireProgram<'a, PIO: Instance> { @@ -321,11 +321,7 @@ impl PioOneWireSearch { /// Search for the next address on the bus pub async fn next(&mut self, pio: &mut PioOneWire<'_, PIO, SM>) -> Option { - if self.finished { - None - } else { - pio.search(self).await - } + if self.finished { None } else { pio.search(self).await } } /// Is finished when all devices have been found diff --git a/embassy-rp/src/pio_programs/pwm.rs b/embassy-rp/src/pio_programs/pwm.rs index f0f837bc5..ba06bb3c1 100644 --- a/embassy-rp/src/pio_programs/pwm.rs +++ b/embassy-rp/src/pio_programs/pwm.rs @@ -6,7 +6,7 @@ use pio::InstructionOperands; use crate::gpio::Level; use crate::pio::{Common, Config, Direction, Instance, LoadedProgram, Pin, PioPin, StateMachine}; -use crate::{clocks, Peri}; +use crate::{Peri, clocks}; /// This converts the duration provided into the number of cycles the PIO needs to run to make it take the same time fn to_pio_cycles(duration: Duration) -> u32 { diff --git a/embassy-rp/src/pio_programs/rotary_encoder.rs b/embassy-rp/src/pio_programs/rotary_encoder.rs index 70b3795e9..6347527e6 100644 --- a/embassy-rp/src/pio_programs/rotary_encoder.rs +++ b/embassy-rp/src/pio_programs/rotary_encoder.rs @@ -1,11 +1,11 @@ //! PIO backed quadrature encoder +use crate::Peri; use crate::gpio::Pull; use crate::pio::{ Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine, }; use crate::pio_programs::clock_divider::calculate_pio_clock_divider; -use crate::Peri; /// This struct represents an Encoder program loaded into pio instruction memory. pub struct PioEncoderProgram<'a, PIO: Instance> { diff --git a/embassy-rp/src/pio_programs/stepper.rs b/embassy-rp/src/pio_programs/stepper.rs index 0e9a8daf9..5762ee189 100644 --- a/embassy-rp/src/pio_programs/stepper.rs +++ b/embassy-rp/src/pio_programs/stepper.rs @@ -2,9 +2,9 @@ use core::mem::{self, MaybeUninit}; +use crate::Peri; use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine}; use crate::pio_programs::clock_divider::calculate_pio_clock_divider; -use crate::Peri; /// This struct represents a Stepper driver program loaded into pio instruction memory. pub struct PioStepperProgram<'a, PIO: Instance> { diff --git a/embassy-rp/src/pio_programs/uart.rs b/embassy-rp/src/pio_programs/uart.rs index 04e39a571..444efb5db 100644 --- a/embassy-rp/src/pio_programs/uart.rs +++ b/embassy-rp/src/pio_programs/uart.rs @@ -5,12 +5,12 @@ use core::convert::Infallible; use embedded_io_async::{ErrorType, Read, Write}; use fixed::traits::ToFixed; +use crate::Peri; use crate::clocks::clk_sys_freq; use crate::gpio::Level; use crate::pio::{ Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine, }; -use crate::Peri; /// This struct represents a uart tx program loaded into pio instruction memory. pub struct PioUartTxProgram<'d, PIO: Instance> { diff --git a/embassy-rp/src/pio_programs/ws2812.rs b/embassy-rp/src/pio_programs/ws2812.rs index 37dd1c4e0..e6851b1a6 100644 --- a/embassy-rp/src/pio_programs/ws2812.rs +++ b/embassy-rp/src/pio_programs/ws2812.rs @@ -4,12 +4,12 @@ use embassy_time::Timer; use fixed::types::U24F8; use smart_leds::{RGB8, RGBW}; +use crate::Peri; use crate::clocks::clk_sys_freq; use crate::dma::{AnyChannel, Channel}; use crate::pio::{ Common, Config, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, }; -use crate::Peri; const T1: u8 = 2; // start bit const T2: u8 = 5; // data bit diff --git a/embassy-rp/src/psram.rs b/embassy-rp/src/psram.rs index ae43dd5aa..25185ead2 100644 --- a/embassy-rp/src/psram.rs +++ b/embassy-rp/src/psram.rs @@ -10,7 +10,7 @@ #![cfg(feature = "_rp235x")] -use critical_section::{acquire, release, CriticalSection, RestoreState}; +use critical_section::{CriticalSection, RestoreState, acquire, release}; use crate::pac; use crate::qmi_cs1::QmiCs1; @@ -251,7 +251,7 @@ impl<'d> Psram<'d> { } /// Verify APS6404L PSRAM device matches expected configuration. - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[inline(never)] fn verify_aps6404l(qmi: &pac::qmi::Qmi, expected_size: usize) -> Result<(), Error> { // APS6404L-specific constants @@ -306,7 +306,7 @@ impl<'d> Psram<'d> { Ok(()) } - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[inline(never)] unsafe fn read_aps6404l_kgd_eid(qmi: &pac::qmi::Qmi) -> (u32, u32) { const RESET_ENABLE_CMD: u8 = 0xf5; @@ -435,7 +435,7 @@ impl<'d> Psram<'d> { } /// Initialize PSRAM with proper timing. - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[inline(never)] fn init_psram(qmi: &pac::qmi::Qmi, xip_ctrl: &pac::xip_ctrl::XipCtrl, config: &Config) -> Result<(), Error> { // Set PSRAM timing for APS6404 @@ -610,7 +610,7 @@ impl<'d> Psram<'d> { Ok(()) } - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[inline(never)] unsafe fn direct_csr_send_init_command(config: &Config, init_cmd: u8) { #[cfg(target_arch = "arm")] diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 1e1ccc4c6..59a3fc9a2 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -3,13 +3,13 @@ use embassy_hal_internal::{Peri, PeripheralType}; pub use embedded_hal_1::pwm::SetDutyCycle; use embedded_hal_1::pwm::{Error, ErrorKind, ErrorType}; -use fixed::traits::ToFixed; use fixed::FixedU16; +use fixed::traits::ToFixed; use pac::pwm::regs::{ChDiv, Intr}; use pac::pwm::vals::Divmode; use crate::gpio::{AnyPin, Pin as GpioPin, Pull, SealedPin as _}; -use crate::{pac, peripherals, RegExt}; +use crate::{RegExt, pac, peripherals}; /// The configuration of a PWM slice. /// Note the period in clock cycles of a slice can be computed as: diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index 8b0deed21..68fb3b765 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs @@ -2,7 +2,7 @@ mod filter; use core::future::poll_fn; -use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::{Peri, PeripheralType}; diff --git a/embassy-rp/src/time_driver.rs b/embassy-rp/src/time_driver.rs index d598287a9..ec1c17ed5 100644 --- a/embassy-rp/src/time_driver.rs +++ b/embassy-rp/src/time_driver.rs @@ -2,8 +2,8 @@ use core::cell::{Cell, RefCell}; use critical_section::CriticalSection; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_time_driver::Driver; use embassy_time_queue_utils::Queue; #[cfg(feature = "rp2040")] diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 6f4e2ee07..43187df2d 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use core::task::Poll; use atomic_polyfill::{AtomicU16, Ordering}; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use embassy_time::{Delay, Timer}; @@ -16,7 +16,7 @@ use crate::gpio::{AnyPin, SealedPin}; use crate::interrupt::typelevel::{Binding, Interrupt as _}; use crate::interrupt::{Interrupt, InterruptExt}; use crate::pac::io::vals::{Inover, Outover}; -use crate::{interrupt, pac, peripherals, RegExt}; +use crate::{RegExt, interrupt, pac, peripherals}; mod buffered; pub use buffered::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, BufferedUartTx}; @@ -863,11 +863,7 @@ impl<'d, M: Mode> Uart<'d, M> { if let Some(pin) = &tx { let funcsel = { let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8; - if (pin_number % 4) == 0 { - 2 - } else { - 11 - } + if (pin_number % 4) == 0 { 2 } else { 11 } }; pin.gpio().ctrl().write(|w| { w.set_funcsel(funcsel); @@ -886,11 +882,7 @@ impl<'d, M: Mode> Uart<'d, M> { if let Some(pin) = &rx { let funcsel = { let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8; - if ((pin_number - 1) % 4) == 0 { - 2 - } else { - 11 - } + if ((pin_number - 1) % 4) == 0 { 2 } else { 11 } }; pin.gpio().ctrl().write(|w| { w.set_funcsel(funcsel); diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs index 671ecbd32..e8273c3f2 100644 --- a/embassy-rp/src/usb.rs +++ b/embassy-rp/src/usb.rs @@ -2,7 +2,7 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::slice; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::PeripheralType; @@ -13,7 +13,7 @@ use embassy_usb_driver::{ }; use crate::interrupt::typelevel::{Binding, Interrupt}; -use crate::{interrupt, pac, peripherals, Peri, RegExt}; +use crate::{Peri, RegExt, interrupt, pac, peripherals}; trait SealedInstance { fn regs() -> crate::pac::usb::Usb; @@ -545,11 +545,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { poll_fn(|cx| { EP_IN_WAKERS[index].register(cx.waker()); let val = T::dpram().ep_in_control(self.info.addr.index() - 1).read(); - if val.enable() { - Poll::Ready(()) - } else { - Poll::Pending - } + if val.enable() { Poll::Ready(()) } else { Poll::Pending } }) .await; trace!("wait_enabled IN OK"); @@ -567,11 +563,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> { poll_fn(|cx| { EP_OUT_WAKERS[index].register(cx.waker()); let val = T::dpram().ep_out_control(self.info.addr.index() - 1).read(); - if val.enable() { - Poll::Ready(()) - } else { - Poll::Pending - } + if val.enable() { Poll::Ready(()) } else { Poll::Pending } }) .await; trace!("wait_enabled OUT OK"); diff --git a/embassy-rp/src/watchdog.rs b/embassy-rp/src/watchdog.rs index 49cf03850..d42601745 100644 --- a/embassy-rp/src/watchdog.rs +++ b/embassy-rp/src/watchdog.rs @@ -11,7 +11,7 @@ use core::marker::PhantomData; use embassy_time::Duration; use crate::peripherals::WATCHDOG; -use crate::{pac, Peri}; +use crate::{Peri, pac}; /// The reason for a system reset from the watchdog. #[derive(Debug, Copy, Clone, PartialEq, Eq)] diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index d7c7a284c..0802b7328 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-stm32-wpan" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Async STM32 WPAN stack for embedded devices in Rust." keywords = ["embedded", "async", "stm32", "ble", "wpan"] diff --git a/embassy-stm32-wpan/src/cmd.rs b/embassy-stm32-wpan/src/cmd.rs index 928357384..5c81a4aa7 100644 --- a/embassy-stm32-wpan/src/cmd.rs +++ b/embassy-stm32-wpan/src/cmd.rs @@ -1,7 +1,7 @@ use core::ptr; -use crate::consts::TlPacketType; use crate::PacketHeader; +use crate::consts::TlPacketType; #[derive(Copy, Clone)] #[repr(C, packed)] diff --git a/embassy-stm32-wpan/src/consts.rs b/embassy-stm32-wpan/src/consts.rs index e2ae6ca86..7ecb22974 100644 --- a/embassy-stm32-wpan/src/consts.rs +++ b/embassy-stm32-wpan/src/consts.rs @@ -1,5 +1,5 @@ -use crate::evt::CsEvt; use crate::PacketHeader; +use crate::evt::CsEvt; #[derive(Debug)] #[repr(C)] diff --git a/embassy-stm32-wpan/src/lhci.rs b/embassy-stm32-wpan/src/lhci.rs index 89f204f99..59c8bfb5d 100644 --- a/embassy-stm32-wpan/src/lhci.rs +++ b/embassy-stm32-wpan/src/lhci.rs @@ -1,9 +1,9 @@ use core::ptr; use crate::cmd::CmdPacket; -use crate::consts::{TlPacketType, TL_EVT_HEADER_SIZE}; +use crate::consts::{TL_EVT_HEADER_SIZE, TlPacketType}; use crate::evt::{CcEvt, EvtPacket, EvtSerial}; -use crate::tables::{DeviceInfoTable, RssInfoTable, SafeBootInfoTable, WirelessFwInfoTable, TL_DEVICE_INFO_TABLE}; +use crate::tables::{DeviceInfoTable, RssInfoTable, SafeBootInfoTable, TL_DEVICE_INFO_TABLE, WirelessFwInfoTable}; const TL_BLEEVT_CC_OPCODE: u8 = 0x0e; const LHCI_OPCODE_C1_DEVICE_INF: u16 = 0xfd62; diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index 40ff14795..f6b1f6021 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs @@ -13,6 +13,7 @@ #![no_std] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] // #![warn(missing_docs)] #![allow(static_mut_refs)] // TODO: Fix @@ -21,7 +22,7 @@ mod fmt; use core::mem::MaybeUninit; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use embassy_hal_internal::Peri; use embassy_stm32::interrupt; @@ -94,7 +95,7 @@ impl<'d> TlMbox<'d> { pub fn init( ipcc: Peri<'d, IPCC>, _irqs: impl interrupt::typelevel::Binding - + interrupt::typelevel::Binding, + + interrupt::typelevel::Binding, config: Config, ) -> Self { // this is an inlined version of TL_Init from the STM32WB firmware as requested by AN5289. diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs index 41cca09e3..480ac3790 100644 --- a/embassy-stm32-wpan/src/mac/driver.rs +++ b/embassy-stm32-wpan/src/mac/driver.rs @@ -6,9 +6,9 @@ use embassy_net_driver::{Capabilities, HardwareAddress, LinkState}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; +use crate::mac::MTU; use crate::mac::event::MacEvent; use crate::mac::runner::Runner; -use crate::mac::MTU; pub struct Driver<'d> { runner: &'d Runner<'d>, diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs index d3099b6b7..2409f994d 100644 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ b/embassy-stm32-wpan/src/mac/runner.rs @@ -7,10 +7,10 @@ use embassy_sync::channel::Channel; use embassy_sync::mutex::Mutex; use embassy_sync::signal::Signal; +use crate::mac::MTU; use crate::mac::commands::DataRequest; use crate::mac::event::MacEvent; use crate::mac::typedefs::{AddressMode, MacAddress, PanId, SecurityLevel}; -use crate::mac::MTU; use crate::sub::mac::Mac; type ZeroCopyPubSub = blocking_mutex::Mutex>>>; diff --git a/embassy-stm32-wpan/src/sub/ble.rs b/embassy-stm32-wpan/src/sub/ble.rs index 0f770d92c..cd69a0479 100644 --- a/embassy-stm32-wpan/src/sub/ble.rs +++ b/embassy-stm32-wpan/src/sub/ble.rs @@ -4,10 +4,10 @@ use embassy_stm32::ipcc::Ipcc; use hci::Opcode; use crate::cmd::CmdPacket; -use crate::consts::{TlPacketType, TL_BLEEVT_CC_OPCODE, TL_BLEEVT_CS_OPCODE}; +use crate::consts::{TL_BLEEVT_CC_OPCODE, TL_BLEEVT_CS_OPCODE, TlPacketType}; use crate::evt::{EvtBox, EvtPacket, EvtStub}; use crate::sub::mm; -use crate::tables::{BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE}; +use crate::tables::{BLE_CMD_BUFFER, BleTable, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE}; use crate::unsafe_linked_list::LinkedListNode; use crate::{channels, evt}; diff --git a/embassy-stm32-wpan/src/sub/mm.rs b/embassy-stm32-wpan/src/sub/mm.rs index 4e4d2f854..62d0de8bd 100644 --- a/embassy-stm32-wpan/src/sub/mm.rs +++ b/embassy-stm32-wpan/src/sub/mm.rs @@ -3,7 +3,7 @@ use core::future::poll_fn; use core::mem::MaybeUninit; use core::task::Poll; -use aligned::{Aligned, A4}; +use aligned::{A4, Aligned}; use cortex_m::interrupt; use embassy_stm32::ipcc::Ipcc; use embassy_sync::waitqueue::AtomicWaker; @@ -12,7 +12,7 @@ use crate::consts::POOL_SIZE; use crate::evt::EvtPacket; #[cfg(feature = "ble")] use crate::tables::BLE_SPARE_EVT_BUF; -use crate::tables::{MemManagerTable, EVT_POOL, FREE_BUF_QUEUE, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE}; +use crate::tables::{EVT_POOL, FREE_BUF_QUEUE, MemManagerTable, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE}; use crate::unsafe_linked_list::LinkedListNode; use crate::{channels, evt}; diff --git a/embassy-stm32-wpan/src/sub/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs index cf6df58bf..8a3382f86 100644 --- a/embassy-stm32-wpan/src/sub/sys.rs +++ b/embassy-stm32-wpan/src/sub/sys.rs @@ -8,7 +8,7 @@ use crate::shci::{SchiCommandStatus, ShciBleInitCmdParam, ShciOpcode}; use crate::sub::mm; use crate::tables::{SysTable, WirelessFwInfoTable}; use crate::unsafe_linked_list::LinkedListNode; -use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE}; +use crate::{Ipcc, SYS_CMD_BUF, SYSTEM_EVT_QUEUE, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE, channels}; /// A guard that, once constructed, allows for sys commands to be sent to CPU2. pub struct Sys { @@ -35,11 +35,7 @@ impl Sys { let info = unsafe { TL_DEVICE_INFO_TABLE.as_mut_ptr().read_volatile().wireless_fw_info_table }; // Zero version indicates that CPU2 wasn't active and didn't fill the information table - if info.version != 0 { - Some(info) - } else { - None - } + if info.version != 0 { Some(info) } else { None } } pub async fn write(&self, opcode: ShciOpcode, payload: &[u8]) { @@ -66,8 +62,8 @@ impl Sys { #[cfg(feature = "mac")] pub async fn shci_c2_mac_802_15_4_init(&self) -> Result { use crate::tables::{ - Mac802_15_4Table, TracesTable, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, - TL_MAC_802_15_4_TABLE, TL_TRACES_TABLE, TRACES_EVT_QUEUE, + MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, Mac802_15_4Table, TL_MAC_802_15_4_TABLE, + TL_TRACES_TABLE, TRACES_EVT_QUEUE, TracesTable, }; unsafe { diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs index fe6fc47a3..1dafed159 100644 --- a/embassy-stm32-wpan/src/tables.rs +++ b/embassy-stm32-wpan/src/tables.rs @@ -1,6 +1,6 @@ use core::mem::MaybeUninit; -use aligned::{Aligned, A4}; +use aligned::{A4, Aligned}; use bit_field::BitField; use crate::cmd::{AclDataPacket, CmdPacket}; @@ -190,94 +190,94 @@ pub struct RefTable { } // --------------------- ref table --------------------- -#[link_section = "TL_REF_TABLE"] +#[unsafe(link_section = "TL_REF_TABLE")] pub static mut TL_REF_TABLE: MaybeUninit = MaybeUninit::uninit(); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_DEVICE_INFO_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_BLE_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_THREAD_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_LLD_TESTS_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_BLE_LLD_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_SYS_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_MEM_MANAGER_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_TRACES_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_MAC_802_15_4_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_ZIGBEE_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); // --------------------- tables --------------------- -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut FREE_BUF_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); #[allow(dead_code)] -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TRACES_EVT_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut CS_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut EVT_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut SYSTEM_EVT_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); // --------------------- app tables --------------------- #[cfg(feature = "mac")] -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut MAC_802_15_4_CMD_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "mac")] -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit< Aligned, > = MaybeUninit::uninit(); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut EVT_POOL: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut SYS_CMD_BUF: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut SYS_SPARE_EVT_BUF: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "mac")] -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut MAC_802_15_4_CNFINDNOT: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "ble")] -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut BLE_CMD_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "ble")] -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut BLE_SPARE_EVT_BUF: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "ble")] -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] // fuck these "magic" numbers from ST ---v---v pub static mut HCI_ACL_DATA_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index a6ee5c4b8..9848daf49 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -6,8 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +### [Unreleased] + +* **Fix(stm32h5):** Prevent a HardFault crash on STM32H5 devices by changing `uid()` to return `[u8; 12]` by value instead of a reference. (Fixes #2696) ## Unreleased - ReleaseDate +- fix flash erase on L4 & L5 - fix: Fixed STM32H5 builds requiring time feature - feat: Derive Clone, Copy for QSPI Config - fix: stm32/i2c in master mode (blocking): subsequent transmissions failed after a NACK was received diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 82bc73708..7c243b350 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-stm32" version = "0.4.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for ST STM32 series microcontrollers" keywords = ["embedded", "async", "stm32", "hal", "embedded-hal"] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index b5f1261fe..eea1acf68 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -9,8 +9,8 @@ use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use stm32_metapac::metadata::ir::BitOffset; use stm32_metapac::metadata::{ - MemoryRegion, MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, - ALL_CHIPS, ALL_PERIPHERAL_VERSIONS, METADATA, + ALL_CHIPS, ALL_PERIPHERAL_VERSIONS, METADATA, MemoryRegion, MemoryRegionKind, PeripheralRccKernelClock, + PeripheralRccRegister, PeripheralRegisters, StopMode, }; #[path = "./build_common.rs"] @@ -105,7 +105,9 @@ fn main() { } (false, false) => { if METADATA.memory.len() != 1 { - panic!("Chip supports single and dual bank configuration. No Cargo feature to select one is enabled. Use the 'single-bank' or 'dual-bank' feature to make your selection") + panic!( + "Chip supports single and dual bank configuration. No Cargo feature to select one is enabled. Use the 'single-bank' or 'dual-bank' feature to make your selection" + ) } METADATA.memory[0] } diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs index 255dc7956..2608160a3 100644 --- a/embassy-stm32/src/adc/adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs @@ -4,7 +4,7 @@ use pac::adc::vals::{Adc4Dmacfg as Dmacfg, Adc4Exten as Exten, Adc4OversamplingR #[cfg(stm32wba)] use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel}; -use super::{blocking_delay_us, AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel}; +use super::{AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel, blocking_delay_us}; use crate::dma::Transfer; #[cfg(stm32u5)] pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; @@ -15,7 +15,7 @@ pub use crate::pac::adc::vals::{Adc4Presc as Presc, Adc4Res as Resolution, Adc4S #[cfg(stm32wba)] pub use crate::pac::adc::vals::{Presc, Res as Resolution, SampleTime}; use crate::time::Hertz; -use crate::{pac, rcc, Peri}; +use crate::{Peri, pac, rcc}; const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); @@ -208,7 +208,10 @@ impl<'d, T: Instance> Adc4<'d, T> { info!("ADC4 frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { - panic!("Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); + panic!( + "Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.", + MAX_ADC_CLK_FREQ.0 / 1_000_000 + ); } let mut s = Self { adc }; diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index f2837a8f1..fc28df346 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs @@ -4,11 +4,11 @@ use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; use pac::adccommon::vals::Presc; use super::{ - blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, + Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, }; use crate::dma::Transfer; use crate::time::Hertz; -use crate::{pac, rcc, Peri}; +use crate::{Peri, pac, rcc}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -168,7 +168,10 @@ impl<'d, T: Instance> Adc<'d, T> { debug!("ADC frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { - panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); + panic!( + "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", + MAX_ADC_CLK_FREQ.0 / 1_000_000 + ); } let mut s = Self { diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index 3cdc9d8fb..f9c23d72b 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -7,7 +7,7 @@ use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::interrupt::{self}; use crate::time::Hertz; -use crate::{rcc, Peri}; +use crate::{Peri, rcc}; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 3aeb6f2c7..73ceb087a 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -6,7 +6,7 @@ use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::time::Hertz; -use crate::{interrupt, rcc, Peri}; +use crate::{Peri, interrupt, rcc}; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs index 84613078c..cd5de54f5 100644 --- a/embassy-stm32/src/adc/f3_v1_1.rs +++ b/embassy-stm32/src/adc/f3_v1_1.rs @@ -9,7 +9,7 @@ use super::Resolution; use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::time::Hertz; -use crate::{interrupt, rcc, Peri}; +use crate::{Peri, interrupt, rcc}; const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ; diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 43498966f..5098aadd8 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -7,11 +7,11 @@ use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; use pac::adccommon::vals::Presc; use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen}; -use super::{blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime}; +use super::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, blocking_delay_us}; use crate::adc::SealedAdcChannel; use crate::dma::Transfer; use crate::time::Hertz; -use crate::{pac, rcc, Peri}; +use crate::{Peri, pac, rcc}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -133,7 +133,10 @@ impl<'d, T: Instance> Adc<'d, T> { trace!("ADC frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { - panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); + panic!( + "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", + MAX_ADC_CLK_FREQ.0 / 1_000_000 + ); } let mut s = Self { diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index ea986f4cf..22ed8295f 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -22,7 +22,7 @@ use core::marker::PhantomData; #[allow(unused)] #[cfg(not(any(adc_f3v3, adc_wba)))] pub use _version::*; -use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_hal_internal::{PeripheralType, impl_peripheral}; #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] use embassy_sync::waitqueue::AtomicWaker; diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs index 6f69e8486..9b2e5b8fe 100644 --- a/embassy-stm32/src/adc/ringbuffered_v2.rs +++ b/embassy-stm32/src/adc/ringbuffered_v2.rs @@ -1,13 +1,13 @@ use core::marker::PhantomData; use core::mem; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use stm32_metapac::adc::vals::SampleTime; use crate::adc::{Adc, AdcChannel, Instance, RxDma}; use crate::dma::{Priority, ReadableRingBuffer, TransferOptions}; use crate::pac::adc::vals; -use crate::{rcc, Peri}; +use crate::{Peri, rcc}; #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct OverrunError; diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index d09374876..a5869d110 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -9,7 +9,7 @@ use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC1; -use crate::{interrupt, rcc, Peri}; +use crate::{Peri, interrupt, rcc}; mod watchdog_v1; pub use watchdog_v1::WatchdogChannels; @@ -66,11 +66,7 @@ pub struct Temperature; impl AdcChannel for Temperature {} impl super::SealedAdcChannel for Temperature { fn channel(&self) -> u8 { - if cfg!(adc_l0) { - 18 - } else { - 16 - } + if cfg!(adc_l0) { 18 } else { 16 } } } diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index e94a25b24..93ec78548 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -2,7 +2,7 @@ use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; use crate::peripherals::ADC1; use crate::time::Hertz; -use crate::{rcc, Peri}; +use crate::{Peri, rcc}; mod ringbuffered_v2; pub use ringbuffered_v2::{RingBufferedAdc, Sequence}; diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 16063ce4d..47632263b 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -10,10 +10,10 @@ use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs}; pub use pac::adc::vals::{Ovsr, Ovss, Presc}; use super::{ - blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, + Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, }; use crate::dma::Transfer; -use crate::{pac, rcc, Peri}; +use crate::{Peri, pac, rcc}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index b66437e6e..c7d0103a6 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -5,11 +5,11 @@ use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; use pac::adccommon::vals::Presc; use super::{ - blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, + Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, }; use crate::dma::Transfer; use crate::time::Hertz; -use crate::{pac, rcc, Peri}; +use crate::{Peri, pac, rcc}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -171,7 +171,10 @@ impl<'d, T: Instance> Adc<'d, T> { info!("ADC frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { - panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); + panic!( + "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", + MAX_ADC_CLK_FREQ.0 / 1_000_000 + ); } #[cfg(stm32h7)] diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs index 8eb188560..507350c42 100644 --- a/embassy-stm32/src/can/bxcan/mod.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs @@ -5,8 +5,8 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::interrupt::InterruptExt; use embassy_hal_internal::PeripheralType; +use embassy_hal_internal::interrupt::InterruptExt; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_sync::waitqueue::AtomicWaker; @@ -22,7 +22,7 @@ use crate::can::enums::{BusError, RefCountOp, TryReadError}; use crate::gpio::{AfType, OutputType, Pull, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::rcc::{self, RccPeripheral}; -use crate::{interrupt, peripherals, Peri}; +use crate::{Peri, interrupt, peripherals}; /// Interrupt handler. pub struct TxInterruptHandler { @@ -186,10 +186,10 @@ impl<'d> Can<'d> { rx: Peri<'d, if_afio!(impl RxPin)>, tx: Peri<'d, if_afio!(impl TxPin)>, _irqs: impl interrupt::typelevel::Binding> - + interrupt::typelevel::Binding> - + interrupt::typelevel::Binding> - + interrupt::typelevel::Binding> - + 'd, + + interrupt::typelevel::Binding> + + interrupt::typelevel::Binding> + + interrupt::typelevel::Binding> + + 'd, ) -> Self { let info = T::info(); let regs = &T::info().regs; diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs index c6a66b469..e08349f02 100644 --- a/embassy-stm32/src/can/fd/config.rs +++ b/embassy-stm32/src/can/fd/config.rs @@ -1,7 +1,7 @@ //! Configuration for FDCAN Module // Note: This file is copied and modified from fdcan crate by Richard Meadows -use core::num::{NonZeroU16, NonZeroU8}; +use core::num::{NonZeroU8, NonZeroU16}; /// Configures the bit timings. /// diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index d8f71e03e..a142a6d63 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -3,8 +3,8 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::interrupt::InterruptExt; use embassy_hal_internal::PeripheralType; +use embassy_hal_internal::interrupt::InterruptExt; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_sync::waitqueue::AtomicWaker; @@ -13,7 +13,7 @@ use crate::can::fd::peripheral::Registers; use crate::gpio::{AfType, OutputType, Pull, SealedPin as _, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::rcc::{self, RccPeripheral}; -use crate::{interrupt, peripherals, Peri}; +use crate::{Peri, interrupt, peripherals}; pub(crate) mod fd; @@ -182,8 +182,8 @@ impl<'d> CanConfigurator<'d> { rx: Peri<'d, impl RxPin>, tx: Peri<'d, impl TxPin>, _irqs: impl interrupt::typelevel::Binding> - + interrupt::typelevel::Binding> - + 'd, + + interrupt::typelevel::Binding> + + 'd, ) -> CanConfigurator<'d> { set_as_af!(rx, AfType::input(Pull::None)); set_as_af!(tx, AfType::output(OutputType::PushPull, Speed::VeryHigh)); @@ -459,7 +459,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, pub async fn write(&mut self, frame: Frame) { self.tx_buf.send(frame).await; self.info.interrupt0.pend(); // Wake for Tx - //T::IT0Interrupt::pend(); // Wake for Tx + //T::IT0Interrupt::pend(); // Wake for Tx } /// Async read frame from RX buffer. @@ -548,7 +548,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' pub async fn write(&mut self, frame: FdFrame) { self.tx_buf.send(frame).await; self.info.interrupt0.pend(); // Wake for Tx - //T::IT0Interrupt::pend(); // Wake for Tx + //T::IT0Interrupt::pend(); // Wake for Tx } /// Async read frame from RX buffer. diff --git a/embassy-stm32/src/can/util.rs b/embassy-stm32/src/can/util.rs index fcdbbad62..6d7f0c16a 100644 --- a/embassy-stm32/src/can/util.rs +++ b/embassy-stm32/src/can/util.rs @@ -1,6 +1,6 @@ //! Utility functions shared between CAN controller types. -use core::num::{NonZeroU16, NonZeroU8}; +use core::num::{NonZeroU8, NonZeroU16}; /// Shared struct to represent bit timings used by calc_can_timings. #[derive(Clone, Copy, Debug)] diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs index 13e5263de..836228599 100644 --- a/embassy-stm32/src/crc/v1.rs +++ b/embassy-stm32/src/crc/v1.rs @@ -1,6 +1,6 @@ use crate::pac::CRC as PAC_CRC; use crate::peripherals::CRC; -use crate::{rcc, Peri}; +use crate::{Peri, rcc}; /// CRC driver. pub struct Crc<'d> { diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs index d834d0971..a566a2e04 100644 --- a/embassy-stm32/src/crc/v2v3.rs +++ b/embassy-stm32/src/crc/v2v3.rs @@ -1,7 +1,7 @@ -use crate::pac::crc::vals; use crate::pac::CRC as PAC_CRC; +use crate::pac::crc::vals; use crate::peripherals::CRC; -use crate::{rcc, Peri}; +use crate::{Peri, rcc}; /// CRC driver. pub struct Crc<'d> { diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 0173b2b5d..4f1115fb7 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -1236,7 +1236,10 @@ impl<'d, T: Instance, M: Mode> Cryp<'d, T, M> { } if C::REQUIRES_PADDING { if last_block_remainder != 0 { - panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); + panic!( + "Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", + C::BLOCK_SIZE + ); } } if last_block { @@ -1703,7 +1706,10 @@ impl<'d, T: Instance> Cryp<'d, T, Async> { } if C::REQUIRES_PADDING { if last_block_remainder != 0 { - panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); + panic!( + "Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", + C::BLOCK_SIZE + ); } } if last_block { diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 08e001337..d74d4a4be 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -8,7 +8,7 @@ use crate::mode::{Async, Blocking, Mode as PeriMode}; #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] use crate::pac::dac; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; mod tsel; use embassy_hal_internal::PeripheralType; diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index bd03f1e00..dcae9f298 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs @@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::dma::Transfer; use crate::gpio::{AfType, Pull}; use crate::interrupt::typelevel::Interrupt; -use crate::{interrupt, rcc, Peri}; +use crate::{Peri, interrupt, rcc}; /// Interrupt handler. pub struct InterruptHandler { diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 73ecab070..90dbf4f09 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -1,6 +1,6 @@ -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::pin::Pin; -use core::sync::atomic::{fence, AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicUsize, Ordering, fence}; use core::task::{Context, Poll, Waker}; use embassy_hal_internal::Peri; diff --git a/embassy-stm32/src/dma/gpdma/mod.rs b/embassy-stm32/src/dma/gpdma/mod.rs index 4a14c2a8e..3e117c331 100644 --- a/embassy-stm32/src/dma/gpdma/mod.rs +++ b/embassy-stm32/src/dma/gpdma/mod.rs @@ -2,7 +2,7 @@ use core::future::Future; use core::pin::Pin; -use core::sync::atomic::{fence, AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicUsize, Ordering, fence}; use core::task::{Context, Poll}; use embassy_hal_internal::Peri; diff --git a/embassy-stm32/src/dma/gpdma/ringbuffered.rs b/embassy-stm32/src/dma/gpdma/ringbuffered.rs index 9ee52193b..94c597e0d 100644 --- a/embassy-stm32/src/dma/gpdma/ringbuffered.rs +++ b/embassy-stm32/src/dma/gpdma/ringbuffered.rs @@ -3,12 +3,12 @@ //! FIXME: Add request_pause functionality? //! FIXME: Stop the DMA, if a user does not queue new transfers (chain of linked-list items ends automatically). use core::future::poll_fn; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use core::task::Waker; use embassy_hal_internal::Peri; -use super::{AnyChannel, TransferOptions, STATE}; +use super::{AnyChannel, STATE, TransferOptions}; use crate::dma::gpdma::linked_list::{RunMode, Table}; use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; use crate::dma::word::Word; diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 5989bfd7c..297fa3674 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -24,7 +24,7 @@ pub(crate) use util::*; pub(crate) mod ringbuffer; pub mod word; -use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_hal_internal::{PeripheralType, impl_peripheral}; use crate::interrupt; diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs index 661fb1728..eff5b4058 100644 --- a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs @@ -2,7 +2,7 @@ use std::task::Waker; use proptest::prop_oneof; use proptest::strategy::{self, BoxedStrategy, Strategy as _}; -use proptest_state_machine::{prop_state_machine, ReferenceStateMachine, StateMachineTest}; +use proptest_state_machine::{ReferenceStateMachine, StateMachineTest, prop_state_machine}; use super::*; diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs index deda956af..fd1682d2b 100644 --- a/embassy-stm32/src/dsihost.rs +++ b/embassy-stm32/src/dsihost.rs @@ -7,7 +7,7 @@ use embassy_hal_internal::PeripheralType; //use crate::gpio::{AnyPin, SealedPin}; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; /// Performs a busy-wait delay for a specified number of microseconds. pub fn blocking_delay_ms(ms: u32) { diff --git a/embassy-stm32/src/dts/mod.rs b/embassy-stm32/src/dts/mod.rs index 1f39c8db5..a75ae0560 100644 --- a/embassy-stm32/src/dts/mod.rs +++ b/embassy-stm32/src/dts/mod.rs @@ -1,7 +1,7 @@ //! Digital Temperature Sensor (DTS) use core::future::poll_fn; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::Peri; diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index 5be1c9739..a77eb8719 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -4,7 +4,7 @@ mod rx_desc; mod tx_desc; use core::marker::PhantomData; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use embassy_hal_internal::Peri; use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; @@ -190,7 +190,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping w.set_fes(Fes::FES100); // fast ethernet speed w.set_dm(Dm::FULL_DUPLEX); // full duplex - // TODO: Carrier sense ? ECRSFD + // TODO: Carrier sense ? ECRSFD }); // Set the mac to pass all multicast packets @@ -350,7 +350,9 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { } #[cfg(any(eth_v1b, eth_v1c))] - config_pins!(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); + config_pins!( + 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 + ); let pins = Pins::Mii([ rx_clk.into(), diff --git a/embassy-stm32/src/eth/v1/rx_desc.rs b/embassy-stm32/src/eth/v1/rx_desc.rs index 2a46c1895..6ade1f29c 100644 --- a/embassy-stm32/src/eth/v1/rx_desc.rs +++ b/embassy-stm32/src/eth/v1/rx_desc.rs @@ -1,4 +1,4 @@ -use core::sync::atomic::{compiler_fence, fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence, fence}; use stm32_metapac::eth::vals::{Rpd, Rps}; use vcell::VolatileCell; diff --git a/embassy-stm32/src/eth/v1/tx_desc.rs b/embassy-stm32/src/eth/v1/tx_desc.rs index 1317d20f4..ba99b66cb 100644 --- a/embassy-stm32/src/eth/v1/tx_desc.rs +++ b/embassy-stm32/src/eth/v1/tx_desc.rs @@ -1,4 +1,4 @@ -use core::sync::atomic::{compiler_fence, fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence, fence}; use vcell::VolatileCell; diff --git a/embassy-stm32/src/eth/v2/descriptors.rs b/embassy-stm32/src/eth/v2/descriptors.rs index 645bfdb14..e335ed8f3 100644 --- a/embassy-stm32/src/eth/v2/descriptors.rs +++ b/embassy-stm32/src/eth/v2/descriptors.rs @@ -1,4 +1,4 @@ -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use vcell::VolatileCell; diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index cf7a9901b..39a6e8b0f 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -1,7 +1,7 @@ mod descriptors; use core::marker::PhantomData; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use embassy_hal_internal::Peri; use stm32_metapac::syscfg::vals::EthSelPhy; @@ -144,7 +144,9 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { .modify(|w| w.set_eth_sel_phy(EthSelPhy::MII_GMII)); }); - config_pins!(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); + config_pins!( + 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 + ); let pins = Pins::Mii([ rx_clk.into(), diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 9fce78f95..12600d4eb 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -5,13 +5,13 @@ use core::marker::PhantomData; use core::pin::Pin; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_hal_internal::{PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, Pull}; -use crate::pac::exti::regs::Lines; use crate::pac::EXTI; -use crate::{interrupt, pac, peripherals, Peri}; +use crate::pac::exti::regs::Lines; +use crate::{Peri, interrupt, pac, peripherals}; const EXTI_COUNT: usize = 16; static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [const { AtomicWaker::new() }; EXTI_COUNT]; diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs index 006dcddeb..a131217b7 100644 --- a/embassy-stm32/src/flash/asynch.rs +++ b/embassy-stm32/src/flash/asynch.rs @@ -1,17 +1,17 @@ use core::marker::PhantomData; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use embassy_hal_internal::drop::OnDrop; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::Mutex; use super::{ - blocking_read, ensure_sector_aligned, family, get_flash_regions, get_sector, Async, Error, Flash, FlashLayout, - FLASH_BASE, FLASH_SIZE, WRITE_SIZE, + Async, Error, FLASH_BASE, FLASH_SIZE, Flash, FlashLayout, WRITE_SIZE, blocking_read, ensure_sector_aligned, family, + get_flash_regions, get_sector, }; use crate::interrupt::InterruptExt; use crate::peripherals::FLASH; -use crate::{interrupt, Peri}; +use crate::{Peri, interrupt}; pub(super) static REGION_ACCESS: Mutex = Mutex::new(()); diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 10023e637..b595938a6 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -1,14 +1,14 @@ use core::marker::PhantomData; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use embassy_hal_internal::drop::OnDrop; use super::{ - family, get_flash_regions, Async, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, - MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE, + Async, Blocking, Error, FLASH_SIZE, FlashBank, FlashLayout, FlashRegion, FlashSector, MAX_ERASE_SIZE, READ_SIZE, + WRITE_SIZE, family, get_flash_regions, }; -use crate::Peri; use crate::_generated::FLASH_BASE; +use crate::Peri; use crate::peripherals::FLASH; /// Internal flash memory driver. diff --git a/embassy-stm32/src/flash/eeprom.rs b/embassy-stm32/src/flash/eeprom.rs index cc3529eb9..39c497e3f 100644 --- a/embassy-stm32/src/flash/eeprom.rs +++ b/embassy-stm32/src/flash/eeprom.rs @@ -1,6 +1,6 @@ use embassy_hal_internal::drop::OnDrop; -use super::{family, Blocking, Error, Flash, EEPROM_BASE, EEPROM_SIZE}; +use super::{Blocking, EEPROM_BASE, EEPROM_SIZE, Error, Flash, family}; #[cfg(eeprom)] impl<'d> Flash<'d, Blocking> { diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs index 3f9dbe945..5c01fce9c 100644 --- a/embassy-stm32/src/flash/f0.rs +++ b/embassy-stm32/src/flash/f0.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; diff --git a/embassy-stm32/src/flash/f1f3.rs b/embassy-stm32/src/flash/f1f3.rs index bf9ad2893..9e469ffbc 100644 --- a/embassy-stm32/src/flash/f1f3.rs +++ b/embassy-stm32/src/flash/f1f3.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; diff --git a/embassy-stm32/src/flash/f2.rs b/embassy-stm32/src/flash/f2.rs index 67e380619..b48ab3b76 100644 --- a/embassy-stm32/src/flash/f2.rs +++ b/embassy-stm32/src/flash/f2.rs @@ -1,9 +1,9 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, Ordering, fence}; use pac::flash::regs::Sr; -use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE}; +use super::{FlashBank, FlashSector, WRITE_SIZE, get_flash_regions}; use crate::flash::Error; use crate::pac; diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 62e0492b5..9c5051492 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -1,10 +1,10 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, Ordering, fence}; use embassy_sync::waitqueue::AtomicWaker; use pac::flash::regs::Sr; -use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE}; +use super::{FlashBank, FlashSector, WRITE_SIZE, get_flash_regions}; use crate::_generated::FLASH_SIZE; use crate::flash::Error; use crate::pac; @@ -246,7 +246,9 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) { feature = "stm32f439zi", ))] if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() { - panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11"); + panic!( + "Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11" + ); } #[cfg(any( @@ -270,14 +272,16 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) { feature = "stm32f439zg", ))] if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() { - panic!("Read corruption for stm32f42xxG and stm32f43xxG in dual bank mode when PA12 is in use for chips below revision 3, see errata 2.2.11"); + panic!( + "Read corruption for stm32f42xxG and stm32f43xxG in dual bank mode when PA12 is in use for chips below revision 3, see errata 2.2.11" + ); } } #[allow(unused)] fn pa12_is_output_pull_low() -> bool { - use pac::gpio::vals; use pac::GPIOA; + use pac::gpio::vals; const PIN: usize = 12; GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULL_DOWN @@ -287,7 +291,7 @@ fn pa12_is_output_pull_low() -> bool { #[cfg(test)] mod tests { use super::*; - use crate::flash::{get_sector, FlashBank}; + use crate::flash::{FlashBank, get_sector}; #[test] #[cfg(stm32f429)] @@ -370,9 +374,13 @@ mod tests { #[cfg(all(bank_setup_configurable))] pub(crate) fn check_bank_setup() { if cfg!(feature = "single-bank") && pac::FLASH.optcr().read().db1m() { - panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use dual-bank config"); + panic!( + "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use dual-bank config" + ); } if cfg!(feature = "dual-bank") && !pac::FLASH.optcr().read().db1m() { - panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use single-bank config"); + panic!( + "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use single-bank config" + ); } } diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 0547c747a..09389c417 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; @@ -99,7 +99,7 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> { #[cfg(test)] mod tests { use super::*; - use crate::flash::{get_sector, FlashBank}; + use crate::flash::{FlashBank, get_sector}; #[test] #[cfg(stm32f732)] @@ -218,9 +218,13 @@ mod tests { #[cfg(all(bank_setup_configurable))] pub(crate) fn check_bank_setup() { if cfg!(feature = "single-bank") && !pac::FLASH.optcr().read().n_dbank() { - panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use dual-bank config"); + panic!( + "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use dual-bank config" + ); } if cfg!(feature = "dual-bank") && pac::FLASH.optcr().read().n_dbank() { - panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use single-bank config"); + panic!( + "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use single-bank config" + ); } } diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index bc1fd360c..d026541a4 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use cortex_m::interrupt; @@ -105,19 +105,27 @@ fn wait_busy() { #[cfg(all(bank_setup_configurable, any(flash_g4c2, flash_g4c3, flash_g4c4)))] pub(crate) fn check_bank_setup() { if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() { - panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"); + panic!( + "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config" + ); } if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() { - panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"); + panic!( + "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config" + ); } } #[cfg(all(bank_setup_configurable, flash_g0x1))] pub(crate) fn check_bank_setup() { if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dual_bank() { - panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use dual-bank config"); + panic!( + "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use dual-bank config" + ); } if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dual_bank() { - panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use single-bank config"); + panic!( + "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use single-bank config" + ); } } diff --git a/embassy-stm32/src/flash/h5.rs b/embassy-stm32/src/flash/h5.rs index fd9bfcc75..88f247879 100644 --- a/embassy-stm32/src/flash/h5.rs +++ b/embassy-stm32/src/flash/h5.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs index f8e210556..91d5da4d6 100644 --- a/embassy-stm32/src/flash/h50.rs +++ b/embassy-stm32/src/flash/h50.rs @@ -1,7 +1,7 @@ /// STM32H50 series flash impl. See RM0492 use core::{ ptr::write_volatile, - sync::atomic::{fence, Ordering}, + sync::atomic::{Ordering, fence}, }; use cortex_m::interrupt; diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index f1d84101c..8a43cce3f 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -1,7 +1,7 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; -use super::{FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; +use super::{BANK1_REGION, FLASH_REGIONS, FlashSector, WRITE_SIZE}; use crate::flash::Error; use crate::pac; diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index 1b82704ec..b3281f2d5 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; @@ -96,14 +96,20 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E #[cfg(any(flash_wl, flash_wb, flash_l4, flash_l5))] { let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; + #[cfg(any(flash_l4, flash_l5))] + let pgn = super::BANK1_REGION.size as u32 / super::BANK1_REGION.erase_size as u32; #[cfg(flash_l4)] - let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; + let (idx, bank) = if idx > (pgn - 1) { + (idx - pgn, true) + } else { + (idx, false) + }; #[cfg(flash_l5)] let (idx, bank) = if pac::FLASH.optr().read().dbank() { - if idx > 255 { - (idx - 256, Some(true)) + if idx > (pgn - 1) { + (idx - pgn, Some(true)) } else { (idx, Some(false)) } @@ -234,19 +240,27 @@ pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> { #[cfg(all(bank_setup_configurable, flash_l5))] pub(crate) fn check_bank_setup() { if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() { - panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"); + panic!( + "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config" + ); } if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() { - panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"); + panic!( + "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config" + ); } } #[cfg(all(bank_setup_configurable, flash_l4))] pub(crate) fn check_bank_setup() { if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dualbank() { - panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use dual-bank config"); + panic!( + "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use dual-bank config" + ); } if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dualbank() { - panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use single-bank config"); + panic!( + "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use single-bank config" + ); } } diff --git a/embassy-stm32/src/flash/u0.rs b/embassy-stm32/src/flash/u0.rs index 68d847eca..a64f6c492 100644 --- a/embassy-stm32/src/flash/u0.rs +++ b/embassy-stm32/src/flash/u0.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use cortex_m::interrupt; diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs index 6c3d4b422..5f1f562c0 100644 --- a/embassy-stm32/src/flash/u5.rs +++ b/embassy-stm32/src/flash/u5.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use super::{FlashBank, FlashSector, WRITE_SIZE}; use crate::flash::Error; diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs index ff18a8bee..8ecfbc522 100644 --- a/embassy-stm32/src/fmc.rs +++ b/embassy-stm32/src/fmc.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use embassy_hal_internal::PeripheralType; use crate::gpio::{AfType, OutputType, Pull, Speed}; -use crate::{rcc, Peri}; +use crate::{Peri, rcc}; /// FMC driver pub struct Fmc<'d, T: Instance> { diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 5a8d23183..b55baffdc 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -4,7 +4,7 @@ use core::convert::Infallible; use critical_section::CriticalSection; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use crate::pac::gpio::{self, vals}; use crate::peripherals; diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index 90c06c0d8..ba573267c 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -19,7 +19,7 @@ use crate::interrupt::typelevel::Interrupt; use crate::mode::Async; use crate::mode::{Blocking, Mode}; use crate::peripherals::HASH; -use crate::{interrupt, pac, peripherals, rcc, Peri}; +use crate::{Peri, interrupt, pac, peripherals, rcc}; #[cfg(hash_v1)] const NUM_CONTEXT_REGS: usize = 51; @@ -514,11 +514,7 @@ impl<'d, T: Instance> Hash<'d, T, Async> { T::regs().imr().modify(|reg| reg.set_dcie(true)); // Check for completion. let bits = T::regs().sr().read(); - if bits.dcis() { - Poll::Ready(()) - } else { - Poll::Pending - } + if bits.dcis() { Poll::Ready(()) } else { Poll::Pending } }) .await; diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs index 573a1851d..4d3a5d68d 100644 --- a/embassy-stm32/src/hsem/mod.rs +++ b/embassy-stm32/src/hsem/mod.rs @@ -2,13 +2,13 @@ use embassy_hal_internal::PeripheralType; -use crate::pac; -use crate::rcc::{self, RccPeripheral}; // TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs. // Those MCUs have a different HSEM implementation (Secure semaphore lock support, // Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute), // which is not yet supported by this code. use crate::Peri; +use crate::pac; +use crate::rcc::{self, RccPeripheral}; /// HSEM error. #[derive(Debug)] diff --git a/embassy-stm32/src/hspi/mod.rs b/embassy-stm32/src/hspi/mod.rs index 95d9e5099..69baa708e 100644 --- a/embassy-stm32/src/hspi/mod.rs +++ b/embassy-stm32/src/hspi/mod.rs @@ -16,7 +16,7 @@ use embassy_embedded_hal::{GetConfig, SetConfig}; use embassy_hal_internal::{Peri, PeripheralType}; pub use enums::*; -use crate::dma::{word, ChannelAndRequest}; +use crate::dma::{ChannelAndRequest, word}; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::hspi::Hspi as Regs; diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 249bac41c..f4bf55d34 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -154,8 +154,8 @@ impl<'d> I2c<'d, Async, Master> { scl: Peri<'d, if_afio!(impl SclPin)>, sda: Peri<'d, if_afio!(impl SdaPin)>, _irq: impl interrupt::typelevel::Binding> - + interrupt::typelevel::Binding> - + 'd, + + interrupt::typelevel::Binding> + + 'd, tx_dma: Peri<'d, impl TxDma>, rx_dma: Peri<'d, impl RxDma>, config: Config, diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 081eb1191..e6b6c7c42 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -8,7 +8,7 @@ use core::future::poll_fn; use core::task::Poll; use embassy_embedded_hal::SetConfig; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_hal_internal::drop::OnDrop; use embedded_hal_1::i2c::Operation; use mode::Master; @@ -762,11 +762,7 @@ impl Timings { mode = Mode::Standard; ccr = { let ccr = clock / (frequency * 2); - if ccr < 4 { - 4 - } else { - ccr - } + if ccr < 4 { 4 } else { ccr } }; } else { const DUTYCYCLE: u8 = 0; diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 0bfc795ac..01b6b8800 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -2,7 +2,7 @@ use core::cmp; use core::future::poll_fn; use core::task::Poll; -use config::{Address, OwnAddresses, OA2}; +use config::{Address, OA2, OwnAddresses}; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::drop::OnDrop; use embedded_hal_1::i2c::Operation; diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index b6d3daf54..db22cfa11 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -3,12 +3,12 @@ use embassy_futures::join::join; use stm32_metapac::spi::vals; -use crate::dma::{ringbuffer, ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer}; +use crate::Peri; +use crate::dma::{ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer, ringbuffer}; use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; use crate::mode::Async; use crate::spi::{Config as SpiConfig, RegsExt as _, *}; use crate::time::Hertz; -use crate::Peri; /// I2S mode #[derive(Copy, Clone)] diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 670d8332c..e1d8b1c2a 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs @@ -1,7 +1,7 @@ //! Inter-Process Communication Controller (IPCC) use core::future::poll_fn; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_sync::waitqueue::AtomicWaker; diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 7e0f7884e..dbf0fe620 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(test), no_std)] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![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 (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" @@ -194,7 +195,7 @@ macro_rules! bind_interrupts { $( #[allow(non_snake_case)] - #[no_mangle] + #[unsafe(no_mangle)] $(#[cfg($cond_irq)])? $(#[doc = $doc])* unsafe extern "C" fn $irq() { @@ -222,7 +223,7 @@ macro_rules! bind_interrupts { } // Reexports -pub use _generated::{peripherals, Peripherals}; +pub use _generated::{Peripherals, peripherals}; pub use embassy_hal_internal::{Peri, PeripheralType}; #[cfg(feature = "unstable-pac")] pub use stm32_metapac as pac; diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 342f73bc8..1b66ca680 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -56,13 +56,13 @@ use core::arch::asm; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use cortex_m::peripheral::SCB; use embassy_executor::*; use crate::interrupt; -use crate::time_driver::{get_driver, RtcDriver}; +use crate::time_driver::{RtcDriver, get_driver}; const THREAD_PENDER: usize = usize::MAX; diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs index 96af9f4d9..a69db3caf 100644 --- a/embassy-stm32/src/lptim/pwm.rs +++ b/embassy-stm32/src/lptim/pwm.rs @@ -4,12 +4,12 @@ use core::marker::PhantomData; use embassy_hal_internal::Peri; -use super::timer::Timer; #[cfg(not(any(lptim_v2a, lptim_v2b)))] use super::OutputPin; -#[cfg(any(lptim_v2a, lptim_v2b))] -use super::{channel::Channel, timer::ChannelDirection, Channel1Pin, Channel2Pin}; +use super::timer::Timer; use super::{BasicInstance, Instance}; +#[cfg(any(lptim_v2a, lptim_v2b))] +use super::{Channel1Pin, Channel2Pin, channel::Channel, timer::ChannelDirection}; #[cfg(gpio_v2)] use crate::gpio::Pull; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs index 0f6ef569c..de2db9872 100644 --- a/embassy-stm32/src/ltdc.rs +++ b/embassy-stm32/src/ltdc.rs @@ -14,7 +14,7 @@ use stm32_metapac::ltdc::vals::{Bf1, Bf2, Cfuif, Clif, Crrif, Cterrif, Pf, Vbr}; use crate::gpio::{AfType, OutputType, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::interrupt::{self}; -use crate::{peripherals, rcc, Peri}; +use crate::{Peri, peripherals, rcc}; static LTDC_WAKER: AtomicWaker = AtomicWaker::new(); diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index e36719ef3..ac8d5de21 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -3,10 +3,10 @@ use embassy_hal_internal::PeripheralType; +use crate::Peri; use crate::pac::opamp::vals::*; #[cfg(not(any(stm32g4, stm32f3)))] use crate::rcc::RccInfo; -use crate::Peri; /// Performs a busy-wait delay for a specified number of microseconds. #[cfg(opamp_v5)] diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index d93cecb69..592a8594a 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -12,14 +12,14 @@ use embassy_hal_internal::PeripheralType; pub use enums::*; use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits}; -use crate::dma::{word, ChannelAndRequest}; +use crate::dma::{ChannelAndRequest, word}; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; -use crate::pac::octospi::{vals, Octospi as Regs}; +use crate::pac::octospi::{Octospi as Regs, vals}; #[cfg(octospim_v1)] use crate::pac::octospim::Octospim; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; /// OPSI driver config. #[derive(Clone, Copy)] diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index b03cd9009..bb4f4f1d0 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -14,7 +14,7 @@ use crate::gpio::{AfType, AnyPin, OutputType, Pull, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::quadspi::Quadspi as Regs; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; /// QSPI transfer configuration. #[derive(Clone, Copy)] diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 63fc195dd..3b2a10581 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -1,6 +1,6 @@ -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; -use crate::pac::common::{Reg, RW}; +use crate::pac::common::{RW, Reg}; pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource; use crate::time::Hertz; diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index 8f2e8db5f..d941054cd 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -1,13 +1,13 @@ use stm32_metapac::flash::vals::Latency; +#[cfg(any(stm32f4, stm32f7))] +use crate::pac::PWR; #[cfg(any(stm32f413, stm32f423, stm32f412))] pub use crate::pac::rcc::vals::Plli2ssrc as Plli2sSource; pub use crate::pac::rcc::vals::{ Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, }; -#[cfg(any(stm32f4, stm32f7))] -use crate::pac::PWR; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 331bab7a0..485edd390 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -597,7 +597,10 @@ pub(crate) unsafe fn init(config: Config) { Hertz(24_000_000) => Usbrefcksel::MHZ24, Hertz(26_000_000) => Usbrefcksel::MHZ26, Hertz(32_000_000) => Usbrefcksel::MHZ32, - _ => panic!("cannot select USBPHYC reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), + _ => panic!( + "cannot select USBPHYC reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", + clk_val + ), }, None => Usbrefcksel::MHZ24, }; diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index 81b89046e..2e1cbd702 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs @@ -499,9 +499,9 @@ pub use pll::*; #[cfg(any(stm32l0, stm32l1))] mod pll { - use super::{pll_enable, PllInstance}; - pub use crate::pac::rcc::vals::{Plldiv as PllDiv, Pllmul as PllMul, Pllsrc as PllSource}; + use super::{PllInstance, pll_enable}; use crate::pac::RCC; + pub use crate::pac::rcc::vals::{Plldiv as PllDiv, Pllmul as PllMul, Pllsrc as PllSource}; use crate::time::Hertz; #[derive(Clone, Copy)] @@ -563,11 +563,11 @@ mod pll { #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))] mod pll { - use super::{pll_enable, PllInstance}; + use super::{PllInstance, pll_enable}; + use crate::pac::RCC; pub use crate::pac::rcc::vals::{ Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PllSource, }; - use crate::pac::RCC; use crate::time::Hertz; #[derive(Clone, Copy)] diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index fa4b45a20..3d961df03 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs @@ -3,6 +3,7 @@ use core::marker::PhantomData; use embassy_hal_internal::PeripheralType; use crate::gpio::{AfType, OutputType, Speed}; +use crate::pac::RCC; #[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; #[cfg(not(any( @@ -31,8 +32,7 @@ pub use crate::pac::rcc::vals::Mcosel as McoSource; rcc_h7rs ))] pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; -use crate::pac::RCC; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; #[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index c41f81816..addfca3c3 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -33,7 +33,7 @@ mod _version; pub use _version::*; use stm32_metapac::RCC; -pub use crate::_generated::{mux, Clocks}; +pub use crate::_generated::{Clocks, mux}; use crate::time::Hertz; #[cfg(feature = "low-power")] diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 06895a99a..7b0dcb63f 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -6,9 +6,9 @@ pub use crate::pac::rcc::vals::{ Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, }; use crate::pac::rcc::vals::{Hseext, Msipllfast, Msipllsel, Msirgsel, Pllmboost, Pllrge}; -#[cfg(all(peri_usb_otg_hs))] -pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG}; use crate::pac::{FLASH, PWR, RCC}; +#[cfg(all(peri_usb_otg_hs))] +pub use crate::pac::{SYSCFG, syscfg::vals::Usbrefcksel}; use crate::rcc::LSI_FREQ; use crate::time::Hertz; @@ -442,7 +442,10 @@ pub(crate) unsafe fn init(config: Config) { Hertz(24_000_000) => Usbrefcksel::MHZ24, Hertz(26_000_000) => Usbrefcksel::MHZ26, Hertz(32_000_000) => Usbrefcksel::MHZ32, - _ => panic!("cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), + _ => panic!( + "cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", + clk_val + ), }, None => Usbrefcksel::MHZ24, }; diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index 481437939..2528996d5 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -7,9 +7,9 @@ pub use crate::pac::rcc::vals::{ Hdiv5, Hpre as AHBPrescaler, Hpre5 as AHB5Prescaler, Hsepre as HsePrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Ppre as APBPrescaler, Sai1sel, Sw as Sysclk, }; -#[cfg(all(peri_usb_otg_hs))] -pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG}; use crate::pac::{FLASH, RCC}; +#[cfg(all(peri_usb_otg_hs))] +pub use crate::pac::{SYSCFG, syscfg::vals::Usbrefcksel}; use crate::rcc::LSI_FREQ; use crate::time::Hertz; @@ -245,7 +245,10 @@ pub(crate) unsafe fn init(config: Config) { Hertz(24_000_000) => Usbrefcksel::MHZ24, Hertz(26_000_000) => Usbrefcksel::MHZ26, Hertz(32_000_000) => Usbrefcksel::MHZ32, - _ => panic!("cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), + _ => panic!( + "cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", + clk_val + ), }, None => Usbrefcksel::MHZ24, }; diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 63654639e..dada9bda1 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -9,7 +9,7 @@ use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; use crate::interrupt::typelevel::Interrupt; -use crate::{interrupt, pac, peripherals, rcc, Peri}; +use crate::{Peri, interrupt, pac, peripherals, rcc}; static RNG_WAKER: AtomicWaker = AtomicWaker::new(); diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs index a81ac6746..999f24714 100644 --- a/embassy-stm32/src/rtc/low_power.rs +++ b/embassy-stm32/src/rtc/low_power.rs @@ -1,7 +1,7 @@ #[cfg(feature = "time")] use embassy_time::{Duration, TICK_HZ}; -use super::{bcd2_to_byte, DateTimeError, Rtc, RtcError}; +use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::RTC; use crate::rtc::SealedInstance; diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 92dec0960..bc6df528b 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -7,13 +7,13 @@ mod low_power; #[cfg(feature = "low-power")] use core::cell::Cell; -#[cfg(feature = "low-power")] -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; #[cfg(feature = "low-power")] use embassy_sync::blocking_mutex::Mutex; +#[cfg(feature = "low-power")] +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use self::datetime::{day_of_week_from_u8, day_of_week_to_u8}; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; +use self::datetime::{day_of_week_from_u8, day_of_week_to_u8}; use crate::pac::rtc::regs::{Dr, Tr}; use crate::time::Hertz; @@ -25,8 +25,8 @@ mod _version; #[allow(unused_imports)] pub use _version::*; -use crate::peripherals::RTC; use crate::Peri; +use crate::peripherals::RTC; /// Errors that can occur on methods on [RtcClock] #[non_exhaustive] diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index d0b52049e..01da5d70a 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -1,4 +1,4 @@ -use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Key, Osel, Pol, TampalrmType}; +use stm32_metapac::rtc::vals::{Calp, Calw8, Calw16, Fmt, Key, Osel, Pol, TampalrmType}; use super::RtcCalibrationCyclePeriod; use crate::pac::rtc::Rtc; diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index fb8b23b79..726d1729a 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -6,12 +6,12 @@ use core::marker::PhantomData; use embassy_hal_internal::PeripheralType; pub use crate::dma::word; -use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; +use crate::dma::{Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer, ringbuffer}; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; pub use crate::pac::sai::vals::Mckdiv as MasterClockDivider; -use crate::pac::sai::{vals, Sai as Regs}; +use crate::pac::sai::{Sai as Regs, vals}; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; /// SAI error #[derive(Debug, PartialEq, Eq, Clone, Copy)] diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index ccbd16cbf..408d1b764 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -11,9 +11,9 @@ use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use sdio_host::common_cmd::{self, Resp, ResponseLen}; -use sdio_host::emmc::{ExtCSD, EMMC}; -use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}; -use sdio_host::{emmc_cmd, sd_cmd, Cmd}; +use sdio_host::emmc::{EMMC, ExtCSD}; +use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus}; +use sdio_host::{Cmd, emmc_cmd, sd_cmd}; #[cfg(sdmmc_v1)] use crate::dma::ChannelAndRequest; diff --git a/embassy-stm32/src/spdifrx/mod.rs b/embassy-stm32/src/spdifrx/mod.rs index b0a32d5d1..6f2d24560 100644 --- a/embassy-stm32/src/spdifrx/mod.rs +++ b/embassy-stm32/src/spdifrx/mod.rs @@ -13,7 +13,7 @@ use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _}; use crate::interrupt::typelevel::Interrupt; use crate::pac::spdifrx::Spdifrx as Regs; use crate::rcc::{RccInfo, SealedRccPeripheral}; -use crate::{interrupt, peripherals, Peri}; +use crate::{Peri, interrupt, peripherals}; /// Possible S/PDIF preamble types. #[allow(dead_code)] diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index c5373a54d..c27d09ea7 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -6,15 +6,15 @@ use core::ptr; use embassy_embedded_hal::SetConfig; use embassy_futures::join::join; -pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +pub use embedded_hal_02::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity}; -use crate::dma::{word, ChannelAndRequest}; +use crate::Peri; +use crate::dma::{ChannelAndRequest, word}; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; -use crate::pac::spi::{regs, vals, Spi as Regs}; +use crate::pac::spi::{Spi as Regs, regs, vals}; use crate::rcc::{RccInfo, SealedRccPeripheral}; use crate::time::Hertz; -use crate::Peri; /// SPI error. #[derive(Debug, PartialEq, Eq, Clone, Copy)] diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 7db74bdf6..74b10a183 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -1,14 +1,14 @@ #![allow(non_snake_case)] use core::cell::{Cell, RefCell}; -use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; use critical_section::CriticalSection; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_time_driver::{Driver, TICK_HZ}; use embassy_time_queue_utils::Queue; -use stm32_metapac::timer::{regs, TimGp16}; +use stm32_metapac::timer::{TimGp16, regs}; use crate::interrupt::typelevel::Interrupt; use crate::pac::timer::vals; diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 484aae1d0..75a83629c 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -7,11 +7,11 @@ pub use stm32_metapac::timer::vals::{Ckd, Ossi, Ossr}; use super::low_level::{CountingMode, OutputPolarity, Timer}; use super::simple_pwm::PwmPin; use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; +use crate::Peri; use crate::gpio::{AnyPin, OutputType}; use crate::time::Hertz; -use crate::timer::low_level::OutputCompareMode; use crate::timer::TimerChannel; -use crate::Peri; +use crate::timer::low_level::OutputCompareMode; /// Complementary PWM pin wrapper. /// @@ -388,7 +388,7 @@ fn compute_dead_time_value(value: u16) -> (Ckd, u8) { #[cfg(test)] mod tests { - use super::{compute_dead_time_value, Ckd}; + use super::{Ckd, compute_dead_time_value}; #[test] fn test_compute_dead_time_value() { diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index 7a25e6c21..2a4ec2db0 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs @@ -8,11 +8,11 @@ use core::task::{Context, Poll}; use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer}; use super::{CaptureCompareInterruptHandler, Channel, GeneralInstance4Channel, TimerPin}; pub use super::{Ch1, Ch2, Ch3, Ch4}; +use crate::Peri; use crate::gpio::{AfType, AnyPin, Pull}; use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::time::Hertz; use crate::timer::TimerChannel; -use crate::Peri; /// Capture pin wrapper. /// diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs index a75b41bd7..fe8681356 100644 --- a/embassy-stm32/src/timer/one_pulse.rs +++ b/embassy-stm32/src/timer/one_pulse.rs @@ -11,12 +11,12 @@ use super::low_level::{ }; use super::{CaptureCompareInterruptHandler, Channel, ExternalTriggerPin, GeneralInstance4Channel, TimerPin}; pub use super::{Ch1, Ch2}; +use crate::Peri; use crate::gpio::{AfType, AnyPin, Pull}; use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::pac::timer::vals::Etp; use crate::time::Hertz; use crate::timer::TimerChannel; -use crate::Peri; /// External input marker type. pub enum Ext {} diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs index 159b5a177..da8a79b09 100644 --- a/embassy-stm32/src/timer/pwm_input.rs +++ b/embassy-stm32/src/timer/pwm_input.rs @@ -2,9 +2,9 @@ use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource}; use super::{Ch1, Ch2, Channel, GeneralInstance4Channel, TimerPin}; +use crate::Peri; use crate::gpio::{AfType, Pull}; use crate::time::Hertz; -use crate::Peri; /// PWM Input driver. /// diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index bb152731c..a547a2a19 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -5,9 +5,9 @@ use stm32_metapac::timer::vals::{self, Sms}; use super::low_level::Timer; pub use super::{Ch1, Ch2}; use super::{GeneralInstance4Channel, TimerPin}; +use crate::Peri; use crate::gpio::{AfType, AnyPin, Pull}; use crate::timer::TimerChannel; -use crate::Peri; /// Qei driver config. #[cfg_attr(feature = "defmt", derive(defmt::Format))] diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index e6165e42b..06315d7f3 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -5,11 +5,11 @@ use core::mem::ManuallyDrop; use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerBits, TimerChannel, TimerPin}; +use crate::Peri; #[cfg(gpio_v2)] use crate::gpio::Pull; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::time::Hertz; -use crate::Peri; /// PWM pin wrapper. /// diff --git a/embassy-stm32/src/tsc/acquisition_banks.rs b/embassy-stm32/src/tsc/acquisition_banks.rs index 7d6442b48..097cf7942 100644 --- a/embassy-stm32/src/tsc/acquisition_banks.rs +++ b/embassy-stm32/src/tsc/acquisition_banks.rs @@ -1,11 +1,11 @@ +use super::TSC_NUM_GROUPS; use super::io_pin::*; #[cfg(any(tsc_v2, tsc_v3))] use super::pin_groups::G7; #[cfg(tsc_v3)] use super::pin_groups::G8; -use super::pin_groups::{pin_roles, G1, G2, G3, G4, G5, G6}; +use super::pin_groups::{G1, G2, G3, G4, G5, G6, pin_roles}; use super::types::{Group, GroupStatus}; -use super::TSC_NUM_GROUPS; /// Represents a collection of TSC (Touch Sensing Controller) pins for an acquisition bank. /// diff --git a/embassy-stm32/src/tsc/pin_groups.rs b/embassy-stm32/src/tsc/pin_groups.rs index 84421f7ff..9347e6bc0 100644 --- a/embassy-stm32/src/tsc/pin_groups.rs +++ b/embassy-stm32/src/tsc/pin_groups.rs @@ -1,11 +1,11 @@ use core::marker::PhantomData; use core::ops::BitOr; +use super::Instance; use super::errors::GroupError; use super::io_pin::*; -use super::Instance; -use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::Peri; +use crate::gpio::{AfType, AnyPin, OutputType, Speed}; /// Pin type definition to control IO parameters #[derive(PartialEq, Clone, Copy)] diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 18aff4fbd..8f259a917 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -19,8 +19,8 @@ use core::marker::PhantomData; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; -use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::PeripheralType; +use embassy_hal_internal::drop::OnDrop; use embassy_sync::waitqueue::AtomicWaker; use crate::dma::{ChannelAndRequest, TransferOptions}; @@ -28,7 +28,7 @@ use crate::interrupt::typelevel::Interrupt; use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState}; use crate::rcc::{self, RccPeripheral}; -use crate::{interrupt, Peri}; +use crate::{Peri, interrupt}; pub(crate) fn init( _cs: critical_section::CriticalSection, diff --git a/embassy-stm32/src/uid.rs b/embassy-stm32/src/uid.rs index 5e38532bd..2d3e2b972 100644 --- a/embassy-stm32/src/uid.rs +++ b/embassy-stm32/src/uid.rs @@ -1,8 +1,8 @@ //! Unique ID (UID) /// Get this device's unique 96-bit ID. -pub fn uid() -> &'static [u8; 12] { - unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() } +pub fn uid() -> [u8; 12] { + unsafe { *crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() } } /// Get this device's unique 96-bit ID, encoded into a string of 24 hexadecimal ASCII digits. diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 10dc02334..69c3a740f 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -5,16 +5,16 @@ use core::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering}; use core::task::Poll; use embassy_embedded_hal::SetConfig; -use embassy_hal_internal::atomic_ring_buffer::RingBuffer; use embassy_hal_internal::Peri; +use embassy_hal_internal::atomic_ring_buffer::RingBuffer; use embassy_sync::waitqueue::AtomicWaker; #[cfg(not(any(usart_v1, usart_v2)))] use super::DePin; use super::{ + Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexReadback, Info, Instance, Regs, RtsPin, RxPin, TxPin, clear_interrupt_flags, configure, half_duplex_set_rx_tx_before_write, rdr, reconfigure, send_break, set_baudrate, - sr, tdr, Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexReadback, Info, Instance, Regs, RtsPin, RxPin, - TxPin, + sr, tdr, }; use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _}; use crate::interrupt::{self, InterruptExt}; diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 0d2d86aca..0e7da634d 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -4,15 +4,16 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicU8, AtomicUsize, Ordering, compiler_fence}; use core::task::Poll; use embassy_embedded_hal::SetConfig; -use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::PeripheralType; +use embassy_hal_internal::drop::OnDrop; use embassy_sync::waitqueue::AtomicWaker; -use futures_util::future::{select, Either}; +use futures_util::future::{Either, select}; +use crate::Peri; use crate::dma::ChannelAndRequest; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::interrupt::typelevel::Interrupt as _; @@ -25,7 +26,6 @@ use crate::pac::usart::Usart as Regs; use crate::pac::usart::{regs, vals}; use crate::rcc::{RccInfo, SealedRccPeripheral}; use crate::time::Hertz; -use crate::Peri; /// Interrupt handler. pub struct InterruptHandler { diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 27071fb31..20bfefd9e 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -1,19 +1,19 @@ use core::future::poll_fn; use core::mem; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_embedded_hal::SetConfig; use embedded_io_async::ReadReady; -use futures_util::future::{select, Either}; +use futures_util::future::{Either, select}; -use super::{rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx}; +use super::{Config, ConfigError, Error, Info, State, UartRx, rdr, reconfigure, set_baudrate, sr}; +use crate::Peri; use crate::dma::ReadableRingBuffer; use crate::gpio::{AnyPin, SealedPin as _}; use crate::mode::Async; use crate::time::Hertz; use crate::usart::Regs; -use crate::Peri; /// Rx-only Ring-buffered UART Driver /// diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 5ce81b131..f6b1a81db 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -2,18 +2,18 @@ use core::marker::PhantomData; use embassy_hal_internal::PeripheralType; use embassy_usb_driver::{EndpointAddress, EndpointAllocError, EndpointType, Event, Unsupported}; -use embassy_usb_synopsys_otg::otg_v1::vals::Dspd; -use embassy_usb_synopsys_otg::otg_v1::Otg; pub use embassy_usb_synopsys_otg::Config; +use embassy_usb_synopsys_otg::otg_v1::Otg; +use embassy_usb_synopsys_otg::otg_v1::vals::Dspd; use embassy_usb_synopsys_otg::{ - on_interrupt as on_interrupt_impl, Bus as OtgBus, ControlPipe, Driver as OtgDriver, Endpoint, In, OtgInstance, Out, - PhyType, State, + Bus as OtgBus, ControlPipe, Driver as OtgDriver, Endpoint, In, OtgInstance, Out, PhyType, State, + on_interrupt as on_interrupt_impl, }; use crate::gpio::{AfType, OutputType, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::rcc::{self, RccPeripheral}; -use crate::{interrupt, Peri}; +use crate::{Peri, interrupt}; const MAX_EP_COUNT: usize = 9; diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 9e08d99b3..d405e4802 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -12,11 +12,11 @@ use embassy_usb_driver::{ Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, }; +use crate::pac::USBRAM; use crate::pac::usb::regs; use crate::pac::usb::vals::{EpType, Stat}; -use crate::pac::USBRAM; use crate::rcc::RccPeripheral; -use crate::{interrupt, Peri}; +use crate::{Peri, interrupt}; /// Interrupt handler. pub struct InterruptHandler { diff --git a/embassy-stm32/src/vrefbuf/mod.rs b/embassy-stm32/src/vrefbuf/mod.rs index ccbd748d5..b061306a0 100644 --- a/embassy-stm32/src/vrefbuf/mod.rs +++ b/embassy-stm32/src/vrefbuf/mod.rs @@ -62,8 +62,7 @@ impl<'d, T: Instance> VoltageReferenceBuffer<'d, T> { } trace!( "Vrefbuf configured with voltage scale {} and impedance mode {}", - voltage_scale as u8, - impedance_mode as u8, + voltage_scale as u8, impedance_mode as u8, ); VoltageReferenceBuffer { vrefbuf: PhantomData } } diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index fb5c3d930..1164739ff 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs @@ -4,8 +4,8 @@ use core::marker::PhantomData; use embassy_hal_internal::PeripheralType; use stm32_metapac::iwdg::vals::{Key, Pr}; -use crate::rcc::LSI_FREQ; use crate::Peri; +use crate::rcc::LSI_FREQ; /// Independent watchdog (IWDG) driver. pub struct IndependentWatchdog<'d, T: Instance> { diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs index 901569f64..a80a2692b 100644 --- a/embassy-stm32/src/xspi/mod.rs +++ b/embassy-stm32/src/xspi/mod.rs @@ -11,15 +11,15 @@ use embassy_embedded_hal::{GetConfig, SetConfig}; use embassy_hal_internal::PeripheralType; pub use enums::*; -use crate::dma::{word, ChannelAndRequest}; +use crate::dma::{ChannelAndRequest, word}; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; -use crate::pac::xspi::vals::*; use crate::pac::xspi::Xspi as Regs; +use crate::pac::xspi::vals::*; #[cfg(xspim_v1)] use crate::pac::xspim::Xspim; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; /// XPSI driver config. #[derive(Clone, Copy)] diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index 64d76baba..0c28cec7d 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-sync" version = "0.7.2" -edition = "2021" +edition = "2024" description = "no-std, no-alloc synchronization primitives with async support" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-sync" diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index de437cc52..dbd24a6c7 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs @@ -50,8 +50,8 @@ use core::task::{Context, Poll}; use heapless::Deque; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; use crate::waitqueue::WakerRegistration; /// Send-only access to a [`Channel`]. @@ -1112,11 +1112,13 @@ mod tests { static CHANNEL: StaticCell> = StaticCell::new(); let c = &*CHANNEL.init(Channel::new()); let c2 = c; - assert!(executor - .spawn(async move { - assert!(c2.try_send(1).is_ok()); - }) - .is_ok()); + assert!( + executor + .spawn(async move { + assert!(c2.try_send(1).is_ok()); + }) + .is_ok() + ); assert_eq!(c.receive().await, 1); } @@ -1143,13 +1145,15 @@ mod tests { // However, I've used the debugger to observe that the send does indeed wait. Delay::new(Duration::from_millis(500)).await; assert_eq!(c.receive().await, 1); - assert!(executor - .spawn(async move { - loop { - c.receive().await; - } - }) - .is_ok()); + assert!( + executor + .spawn(async move { + loop { + c.receive().await; + } + }) + .is_ok() + ); send_task_1.unwrap().await; send_task_2.unwrap().await; } diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs index 5d91b4d9c..1cfde8b10 100644 --- a/embassy-sync/src/lib.rs +++ b/embassy-sync/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![allow(async_fn_in_trait)] #![allow(clippy::new_without_default)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs index aea682899..96b834f02 100644 --- a/embassy-sync/src/mutex.rs +++ b/embassy-sync/src/mutex.rs @@ -2,13 +2,13 @@ //! //! This module provides a mutex that can be used to synchronize data between asynchronous tasks. use core::cell::{RefCell, UnsafeCell}; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::ops::{Deref, DerefMut}; use core::task::Poll; use core::{fmt, mem}; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex as BlockingMutex; +use crate::blocking_mutex::raw::RawMutex; use crate::waitqueue::WakerRegistration; /// Error returned by [`Mutex::try_lock`] diff --git a/embassy-sync/src/once_lock.rs b/embassy-sync/src/once_lock.rs index 73edfea9a..2af19ca20 100644 --- a/embassy-sync/src/once_lock.rs +++ b/embassy-sync/src/once_lock.rs @@ -2,7 +2,7 @@ use core::cell::Cell; use core::fmt::{Debug, Formatter}; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::mem::MaybeUninit; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs index 6d624979a..215a556d9 100644 --- a/embassy-sync/src/pipe.rs +++ b/embassy-sync/src/pipe.rs @@ -7,8 +7,8 @@ use core::ops::Range; use core::pin::Pin; use core::task::{Context, Poll}; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; use crate::ring_buffer::RingBuffer; use crate::waitqueue::WakerRegistration; diff --git a/embassy-sync/src/priority_channel.rs b/embassy-sync/src/priority_channel.rs index 715a20e86..1af7d9221 100644 --- a/embassy-sync/src/priority_channel.rs +++ b/embassy-sync/src/priority_channel.rs @@ -8,11 +8,11 @@ use core::future::Future; use core::pin::Pin; use core::task::{Context, Poll}; -pub use heapless::binary_heap::{Kind, Max, Min}; use heapless::BinaryHeap; +pub use heapless::binary_heap::{Kind, Max, Min}; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; use crate::channel::{DynamicChannel, DynamicReceiver, DynamicSender, TryReceiveError, TrySendError}; use crate::waitqueue::WakerRegistration; @@ -799,11 +799,13 @@ mod tests { static CHANNEL: StaticCell> = StaticCell::new(); let c = &*CHANNEL.init(PriorityChannel::new()); let c2 = c; - assert!(executor - .spawn(async move { - assert!(c2.try_send(1).is_ok()); - }) - .is_ok()); + assert!( + executor + .spawn(async move { + assert!(c2.try_send(1).is_ok()); + }) + .is_ok() + ); assert_eq!(c.receive().await, 1); } @@ -830,13 +832,15 @@ mod tests { // However, I've used the debugger to observe that the send does indeed wait. Delay::new(Duration::from_millis(500)).await; assert_eq!(c.receive().await, 1); - assert!(executor - .spawn(async move { - loop { - c.receive().await; - } - }) - .is_ok()); + assert!( + executor + .spawn(async move { + loop { + c.receive().await; + } + }) + .is_ok() + ); send_task_1.unwrap().await; send_task_2.unwrap().await; } diff --git a/embassy-sync/src/pubsub/mod.rs b/embassy-sync/src/pubsub/mod.rs index ad9402f5a..127a208f1 100644 --- a/embassy-sync/src/pubsub/mod.rs +++ b/embassy-sync/src/pubsub/mod.rs @@ -10,8 +10,8 @@ use heapless::Deque; use self::publisher::{ImmediatePub, Pub}; use self::subscriber::Sub; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; use crate::waitqueue::MultiWakerRegistration; pub mod publisher; diff --git a/embassy-sync/src/ring_buffer.rs b/embassy-sync/src/ring_buffer.rs index f03b7dd8f..608447cd6 100644 --- a/embassy-sync/src/ring_buffer.rs +++ b/embassy-sync/src/ring_buffer.rs @@ -95,11 +95,7 @@ impl RingBuffer { fn wrap(&self, n: usize) -> usize { assert!(n <= N); - if n == N { - 0 - } else { - n - } + if n == N { 0 } else { n } } } diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs index e43388c4d..918a6aa41 100644 --- a/embassy-sync/src/rwlock.rs +++ b/embassy-sync/src/rwlock.rs @@ -3,12 +3,12 @@ //! This module provides a read-write lock that can be used to synchronize data between asynchronous tasks. use core::cell::{RefCell, UnsafeCell}; use core::fmt; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::ops::{Deref, DerefMut}; use core::task::Poll; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex as BlockingMutex; +use crate::blocking_mutex::raw::RawMutex; use crate::waitqueue::WakerRegistration; /// Error returned by [`RwLock::try_read`] and [`RwLock::try_write`] when the lock is already held. diff --git a/embassy-sync/src/semaphore.rs b/embassy-sync/src/semaphore.rs index 4e82b0fcd..8d2413931 100644 --- a/embassy-sync/src/semaphore.rs +++ b/embassy-sync/src/semaphore.rs @@ -1,13 +1,13 @@ //! A synchronization primitive for controlling access to a pool of resources. use core::cell::{Cell, RefCell}; use core::convert::Infallible; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::task::{Poll, Waker}; use heapless::Deque; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; use crate::waitqueue::WakerRegistration; /// An asynchronous semaphore. diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs index 229b1fa99..cc02228cf 100644 --- a/embassy-sync/src/signal.rs +++ b/embassy-sync/src/signal.rs @@ -1,10 +1,10 @@ //! A synchronization primitive for passing the latest value to a task. use core::cell::Cell; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::task::{Context, Poll, Waker}; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; /// Single-slot signaling primitive for a _single_ consumer. /// diff --git a/embassy-sync/src/waitqueue/atomic_waker.rs b/embassy-sync/src/waitqueue/atomic_waker.rs index 5a9910e7f..d2bf890e5 100644 --- a/embassy-sync/src/waitqueue/atomic_waker.rs +++ b/embassy-sync/src/waitqueue/atomic_waker.rs @@ -1,8 +1,8 @@ use core::cell::Cell; use core::task::Waker; -use crate::blocking_mutex::raw::{CriticalSectionRawMutex, RawMutex}; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::{CriticalSectionRawMutex, RawMutex}; /// Utility struct to register and wake a waker. /// If a waker is registered, registering another waker will replace the previous one without waking it. diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 332ab5405..0f8a8d679 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -1,13 +1,13 @@ //! A synchronization primitive for passing the latest value to **multiple** receivers. use core::cell::RefCell; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::ops::{Deref, DerefMut}; use core::task::{Context, Poll}; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; use crate::waitqueue::MultiWakerRegistration; /// The `Watch` is a single-slot signaling primitive that allows _multiple_ (`N`) receivers to concurrently await diff --git a/embassy-sync/src/zerocopy_channel.rs b/embassy-sync/src/zerocopy_channel.rs index b3f7dbe8c..c572592b8 100644 --- a/embassy-sync/src/zerocopy_channel.rs +++ b/embassy-sync/src/zerocopy_channel.rs @@ -15,12 +15,12 @@ //! another message will result in an error being returned. use core::cell::RefCell; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::task::{Context, Poll}; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; use crate::waitqueue::WakerRegistration; /// A bounded zero-copy channel for communicating between asynchronous tasks @@ -296,11 +296,7 @@ struct State { impl State { fn increment(&self, i: usize) -> usize { - if i + 1 == self.capacity { - 0 - } else { - i + 1 - } + if i + 1 == self.capacity { 0 } else { i + 1 } } fn clear(&mut self) { diff --git a/embassy-time-driver/Cargo.toml b/embassy-time-driver/Cargo.toml index 56ef3d15f..a52e82433 100644 --- a/embassy-time-driver/Cargo.toml +++ b/embassy-time-driver/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-time-driver" version = "0.2.1" -edition = "2021" +edition = "2024" description = "Driver trait for embassy-time" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-time-driver" diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index 44d9a156a..f3e8e0153 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -89,7 +89,7 @@ //! Instead of the usual "trait + generic params" approach, calls from embassy to the driver are done via `extern` functions. //! //! `embassy` internally defines the driver function as `extern "Rust" { fn _embassy_time_now() -> u64; }` and calls it. -//! The driver crate defines the function as `#[no_mangle] fn _embassy_time_now() -> u64`. The linker will resolve the +//! The driver crate defines the function as `#[unsafe(no_mangle)] fn _embassy_time_now() -> u64`. The linker will resolve the //! calls from the `embassy` crate to call into the driver crate. //! //! If there is none or multiple drivers in the crate tree, linking will fail. @@ -133,7 +133,7 @@ pub trait Driver: Send + Sync + 'static { fn schedule_wake(&self, at: u64, waker: &Waker); } -extern "Rust" { +unsafe extern "Rust" { fn _embassy_time_now() -> u64; fn _embassy_time_schedule_wake(at: u64, waker: &Waker); } @@ -158,13 +158,13 @@ macro_rules! time_driver_impl { (static $name:ident: $t: ty = $val:expr) => { static $name: $t = $val; - #[no_mangle] + #[unsafe(no_mangle)] #[inline] fn _embassy_time_now() -> u64 { <$t as $crate::Driver>::now(&$name) } - #[no_mangle] + #[unsafe(no_mangle)] #[inline] fn _embassy_time_schedule_wake(at: u64, waker: &core::task::Waker) { <$t as $crate::Driver>::schedule_wake(&$name, at, waker); diff --git a/embassy-time-queue-utils/Cargo.toml b/embassy-time-queue-utils/Cargo.toml index 13da62874..8da30c544 100644 --- a/embassy-time-queue-utils/Cargo.toml +++ b/embassy-time-queue-utils/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-time-queue-utils" version = "0.3.0" -edition = "2021" +edition = "2024" description = "Timer queue driver trait for embassy-time" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-time-queue-utils" diff --git a/embassy-time-queue-utils/src/queue_generic.rs b/embassy-time-queue-utils/src/queue_generic.rs index bff7a4735..88986953d 100644 --- a/embassy-time-queue-utils/src/queue_generic.rs +++ b/embassy-time-queue-utils/src/queue_generic.rs @@ -2,7 +2,7 @@ //! //! Time queue drivers may use this to simplify their implementation. -use core::cmp::{min, Ordering}; +use core::cmp::{Ordering, min}; use core::task::Waker; use heapless::Vec; diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index bad6ecf97..05614dbf5 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-time" version = "0.5.0" -edition = "2021" +edition = "2024" description = "Instant and Duration for embedded no-std systems, with async timer support" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-time" diff --git a/embassy-time/src/duration.rs b/embassy-time/src/duration.rs index b3ea0468d..b2bfd6de9 100644 --- a/embassy-time/src/duration.rs +++ b/embassy-time/src/duration.rs @@ -175,13 +175,7 @@ impl Duration { /// NOTE: Giving this function a hz >= the TICK_HZ of your platform will clamp the Duration to 1 /// tick. Doing so will not deadlock, but will certainly not produce the desired output. pub const fn from_hz(hz: u64) -> Duration { - let ticks = { - if hz >= TICK_HZ { - 1 - } else { - (TICK_HZ + hz / 2) / hz - } - }; + let ticks = { if hz >= TICK_HZ { 1 } else { (TICK_HZ + hz / 2) / hz } }; Duration { ticks } } diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs index 77f4b344d..e375fe93e 100644 --- a/embassy-time/src/lib.rs +++ b/embassy-time/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(any(feature = "std", feature = "wasm", test)), no_std)] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![allow(clippy::new_without_default)] #![warn(missing_docs)] @@ -27,18 +28,14 @@ mod driver_std; #[cfg(feature = "wasm")] mod driver_wasm; -pub use delay::{block_for, Delay}; +pub use delay::{Delay, block_for}; pub use duration::Duration; pub use embassy_time_driver::TICK_HZ; pub use instant::Instant; -pub use timer::{with_deadline, with_timeout, Ticker, TimeoutError, Timer, WithTimeout}; +pub use timer::{Ticker, TimeoutError, Timer, WithTimeout, with_deadline, with_timeout}; const fn gcd(a: u64, b: u64) -> u64 { - if b == 0 { - a - } else { - gcd(b, a % b) - } + if b == 0 { a } else { gcd(b, a % b) } } pub(crate) const GCD_1K: u64 = gcd(TICK_HZ, 1_000); diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index fcf79f58e..2f5967c63 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -1,9 +1,9 @@ -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::pin::Pin; use core::task::{Context, Poll}; -use futures_core::stream::FusedStream; use futures_core::Stream; +use futures_core::stream::FusedStream; use crate::{Duration, Instant}; diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index e70ab970e..8b32582c0 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-usb-dfu" version = "0.2.0" description = "An implementation of the USB DFU 1.1 protocol, using embassy-boot" diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs index 78eb2c083..1ea1a74fe 100644 --- a/embassy-usb-dfu/src/application.rs +++ b/embassy-usb-dfu/src/application.rs @@ -6,11 +6,11 @@ use embassy_usb::driver::Driver; use embassy_usb::{Builder, FunctionBuilder, Handler}; use embedded_storage::nor_flash::NorFlash; +use crate::Reset; use crate::consts::{ - DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_RT, + APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_RT, DfuAttributes, Request, State, Status, USB_CLASS_APPN_SPEC, }; -use crate::Reset; /// Generic interface for a system that can signal to the bootloader that USB DFU mode is needed on the next boot. /// diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs index 7c28d04cf..2ed4511ce 100644 --- a/embassy-usb-dfu/src/dfu.rs +++ b/embassy-usb-dfu/src/dfu.rs @@ -5,11 +5,11 @@ use embassy_usb::driver::Driver; use embassy_usb::{Builder, FunctionBuilder, Handler}; use embedded_storage::nor_flash::{NorFlash, NorFlashErrorKind}; +use crate::Reset; use crate::consts::{ - DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_DFU, + APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_DFU, DfuAttributes, Request, State, Status, USB_CLASS_APPN_SPEC, }; -use crate::Reset; /// Internal state for USB DFU pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> { diff --git a/embassy-usb-driver/Cargo.toml b/embassy-usb-driver/Cargo.toml index 6e4c31273..3f43f60a3 100644 --- a/embassy-usb-driver/Cargo.toml +++ b/embassy-usb-driver/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-usb-driver" version = "0.2.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Driver trait for `embassy-usb`, an async USB device stack for embedded devices." keywords = ["embedded", "async", "usb", "hal", "embedded-hal"] diff --git a/embassy-usb-driver/src/lib.rs b/embassy-usb-driver/src/lib.rs index 59845a268..f19e0a401 100644 --- a/embassy-usb-driver/src/lib.rs +++ b/embassy-usb-driver/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml index 6d13653bf..683821759 100644 --- a/embassy-usb-logger/Cargo.toml +++ b/embassy-usb-logger/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-usb-logger" version = "0.5.1" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "`log` implementation for USB serial using `embassy-usb`." keywords = ["embedded", "log", "usb", "hal", "serial"] diff --git a/embassy-usb-synopsys-otg/Cargo.toml b/embassy-usb-synopsys-otg/Cargo.toml index 61b14a215..eca68095d 100644 --- a/embassy-usb-synopsys-otg/Cargo.toml +++ b/embassy-usb-synopsys-otg/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-usb-synopsys-otg" version = "0.3.1" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "`embassy-usb-driver` implementation for Synopsys OTG USB controllers" keywords = ["embedded", "async", "usb", "hal", "embedded-hal"] diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs index 6b4a87bdf..d94209f45 100644 --- a/embassy-usb-synopsys-otg/src/lib.rs +++ b/embassy-usb-synopsys-otg/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(test), no_std)] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] @@ -22,7 +23,7 @@ use crate::fmt::Bytes; pub mod otg_v1; -use otg_v1::{regs, vals, Otg}; +use otg_v1::{Otg, regs, vals}; /// Handle interrupts. pub unsafe fn on_interrupt(r: Otg, state: &State, ep_count: usize) { @@ -679,9 +680,7 @@ impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> { if let Some(ep) = self.ep_in[i] { trace!( "configuring tx fifo ep={}, offset={}, size={}", - i, - fifo_top, - ep.fifo_size_words + i, fifo_top, ep.fifo_size_words ); let dieptxf = if i == 0 { regs.dieptxf0() } else { regs.dieptxf(i - 1) }; @@ -1158,9 +1157,7 @@ impl<'d> embassy_usb_driver::EndpointIn for Endpoint<'d, In> { let dtxfsts = self.regs.dtxfsts(index).read(); trace!( "write ep={:?}: diepctl {:08x} ftxfsts {:08x}", - self.info.addr, - diepctl.0, - dtxfsts.0 + self.info.addr, diepctl.0, dtxfsts.0 ); if !diepctl.usbaep() { trace!("write ep={:?} wait for prev: error disabled", self.info.addr); @@ -1375,11 +1372,7 @@ fn ep_irq_mask(eps: &[Option]) -> u16 { eps.iter().enumerate().fold( 0, |mask, (index, ep)| { - if ep.is_some() { - mask | (1 << index) - } else { - mask - } + if ep.is_some() { mask | (1 << index) } else { mask } }, ) } diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index bff48c4a6..aeb7392f1 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-usb" version = "0.5.1" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Async USB device stack for embedded devices in Rust." keywords = ["embedded", "async", "usb", "hal", "embedded-hal"] diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index 8d7abe46c..6fc2a5a22 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -5,7 +5,7 @@ use crate::descriptor::{BosWriter, DescriptorWriter, SynchronizationType, UsageT use crate::driver::{Driver, Endpoint, EndpointAddress, EndpointInfo, EndpointType}; use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter}; use crate::types::{InterfaceNumber, StringIndex}; -use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; +use crate::{Handler, Interface, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START, UsbDevice}; #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -176,7 +176,9 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { if config.composite_with_iads && (config.device_class != 0xEF || config.device_sub_class != 0x02 || config.device_protocol != 0x01) { - panic!("if composite_with_iads is set, you must set device_class = 0xEF, device_sub_class = 0x02, device_protocol = 0x01"); + panic!( + "if composite_with_iads is set, you must set device_class = 0xEF, device_sub_class = 0x02, device_protocol = 0x01" + ); } assert!( @@ -337,7 +339,8 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> { num_alt_settings: 0, }; - assert!(self.builder.interfaces.push(iface).is_ok(), + assert!( + self.builder.interfaces.push(iface).is_ok(), "embassy-usb: interface list full. Increase the `max_interface_count` compile-time setting. Current value: {}", MAX_INTERFACE_COUNT ); diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs index 0a1a5e64f..388e21fbd 100644 --- a/embassy-usb/src/class/cdc_acm.rs +++ b/embassy-usb/src/class/cdc_acm.rs @@ -1,7 +1,7 @@ //! CDC-ACM class implementation, aka Serial over USB. use core::cell::{Cell, RefCell}; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::mem::{self, MaybeUninit}; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; diff --git a/embassy-usb/src/class/cdc_ncm/embassy_net.rs b/embassy-usb/src/class/cdc_ncm/embassy_net.rs index 57d322946..c83ff468a 100644 --- a/embassy-usb/src/class/cdc_ncm/embassy_net.rs +++ b/embassy-usb/src/class/cdc_ncm/embassy_net.rs @@ -1,6 +1,6 @@ //! [`embassy-net`](https://crates.io/crates/embassy-net) driver for the CDC-NCM class. -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::LinkState; use embassy_usb_driver::Driver; diff --git a/embassy-usb/src/class/cdc_ncm/mod.rs b/embassy-usb/src/class/cdc_ncm/mod.rs index 3af853091..9b6dd9f21 100644 --- a/embassy-usb/src/class/cdc_ncm/mod.rs +++ b/embassy-usb/src/class/cdc_ncm/mod.rs @@ -14,7 +14,7 @@ //! This is due to regex spaghetti: //! and this nonsense in the linux kernel: -use core::mem::{size_of, MaybeUninit}; +use core::mem::{MaybeUninit, size_of}; use core::ptr::{addr_of, copy_nonoverlapping}; use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType}; diff --git a/embassy-usb/src/class/cmsis_dap_v2.rs b/embassy-usb/src/class/cmsis_dap_v2.rs index a9fd9cdf0..0e2356f17 100644 --- a/embassy-usb/src/class/cmsis_dap_v2.rs +++ b/embassy-usb/src/class/cmsis_dap_v2.rs @@ -4,7 +4,7 @@ use core::mem::MaybeUninit; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; use crate::types::StringIndex; -use crate::{msos, Builder, Handler}; +use crate::{Builder, Handler, msos}; /// State for the CMSIS-DAP v2 USB class. pub struct State { diff --git a/embassy-usb/src/class/midi.rs b/embassy-usb/src/class/midi.rs index 1d152ca44..d29172be1 100644 --- a/embassy-usb/src/class/midi.rs +++ b/embassy-usb/src/class/midi.rs @@ -1,7 +1,7 @@ //! MIDI class implementation. -use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; use crate::Builder; +use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; /// This should be used as `device_class` when building the `UsbDevice`. pub const USB_AUDIO_CLASS: u8 = 0x01; diff --git a/embassy-usb/src/class/uac1/speaker.rs b/embassy-usb/src/class/uac1/speaker.rs index 9565e2a25..46e0420d5 100644 --- a/embassy-usb/src/class/uac1/speaker.rs +++ b/embassy-usb/src/class/uac1/speaker.rs @@ -11,7 +11,7 @@ //! The class provides volume and mute controls for each channel. use core::cell::{Cell, RefCell}; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::sync::atomic::{AtomicBool, AtomicU32, Ordering}; use core::task::Poll; @@ -22,7 +22,7 @@ use heapless::Vec; use super::class_codes::*; use super::terminal_type::TerminalType; -use super::{Channel, ChannelConfig, FeedbackRefresh, SampleWidth, MAX_AUDIO_CHANNEL_COUNT, MAX_AUDIO_CHANNEL_INDEX}; +use super::{Channel, ChannelConfig, FeedbackRefresh, MAX_AUDIO_CHANNEL_COUNT, MAX_AUDIO_CHANNEL_INDEX, SampleWidth}; use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType}; use crate::descriptor::{SynchronizationType, UsageType}; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut, EndpointType}; diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index e9a6fd79a..c79dd02eb 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs @@ -1,10 +1,10 @@ //! Utilities for writing USB descriptors. use embassy_usb_driver::EndpointType; +use crate::CONFIGURATION_VALUE; use crate::builder::Config; use crate::driver::EndpointInfo; use crate::types::{InterfaceNumber, StringIndex}; -use crate::CONFIGURATION_VALUE; /// Standard descriptor types #[allow(missing_docs)] diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index 0638fd0a2..0c10c08df 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] @@ -20,7 +21,7 @@ mod config { include!(concat!(env!("OUT_DIR"), "/config.rs")); } -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use heapless::Vec; pub use crate::builder::{Builder, Config, FunctionBuilder, InterfaceAltBuilder, InterfaceBuilder, UsbVersion}; diff --git a/embassy-usb/src/msos.rs b/embassy-usb/src/msos.rs index 9f4e1a57b..66689871e 100644 --- a/embassy-usb/src/msos.rs +++ b/embassy-usb/src/msos.rs @@ -4,7 +4,7 @@ use core::mem::size_of; -use crate::descriptor::{capability_type, BosWriter}; +use crate::descriptor::{BosWriter, capability_type}; use crate::types::InterfaceNumber; /// A serialized Microsoft OS 2.0 Descriptor set. diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index f5f89ecb5..55053bc33 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-nrf-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index d86386b00..70a2c28c3 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-rp-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index cd5f422fc..2dc75d939 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32f3-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index c3921a166..5c372fb19 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32f7-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index ca186d4d9..641a2ba96 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32h7-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index be08956f1..4a168be15 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32l0-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 207eed733..af2cb3881 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32l1-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 22b9642d8..032e934aa 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32l4-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index e2be4f470..ea4c26681 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32wb-dfu-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs index 5e7b71f5a..1ae28bf3a 100644 --- a/examples/boot/application/stm32wb-dfu/src/main.rs +++ b/examples/boot/application/stm32wb-dfu/src/main.rs @@ -13,9 +13,9 @@ use embassy_stm32::usb::{self, Driver}; use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::Mutex; use embassy_time::Duration; -use embassy_usb::{msos, Builder}; +use embassy_usb::{Builder, msos}; use embassy_usb_dfu::consts::DfuAttributes; -use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; +use embassy_usb_dfu::{Control, ResetImmediate, usb_dfu}; use panic_reset as _; bind_interrupts!(struct Irqs { diff --git a/examples/boot/application/stm32wba-dfu/Cargo.toml b/examples/boot/application/stm32wba-dfu/Cargo.toml index 6f4213b2c..d6f7dc3b6 100644 --- a/examples/boot/application/stm32wba-dfu/Cargo.toml +++ b/examples/boot/application/stm32wba-dfu/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32wba-dfu-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32wba-dfu/src/main.rs b/examples/boot/application/stm32wba-dfu/src/main.rs index bf17a7150..8adb2e7c0 100644 --- a/examples/boot/application/stm32wba-dfu/src/main.rs +++ b/examples/boot/application/stm32wba-dfu/src/main.rs @@ -12,9 +12,9 @@ use embassy_stm32::usb::{self, Driver}; use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::Mutex; use embassy_time::Duration; -use embassy_usb::{msos, Builder}; +use embassy_usb::{Builder, msos}; use embassy_usb_dfu::consts::DfuAttributes; -use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; +use embassy_usb_dfu::{Control, ResetImmediate, usb_dfu}; use panic_reset as _; bind_interrupts!(struct Irqs { diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 8d1446ba9..c7fa811c9 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32wl-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs index e4526927f..3f381fd80 100644 --- a/examples/boot/application/stm32wl/src/bin/a.rs +++ b/examples/boot/application/stm32wl/src/bin/a.rs @@ -8,10 +8,10 @@ use defmt_rtt::*; use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; +use embassy_stm32::SharedData; use embassy_stm32::exti::ExtiInput; use embassy_stm32::flash::{Flash, WRITE_SIZE}; use embassy_stm32::gpio::{Level, Output, Pull, Speed}; -use embassy_stm32::SharedData; use embassy_sync::mutex::Mutex; use panic_reset as _; diff --git a/examples/boot/application/stm32wl/src/bin/b.rs b/examples/boot/application/stm32wl/src/bin/b.rs index 6016a9555..952e94a58 100644 --- a/examples/boot/application/stm32wl/src/bin/b.rs +++ b/examples/boot/application/stm32wl/src/bin/b.rs @@ -6,8 +6,8 @@ use core::mem::MaybeUninit; #[cfg(feature = "defmt")] use defmt_rtt::*; use embassy_executor::Spawner; -use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::SharedData; +use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_time::Timer; use panic_reset as _; diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml index 72b7114d4..1fea2b7d7 100644 --- a/examples/boot/bootloader/nrf/Cargo.toml +++ b/examples/boot/bootloader/nrf/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "nrf-bootloader-example" version = "0.1.0" description = "Bootloader for nRF chips" diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs index b849a0df3..76c4c1048 100644 --- a/examples/boot/bootloader/nrf/src/main.rs +++ b/examples/boot/bootloader/nrf/src/main.rs @@ -38,8 +38,8 @@ fn main() -> ! { unsafe { bl.load(active_offset) } } -#[no_mangle] -#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +#[unsafe(no_mangle)] +#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))] unsafe extern "C" fn HardFault() { cortex_m::peripheral::SCB::sys_reset(); } @@ -47,7 +47,7 @@ unsafe extern "C" fn HardFault() { #[exception] unsafe fn DefaultHandler(_: i16) -> ! { const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16; panic!("DefaultHandler #{:?}", irqn); } diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml index 93a1c4edf..188bcab36 100644 --- a/examples/boot/bootloader/rp/Cargo.toml +++ b/examples/boot/bootloader/rp/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "rp-bootloader-example" version = "0.1.0" description = "Example bootloader for RP2040 chips" diff --git a/examples/boot/bootloader/rp/src/main.rs b/examples/boot/bootloader/rp/src/main.rs index 25b1657b8..7ebefd374 100644 --- a/examples/boot/bootloader/rp/src/main.rs +++ b/examples/boot/bootloader/rp/src/main.rs @@ -34,8 +34,8 @@ fn main() -> ! { unsafe { bl.load(embassy_rp::flash::FLASH_BASE as u32 + active_offset) } } -#[no_mangle] -#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +#[unsafe(no_mangle)] +#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))] unsafe extern "C" fn HardFault() { cortex_m::peripheral::SCB::sys_reset(); } @@ -43,7 +43,7 @@ unsafe extern "C" fn HardFault() { #[exception] unsafe fn DefaultHandler(_: i16) -> ! { const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16; panic!("DefaultHandler #{:?}", irqn); } diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml index 95ca20a59..cf68921dc 100644 --- a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml +++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "stm32-bootloader-dual-bank-flash-example" version = "0.1.0" description = "Example bootloader for dual-bank flash STM32 chips" diff --git a/examples/boot/bootloader/stm32-dual-bank/src/main.rs b/examples/boot/bootloader/stm32-dual-bank/src/main.rs index 4d2e82d26..f0063fb5c 100644 --- a/examples/boot/bootloader/stm32-dual-bank/src/main.rs +++ b/examples/boot/bootloader/stm32-dual-bank/src/main.rs @@ -7,7 +7,7 @@ use cortex_m_rt::{entry, exception}; #[cfg(feature = "defmt")] use defmt_rtt as _; use embassy_boot_stm32::*; -use embassy_stm32::flash::{Flash, BANK1_REGION}; +use embassy_stm32::flash::{BANK1_REGION, Flash}; use embassy_sync::blocking_mutex::Mutex; #[entry] @@ -33,8 +33,8 @@ fn main() -> ! { unsafe { bl.load(BANK1_REGION.base + active_offset) } } -#[no_mangle] -#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +#[unsafe(no_mangle)] +#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))] unsafe extern "C" fn HardFault() { cortex_m::peripheral::SCB::sys_reset(); } @@ -42,7 +42,7 @@ unsafe extern "C" fn HardFault() { #[exception] unsafe fn DefaultHandler(_: i16) -> ! { const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16; panic!("DefaultHandler #{:?}", irqn); } diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml index 526637f37..e457310b9 100644 --- a/examples/boot/bootloader/stm32/Cargo.toml +++ b/examples/boot/bootloader/stm32/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "stm32-bootloader-example" version = "0.1.0" description = "Example bootloader for STM32 chips" diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs index 99a7a6a6b..383ad912d 100644 --- a/examples/boot/bootloader/stm32/src/main.rs +++ b/examples/boot/bootloader/stm32/src/main.rs @@ -7,7 +7,7 @@ use cortex_m_rt::{entry, exception}; #[cfg(feature = "defmt")] use defmt_rtt as _; use embassy_boot_stm32::*; -use embassy_stm32::flash::{Flash, BANK1_REGION}; +use embassy_stm32::flash::{BANK1_REGION, Flash}; use embassy_sync::blocking_mutex::Mutex; #[entry] @@ -32,8 +32,8 @@ fn main() -> ! { unsafe { bl.load(BANK1_REGION.base + active_offset) } } -#[no_mangle] -#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +#[unsafe(no_mangle)] +#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))] unsafe extern "C" fn HardFault() { cortex_m::peripheral::SCB::sys_reset(); } @@ -41,7 +41,7 @@ unsafe extern "C" fn HardFault() { #[exception] unsafe fn DefaultHandler(_: i16) -> ! { const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16; panic!("DefaultHandler #{:?}", irqn); } diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index ef10aeabf..75b7081df 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "stm32wb-dfu-bootloader-example" version = "0.1.0" description = "Example USB DFUbootloader for the STM32WB series of chips" diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index 107f243fd..9ee82846d 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -7,14 +7,14 @@ use cortex_m_rt::{entry, exception}; #[cfg(feature = "defmt")] use defmt_rtt as _; use embassy_boot_stm32::*; -use embassy_stm32::flash::{Flash, BANK1_REGION, WRITE_SIZE}; +use embassy_stm32::flash::{BANK1_REGION, Flash, WRITE_SIZE}; use embassy_stm32::rcc::WPAN_DEFAULT; use embassy_stm32::usb::Driver; use embassy_stm32::{bind_interrupts, peripherals, usb}; use embassy_sync::blocking_mutex::Mutex; -use embassy_usb::{msos, Builder}; +use embassy_usb::{Builder, msos}; use embassy_usb_dfu::consts::DfuAttributes; -use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; +use embassy_usb_dfu::{Control, ResetImmediate, usb_dfu}; bind_interrupts!(struct Irqs { USB_LP => usb::InterruptHandler; @@ -109,8 +109,8 @@ fn main() -> ! { unsafe { bl.load(BANK1_REGION.base + active_offset) } } -#[no_mangle] -#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +#[unsafe(no_mangle)] +#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))] unsafe extern "C" fn HardFault() { cortex_m::peripheral::SCB::sys_reset(); } @@ -118,7 +118,7 @@ unsafe extern "C" fn HardFault() { #[exception] unsafe fn DefaultHandler(_: i16) -> ! { const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16; panic!("DefaultHandler #{:?}", irqn); } diff --git a/examples/boot/bootloader/stm32wba-dfu/Cargo.toml b/examples/boot/bootloader/stm32wba-dfu/Cargo.toml index 16de7684e..eee2b2f71 100644 --- a/examples/boot/bootloader/stm32wba-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wba-dfu/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "stm32wba6-dfu-bootloader-example" version = "0.1.0" description = "Example USB DFUbootloader for the STM32WBA series of chips" diff --git a/examples/boot/bootloader/stm32wba-dfu/src/main.rs b/examples/boot/bootloader/stm32wba-dfu/src/main.rs index 75d8d4199..b33a75d95 100644 --- a/examples/boot/bootloader/stm32wba-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wba-dfu/src/main.rs @@ -7,13 +7,13 @@ use cortex_m_rt::{entry, exception}; #[cfg(feature = "defmt")] use defmt_rtt as _; use embassy_boot_stm32::*; -use embassy_stm32::flash::{Flash, BANK1_REGION, WRITE_SIZE}; +use embassy_stm32::flash::{BANK1_REGION, Flash, WRITE_SIZE}; use embassy_stm32::usb::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_sync::blocking_mutex::Mutex; -use embassy_usb::{msos, Builder}; +use embassy_usb::{Builder, msos}; use embassy_usb_dfu::consts::DfuAttributes; -use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; +use embassy_usb_dfu::{Control, ResetImmediate, usb_dfu}; bind_interrupts!(struct Irqs { USB_OTG_HS => usb::InterruptHandler; @@ -138,8 +138,8 @@ fn main() -> ! { unsafe { bl.load(BANK1_REGION.base + active_offset) } } -#[no_mangle] -#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +#[unsafe(no_mangle)] +#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))] unsafe extern "C" fn HardFault() { cortex_m::peripheral::SCB::sys_reset(); } @@ -147,7 +147,7 @@ unsafe extern "C" fn HardFault() { #[exception] unsafe fn DefaultHandler(_: i16) -> ! { const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16; panic!("DefaultHandler #{:?}", irqn); } diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml index 579748595..94903b3f8 100644 --- a/examples/lpc55s69/Cargo.toml +++ b/examples/lpc55s69/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nxp-lpc55s69-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/mimxrt1011/Cargo.toml b/examples/mimxrt1011/Cargo.toml index 3038f5d4d..d784ce729 100644 --- a/examples/mimxrt1011/Cargo.toml +++ b/examples/mimxrt1011/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-imxrt1011-examples" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/examples/mimxrt1011/src/lib.rs b/examples/mimxrt1011/src/lib.rs index f0391ef57..36d3e2fb3 100644 --- a/examples/mimxrt1011/src/lib.rs +++ b/examples/mimxrt1011/src/lib.rs @@ -71,5 +71,5 @@ pub const SERIAL_NOR_CONFIGURATION_BLOCK: nor::ConfigurationBlock = .ip_cmd_serial_clk_freq(nor::SerialClockFrequency::MHz30); #[unsafe(no_mangle)] -#[cfg_attr(all(target_arch = "arm", target_os = "none"), link_section = ".fcb")] +#[cfg_attr(all(target_arch = "arm", target_os = "none"), unsafe(link_section = ".fcb"))] pub static FLEXSPI_CONFIGURATION_BLOCK: nor::ConfigurationBlock = SERIAL_NOR_CONFIGURATION_BLOCK; diff --git a/examples/mimxrt1062-evk/Cargo.toml b/examples/mimxrt1062-evk/Cargo.toml index 82a24490d..29a80db12 100644 --- a/examples/mimxrt1062-evk/Cargo.toml +++ b/examples/mimxrt1062-evk/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-imxrt1062-evk-examples" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/examples/mimxrt1062-evk/src/lib.rs b/examples/mimxrt1062-evk/src/lib.rs index 3f99f9db3..e952b91ec 100644 --- a/examples/mimxrt1062-evk/src/lib.rs +++ b/examples/mimxrt1062-evk/src/lib.rs @@ -55,6 +55,6 @@ pub const SERIAL_NOR_CONFIGURATION_BLOCK: nor::ConfigurationBlock = .sector_size(4096) .ip_cmd_serial_clk_freq(nor::SerialClockFrequency::MHz30); -#[no_mangle] -#[cfg_attr(all(target_arch = "arm", target_os = "none"), link_section = ".fcb")] +#[unsafe(no_mangle)] +#[cfg_attr(all(target_arch = "arm", target_os = "none"), unsafe(link_section = ".fcb"))] pub static FLEXSPI_CONFIGURATION_BLOCK: nor::ConfigurationBlock = SERIAL_NOR_CONFIGURATION_BLOCK; diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml index 3f7ad8485..dc09e97e7 100644 --- a/examples/mimxrt6/Cargo.toml +++ b/examples/mimxrt6/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-imxrt-examples" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/examples/mimxrt6/src/bin/button.rs b/examples/mimxrt6/src/bin/button.rs index efb7f14af..a9bdde98e 100644 --- a/examples/mimxrt6/src/bin/button.rs +++ b/examples/mimxrt6/src/bin/button.rs @@ -3,7 +3,7 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_imxrt::gpio; use {defmt_rtt as _, embassy_imxrt_examples as _, panic_probe as _}; diff --git a/examples/mspm0c1104/Cargo.toml b/examples/mspm0c1104/Cargo.toml index 21434106a..74301bc9c 100644 --- a/examples/mspm0c1104/Cargo.toml +++ b/examples/mspm0c1104/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-mspm0-c1104-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/mspm0c1104/src/bin/blinky.rs b/examples/mspm0c1104/src/bin/blinky.rs index 0d974cc5e..345077b37 100644 --- a/examples/mspm0c1104/src/bin/blinky.rs +++ b/examples/mspm0c1104/src/bin/blinky.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Level, Output}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Level, Output}; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0c1104/src/bin/button.rs b/examples/mspm0c1104/src/bin/button.rs index 7face1618..557d997cd 100644 --- a/examples/mspm0c1104/src/bin/button.rs +++ b/examples/mspm0c1104/src/bin/button.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use {defmt_rtt as _, panic_halt as _}; #[embassy_executor::main] diff --git a/examples/mspm0g3507/Cargo.toml b/examples/mspm0g3507/Cargo.toml index 616b82adb..8c230f038 100644 --- a/examples/mspm0g3507/Cargo.toml +++ b/examples/mspm0g3507/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-mspm0-g3507-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/mspm0g3507/src/bin/adc.rs b/examples/mspm0g3507/src/bin/adc.rs index ceccc7c02..cf1abb471 100644 --- a/examples/mspm0g3507/src/bin/adc.rs +++ b/examples/mspm0g3507/src/bin/adc.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_mspm0::adc::{self, Adc, Vrsel}; -use embassy_mspm0::{bind_interrupts, peripherals, Config}; +use embassy_mspm0::{Config, bind_interrupts, peripherals}; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0g3507/src/bin/blinky.rs b/examples/mspm0g3507/src/bin/blinky.rs index 055a5cd81..47eaf1535 100644 --- a/examples/mspm0g3507/src/bin/blinky.rs +++ b/examples/mspm0g3507/src/bin/blinky.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Level, Output}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Level, Output}; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0g3507/src/bin/button.rs b/examples/mspm0g3507/src/bin/button.rs index cde1f2892..76f3a1aba 100644 --- a/examples/mspm0g3507/src/bin/button.rs +++ b/examples/mspm0g3507/src/bin/button.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use {defmt_rtt as _, panic_halt as _}; #[embassy_executor::main] diff --git a/examples/mspm0g3507/src/bin/i2c_target.rs b/examples/mspm0g3507/src/bin/i2c_target.rs new file mode 100644 index 000000000..5dd718eaf --- /dev/null +++ b/examples/mspm0g3507/src/bin/i2c_target.rs @@ -0,0 +1,63 @@ +//! Example of using async I2C target +//! +//! This uses the virtual COM port provided on the LP-MSPM0G3507 board. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::i2c::Config; +use embassy_mspm0::i2c_target::{Command, Config as TargetConfig, I2cTarget, ReadStatus}; +use embassy_mspm0::peripherals::I2C1; +use embassy_mspm0::{bind_interrupts, i2c}; +use {defmt_rtt as _, panic_halt as _}; + +bind_interrupts!(struct Irqs { + I2C1 => i2c::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let p = embassy_mspm0::init(Default::default()); + + let instance = p.I2C1; + let scl = p.PB2; + let sda = p.PB3; + + let config = Config::default(); + let mut target_config = TargetConfig::default(); + target_config.target_addr = 0x48; + target_config.general_call = true; + let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config, target_config).unwrap(); + + let mut read = [0u8; 8]; + let data = [8u8; 2]; + let data_wr = [9u8; 2]; + + loop { + match i2c.listen(&mut read).await { + Ok(Command::GeneralCall(_)) => info!("General call received"), + Ok(Command::Read) => { + info!("Read command received"); + match i2c.respond_to_read(&data).await.unwrap() { + ReadStatus::Done => info!("Finished reading"), + ReadStatus::NeedMoreBytes => { + info!("Read needs more bytes - will reset"); + i2c.reset().unwrap(); + } + ReadStatus::LeftoverBytes(_) => { + info!("Leftover bytes received"); + i2c.flush_tx_fifo(); + } + } + } + Ok(Command::Write(_)) => info!("Write command received"), + Ok(Command::WriteRead(_)) => { + info!("Write-Read command received"); + i2c.respond_and_fill(&data_wr, 0xFE).await.unwrap(); + } + Err(e) => info!("Got error {}", e), + } + } +} diff --git a/examples/mspm0g3519/Cargo.toml b/examples/mspm0g3519/Cargo.toml index ae699d6f4..0f5e58343 100644 --- a/examples/mspm0g3519/Cargo.toml +++ b/examples/mspm0g3519/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-mspm0-g3519-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/mspm0g3519/src/bin/blinky.rs b/examples/mspm0g3519/src/bin/blinky.rs index 055a5cd81..47eaf1535 100644 --- a/examples/mspm0g3519/src/bin/blinky.rs +++ b/examples/mspm0g3519/src/bin/blinky.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Level, Output}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Level, Output}; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0g3519/src/bin/button.rs b/examples/mspm0g3519/src/bin/button.rs index c81cc2918..21e7873d8 100644 --- a/examples/mspm0g3519/src/bin/button.rs +++ b/examples/mspm0g3519/src/bin/button.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use {defmt_rtt as _, panic_halt as _}; #[embassy_executor::main] diff --git a/examples/mspm0l1306/Cargo.toml b/examples/mspm0l1306/Cargo.toml index 8100e11da..d5b5e9d3e 100644 --- a/examples/mspm0l1306/Cargo.toml +++ b/examples/mspm0l1306/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-mspm0-l1306-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/mspm0l1306/src/bin/adc.rs b/examples/mspm0l1306/src/bin/adc.rs index 2806b98cc..235396b8a 100644 --- a/examples/mspm0l1306/src/bin/adc.rs +++ b/examples/mspm0l1306/src/bin/adc.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_mspm0::adc::{self, Adc, Vrsel}; -use embassy_mspm0::{bind_interrupts, peripherals, Config}; +use embassy_mspm0::{Config, bind_interrupts, peripherals}; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0l1306/src/bin/blinky.rs b/examples/mspm0l1306/src/bin/blinky.rs index 055a5cd81..47eaf1535 100644 --- a/examples/mspm0l1306/src/bin/blinky.rs +++ b/examples/mspm0l1306/src/bin/blinky.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Level, Output}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Level, Output}; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0l1306/src/bin/button.rs b/examples/mspm0l1306/src/bin/button.rs index d8c85947f..33e682272 100644 --- a/examples/mspm0l1306/src/bin/button.rs +++ b/examples/mspm0l1306/src/bin/button.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use {defmt_rtt as _, panic_halt as _}; #[embassy_executor::main] diff --git a/examples/mspm0l1306/src/bin/i2c_target.rs b/examples/mspm0l1306/src/bin/i2c_target.rs new file mode 100644 index 000000000..4d147d08b --- /dev/null +++ b/examples/mspm0l1306/src/bin/i2c_target.rs @@ -0,0 +1,63 @@ +//! Example of using async I2C target +//! +//! This uses the virtual COM port provided on the LP-MSPM0L1306 board. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::i2c::Config; +use embassy_mspm0::i2c_target::{Command, Config as TargetConfig, I2cTarget, ReadStatus}; +use embassy_mspm0::peripherals::I2C0; +use embassy_mspm0::{bind_interrupts, i2c}; +use {defmt_rtt as _, panic_halt as _}; + +bind_interrupts!(struct Irqs { + I2C0 => i2c::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let p = embassy_mspm0::init(Default::default()); + + let instance = p.I2C0; + let scl = p.PA1; + let sda = p.PA0; + + let config = Config::default(); + let mut target_config = TargetConfig::default(); + target_config.target_addr = 0x48; + target_config.general_call = true; + let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config, target_config).unwrap(); + + let mut read = [0u8; 8]; + let data = [8u8; 2]; + let data_wr = [9u8; 2]; + + loop { + match i2c.listen(&mut read).await { + Ok(Command::GeneralCall(_)) => info!("General call received"), + Ok(Command::Read) => { + info!("Read command received"); + match i2c.respond_to_read(&data).await.unwrap() { + ReadStatus::Done => info!("Finished reading"), + ReadStatus::NeedMoreBytes => { + info!("Read needs more bytes - will reset"); + i2c.reset().unwrap(); + } + ReadStatus::LeftoverBytes(_) => { + info!("Leftover bytes received"); + i2c.flush_tx_fifo(); + } + } + } + Ok(Command::Write(_)) => info!("Write command received"), + Ok(Command::WriteRead(_)) => { + info!("Write-Read command received"); + i2c.respond_and_fill(&data_wr, 0xFE).await.unwrap(); + } + Err(e) => info!("Got error {}", e), + } + } +} diff --git a/examples/mspm0l2228/Cargo.toml b/examples/mspm0l2228/Cargo.toml index 3add7b8e8..1d27ae64a 100644 --- a/examples/mspm0l2228/Cargo.toml +++ b/examples/mspm0l2228/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-mspm0-l2228-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/mspm0l2228/src/bin/blinky.rs b/examples/mspm0l2228/src/bin/blinky.rs index 055a5cd81..47eaf1535 100644 --- a/examples/mspm0l2228/src/bin/blinky.rs +++ b/examples/mspm0l2228/src/bin/blinky.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Level, Output}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Level, Output}; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0l2228/src/bin/button.rs b/examples/mspm0l2228/src/bin/button.rs index 47bfd274b..bad1cb138 100644 --- a/examples/mspm0l2228/src/bin/button.rs +++ b/examples/mspm0l2228/src/bin/button.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use {defmt_rtt as _, panic_halt as _}; #[embassy_executor::main] diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index d2d0ae093..5caabf228 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf-rtos-trace-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index 082d85e5b..c7492f562 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf51-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index 7835320e5..1711a3d8d 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf52810-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf52840-edf/Cargo.toml b/examples/nrf52840-edf/Cargo.toml index 67a624d6d..8b1db4652 100644 --- a/examples/nrf52840-edf/Cargo.toml +++ b/examples/nrf52840-edf/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf52840-edf-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf52840-edf/src/bin/basic.rs b/examples/nrf52840-edf/src/bin/basic.rs index d888e17d1..f7214790d 100644 --- a/examples/nrf52840-edf/src/bin/basic.rs +++ b/examples/nrf52840-edf/src/bin/basic.rs @@ -12,7 +12,7 @@ #![no_std] #![no_main] -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use defmt::unwrap; use embassy_executor::Spawner; diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index d860626a1..26b21598f 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf52840-rtic-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf52840-rtic/src/bin/blinky.rs b/examples/nrf52840-rtic/src/bin/blinky.rs index 2adac7e0a..671082117 100644 --- a/examples/nrf52840-rtic/src/bin/blinky.rs +++ b/examples/nrf52840-rtic/src/bin/blinky.rs @@ -7,7 +7,7 @@ use {defmt_rtt as _, panic_probe as _}; mod app { use defmt::info; use embassy_nrf::gpio::{Level, Output, OutputDrive}; - use embassy_nrf::{peripherals, Peri}; + use embassy_nrf::{Peri, peripherals}; use embassy_time::Timer; #[shared] diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 5b3e176c0..a026d6352 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf52840-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf52840/src/bin/channel_sender_receiver.rs b/examples/nrf52840/src/bin/channel_sender_receiver.rs index 09050db68..de694eaa0 100644 --- a/examples/nrf52840/src/bin/channel_sender_receiver.rs +++ b/examples/nrf52840/src/bin/channel_sender_receiver.rs @@ -3,8 +3,8 @@ use defmt::unwrap; use embassy_executor::Spawner; -use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive}; use embassy_nrf::Peri; +use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::channel::{Channel, Receiver, Sender}; use embassy_time::Timer; diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs index e59afd37f..5a988d89b 100644 --- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs +++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_net::tcp::TcpSocket; use embassy_net::StackResources; +use embassy_net::tcp::TcpSocket; use embassy_net_enc28j60::Enc28j60; use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::rng::Rng; diff --git a/examples/nrf52840/src/bin/i2s_effect.rs b/examples/nrf52840/src/bin/i2s_effect.rs index 9eadeb4e4..c31b78614 100644 --- a/examples/nrf52840/src/bin/i2s_effect.rs +++ b/examples/nrf52840/src/bin/i2s_effect.rs @@ -5,7 +5,7 @@ use core::f32::consts::PI; use defmt::{error, info}; use embassy_executor::Spawner; -use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S}; +use embassy_nrf::i2s::{self, Channels, Config, I2S, MasterClock, MultiBuffering, Sample as _, SampleWidth}; use embassy_nrf::{bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; @@ -102,11 +102,7 @@ impl SineOsc { #[inline] fn abs(value: f32) -> f32 { - if value < 0.0 { - -value - } else { - value - } + if value < 0.0 { -value } else { value } } #[inline] diff --git a/examples/nrf52840/src/bin/i2s_monitor.rs b/examples/nrf52840/src/bin/i2s_monitor.rs index 799be351f..66b429b09 100644 --- a/examples/nrf52840/src/bin/i2s_monitor.rs +++ b/examples/nrf52840/src/bin/i2s_monitor.rs @@ -3,7 +3,7 @@ use defmt::{debug, error, info}; use embassy_executor::Spawner; -use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; +use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, I2S, MasterClock, Sample as _, SampleWidth}; use embassy_nrf::pwm::{Prescaler, SimplePwm}; use embassy_nrf::{bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/nrf52840/src/bin/i2s_waveform.rs b/examples/nrf52840/src/bin/i2s_waveform.rs index 137d82840..ce7a68d3a 100644 --- a/examples/nrf52840/src/bin/i2s_waveform.rs +++ b/examples/nrf52840/src/bin/i2s_waveform.rs @@ -5,7 +5,7 @@ use core::f32::consts::PI; use defmt::{error, info}; use embassy_executor::Spawner; -use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; +use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, I2S, MasterClock, Sample as _, SampleWidth}; use embassy_nrf::{bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; @@ -140,11 +140,7 @@ impl SineOsc { #[inline] fn abs(value: f32) -> f32 { - if value < 0.0 { - -value - } else { - value - } + if value < 0.0 { -value } else { value } } #[inline] diff --git a/examples/nrf52840/src/bin/multiprio.rs b/examples/nrf52840/src/bin/multiprio.rs index 4d9b986d4..dc566adee 100644 --- a/examples/nrf52840/src/bin/multiprio.rs +++ b/examples/nrf52840/src/bin/multiprio.rs @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn EGU1_SWI1() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn EGU0_SWI0() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/nrf52840/src/bin/raw_spawn.rs b/examples/nrf52840/src/bin/raw_spawn.rs index b80954408..783be763d 100644 --- a/examples/nrf52840/src/bin/raw_spawn.rs +++ b/examples/nrf52840/src/bin/raw_spawn.rs @@ -5,8 +5,8 @@ use core::mem; use cortex_m_rt::entry; use defmt::{info, unwrap}; -use embassy_executor::raw::TaskStorage; use embassy_executor::Executor; +use embassy_executor::raw::TaskStorage; use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -48,5 +48,5 @@ fn main() -> ! { } unsafe fn make_static(t: &T) -> &'static T { - mem::transmute(t) + unsafe { mem::transmute(t) } } diff --git a/examples/nrf52840/src/bin/rtc.rs b/examples/nrf52840/src/bin/rtc.rs index 9d475df7f..56a0c25f4 100644 --- a/examples/nrf52840/src/bin/rtc.rs +++ b/examples/nrf52840/src/bin/rtc.rs @@ -7,8 +7,8 @@ use embassy_executor::Spawner; use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::interrupt; use embassy_nrf::rtc::Rtc; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use portable_atomic::AtomicU64; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index a75b967b4..14a1004d7 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs @@ -3,11 +3,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_net::tcp::TcpSocket; use embassy_net::StackResources; +use embassy_net::tcp::TcpSocket; use embassy_nrf::rng::Rng; -use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::usb::Driver; +use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::{bind_interrupts, pac, peripherals, rng, usb}; use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index 540580c31..7b7303526 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs @@ -6,10 +6,10 @@ use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_nrf::gpio::{Input, Pull}; -use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::usb::Driver; +use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::signal::Signal; @@ -244,7 +244,9 @@ impl Handler for MyDeviceHandler { fn suspended(&mut self, suspended: bool) { if suspended { - info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled)."); + info!( + "Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled)." + ); SUSPENDED.store(true, Ordering::Release); } else { SUSPENDED.store(false, Ordering::Release); diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index efc28203c..6bee4546b 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs @@ -6,8 +6,8 @@ use core::sync::atomic::{AtomicU8, Ordering}; use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::usb::Driver; +use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; use embassy_time::Timer; use embassy_usb::class::hid::{ diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs index e7c2d0854..469002bc7 100644 --- a/examples/nrf52840/src/bin/usb_serial.rs +++ b/examples/nrf52840/src/bin/usb_serial.rs @@ -4,8 +4,8 @@ use defmt::{info, panic}; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; use embassy_nrf::usb::Driver; +use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs index b6a983854..67b2bccbb 100644 --- a/examples/nrf52840/src/bin/usb_serial_multitask.rs +++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs @@ -3,8 +3,8 @@ use defmt::{info, panic, unwrap}; use embassy_executor::Spawner; -use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::usb::Driver; +use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs index e30e08a01..cd4d5bca1 100644 --- a/examples/nrf52840/src/bin/usb_serial_winusb.rs +++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs @@ -4,8 +4,8 @@ use defmt::{info, panic}; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; use embassy_nrf::usb::Driver; +use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index 1bc35746a..07752ffc4 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -3,8 +3,8 @@ use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; -use embassy_net::tcp::TcpSocket; use embassy_net::StackResources; +use embassy_net::tcp::TcpSocket; use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::rng::Rng; use embassy_nrf::spim::{self, Spim}; diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 256fee08d..4dcbdd715 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf5340-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf5340/src/bin/nrf5340dk_internal_caps.rs b/examples/nrf5340/src/bin/nrf5340dk_internal_caps.rs new file mode 100644 index 000000000..0b1fb852e --- /dev/null +++ b/examples/nrf5340/src/bin/nrf5340dk_internal_caps.rs @@ -0,0 +1,30 @@ +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_nrf::config::{Config, HfclkSource, LfclkSource, LfxoCapacitance}; +use embassy_nrf::pac; +use {defmt_rtt as _, panic_probe as _}; + +fn print_xosc32mcaps() { + let value = pac::OSCILLATORS.xosc32mcaps().read(); + info!("XOSC32MCAPS.ENABLE = {}", value.enable()); + info!("XOSC32MCAPS.CAPVALUE = {}", value.capvalue()); +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Before init:"); + print_xosc32mcaps(); + + let mut config = Config::default(); + config.hfclk_source = HfclkSource::Internal; + config.lfclk_source = LfclkSource::ExternalXtal; + config.internal_capacitors.hfxo = None; // keep the value from the FICR + config.internal_capacitors.lfxo = Some(LfxoCapacitance::_7pF); + let _p = embassy_nrf::init(config); + + info!("After init:"); + print_xosc32mcaps(); +} diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml index 9c24cdab4..541e79fcb 100644 --- a/examples/nrf54l15/Cargo.toml +++ b/examples/nrf54l15/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf54l15-examples" version = "0.1.0" license = "MIT OR Apache-2.0" @@ -8,6 +8,7 @@ publish = false [dependencies] embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "1.0.1" @@ -18,6 +19,7 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" embedded-storage = "0.3.1" +portable-atomic = "1" [profile.release] debug = 2 diff --git a/examples/nrf54l15/src/bin/rtc.rs b/examples/nrf54l15/src/bin/rtc.rs new file mode 100644 index 000000000..a45aaca52 --- /dev/null +++ b/examples/nrf54l15/src/bin/rtc.rs @@ -0,0 +1,56 @@ +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::interrupt; +use embassy_nrf::rtc::Rtc; +use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use portable_atomic::AtomicU64; +use {defmt_rtt as _, panic_probe as _}; + +// 64 bit counter which will never overflow. +static TICK_COUNTER: AtomicU64 = AtomicU64::new(0); +static RTC: Mutex>>> = Mutex::new(RefCell::new(None)); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + defmt::println!("nRF54L15 RTC example"); + let p = embassy_nrf::init(Default::default()); + let mut led = Output::new(p.P2_09, Level::High, OutputDrive::Standard); + // Counter resolution is 125 ms. + let mut rtc = Rtc::new(p.RTC10, (1 << 12) - 1).unwrap(); + rtc.enable_interrupt(embassy_nrf::rtc::Interrupt::Tick, true); + rtc.enable_event(embassy_nrf::rtc::Interrupt::Tick); + rtc.enable(); + RTC.lock(|r| { + let mut rtc_borrow = r.borrow_mut(); + *rtc_borrow = Some(rtc); + }); + + let mut last_counter_val = 0; + loop { + let current = TICK_COUNTER.load(core::sync::atomic::Ordering::Relaxed); + if current != last_counter_val { + led.toggle(); + last_counter_val = current; + } + } +} + +#[interrupt] +fn RTC10() { + // For 64-bit, we do not need to worry about overflowing, at least not for realistic program + // lifetimes. + TICK_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed); + RTC.lock(|r| { + let mut rtc_borrow = r.borrow_mut(); + rtc_borrow + .as_mut() + .unwrap() + .reset_event(embassy_nrf::rtc::Interrupt::Tick); + }); +} diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml index 89a6c7c94..7f1f5239a 100644 --- a/examples/nrf9151/ns/Cargo.toml +++ b/examples/nrf9151/ns/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf9151-non-secure-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml index 870311c5d..ce71cc456 100644 --- a/examples/nrf9151/s/Cargo.toml +++ b/examples/nrf9151/s/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf9151-secure-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index 274e26dd6..ae3b2eeb1 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf9160-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 460a4cfae..07fa57e63 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -11,11 +11,11 @@ use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; use embassy_net::{Ipv4Cidr, Stack, StackResources}; use embassy_net_nrf91::context::Status; -use embassy_net_nrf91::{context, Runner, State, TraceBuffer, TraceReader}; +use embassy_net_nrf91::{Runner, State, TraceBuffer, TraceReader, context}; use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive}; use embassy_nrf::uarte::Baudrate; -use embassy_nrf::{bind_interrupts, interrupt, peripherals, uarte, Peri}; +use embassy_nrf::{Peri, bind_interrupts, interrupt, peripherals, uarte}; use embassy_time::{Duration, Timer}; use embedded_io_async::Write; use heapless::Vec; @@ -101,7 +101,7 @@ async fn blink_task(pin: Peri<'static, AnyPin>) { } } -extern "C" { +unsafe extern "C" { static __start_ipc: u8; static __end_ipc: u8; } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 97e019cdf..640addb28 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-rp-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/rp/src/bin/assign_resources.rs b/examples/rp/src/bin/assign_resources.rs index 4ee4278b5..aaa134768 100644 --- a/examples/rp/src/bin/assign_resources.rs +++ b/examples/rp/src/bin/assign_resources.rs @@ -14,9 +14,9 @@ use assign_resources::assign_resources; use defmt::*; use embassy_executor::Spawner; +use embassy_rp::Peri; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{self, PIN_20, PIN_21}; -use embassy_rp::Peri; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/debounce.rs b/examples/rp/src/bin/debounce.rs index 0077f19fc..6eeb01d0a 100644 --- a/examples/rp/src/bin/debounce.rs +++ b/examples/rp/src/bin/debounce.rs @@ -7,7 +7,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::gpio::{Input, Level, Pull}; -use embassy_time::{with_deadline, Duration, Instant, Timer}; +use embassy_time::{Duration, Instant, Timer, with_deadline}; use {defmt_rtt as _, panic_probe as _}; pub struct Debouncer<'a> { diff --git a/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs index 49d28071a..cb667f24f 100644 --- a/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs +++ b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs @@ -12,8 +12,8 @@ use core::str::FromStr; use defmt::*; use embassy_executor::Spawner; use embassy_futures::yield_now; -use embassy_net::icmp::ping::{PingManager, PingParams}; use embassy_net::icmp::PacketMetadata; +use embassy_net::icmp::ping::{PingManager, PingParams}; use embassy_net::{Ipv4Cidr, Stack, StackResources}; use embassy_net_wiznet::chip::W5500; use embassy_net_wiznet::*; @@ -99,7 +99,7 @@ async fn main(spawner: Spawner) { // Create the ping manager instance let mut ping_manager = PingManager::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); let addr = "192.168.8.1"; // Address to ping to - // Create the PingParams with the target address + // Create the PingParams with the target address let mut ping_params = PingParams::new(Ipv4Addr::from_str(addr).unwrap()); // (optional) Set custom properties of the ping ping_params.set_payload(b"Hello, Ping!"); // custom payload diff --git a/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs b/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs index f51df2df9..b402029b5 100644 --- a/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs @@ -65,7 +65,7 @@ async fn main(spawner: Spawner) { // Construct an SPI driver backed by a PIO state machine let mut spi_cfg = SpiConfig::default(); spi_cfg.frequency = 12_500_000; // The PIO SPI program is much less stable than the actual SPI - // peripheral, use higher speeds at your peril + // peripheral, use higher speeds at your peril let spi = Spi::new(&mut common, sm0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg); // Further control pins diff --git a/examples/rp/src/bin/interrupt.rs b/examples/rp/src/bin/interrupt.rs index 2748f778a..2605622ab 100644 --- a/examples/rp/src/bin/interrupt.rs +++ b/examples/rp/src/bin/interrupt.rs @@ -16,8 +16,8 @@ use embassy_rp::adc::{self, Adc, Blocking}; use embassy_rp::gpio::Pull; use embassy_rp::interrupt; use embassy_rp::pwm::{Config, Pwm}; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_time::{Duration, Ticker}; use portable_atomic::{AtomicU32, Ordering}; diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs index 3a6367420..d289f8020 100644 --- a/examples/rp/src/bin/multicore.rs +++ b/examples/rp/src/bin/multicore.rs @@ -8,7 +8,7 @@ use defmt::*; use embassy_executor::Executor; use embassy_rp::gpio::{Level, Output}; -use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_rp::multicore::{Stack, spawn_core1}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_time::Timer; diff --git a/examples/rp/src/bin/multiprio.rs b/examples/rp/src/bin/multiprio.rs index 96cdf8fb1..310047505 100644 --- a/examples/rp/src/bin/multiprio.rs +++ b/examples/rp/src/bin/multiprio.rs @@ -61,7 +61,7 @@ use defmt::{info, unwrap}; use embassy_executor::{Executor, InterruptExecutor}; use embassy_rp::interrupt; use embassy_rp::interrupt::{InterruptExt, Priority}; -use embassy_time::{Instant, Timer, TICK_HZ}; +use embassy_time::{Instant, TICK_HZ, Timer}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn SWI_IRQ_1() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn SWI_IRQ_0() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index 9f25e1087..cd26a5371 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -20,11 +20,11 @@ use assign_resources::assign_resources; use defmt::*; use embassy_executor::Spawner; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Pull}; -use embassy_rp::{bind_interrupts, peripherals, Peri}; +use embassy_rp::{Peri, bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::Mutex; use embassy_sync::{channel, signal}; diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 83b17308b..a98185a8e 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -7,7 +7,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig}; +use embassy_rp::clocks::{ClockConfig, clk_sys_freq, core_voltage}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; diff --git a/examples/rp/src/bin/overclock_manual.rs b/examples/rp/src/bin/overclock_manual.rs index dea5cfb3c..18397f9a8 100644 --- a/examples/rp/src/bin/overclock_manual.rs +++ b/examples/rp/src/bin/overclock_manual.rs @@ -7,7 +7,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage, PllConfig}; +use embassy_rp::clocks::{ClockConfig, CoreVoltage, PllConfig, clk_sys_freq, core_voltage}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 1743a417e..55e983c36 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -7,7 +7,7 @@ use embassy_executor::Spawner; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; -use embassy_rp::{bind_interrupts, Peri}; +use embassy_rp::{Peri, bind_interrupts}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/pio_stepper.rs b/examples/rp/src/bin/pio_stepper.rs index 3862c248b..e8f203990 100644 --- a/examples/rp/src/bin/pio_stepper.rs +++ b/examples/rp/src/bin/pio_stepper.rs @@ -10,7 +10,7 @@ use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::pio_programs::stepper::{PioStepper, PioStepperProgram}; -use embassy_time::{with_timeout, Duration, Timer}; +use embassy_time::{Duration, Timer, with_timeout}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index 9dd07ab6e..f985bf7cf 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs @@ -9,9 +9,9 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; -use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_rp::Peri; +use embassy_rp::peripherals::{PIN_4, PIN_25, PWM_SLICE2, PWM_SLICE4}; +use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/rtc_alarm.rs b/examples/rp/src/bin/rtc_alarm.rs index 94b5fbd27..bde49ccd5 100644 --- a/examples/rp/src/bin/rtc_alarm.rs +++ b/examples/rp/src/bin/rtc_alarm.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_rp::bind_interrupts; use embassy_rp::rtc::{DateTime, DateTimeFilter, DayOfWeek, Rtc}; use embassy_time::Timer; diff --git a/examples/rp/src/bin/sharing.rs b/examples/rp/src/bin/sharing.rs index d4c89946b..618ab9117 100644 --- a/examples/rp/src/bin/sharing.rs +++ b/examples/rp/src/bin/sharing.rs @@ -52,7 +52,7 @@ bind_interrupts!(struct Irqs { #[interrupt] unsafe fn SWI_IRQ_0() { - EXECUTOR_HI.on_interrupt() + unsafe { EXECUTOR_HI.on_interrupt() } } #[entry] diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs index dd114a4ae..4bf924e56 100644 --- a/examples/rp/src/bin/spi_display.rs +++ b/examples/rp/src/bin/spi_display.rs @@ -15,19 +15,19 @@ use embassy_executor::Spawner; use embassy_rp::gpio::{Level, Output}; use embassy_rp::spi; use embassy_rp::spi::Spi; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_time::Delay; use embedded_graphics::image::{Image, ImageRawLE}; -use embedded_graphics::mono_font::ascii::FONT_10X20; use embedded_graphics::mono_font::MonoTextStyle; +use embedded_graphics::mono_font::ascii::FONT_10X20; use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use embedded_graphics::text::Text; +use mipidsi::Builder; use mipidsi::models::ST7789; use mipidsi::options::{Orientation, Rotation}; -use mipidsi::Builder; use {defmt_rtt as _, panic_probe as _}; use crate::touch::Touch; @@ -167,11 +167,7 @@ mod touch { let x = ((x - cal.x1) * cal.sx / (cal.x2 - cal.x1)).clamp(0, cal.sx); let y = ((y - cal.y1) * cal.sy / (cal.y2 - cal.y1)).clamp(0, cal.sy); - if x == 0 && y == 0 { - None - } else { - Some((x, y)) - } + if x == 0 && y == 0 { None } else { Some((x, y)) } } } } diff --git a/examples/rp/src/bin/spi_gc9a01.rs b/examples/rp/src/bin/spi_gc9a01.rs index fdef09d4b..fd007b9bd 100644 --- a/examples/rp/src/bin/spi_gc9a01.rs +++ b/examples/rp/src/bin/spi_gc9a01.rs @@ -16,16 +16,16 @@ use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Level, Output}; use embassy_rp::spi; use embassy_rp::spi::{Blocking, Spi}; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_time::{Delay, Duration, Timer}; use embedded_graphics::image::{Image, ImageRawLE}; use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; +use mipidsi::Builder; use mipidsi::models::GC9A01; use mipidsi::options::{ColorInversion, ColorOrder}; -use mipidsi::Builder; use {defmt_rtt as _, panic_probe as _}; const DISPLAY_FREQ: u32 = 64_000_000; diff --git a/examples/rp/src/bin/uart_r503.rs b/examples/rp/src/bin/uart_r503.rs index 085be280b..a25d45b18 100644 --- a/examples/rp/src/bin/uart_r503.rs +++ b/examples/rp/src/bin/uart_r503.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::UART0; use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart}; -use embassy_time::{with_timeout, Duration, Timer}; +use embassy_time::{Duration, Timer, with_timeout}; use heapless::Vec; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 912e52e96..b62a602b1 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs @@ -7,8 +7,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_net::tcp::TcpSocket; use embassy_net::StackResources; +use embassy_net::tcp::TcpSocket; use embassy_rp::clocks::RoscRng; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, InterruptHandler}; diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs index b79012acb..23d0c9e8b 100644 --- a/examples/rp/src/bin/usb_serial.rs +++ b/examples/rp/src/bin/usb_serial.rs @@ -10,9 +10,9 @@ use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, Instance, InterruptHandler}; +use embassy_usb::UsbDevice; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::UsbDevice; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index 128599e0d..0828dbbb9 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -7,7 +7,7 @@ use core::str::from_utf8; -use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; +use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs index b2e08c517..aa6ee4df0 100644 --- a/examples/rp/src/bin/wifi_blinky.rs +++ b/examples/rp/src/bin/wifi_blinky.rs @@ -5,7 +5,7 @@ #![no_std] #![no_main] -use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; +use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index c884aa2ba..7e3de1db9 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -7,7 +7,7 @@ use core::str; -use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; +use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 126475779..e39de4902 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -8,7 +8,7 @@ use core::str::from_utf8; use cyw43::JoinOptions; -use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; +use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index 079def370..b618d2b38 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs @@ -8,7 +8,7 @@ use core::str::from_utf8; use cyw43::JoinOptions; -use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; +use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; use defmt::*; use embassy_executor::Spawner; use embassy_net::dns::DnsSocket; diff --git a/examples/rp/src/bin/zerocopy.rs b/examples/rp/src/bin/zerocopy.rs index d603e1ed3..fc5f95e6e 100644 --- a/examples/rp/src/bin/zerocopy.rs +++ b/examples/rp/src/bin/zerocopy.rs @@ -11,7 +11,7 @@ use embassy_executor::Spawner; use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; use embassy_rp::gpio::Pull; use embassy_rp::peripherals::DMA_CH0; -use embassy_rp::{bind_interrupts, Peri}; +use embassy_rp::{Peri, bind_interrupts}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender}; use embassy_time::{Duration, Ticker, Timer}; diff --git a/examples/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml index 40fbb5798..39a4f421a 100644 --- a/examples/rp235x/Cargo.toml +++ b/examples/rp235x/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-rp2350-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/rp235x/src/bin/assign_resources.rs b/examples/rp235x/src/bin/assign_resources.rs index 4ee4278b5..aaa134768 100644 --- a/examples/rp235x/src/bin/assign_resources.rs +++ b/examples/rp235x/src/bin/assign_resources.rs @@ -14,9 +14,9 @@ use assign_resources::assign_resources; use defmt::*; use embassy_executor::Spawner; +use embassy_rp::Peri; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{self, PIN_20, PIN_21}; -use embassy_rp::Peri; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp235x/src/bin/debounce.rs b/examples/rp235x/src/bin/debounce.rs index 0077f19fc..6eeb01d0a 100644 --- a/examples/rp235x/src/bin/debounce.rs +++ b/examples/rp235x/src/bin/debounce.rs @@ -7,7 +7,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::gpio::{Input, Level, Pull}; -use embassy_time::{with_deadline, Duration, Instant, Timer}; +use embassy_time::{Duration, Instant, Timer, with_deadline}; use {defmt_rtt as _, panic_probe as _}; pub struct Debouncer<'a> { diff --git a/examples/rp235x/src/bin/ethernet_w5500_icmp_ping.rs b/examples/rp235x/src/bin/ethernet_w5500_icmp_ping.rs index 309d3e4f7..227e68029 100644 --- a/examples/rp235x/src/bin/ethernet_w5500_icmp_ping.rs +++ b/examples/rp235x/src/bin/ethernet_w5500_icmp_ping.rs @@ -12,8 +12,8 @@ use core::str::FromStr; use defmt::*; use embassy_executor::Spawner; use embassy_futures::yield_now; -use embassy_net::icmp::ping::{PingManager, PingParams}; use embassy_net::icmp::PacketMetadata; +use embassy_net::icmp::ping::{PingManager, PingParams}; use embassy_net::{Ipv4Cidr, Stack, StackResources}; use embassy_net_wiznet::chip::W5500; use embassy_net_wiznet::*; @@ -99,7 +99,7 @@ async fn main(spawner: Spawner) { // Create the ping manager instance let mut ping_manager = PingManager::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); let addr = "192.168.8.1"; // Address to ping to - // Create the PingParams with the target address + // Create the PingParams with the target address let mut ping_params = PingParams::new(Ipv4Addr::from_str(addr).unwrap()); // (optional) Set custom properties of the ping ping_params.set_payload(b"Hello, Ping!"); // custom payload diff --git a/examples/rp235x/src/bin/interrupt.rs b/examples/rp235x/src/bin/interrupt.rs index 88513180c..1b18f6931 100644 --- a/examples/rp235x/src/bin/interrupt.rs +++ b/examples/rp235x/src/bin/interrupt.rs @@ -16,8 +16,8 @@ use embassy_rp::adc::{self, Adc, Blocking}; use embassy_rp::gpio::Pull; use embassy_rp::interrupt; use embassy_rp::pwm::{Config, Pwm}; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_time::{Duration, Ticker}; use portable_atomic::{AtomicU32, Ordering}; diff --git a/examples/rp235x/src/bin/multicore.rs b/examples/rp235x/src/bin/multicore.rs index 4f82801d6..9b61fdbca 100644 --- a/examples/rp235x/src/bin/multicore.rs +++ b/examples/rp235x/src/bin/multicore.rs @@ -8,7 +8,7 @@ use defmt::*; use embassy_executor::Executor; use embassy_rp::gpio::{Level, Output}; -use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_rp::multicore::{Stack, spawn_core1}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_time::Timer; diff --git a/examples/rp235x/src/bin/multicore_stack_overflow.rs b/examples/rp235x/src/bin/multicore_stack_overflow.rs index dba44aa23..9efe89318 100644 --- a/examples/rp235x/src/bin/multicore_stack_overflow.rs +++ b/examples/rp235x/src/bin/multicore_stack_overflow.rs @@ -6,7 +6,7 @@ use defmt::*; use embassy_executor::Executor; use embassy_rp::gpio::{Level, Output}; -use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_rp::multicore::{Stack, spawn_core1}; use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp235x/src/bin/multiprio.rs b/examples/rp235x/src/bin/multiprio.rs index 96cdf8fb1..310047505 100644 --- a/examples/rp235x/src/bin/multiprio.rs +++ b/examples/rp235x/src/bin/multiprio.rs @@ -61,7 +61,7 @@ use defmt::{info, unwrap}; use embassy_executor::{Executor, InterruptExecutor}; use embassy_rp::interrupt; use embassy_rp::interrupt::{InterruptExt, Priority}; -use embassy_time::{Instant, Timer, TICK_HZ}; +use embassy_time::{Instant, TICK_HZ, Timer}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn SWI_IRQ_1() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn SWI_IRQ_0() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/rp235x/src/bin/overclock.rs b/examples/rp235x/src/bin/overclock.rs index 5fd97ef97..cba137f3a 100644 --- a/examples/rp235x/src/bin/overclock.rs +++ b/examples/rp235x/src/bin/overclock.rs @@ -12,7 +12,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage}; +use embassy_rp::clocks::{ClockConfig, CoreVoltage, clk_sys_freq, core_voltage}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; diff --git a/examples/rp235x/src/bin/pio_async.rs b/examples/rp235x/src/bin/pio_async.rs index d76930f5c..a392fe37e 100644 --- a/examples/rp235x/src/bin/pio_async.rs +++ b/examples/rp235x/src/bin/pio_async.rs @@ -7,7 +7,7 @@ use embassy_executor::Spawner; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; -use embassy_rp::{bind_interrupts, Peri}; +use embassy_rp::{Peri, bind_interrupts}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp235x/src/bin/pio_i2s_rx.rs b/examples/rp235x/src/bin/pio_i2s_rx.rs index c3f505b13..6735c402f 100644 --- a/examples/rp235x/src/bin/pio_i2s_rx.rs +++ b/examples/rp235x/src/bin/pio_i2s_rx.rs @@ -34,7 +34,7 @@ const SAMPLE_RATE: u32 = 48_000; const BIT_DEPTH: u32 = 16; const CHANNELS: u32 = 2; const USE_ONBOARD_PULLDOWN: bool = false; // whether or not to use the onboard pull-down resistor, - // which has documented issues on many RP235x boards +// which has documented issues on many RP235x boards #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs b/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs index 61af94560..948699e40 100644 --- a/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs +++ b/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs @@ -9,7 +9,7 @@ use embassy_executor::Spawner; use embassy_rp::gpio::Pull; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::program::pio_asm; -use embassy_rp::{bind_interrupts, pio, Peri}; +use embassy_rp::{Peri, bind_interrupts, pio}; use embassy_time::Timer; use fixed::traits::ToFixed; use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine}; diff --git a/examples/rp235x/src/bin/pio_stepper.rs b/examples/rp235x/src/bin/pio_stepper.rs index 931adbeda..9b33710ad 100644 --- a/examples/rp235x/src/bin/pio_stepper.rs +++ b/examples/rp235x/src/bin/pio_stepper.rs @@ -10,7 +10,7 @@ use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::pio_programs::stepper::{PioStepper, PioStepperProgram}; -use embassy_time::{with_timeout, Duration, Timer}; +use embassy_time::{Duration, Timer, with_timeout}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/rp235x/src/bin/pwm.rs b/examples/rp235x/src/bin/pwm.rs index 289480c85..971e86aa7 100644 --- a/examples/rp235x/src/bin/pwm.rs +++ b/examples/rp235x/src/bin/pwm.rs @@ -9,9 +9,9 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; -use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_rp::Peri; +use embassy_rp::peripherals::{PIN_4, PIN_25, PWM_SLICE2, PWM_SLICE4}; +use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs b/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs index 2cfb2038d..670f302a4 100644 --- a/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs +++ b/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs @@ -10,7 +10,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::config::Config; use embassy_rp::gpio::Output; -use embassy_rp::{gpio, peripherals, pwm, Peri}; +use embassy_rp::{Peri, gpio, peripherals, pwm}; use embassy_time::{Duration, Timer}; use tb6612fng::{DriveCommand, Motor, Tb6612fng}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp235x/src/bin/sharing.rs b/examples/rp235x/src/bin/sharing.rs index d4c89946b..618ab9117 100644 --- a/examples/rp235x/src/bin/sharing.rs +++ b/examples/rp235x/src/bin/sharing.rs @@ -52,7 +52,7 @@ bind_interrupts!(struct Irqs { #[interrupt] unsafe fn SWI_IRQ_0() { - EXECUTOR_HI.on_interrupt() + unsafe { EXECUTOR_HI.on_interrupt() } } #[entry] diff --git a/examples/rp235x/src/bin/spi_display.rs b/examples/rp235x/src/bin/spi_display.rs index 9967abefd..3cef93f62 100644 --- a/examples/rp235x/src/bin/spi_display.rs +++ b/examples/rp235x/src/bin/spi_display.rs @@ -15,19 +15,19 @@ use embassy_executor::Spawner; use embassy_rp::gpio::{Level, Output}; use embassy_rp::spi; use embassy_rp::spi::{Blocking, Spi}; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_time::Delay; use embedded_graphics::image::{Image, ImageRawLE}; -use embedded_graphics::mono_font::ascii::FONT_10X20; use embedded_graphics::mono_font::MonoTextStyle; +use embedded_graphics::mono_font::ascii::FONT_10X20; use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use embedded_graphics::text::Text; +use mipidsi::Builder; use mipidsi::models::ST7789; use mipidsi::options::{Orientation, Rotation}; -use mipidsi::Builder; use {defmt_rtt as _, panic_probe as _}; use crate::touch::Touch; @@ -167,11 +167,7 @@ mod touch { let x = ((x - cal.x1) * cal.sx / (cal.x2 - cal.x1)).clamp(0, cal.sx); let y = ((y - cal.y1) * cal.sy / (cal.y2 - cal.y1)).clamp(0, cal.sy); - if x == 0 && y == 0 { - None - } else { - Some((x, y)) - } + if x == 0 && y == 0 { None } else { Some((x, y)) } } } } diff --git a/examples/rp235x/src/bin/uart_r503.rs b/examples/rp235x/src/bin/uart_r503.rs index 085be280b..a25d45b18 100644 --- a/examples/rp235x/src/bin/uart_r503.rs +++ b/examples/rp235x/src/bin/uart_r503.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::UART0; use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart}; -use embassy_time::{with_timeout, Duration, Timer}; +use embassy_time::{Duration, Timer, with_timeout}; use heapless::Vec; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp235x/src/bin/zerocopy.rs b/examples/rp235x/src/bin/zerocopy.rs index 62ba4cfb8..55deffd5f 100644 --- a/examples/rp235x/src/bin/zerocopy.rs +++ b/examples/rp235x/src/bin/zerocopy.rs @@ -11,7 +11,7 @@ use embassy_executor::Spawner; use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; use embassy_rp::gpio::Pull; use embassy_rp::peripherals::DMA_CH0; -use embassy_rp::{bind_interrupts, Peri}; +use embassy_rp::{Peri, bind_interrupts}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender}; use embassy_time::{Duration, Ticker, Timer}; diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 449c5ddca..6dc6a353d 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-std-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index bb7b57496..696a95854 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32c0-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32c0/src/bin/rtc.rs b/examples/stm32c0/src/bin/rtc.rs index 82d8a37ba..feb27f6d9 100644 --- a/examples/stm32c0/src/bin/rtc.rs +++ b/examples/stm32c0/src/bin/rtc.rs @@ -4,8 +4,8 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::Config; +use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 11ecbe3c2..a78873d21 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-stm32f0-examples" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/examples/stm32f0/src/bin/button_controlled_blink.rs b/examples/stm32f0/src/bin/button_controlled_blink.rs index f232e3290..0b678af01 100644 --- a/examples/stm32f0/src/bin/button_controlled_blink.rs +++ b/examples/stm32f0/src/bin/button_controlled_blink.rs @@ -7,9 +7,9 @@ use core::sync::atomic::{AtomicU32, Ordering}; use defmt::info; use embassy_executor::Spawner; +use embassy_stm32::Peri; use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::{AnyPin, Level, Output, Pull, Speed}; -use embassy_stm32::Peri; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f0/src/bin/multiprio.rs b/examples/stm32f0/src/bin/multiprio.rs index b5244afc8..9a8dc5685 100644 --- a/examples/stm32f0/src/bin/multiprio.rs +++ b/examples/stm32f0/src/bin/multiprio.rs @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn USART1() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn USART2() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index dcb58796b..5714b149a 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32f1-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index ad0c8a5a5..cbe13b206 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs @@ -5,11 +5,11 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::can::frame::Envelope; use embassy_stm32::can::{ - filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, - TxInterruptHandler, + Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, + TxInterruptHandler, filter, }; use embassy_stm32::peripherals::CAN; -use embassy_stm32::{bind_interrupts, Config}; +use embassy_stm32::{Config, bind_interrupts}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f1/src/bin/input_capture.rs b/examples/stm32f1/src/bin/input_capture.rs index b5b26938d..6232d8c17 100644 --- a/examples/stm32f1/src/bin/input_capture.rs +++ b/examples/stm32f1/src/bin/input_capture.rs @@ -7,7 +7,7 @@ use embassy_stm32::gpio::{AfioRemap, Level, Output, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; use embassy_stm32::timer::{self, Channel}; -use embassy_stm32::{bind_interrupts, peripherals, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f1/src/bin/pwm_input.rs b/examples/stm32f1/src/bin/pwm_input.rs index 9ae747018..136c5c555 100644 --- a/examples/stm32f1/src/bin/pwm_input.rs +++ b/examples/stm32f1/src/bin/pwm_input.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::{AfioRemap, Level, Output, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::pwm_input::PwmInput; -use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals, timer}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs index 77ec307b9..5ff54a521 100644 --- a/examples/stm32f1/src/bin/usb_serial.rs +++ b/examples/stm32f1/src/bin/usb_serial.rs @@ -7,11 +7,11 @@ use embassy_futures::join::join; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_time::Timer; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 498c20d84..f726018c3 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32f2-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32f2/src/bin/pll.rs b/examples/stm32f2/src/bin/pll.rs index e39e2daec..4418bf502 100644 --- a/examples/stm32f2/src/bin/pll.rs +++ b/examples/stm32f2/src/bin/pll.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::time::Hertz; use embassy_stm32::Config; +use embassy_stm32::time::Hertz; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 23025ef0b..4349e8055 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32f3-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32f3/src/bin/button_events.rs b/examples/stm32f3/src/bin/button_events.rs index a54d03212..99957a641 100644 --- a/examples/stm32f3/src/bin/button_events.rs +++ b/examples/stm32f3/src/bin/button_events.rs @@ -15,7 +15,7 @@ use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::channel::Channel; -use embassy_time::{with_timeout, Duration, Timer}; +use embassy_time::{Duration, Timer, with_timeout}; use {defmt_rtt as _, panic_probe as _}; struct Leds<'a> { diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs index 2f2ffdea2..8375e0e8e 100644 --- a/examples/stm32f3/src/bin/multiprio.rs +++ b/examples/stm32f3/src/bin/multiprio.rs @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn UART4() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn UART5() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs index 5760f2c1c..58b801c36 100644 --- a/examples/stm32f3/src/bin/usb_serial.rs +++ b/examples/stm32f3/src/bin/usb_serial.rs @@ -7,11 +7,11 @@ use embassy_futures::join::join; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::time::mhz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_time::Timer; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index 3495b118c..cf22633dd 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32f334-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index 0528a9637..a993b00ca 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC1; use embassy_stm32::time::mhz; -use embassy_stm32::{adc, bind_interrupts, Config}; +use embassy_stm32::{Config, adc, bind_interrupts}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs index c344935d7..3e621f2a1 100644 --- a/examples/stm32f334/src/bin/opamp.rs +++ b/examples/stm32f334/src/bin/opamp.rs @@ -7,7 +7,7 @@ use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::opamp::OpAmp; use embassy_stm32::peripherals::ADC2; use embassy_stm32::time::mhz; -use embassy_stm32::{adc, bind_interrupts, Config}; +use embassy_stm32::{Config, adc, bind_interrupts}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index 2b0686121..68a61ae22 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -3,9 +3,9 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::hrtim::*; use embassy_stm32::time::{khz, mhz}; -use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index fb5f86aac..d06b7505c 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32f4-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs index 2ec48640e..c24f01753 100644 --- a/examples/stm32f4/src/bin/adc_dma.rs +++ b/examples/stm32f4/src/bin/adc_dma.rs @@ -3,8 +3,8 @@ use cortex_m::singleton; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, RingBufferedAdc, SampleTime, Sequence}; use embassy_stm32::Peripherals; +use embassy_stm32::adc::{Adc, RingBufferedAdc, SampleTime, Sequence}; use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index f41a60529..2d72b6b0b 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -9,7 +9,7 @@ use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use embedded_io_async::Write; use static_cell::StaticCell; diff --git a/examples/stm32f4/src/bin/eth_compliance_test.rs b/examples/stm32f4/src/bin/eth_compliance_test.rs index 52f9d57f6..734a14c2c 100644 --- a/examples/stm32f4/src/bin/eth_compliance_test.rs +++ b/examples/stm32f4/src/bin/eth_compliance_test.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue, StationManagement}; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/eth_w5500.rs b/examples/stm32f4/src/bin/eth_w5500.rs index 7ce3bfe75..cccf20949 100644 --- a/examples/stm32f4/src/bin/eth_w5500.rs +++ b/examples/stm32f4/src/bin/eth_w5500.rs @@ -13,7 +13,7 @@ use embassy_stm32::mode::Async; use embassy_stm32::rng::Rng; use embassy_stm32::spi::Spi; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, peripherals, rng, spi, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, rng, spi}; use embassy_time::{Delay, Timer}; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_io_async::Write; diff --git a/examples/stm32f4/src/bin/flash_async.rs b/examples/stm32f4/src/bin/flash_async.rs index 2feb9de09..14f029747 100644 --- a/examples/stm32f4/src/bin/flash_async.rs +++ b/examples/stm32f4/src/bin/flash_async.rs @@ -5,7 +5,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; use embassy_stm32::flash::{Flash, InterruptHandler}; use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; -use embassy_stm32::{bind_interrupts, Peri}; +use embassy_stm32::{Peri, bind_interrupts}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/input_capture.rs b/examples/stm32f4/src/bin/input_capture.rs index 9998c4733..3ff96584d 100644 --- a/examples/stm32f4/src/bin/input_capture.rs +++ b/examples/stm32f4/src/bin/input_capture.rs @@ -7,7 +7,7 @@ use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; use embassy_stm32::timer::{self, Channel}; -use embassy_stm32::{bind_interrupts, peripherals, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs index 2f2ffdea2..8375e0e8e 100644 --- a/examples/stm32f4/src/bin/multiprio.rs +++ b/examples/stm32f4/src/bin/multiprio.rs @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn UART4() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn UART5() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs index c981f1a76..50008a37b 100644 --- a/examples/stm32f4/src/bin/pwm_complementary.rs +++ b/examples/stm32f4/src/bin/pwm_complementary.rs @@ -5,9 +5,9 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; +use embassy_stm32::timer::Channel; use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; use embassy_stm32::timer::simple_pwm::PwmPin; -use embassy_stm32::timer::Channel; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/pwm_input.rs b/examples/stm32f4/src/bin/pwm_input.rs index e8bfa524f..d8ea56a34 100644 --- a/examples/stm32f4/src/bin/pwm_input.rs +++ b/examples/stm32f4/src/bin/pwm_input.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::pwm_input::PwmInput; -use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals, timer}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs index 82d8a37ba..feb27f6d9 100644 --- a/examples/stm32f4/src/bin/rtc.rs +++ b/examples/stm32f4/src/bin/rtc.rs @@ -4,8 +4,8 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::Config; +use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs index e97b63925..fe0f887bf 100644 --- a/examples/stm32f4/src/bin/sdmmc.rs +++ b/examples/stm32f4/src/bin/sdmmc.rs @@ -4,8 +4,8 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::sdmmc::{DataBlock, Sdmmc}; -use embassy_stm32::time::{mhz, Hertz}; -use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; +use embassy_stm32::time::{Hertz, mhz}; +use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; use {defmt_rtt as _, panic_probe as _}; /// This is a safeguard to not overwrite any data on the SD card. diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index 7abbe8719..a5e625edd 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -3,12 +3,12 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_net::tcp::TcpSocket; use embassy_net::StackResources; +use embassy_net::tcp::TcpSocket; use embassy_stm32::rng::{self, Rng}; use embassy_stm32::time::Hertz; use embassy_stm32::usb::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, UsbDevice}; diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index 86b6fa95f..9971e43f5 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -10,7 +10,7 @@ use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::Pull; use embassy_stm32::time::Hertz; use embassy_stm32::usb::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_usb::class::hid::{ HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State, }; diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index 977db4c15..e83d01f88 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -8,13 +8,13 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_time::Timer; +use embassy_usb::Builder; use embassy_usb::class::hid::{ HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State, }; use embassy_usb::control::OutResponse; -use embassy_usb::Builder; use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs index bbbcc082b..511f0b281 100644 --- a/examples/stm32f4/src/bin/usb_raw.rs +++ b/examples/stm32f4/src/bin/usb_raw.rs @@ -53,7 +53,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::time::Hertz; use embassy_stm32::usb::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType}; use embassy_usb::msos::{self, windows_version}; use embassy_usb::types::InterfaceNumber; diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index e62b2d8d6..2e81e0a59 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32f4/src/bin/usb_uac_speaker.rs b/examples/stm32f4/src/bin/usb_uac_speaker.rs index 79bd2d914..b92f4531e 100644 --- a/examples/stm32f4/src/bin/usb_uac_speaker.rs +++ b/examples/stm32f4/src/bin/usb_uac_speaker.rs @@ -6,9 +6,9 @@ use core::cell::{Cell, RefCell}; use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, interrupt, peripherals, timer, usb, Config}; -use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; +use embassy_stm32::{Config, bind_interrupts, interrupt, peripherals, timer, usb}; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; use embassy_sync::signal::Signal; use embassy_sync::zerocopy_channel; use embassy_usb::class::uac1; diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs index 5153e1cfd..ccfd0661e 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm.rs @@ -15,9 +15,9 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; +use embassy_stm32::timer::Channel; use embassy_stm32::timer::low_level::CountingMode; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::timer::Channel; use embassy_time::{Duration, Ticker, Timer}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml index f1d0e411a..5216e19b4 100644 --- a/examples/stm32f469/Cargo.toml +++ b/examples/stm32f469/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32f469-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32f469/src/bin/dsi_bsp.rs b/examples/stm32f469/src/bin/dsi_bsp.rs index 3a24d5dcf..d659291ff 100644 --- a/examples/stm32f469/src/bin/dsi_bsp.rs +++ b/examples/stm32f469/src/bin/dsi_bsp.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dsihost::{blocking_delay_ms, DsiHost, PacketType}; +use embassy_stm32::dsihost::{DsiHost, PacketType, blocking_delay_ms}; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::ltdc::Ltdc; use embassy_stm32::pac::dsihost::regs::{Ier0, Ier1}; @@ -211,7 +211,7 @@ async fn main(_spawner: Spawner) { const HORIZONTAL_SYNC_ACTIVE: u16 = 4; // ((HSA as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32 ) as u16; const HORIZONTAL_BACK_PORCH: u16 = 77; //((HBP as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32) as u16; const HORIZONTAL_LINE: u16 = 1982; //(((HACT + HSA + HBP + HFP) as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32 ) as u16; /* Value depending on display orientation choice portrait/landscape */ - // FIXME: Make depend on orientation + // FIXME: Make depend on orientation const VERTICAL_SYNC_ACTIVE: u16 = VSA; const VERTICAL_BACK_PORCH: u16 = VBP; const VERTICAL_FRONT_PORCH: u16 = VFP; @@ -658,7 +658,7 @@ const NT35510_RASET_LANDSCAPE: &[u8] = &[NT35510_CMD_RASET, 0x00, 0x00, 0x01, 0x const NT35510_WRITES_26: &[u8] = &[NT35510_CMD_TEEON, 0x00]; // Tear on const NT35510_WRITES_27: &[u8] = &[NT35510_CMD_SLPOUT, 0x00]; // Sleep out - // 28,29 missing +// 28,29 missing const NT35510_WRITES_30: &[u8] = &[NT35510_CMD_DISPON, 0x00]; // Display on const NT35510_WRITES_31: &[u8] = &[NT35510_CMD_WRDISBV, 0x7F]; diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 5d7763334..565277394 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32f7-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index 9a91ac814..2f3f6db84 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -use core::num::{NonZeroU16, NonZeroU8}; +use core::num::{NonZeroU8, NonZeroU16}; use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs index a31e9b4f2..9ccef0b82 100644 --- a/examples/stm32f7/src/bin/cryp.rs +++ b/examples/stm32f7/src/bin/cryp.rs @@ -1,13 +1,13 @@ #![no_std] #![no_main] +use aes_gcm::Aes128Gcm; use aes_gcm::aead::heapless::Vec; use aes_gcm::aead::{AeadInPlace, KeyInit}; -use aes_gcm::Aes128Gcm; use defmt::info; use embassy_executor::Spawner; use embassy_stm32::cryp::{self, *}; -use embassy_stm32::{bind_interrupts, peripherals, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals}; use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index b13b7bdda..f8a129239 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -9,7 +9,7 @@ use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use embedded_io_async::Write; use static_cell::StaticCell; diff --git a/examples/stm32f7/src/bin/hash.rs b/examples/stm32f7/src/bin/hash.rs index c2d1a7158..4fd465df6 100644 --- a/examples/stm32f7/src/bin/hash.rs +++ b/examples/stm32f7/src/bin/hash.rs @@ -4,7 +4,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_stm32::hash::*; -use embassy_stm32::{bind_interrupts, hash, peripherals, Config}; +use embassy_stm32::{Config, bind_interrupts, hash, peripherals}; use embassy_time::Instant; use hmac::{Hmac, Mac}; use sha2::{Digest, Sha256}; diff --git a/examples/stm32f7/src/bin/qspi.rs b/examples/stm32f7/src/bin/qspi.rs index 80652b865..e8ef3ad81 100644 --- a/examples/stm32f7/src/bin/qspi.rs +++ b/examples/stm32f7/src/bin/qspi.rs @@ -4,11 +4,11 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_stm32::Config as StmCfg; use embassy_stm32::mode::Async; use embassy_stm32::qspi::enums::{AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize, *}; use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, TransferConfig}; use embassy_stm32::time::mhz; -use embassy_stm32::Config as StmCfg; use {defmt_rtt as _, panic_probe as _}; const MEMORY_PAGE_SIZE: usize = 256; diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs index 787bef25e..8809b5d0c 100644 --- a/examples/stm32f7/src/bin/sdmmc.rs +++ b/examples/stm32f7/src/bin/sdmmc.rs @@ -4,8 +4,8 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::sdmmc::Sdmmc; -use embassy_stm32::time::{mhz, Hertz}; -use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; +use embassy_stm32::time::{Hertz, mhz}; +use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index 349012888..9a30b2c20 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 1c9451469..16f28500d 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32g0-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs index 705905f01..88ee7ea86 100644 --- a/examples/stm32g0/src/bin/hf_timer.rs +++ b/examples/stm32g0/src/bin/hf_timer.rs @@ -3,12 +3,12 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_stm32::Config as PeripheralConfig; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; +use embassy_stm32::timer::Channel; use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; use embassy_stm32::timer::simple_pwm::PwmPin; -use embassy_stm32::timer::Channel; -use embassy_stm32::Config as PeripheralConfig; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32g0/src/bin/input_capture.rs b/examples/stm32g0/src/bin/input_capture.rs index 5501a6941..ca3e8eb41 100644 --- a/examples/stm32g0/src/bin/input_capture.rs +++ b/examples/stm32g0/src/bin/input_capture.rs @@ -13,10 +13,10 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, OutputType, Pull, Speed}; use embassy_stm32::time::khz; +use embassy_stm32::timer::Channel; use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::timer::Channel; -use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals, timer}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g0/src/bin/pwm_complementary.rs b/examples/stm32g0/src/bin/pwm_complementary.rs index dbd9194c9..9856dd953 100644 --- a/examples/stm32g0/src/bin/pwm_complementary.rs +++ b/examples/stm32g0/src/bin/pwm_complementary.rs @@ -17,9 +17,9 @@ use defmt::info; use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; +use embassy_stm32::timer::Channel; use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; use embassy_stm32::timer::simple_pwm::PwmPin; -use embassy_stm32::timer::Channel; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32g0/src/bin/pwm_input.rs b/examples/stm32g0/src/bin/pwm_input.rs index 72aa07c03..5da19e077 100644 --- a/examples/stm32g0/src/bin/pwm_input.rs +++ b/examples/stm32g0/src/bin/pwm_input.rs @@ -14,7 +14,7 @@ use embassy_stm32::gpio::{Level, Output, OutputType, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::pwm_input::PwmInput; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals, timer}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g0/src/bin/rtc.rs b/examples/stm32g0/src/bin/rtc.rs index 50fb6398e..21da204cc 100644 --- a/examples/stm32g0/src/bin/rtc.rs +++ b/examples/stm32g0/src/bin/rtc.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rtc::{DateTime, DayOfWeek, Rtc, RtcConfig}; use embassy_stm32::Config; +use embassy_stm32::rtc::{DateTime, DayOfWeek, Rtc, RtcConfig}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g0/src/bin/usb_serial.rs b/examples/stm32g0/src/bin/usb_serial.rs index 162dfd86b..7dab393ac 100644 --- a/examples/stm32g0/src/bin/usb_serial.rs +++ b/examples/stm32g0/src/bin/usb_serial.rs @@ -5,10 +5,10 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 102960980..6fd282d6d 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32g4-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index adca846d8..920142a18 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g4/src/bin/adc_differential.rs b/examples/stm32g4/src/bin/adc_differential.rs index 78d071d45..301f0da84 100644 --- a/examples/stm32g4/src/bin/adc_differential.rs +++ b/examples/stm32g4/src/bin/adc_differential.rs @@ -8,8 +8,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g4/src/bin/adc_dma.rs b/examples/stm32g4/src/bin/adc_dma.rs index 202704085..a82067049 100644 --- a/examples/stm32g4/src/bin/adc_dma.rs +++ b/examples/stm32g4/src/bin/adc_dma.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, AdcChannel as _, SampleTime}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, AdcChannel as _, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g4/src/bin/adc_oversampling.rs b/examples/stm32g4/src/bin/adc_oversampling.rs index d31eb20f8..1e464183a 100644 --- a/examples/stm32g4/src/bin/adc_oversampling.rs +++ b/examples/stm32g4/src/bin/adc_oversampling.rs @@ -7,9 +7,9 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::adc::vals::{Rovsm, Trovs}; use embassy_stm32::adc::{Adc, SampleTime}; -use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index 90004f874..7ff7bd7b4 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::peripherals::*; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, can, Config}; +use embassy_stm32::{Config, bind_interrupts, can}; use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs index 2e87d3931..b23984b3a 100644 --- a/examples/stm32g4/src/bin/usb_c_pd.rs +++ b/examples/stm32g4/src/bin/usb_c_pd.rs @@ -1,11 +1,11 @@ #![no_std] #![no_main] -use defmt::{error, info, Format}; +use defmt::{Format, error, info}; use embassy_executor::Spawner; use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, Ucpd}; -use embassy_stm32::{bind_interrupts, peripherals, Config}; -use embassy_time::{with_timeout, Duration}; +use embassy_stm32::{Config, bind_interrupts, peripherals}; +use embassy_time::{Duration, with_timeout}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index 9f66f0c53..a62da6d97 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{self, Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 66680c027..475ba7e8a 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h5-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h5/src/bin/adc.rs b/examples/stm32h5/src/bin/adc.rs index c5d508ece..0566320d4 100644 --- a/examples/stm32h5/src/bin/adc.rs +++ b/examples/stm32h5/src/bin/adc.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs index 194239d47..b1923547e 100644 --- a/examples/stm32h5/src/bin/can.rs +++ b/examples/stm32h5/src/bin/can.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::peripherals::*; -use embassy_stm32::{bind_interrupts, can, rcc, Config}; +use embassy_stm32::{Config, bind_interrupts, can, rcc}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h5/src/bin/dts.rs b/examples/stm32h5/src/bin/dts.rs index 8c18fafea..7c856b5b3 100644 --- a/examples/stm32h5/src/bin/dts.rs +++ b/examples/stm32h5/src/bin/dts.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::dts::{Dts, InterruptHandler, SampleTime}; use embassy_stm32::peripherals::DTS; use embassy_stm32::rcc::frequency; -use embassy_stm32::{bind_interrupts, dts, Config}; +use embassy_stm32::{Config, bind_interrupts, dts}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index a84fe358b..a5c6cee26 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -12,7 +12,7 @@ use embassy_stm32::rcc::{ }; use embassy_stm32::rng::Rng; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use embedded_io_async::Write; use static_cell::StaticCell; diff --git a/examples/stm32h5/src/bin/sai.rs b/examples/stm32h5/src/bin/sai.rs index 0e182f9cf..6632a7f98 100644 --- a/examples/stm32h5/src/bin/sai.rs +++ b/examples/stm32h5/src/bin/sai.rs @@ -3,7 +3,7 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::{sai, Config}; +use embassy_stm32::{Config, sai}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32h5/src/bin/usb_c_pd.rs b/examples/stm32h5/src/bin/usb_c_pd.rs index acb03e498..ab6efff32 100644 --- a/examples/stm32h5/src/bin/usb_c_pd.rs +++ b/examples/stm32h5/src/bin/usb_c_pd.rs @@ -3,12 +3,12 @@ #![no_std] #![no_main] -use defmt::{error, info, Format}; +use defmt::{Format, error, info}; use embassy_executor::Spawner; use embassy_stm32::gpio::Output; use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, Ucpd}; -use embassy_stm32::{bind_interrupts, peripherals, Config}; -use embassy_time::{with_timeout, Duration}; +use embassy_stm32::{Config, bind_interrupts, peripherals}; +use embassy_time::{Duration, with_timeout}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index e8f536133..f72851ed7 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h5/src/bin/usb_uac_speaker.rs b/examples/stm32h5/src/bin/usb_uac_speaker.rs index 86873cabd..f75b1fd8a 100644 --- a/examples/stm32h5/src/bin/usb_uac_speaker.rs +++ b/examples/stm32h5/src/bin/usb_uac_speaker.rs @@ -6,9 +6,9 @@ use core::cell::{Cell, RefCell}; use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, interrupt, peripherals, timer, usb, Config}; -use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; +use embassy_stm32::{Config, bind_interrupts, interrupt, peripherals, timer, usb}; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; use embassy_sync::signal::Signal; use embassy_sync::zerocopy_channel; use embassy_usb::class::uac1; diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 9a2080013..5993110de 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h7-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs index 98504ddf6..a53c9d8d5 100644 --- a/examples/stm32h7/src/bin/adc.rs +++ b/examples/stm32h7/src/bin/adc.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/adc_dma.rs b/examples/stm32h7/src/bin/adc_dma.rs index f06b5d06e..cedb32e47 100644 --- a/examples/stm32h7/src/bin/adc_dma.rs +++ b/examples/stm32h7/src/bin/adc_dma.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, AdcChannel as _, SampleTime}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, AdcChannel as _, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs index 039008d17..c593d5e0b 100644 --- a/examples/stm32h7/src/bin/camera.rs +++ b/examples/stm32h7/src/bin/camera.rs @@ -6,7 +6,7 @@ use embassy_stm32::dcmi::{self, *}; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::i2c::I2c; use embassy_stm32::rcc::{Mco, Mco1Source, McoConfig, McoPrescaler}; -use embassy_stm32::{bind_interrupts, i2c, peripherals, Config}; +use embassy_stm32::{Config, bind_interrupts, i2c, peripherals}; use embassy_time::Timer; use ov7725::*; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs index 0af11ef3e..49830f9b7 100644 --- a/examples/stm32h7/src/bin/can.rs +++ b/examples/stm32h7/src/bin/can.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::peripherals::*; -use embassy_stm32::{bind_interrupts, can, rcc, Config}; +use embassy_stm32::{Config, bind_interrupts, can, rcc}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs index 27df80336..fa22837c5 100644 --- a/examples/stm32h7/src/bin/dac.rs +++ b/examples/stm32h7/src/bin/dac.rs @@ -3,8 +3,8 @@ use cortex_m_rt::entry; use defmt::*; -use embassy_stm32::dac::{DacCh1, Value}; use embassy_stm32::Config; +use embassy_stm32::dac::{DacCh1, Value}; use {defmt_rtt as _, panic_probe as _}; #[entry] diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index df37e9d78..9ccefa761 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs @@ -3,6 +3,7 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Peri; use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; use embassy_stm32::mode::Async; use embassy_stm32::pac::timer::vals::Mms; @@ -10,7 +11,6 @@ use embassy_stm32::peripherals::{DAC1, TIM6, TIM7}; use embassy_stm32::rcc::frequency; use embassy_stm32::time::Hertz; use embassy_stm32::timer::low_level::Timer; -use embassy_stm32::Peri; use micromath::F32Ext; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index 6c215362d..589f4426e 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -8,7 +8,7 @@ use embassy_net::{Ipv4Address, StackResources}; use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use embedded_io_async::Write; use static_cell::StaticCell; diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index 10ac57fc9..fed8f1a9c 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -5,12 +5,12 @@ use core::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use defmt::*; use embassy_executor::Spawner; -use embassy_net::tcp::client::{TcpClient, TcpClientState}; use embassy_net::StackResources; +use embassy_net::tcp::client::{TcpClient, TcpClientState}; use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use embedded_io_async::Write; use embedded_nal_async::TcpConnect; diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs index c6a108471..c3c631f0f 100644 --- a/examples/stm32h7/src/bin/eth_client_mii.rs +++ b/examples/stm32h7/src/bin/eth_client_mii.rs @@ -5,12 +5,12 @@ use core::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use defmt::*; use embassy_executor::Spawner; -use embassy_net::tcp::client::{TcpClient, TcpClientState}; use embassy_net::StackResources; +use embassy_net::tcp::client::{TcpClient, TcpClientState}; use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use embedded_io_async::Write; use embedded_nal_async::TcpConnect; diff --git a/examples/stm32h7/src/bin/fmc.rs b/examples/stm32h7/src/bin/fmc.rs index 5e5e6ccc8..b65d50443 100644 --- a/examples/stm32h7/src/bin/fmc.rs +++ b/examples/stm32h7/src/bin/fmc.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::fmc::Fmc; use embassy_stm32::Config; +use embassy_stm32::fmc::Fmc; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/i2c_shared.rs b/examples/stm32h7/src/bin/i2c_shared.rs index 9e45d845f..08ff812f2 100644 --- a/examples/stm32h7/src/bin/i2c_shared.rs +++ b/examples/stm32h7/src/bin/i2c_shared.rs @@ -9,8 +9,8 @@ use embassy_executor::Spawner; use embassy_stm32::i2c::{self, I2c}; use embassy_stm32::mode::Async; use embassy_stm32::{bind_interrupts, peripherals}; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::NoopMutex; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_time::{Duration, Timer}; use embedded_hal_1::i2c::I2c as _; use static_cell::StaticCell; diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index 12abb8693..f17fb2aaa 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{AfType, Flex, OutputType, Speed}; -use embassy_stm32::time::{khz, Hertz}; +use embassy_stm32::time::{Hertz, khz}; use embassy_stm32::timer::low_level::{OutputCompareMode, Timer as LLTimer}; use embassy_stm32::timer::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance32bit4Channel, TimerPin}; use embassy_stm32::{Config, Peri}; diff --git a/examples/stm32h7/src/bin/multiprio.rs b/examples/stm32h7/src/bin/multiprio.rs index 2f2ffdea2..8375e0e8e 100644 --- a/examples/stm32h7/src/bin/multiprio.rs +++ b/examples/stm32h7/src/bin/multiprio.rs @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn UART4() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn UART5() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs index 73b43be69..ffd117580 100644 --- a/examples/stm32h7/src/bin/pwm.rs +++ b/examples/stm32h7/src/bin/pwm.rs @@ -3,10 +3,10 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/rng.rs b/examples/stm32h7/src/bin/rng.rs index a9ef7200d..489747678 100644 --- a/examples/stm32h7/src/bin/rng.rs +++ b/examples/stm32h7/src/bin/rng.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, rng}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h7/src/bin/rtc.rs b/examples/stm32h7/src/bin/rtc.rs index 0adb48877..1bd71637b 100644 --- a/examples/stm32h7/src/bin/rtc.rs +++ b/examples/stm32h7/src/bin/rtc.rs @@ -4,9 +4,9 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; 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 _}; diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs index 96840d8ff..4977fec79 100644 --- a/examples/stm32h7/src/bin/sdmmc.rs +++ b/examples/stm32h7/src/bin/sdmmc.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::sdmmc::Sdmmc; use embassy_stm32::time::mhz; -use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs index dce30a4a7..61f31be24 100644 --- a/examples/stm32h7/src/bin/spi.rs +++ b/examples/stm32h7/src/bin/spi.rs @@ -9,7 +9,7 @@ use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Blocking; use embassy_stm32::time::mhz; -use embassy_stm32::{spi, Config}; +use embassy_stm32::{Config, spi}; use heapless::String; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs index 828f687b8..be6a26d82 100644 --- a/examples/stm32h7/src/bin/spi_bdma.rs +++ b/examples/stm32h7/src/bin/spi_bdma.rs @@ -9,7 +9,7 @@ use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Async; use embassy_stm32::time::mhz; -use embassy_stm32::{spi, Config}; +use embassy_stm32::{Config, spi}; use grounded::uninit::GroundedArrayCell; use heapless::String; use static_cell::StaticCell; diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs index 2197fabce..20cb67ba0 100644 --- a/examples/stm32h7/src/bin/spi_dma.rs +++ b/examples/stm32h7/src/bin/spi_dma.rs @@ -9,7 +9,7 @@ use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Async; use embassy_stm32::time::mhz; -use embassy_stm32::{spi, Config}; +use embassy_stm32::{Config, spi}; use heapless::String; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index 50bb964da..d0470101b 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs @@ -5,10 +5,10 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml index 7e4ccc528..93a5109e2 100644 --- a/examples/stm32h723/Cargo.toml +++ b/examples/stm32h723/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h723-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h723/src/bin/spdifrx.rs b/examples/stm32h723/src/bin/spdifrx.rs index b75a03ae8..cdbd69b89 100644 --- a/examples/stm32h723/src/bin/spdifrx.rs +++ b/examples/stm32h723/src/bin/spdifrx.rs @@ -7,9 +7,9 @@ use defmt::{info, trace}; use embassy_executor::Spawner; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_stm32::spdifrx::{self, Spdifrx}; -use embassy_stm32::{bind_interrupts, peripherals, sai, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals, sai}; use grounded::uninit::GroundedArrayCell; use hal::sai::*; use {defmt_rtt as _, embassy_stm32 as hal, panic_probe as _}; diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index 22b7ad96a..1ad2eeb2e 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h735-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h735/src/bin/ltdc.rs b/examples/stm32h735/src/bin/ltdc.rs index 8a99f745d..f042e04c2 100644 --- a/examples/stm32h735/src/bin/ltdc.rs +++ b/examples/stm32h735/src/bin/ltdc.rs @@ -15,14 +15,14 @@ use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::ltdc::{self, Ltdc, LtdcConfiguration, LtdcLayer, LtdcLayerConfig, PolarityActive, PolarityEdge}; use embassy_stm32::{bind_interrupts, peripherals}; use embassy_time::{Duration, Timer}; +use embedded_graphics::Pixel; use embedded_graphics::draw_target::DrawTarget; use embedded_graphics::geometry::{OriginDimensions, Point, Size}; use embedded_graphics::image::Image; -use embedded_graphics::pixelcolor::raw::RawU24; use embedded_graphics::pixelcolor::Rgb888; +use embedded_graphics::pixelcolor::raw::RawU24; use embedded_graphics::prelude::*; use embedded_graphics::primitives::Rectangle; -use embedded_graphics::Pixel; use heapless::{Entry, FnvIndexMap}; use tinybmp::Bmp; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h742/Cargo.toml b/examples/stm32h742/Cargo.toml index c76340b5f..9b5e5d93d 100644 --- a/examples/stm32h742/Cargo.toml +++ b/examples/stm32h742/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h742-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h742/src/bin/qspi.rs b/examples/stm32h742/src/bin/qspi.rs index 9e79d7089..a88c8f249 100644 --- a/examples/stm32h742/src/bin/qspi.rs +++ b/examples/stm32h742/src/bin/qspi.rs @@ -4,10 +4,10 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_stm32::Config as StmCfg; use embassy_stm32::mode::Blocking; use embassy_stm32::qspi::enums::{AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize, *}; use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, TransferConfig}; -use embassy_stm32::Config as StmCfg; use {defmt_rtt as _, panic_probe as _}; const MEMORY_PAGE_SIZE: usize = 256; diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index c73f9df79..b5c313523 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h755cm4-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h755cm4/src/bin/blinky.rs b/examples/stm32h755cm4/src/bin/blinky.rs index 39112c1f5..0ee3c68dc 100644 --- a/examples/stm32h755cm4/src/bin/blinky.rs +++ b/examples/stm32h755cm4/src/bin/blinky.rs @@ -5,8 +5,8 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::SharedData; +use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h755cm4/src/bin/intercore.rs b/examples/stm32h755cm4/src/bin/intercore.rs index f584e31e9..c0db8cdd3 100644 --- a/examples/stm32h755cm4/src/bin/intercore.rs +++ b/examples/stm32h755cm4/src/bin/intercore.rs @@ -85,7 +85,7 @@ mod shared { } } - #[link_section = ".ram_d3"] + #[unsafe(link_section = ".ram_d3")] pub static SHARED_LED_STATE: SharedLedState = SharedLedState::new(); } @@ -93,13 +93,13 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::SharedData; +use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_time::Timer; use shared::SHARED_LED_STATE; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".ram_d3"] +#[unsafe(link_section = ".ram_d3")] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); /// Task that continuously blinks the red LED as a heartbeat indicator diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index c34d4e45c..7a1519aae 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h755cm7-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h755cm7/src/bin/blinky.rs b/examples/stm32h755cm7/src/bin/blinky.rs index b30bf4de8..e8f5a1c43 100644 --- a/examples/stm32h755cm7/src/bin/blinky.rs +++ b/examples/stm32h755cm7/src/bin/blinky.rs @@ -5,8 +5,8 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::SharedData; +use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h755cm7/src/bin/intercore.rs b/examples/stm32h755cm7/src/bin/intercore.rs index a4e1b5ff4..3df0b26d7 100644 --- a/examples/stm32h755cm7/src/bin/intercore.rs +++ b/examples/stm32h755cm7/src/bin/intercore.rs @@ -97,7 +97,7 @@ mod shared { } } - #[link_section = ".ram_d3"] + #[unsafe(link_section = ".ram_d3")] pub static SHARED_LED_STATE: SharedLedState = SharedLedState::new(); // Memory region constants for MPU configuration @@ -106,7 +106,7 @@ mod shared { pub const SRAM4_REGION_NUMBER: u8 = 0; } -#[link_section = ".ram_d3"] +#[unsafe(link_section = ".ram_d3")] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); /// Configure MPU to make SRAM4 region non-cacheable diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index 1917749c5..4cd7b84e5 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h7b0-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs b/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs index dffb740a9..865062f4b 100644 --- a/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs +++ b/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs @@ -5,6 +5,7 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::mode::Blocking; use embassy_stm32::ospi::{ @@ -12,7 +13,6 @@ use embassy_stm32::ospi::{ OspiWidth, TransferConfig, WrapSize, }; use embassy_stm32::time::Hertz; -use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index bfe59b68d..445916972 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h7rs-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h7rs/src/bin/blinky.rs b/examples/stm32h7rs/src/bin/blinky.rs index 5fd50fb15..4c0864ff6 100644 --- a/examples/stm32h7rs/src/bin/blinky.rs +++ b/examples/stm32h7rs/src/bin/blinky.rs @@ -3,9 +3,9 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; 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 _}; diff --git a/examples/stm32h7rs/src/bin/can.rs b/examples/stm32h7rs/src/bin/can.rs index 0af11ef3e..49830f9b7 100644 --- a/examples/stm32h7rs/src/bin/can.rs +++ b/examples/stm32h7rs/src/bin/can.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::peripherals::*; -use embassy_stm32::{bind_interrupts, can, rcc, Config}; +use embassy_stm32::{Config, bind_interrupts, can, rcc}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7rs/src/bin/eth.rs b/examples/stm32h7rs/src/bin/eth.rs index 67f541564..5ce1d4765 100644 --- a/examples/stm32h7rs/src/bin/eth.rs +++ b/examples/stm32h7rs/src/bin/eth.rs @@ -8,7 +8,7 @@ use embassy_net::{Ipv4Address, Ipv4Cidr, StackResources}; use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use heapless::Vec; use static_cell::StaticCell; diff --git a/examples/stm32h7rs/src/bin/multiprio.rs b/examples/stm32h7rs/src/bin/multiprio.rs index 2f2ffdea2..8375e0e8e 100644 --- a/examples/stm32h7rs/src/bin/multiprio.rs +++ b/examples/stm32h7rs/src/bin/multiprio.rs @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn UART4() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn UART5() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/stm32h7rs/src/bin/rng.rs b/examples/stm32h7rs/src/bin/rng.rs index a9ef7200d..489747678 100644 --- a/examples/stm32h7rs/src/bin/rng.rs +++ b/examples/stm32h7rs/src/bin/rng.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, rng}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h7rs/src/bin/rtc.rs b/examples/stm32h7rs/src/bin/rtc.rs index 0adb48877..1bd71637b 100644 --- a/examples/stm32h7rs/src/bin/rtc.rs +++ b/examples/stm32h7rs/src/bin/rtc.rs @@ -4,9 +4,9 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; 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 _}; diff --git a/examples/stm32h7rs/src/bin/usb_serial.rs b/examples/stm32h7rs/src/bin/usb_serial.rs index 23abc3e2f..3e295dd51 100644 --- a/examples/stm32h7rs/src/bin/usb_serial.rs +++ b/examples/stm32h7rs/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs b/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs index 4c1b450b4..d91ae9de0 100644 --- a/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs +++ b/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs @@ -8,6 +8,7 @@ use core::cmp::min; use defmt::info; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::mode::Blocking; use embassy_stm32::time::Hertz; @@ -15,7 +16,6 @@ use embassy_stm32::xspi::{ AddressSize, ChipSelectHighTime, DummyCycles, FIFOThresholdLevel, Instance, MemorySize, MemoryType, TransferConfig, WrapSize, Xspi, XspiWidth, }; -use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index d42cdac15..a9c71d655 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32l0-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32l0/src/bin/button_exti.rs b/examples/stm32l0/src/bin/button_exti.rs index 4945da7ce..7ff4a7d52 100644 --- a/examples/stm32l0/src/bin/button_exti.rs +++ b/examples/stm32l0/src/bin/button_exti.rs @@ -3,9 +3,9 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::Pull; -use embassy_stm32::Config; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32l0/src/bin/dds.rs b/examples/stm32l0/src/bin/dds.rs index eaa7a61a8..d8f9020d4 100644 --- a/examples/stm32l0/src/bin/dds.rs +++ b/examples/stm32l0/src/bin/dds.rs @@ -12,7 +12,7 @@ use embassy_stm32::time::hz; use embassy_stm32::timer::low_level::{Timer as LLTimer, *}; use embassy_stm32::timer::simple_pwm::PwmPin; use embassy_stm32::timer::{Ch3, Channel}; -use embassy_stm32::{interrupt, pac, Config}; +use embassy_stm32::{Config, interrupt, pac}; use panic_probe as _; const DDS_SINE_DATA: [u8; 256] = [ diff --git a/examples/stm32l0/src/bin/eeprom.rs b/examples/stm32l0/src/bin/eeprom.rs index 370246644..a33088f36 100644 --- a/examples/stm32l0/src/bin/eeprom.rs +++ b/examples/stm32l0/src/bin/eeprom.rs @@ -3,7 +3,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::flash::{Flash, EEPROM_BASE, EEPROM_SIZE}; +use embassy_stm32::flash::{EEPROM_BASE, EEPROM_SIZE, Flash}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32l0/src/bin/raw_spawn.rs b/examples/stm32l0/src/bin/raw_spawn.rs index 6385e3c8f..8e8fe0240 100644 --- a/examples/stm32l0/src/bin/raw_spawn.rs +++ b/examples/stm32l0/src/bin/raw_spawn.rs @@ -5,8 +5,8 @@ use core::mem; use cortex_m_rt::entry; use defmt::*; -use embassy_executor::raw::TaskStorage; use embassy_executor::Executor; +use embassy_executor::raw::TaskStorage; use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -48,5 +48,5 @@ fn main() -> ! { } unsafe fn make_static(t: &T) -> &'static T { - mem::transmute(t) + unsafe { mem::transmute(t) } } diff --git a/examples/stm32l0/src/bin/usb_serial.rs b/examples/stm32l0/src/bin/usb_serial.rs index fdb1aeb59..612082f29 100644 --- a/examples/stm32l0/src/bin/usb_serial.rs +++ b/examples/stm32l0/src/bin/usb_serial.rs @@ -6,9 +6,9 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{self, Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 76ceade9c..7f6b31ed5 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32l1-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32l1/src/bin/eeprom.rs b/examples/stm32l1/src/bin/eeprom.rs index 370246644..a33088f36 100644 --- a/examples/stm32l1/src/bin/eeprom.rs +++ b/examples/stm32l1/src/bin/eeprom.rs @@ -3,7 +3,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::flash::{Flash, EEPROM_BASE, EEPROM_SIZE}; +use embassy_stm32::flash::{EEPROM_BASE, EEPROM_SIZE, Flash}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32l1/src/bin/usb_serial.rs b/examples/stm32l1/src/bin/usb_serial.rs index a35f1d7a7..c54d37f9d 100644 --- a/examples/stm32l1/src/bin/usb_serial.rs +++ b/examples/stm32l1/src/bin/usb_serial.rs @@ -6,9 +6,9 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{self, Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 1b7f15b1d..936472199 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32l4-examples" version = "0.1.1" license = "MIT OR Apache-2.0" diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs index c557ac6d7..40e907940 100644 --- a/examples/stm32l4/src/bin/adc.rs +++ b/examples/stm32l4/src/bin/adc.rs @@ -2,8 +2,8 @@ #![no_main] use defmt::*; -use embassy_stm32::adc::{Adc, Resolution}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, Resolution}; use {defmt_rtt as _, panic_probe as _}; #[cortex_m_rt::entry] diff --git a/examples/stm32l4/src/bin/can.rs b/examples/stm32l4/src/bin/can.rs index 3c4cdac24..bd361417e 100644 --- a/examples/stm32l4/src/bin/can.rs +++ b/examples/stm32l4/src/bin/can.rs @@ -8,7 +8,7 @@ use embassy_stm32::can::{ Can, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, }; use embassy_stm32::peripherals::CAN1; -use embassy_stm32::{bind_interrupts, Config}; +use embassy_stm32::{Config, bind_interrupts}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index 44edec728..bfdf858c5 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs @@ -3,6 +3,7 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Peri; use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; use embassy_stm32::mode::Async; use embassy_stm32::pac::timer::vals::Mms; @@ -10,7 +11,6 @@ use embassy_stm32::peripherals::{DAC1, TIM6, TIM7}; use embassy_stm32::rcc::frequency; use embassy_stm32::time::Hertz; use embassy_stm32::timer::low_level::Timer; -use embassy_stm32::Peri; use micromath::F32Ext; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32l4/src/bin/rng.rs b/examples/stm32l4/src/bin/rng.rs index 14d0e3c1e..4d9f83ad8 100644 --- a/examples/stm32l4/src/bin/rng.rs +++ b/examples/stm32l4/src/bin/rng.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, PllSource, Sysclk}; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, rng}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs index f554f0f78..1d26cd008 100644 --- a/examples/stm32l4/src/bin/rtc.rs +++ b/examples/stm32l4/src/bin/rtc.rs @@ -4,9 +4,9 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::time::Hertz; -use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 24efe526f..8e54938d1 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -16,14 +16,14 @@ use core::marker::PhantomData; use core::sync::atomic::{AtomicI32, Ordering}; -use defmt::{error, info, println, unwrap, Format}; +use defmt::{Format, error, info, println, unwrap}; use defmt_rtt as _; // global logger use embassy_executor::Spawner; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_futures::yield_now; use embassy_net::tcp::TcpSocket; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4}; -use embassy_net_adin1110::{Device, Runner, ADIN1110}; +use embassy_net_adin1110::{ADIN1110, Device, Runner}; use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; use embassy_stm32::i2c::{self, Config as I2C_Config, I2c}; use embassy_stm32::mode::Async; @@ -159,7 +159,9 @@ async fn main(spawner: Spawner) { // Check the SPI mode selected with the "HW CFG" dip-switch if !cfg1_spi_mode { - error!("Driver doesn´t support SPI Protolcol \"OPEN Alliance\".\nplease use the \"Generic SPI\"! Turn On \"HW CFG\": \"SPI_CFG1\""); + error!( + "Driver doesn´t support SPI Protolcol \"OPEN Alliance\".\nplease use the \"Generic SPI\"! Turn On \"HW CFG\": \"SPI_CFG1\"" + ); loop { led_uc2_red.toggle(); Timer::after(Duration::from_hz(10)).await; diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index af90e297e..17cd107f6 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use defmt_rtt as _; // global logger use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use panic_probe as _; bind_interrupts!(struct Irqs { diff --git a/examples/stm32l432/Cargo.toml b/examples/stm32l432/Cargo.toml index f173c651e..14f41992d 100644 --- a/examples/stm32l432/Cargo.toml +++ b/examples/stm32l432/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32l432-examples" version = "0.1.1" license = "MIT OR Apache-2.0" diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 9999300b8..b6158c854 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32l5-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32l5/src/bin/rng.rs b/examples/stm32l5/src/bin/rng.rs index 0a644e73d..d6302e106 100644 --- a/examples/stm32l5/src/bin/rng.rs +++ b/examples/stm32l5/src/bin/rng.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllRDiv, PllSource, Sysclk}; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, rng}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index 25aa9ef69..d2cbeb550 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -3,11 +3,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_net::tcp::TcpSocket; use embassy_net::StackResources; +use embassy_net::tcp::TcpSocket; use embassy_stm32::rng::Rng; use embassy_stm32::usb::Driver; -use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, rng, usb}; use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, UsbDevice}; diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index 8c7cdbef5..d8f2de941 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs @@ -7,13 +7,13 @@ use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_time::Timer; +use embassy_usb::Builder; use embassy_usb::class::hid::{ HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State, }; use embassy_usb::control::OutResponse; -use embassy_usb::Builder; use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs index a64bda31b..4f77fc1d7 100644 --- a/examples/stm32l5/src/bin/usb_serial.rs +++ b/examples/stm32l5/src/bin/usb_serial.rs @@ -5,10 +5,10 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 9318414a5..9f5227e3f 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32u0-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32u0/src/bin/adc.rs b/examples/stm32u0/src/bin/adc.rs index c8252e4e1..32a54299d 100644 --- a/examples/stm32u0/src/bin/adc.rs +++ b/examples/stm32u0/src/bin/adc.rs @@ -2,8 +2,8 @@ #![no_main] use defmt::*; -use embassy_stm32::adc::{Adc, Resolution}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, Resolution}; use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32u0/src/bin/rng.rs b/examples/stm32u0/src/bin/rng.rs index 89445b042..07deda94c 100644 --- a/examples/stm32u0/src/bin/rng.rs +++ b/examples/stm32u0/src/bin/rng.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rcc::mux::Clk48sel; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, rng}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32u0/src/bin/rtc.rs b/examples/stm32u0/src/bin/rtc.rs index 72fa0fde4..d071cfbc7 100644 --- a/examples/stm32u0/src/bin/rtc.rs +++ b/examples/stm32u0/src/bin/rtc.rs @@ -4,8 +4,8 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::Config; +use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32u0/src/bin/usb_serial.rs b/examples/stm32u0/src/bin/usb_serial.rs index 273f40643..77d0640f6 100644 --- a/examples/stm32u0/src/bin/usb_serial.rs +++ b/examples/stm32u0/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use defmt_rtt as _; // global logger use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use panic_probe as _; bind_interrupts!(struct Irqs { diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index f2ffe52c5..7a1e62406 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32u5-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs index d2aa28087..91e33053e 100644 --- a/examples/stm32u5/src/bin/adc.rs +++ b/examples/stm32u5/src/bin/adc.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_stm32::adc; -use embassy_stm32::adc::{adc4, AdcChannel}; +use embassy_stm32::adc::{AdcChannel, adc4}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32u5/src/bin/ltdc.rs b/examples/stm32u5/src/bin/ltdc.rs index 46d1c120f..d1fddb679 100644 --- a/examples/stm32u5/src/bin/ltdc.rs +++ b/examples/stm32u5/src/bin/ltdc.rs @@ -13,14 +13,14 @@ use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::ltdc::{self, Ltdc, LtdcConfiguration, LtdcLayer, LtdcLayerConfig, PolarityActive, PolarityEdge}; use embassy_stm32::{bind_interrupts, peripherals}; use embassy_time::{Duration, Timer}; +use embedded_graphics::Pixel; use embedded_graphics::draw_target::DrawTarget; use embedded_graphics::geometry::{OriginDimensions, Point, Size}; use embedded_graphics::image::Image; -use embedded_graphics::pixelcolor::raw::RawU24; use embedded_graphics::pixelcolor::Rgb888; +use embedded_graphics::pixelcolor::raw::RawU24; use embedded_graphics::prelude::*; use embedded_graphics::primitives::Rectangle; -use embedded_graphics::Pixel; use heapless::{Entry, FnvIndexMap}; use tinybmp::Bmp; use {defmt_rtt as _, panic_probe as _}; @@ -317,7 +317,7 @@ impl OriginDimensions for DoubleBuffer { mod rcc_setup { use embassy_stm32::time::Hertz; - use embassy_stm32::{rcc, Config, Peripherals}; + use embassy_stm32::{Config, Peripherals, rcc}; /// Sets up clocks for the stm32u5g9zj mcu /// change this if you plan to use a different microcontroller diff --git a/examples/stm32u5/src/bin/usb_hs_serial.rs b/examples/stm32u5/src/bin/usb_hs_serial.rs index d37e7777b..c444d3479 100644 --- a/examples/stm32u5/src/bin/usb_hs_serial.rs +++ b/examples/stm32u5/src/bin/usb_hs_serial.rs @@ -6,10 +6,10 @@ use defmt_rtt as _; // global logger use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use panic_probe as _; bind_interrupts!(struct Irqs { diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index ff7f4e5be..c0a768cbb 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use defmt_rtt as _; // global logger use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use panic_probe as _; bind_interrupts!(struct Irqs { diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 7ab13c290..783690c11 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32wb-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs index 3bd8b4a63..f309ca3a2 100644 --- a/examples/stm32wb/src/bin/eddystone_beacon.rs +++ b/examples/stm32wb/src/bin/eddystone_beacon.rs @@ -8,15 +8,15 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32_wpan::TlMbox; +use embassy_stm32_wpan::hci::BdAddr; use embassy_stm32_wpan::hci::host::uart::UartHci; use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; use embassy_stm32_wpan::hci::types::AdvertisingType; use embassy_stm32_wpan::hci::vendor::command::gap::{AdvertisingDataType, DiscoverableParameters, GapCommands, Role}; use embassy_stm32_wpan::hci::vendor::command::gatt::GattCommands; use embassy_stm32_wpan::hci::vendor::command::hal::{ConfigData, HalCommands, PowerLevel}; -use embassy_stm32_wpan::hci::BdAddr; use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp; -use embassy_stm32_wpan::TlMbox; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs index 5d927bc00..2ed257566 100644 --- a/examples/stm32wb/src/bin/gatt_server.rs +++ b/examples/stm32wb/src/bin/gatt_server.rs @@ -8,6 +8,7 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32_wpan::TlMbox; use embassy_stm32_wpan::hci::event::command::{CommandComplete, ReturnParameters}; use embassy_stm32_wpan::hci::host::uart::{Packet, UartHci}; use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; @@ -28,7 +29,6 @@ use embassy_stm32_wpan::hci::{BdAddr, Event}; use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp; use embassy_stm32_wpan::sub::ble::Ble; use embassy_stm32_wpan::sub::mm; -use embassy_stm32_wpan::TlMbox; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs index ede6cf4b9..18a52e162 100644 --- a/examples/stm32wb/src/bin/mac_ffd.rs +++ b/examples/stm32wb/src/bin/mac_ffd.rs @@ -6,11 +6,11 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32_wpan::TlMbox; use embassy_stm32_wpan::mac::commands::{AssociateResponse, ResetRequest, SetRequest, StartRequest}; use embassy_stm32_wpan::mac::event::MacEvent; use embassy_stm32_wpan::mac::typedefs::{MacChannel, MacStatus, PanId, PibId, SecurityLevel}; use embassy_stm32_wpan::sub::mm; -use embassy_stm32_wpan::TlMbox; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs index cc3b21e2e..5296943a1 100644 --- a/examples/stm32wb/src/bin/mac_ffd_net.rs +++ b/examples/stm32wb/src/bin/mac_ffd_net.rs @@ -6,11 +6,11 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32_wpan::TlMbox; use embassy_stm32_wpan::mac::commands::{ResetRequest, SetRequest, StartRequest}; use embassy_stm32_wpan::mac::typedefs::{MacChannel, PanId, PibId}; use embassy_stm32_wpan::mac::{self, Runner}; use embassy_stm32_wpan::sub::mm; -use embassy_stm32_wpan::TlMbox; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs index d872104a8..883179023 100644 --- a/examples/stm32wb/src/bin/mac_rfd.rs +++ b/examples/stm32wb/src/bin/mac_rfd.rs @@ -6,13 +6,13 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32_wpan::TlMbox; use embassy_stm32_wpan::mac::commands::{AssociateRequest, DataRequest, GetRequest, ResetRequest, SetRequest}; use embassy_stm32_wpan::mac::event::MacEvent; use embassy_stm32_wpan::mac::typedefs::{ AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel, }; use embassy_stm32_wpan::sub::mm; -use embassy_stm32_wpan::TlMbox; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs index 95c73872b..16d0a1527 100644 --- a/examples/stm32wb/src/bin/tl_mbox_mac.rs +++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs @@ -6,8 +6,8 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; -use embassy_stm32_wpan::sub::mm; use embassy_stm32_wpan::TlMbox; +use embassy_stm32_wpan::sub::mm; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index e1196614a..3496b41b0 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32wba-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32wba/src/bin/adc.rs b/examples/stm32wba/src/bin/adc.rs index a9651d57e..8c80470b8 100644 --- a/examples/stm32wba/src/bin/adc.rs +++ b/examples/stm32wba/src/bin/adc.rs @@ -2,7 +2,7 @@ #![no_main] use defmt::*; -use embassy_stm32::adc::{adc4, AdcChannel}; +use embassy_stm32::adc::{AdcChannel, adc4}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32wba/src/bin/pwm.rs b/examples/stm32wba/src/bin/pwm.rs index de690fda0..f20c77a7c 100644 --- a/examples/stm32wba/src/bin/pwm.rs +++ b/examples/stm32wba/src/bin/pwm.rs @@ -4,13 +4,13 @@ use defmt::*; use defmt_rtt as _; // global logger use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::gpio::OutputType; use embassy_stm32::rcc::{ AHB5Prescaler, AHBPrescaler, APBPrescaler, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale, }; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::Config; use embassy_time::Timer; use panic_probe as _; diff --git a/examples/stm32wba6/Cargo.toml b/examples/stm32wba6/Cargo.toml index f98317846..04bb27cb0 100644 --- a/examples/stm32wba6/Cargo.toml +++ b/examples/stm32wba6/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32wba6-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32wba6/src/bin/adc.rs b/examples/stm32wba6/src/bin/adc.rs index a9651d57e..8c80470b8 100644 --- a/examples/stm32wba6/src/bin/adc.rs +++ b/examples/stm32wba6/src/bin/adc.rs @@ -2,7 +2,7 @@ #![no_main] use defmt::*; -use embassy_stm32::adc::{adc4, AdcChannel}; +use embassy_stm32::adc::{AdcChannel, adc4}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32wba6/src/bin/pwm.rs b/examples/stm32wba6/src/bin/pwm.rs index 2c696834a..64ae01945 100644 --- a/examples/stm32wba6/src/bin/pwm.rs +++ b/examples/stm32wba6/src/bin/pwm.rs @@ -4,13 +4,13 @@ use defmt::*; use defmt_rtt as _; // global logger use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::gpio::OutputType; use embassy_stm32::rcc::{ AHB5Prescaler, AHBPrescaler, APBPrescaler, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale, }; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::Config; use embassy_time::Timer; use panic_probe as _; diff --git a/examples/stm32wba6/src/bin/usb_hs_serial.rs b/examples/stm32wba6/src/bin/usb_hs_serial.rs index 20bdeaac3..a60eeb480 100644 --- a/examples/stm32wba6/src/bin/usb_hs_serial.rs +++ b/examples/stm32wba6/src/bin/usb_hs_serial.rs @@ -5,10 +5,10 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 825d25c0d..1754aa0b8 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32wl-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32wl/src/bin/adc.rs b/examples/stm32wl/src/bin/adc.rs index 118f02ae1..6b21b086b 100644 --- a/examples/stm32wl/src/bin/adc.rs +++ b/examples/stm32wl/src/bin/adc.rs @@ -5,8 +5,8 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, CkModePclk, Clock, SampleTime}; use embassy_stm32::SharedData; +use embassy_stm32::adc::{Adc, CkModePclk, Clock, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32wl/src/bin/blinky.rs b/examples/stm32wl/src/bin/blinky.rs index a2a90871d..f7f57e35c 100644 --- a/examples/stm32wl/src/bin/blinky.rs +++ b/examples/stm32wl/src/bin/blinky.rs @@ -5,8 +5,8 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::SharedData; +use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32wl/src/bin/button.rs b/examples/stm32wl/src/bin/button.rs index 21bcd2ac6..07bc95ad7 100644 --- a/examples/stm32wl/src/bin/button.rs +++ b/examples/stm32wl/src/bin/button.rs @@ -5,8 +5,8 @@ use core::mem::MaybeUninit; use cortex_m_rt::entry; use defmt::*; -use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; use embassy_stm32::SharedData; +use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; use {defmt_rtt as _, panic_probe as _}; #[unsafe(link_section = ".shared_data")] diff --git a/examples/stm32wl/src/bin/button_exti.rs b/examples/stm32wl/src/bin/button_exti.rs index 0a8aece34..953b13bac 100644 --- a/examples/stm32wl/src/bin/button_exti.rs +++ b/examples/stm32wl/src/bin/button_exti.rs @@ -5,9 +5,9 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::SharedData; use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::Pull; -use embassy_stm32::SharedData; use {defmt_rtt as _, panic_probe as _}; #[unsafe(link_section = ".shared_data")] diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs index 320a9723a..bc707820d 100644 --- a/examples/stm32wl/src/bin/flash.rs +++ b/examples/stm32wl/src/bin/flash.rs @@ -5,8 +5,8 @@ use core::mem::MaybeUninit; use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::flash::Flash; use embassy_stm32::SharedData; +use embassy_stm32::flash::Flash; use {defmt_rtt as _, panic_probe as _}; #[unsafe(link_section = ".shared_data")] diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs index 68b9d7d00..931f9819a 100644 --- a/examples/stm32wl/src/bin/random.rs +++ b/examples/stm32wl/src/bin/random.rs @@ -7,7 +7,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rng::{self, Rng}; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, peripherals, SharedData}; +use embassy_stm32::{SharedData, bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs index 505a85f47..829ea2de7 100644 --- a/examples/stm32wl/src/bin/uart_async.rs +++ b/examples/stm32wl/src/bin/uart_async.rs @@ -6,7 +6,7 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::usart::{Config, InterruptHandler, Uart}; -use embassy_stm32::{bind_interrupts, peripherals, SharedData}; +use embassy_stm32::{SharedData, bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index e8897506c..79d50b584 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-wasm-example" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/rustfmt.toml b/rustfmt.toml index 2561562fd..3d5eeed93 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,4 @@ group_imports = "StdExternalCrate" imports_granularity = "Module" -edition = "2021" +edition = "2024" max_width = 120 diff --git a/tests/mspm0/Cargo.toml b/tests/mspm0/Cargo.toml index 227d898d5..df52b538d 100644 --- a/tests/mspm0/Cargo.toml +++ b/tests/mspm0/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-mspm0-tests" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/tests/mspm0/src/bin/dma.rs b/tests/mspm0/src/bin/dma.rs index 6fd973a18..9c56acadc 100644 --- a/tests/mspm0/src/bin/dma.rs +++ b/tests/mspm0/src/bin/dma.rs @@ -11,8 +11,8 @@ use core::slice; use defmt::{assert, assert_eq, *}; use embassy_executor::Spawner; -use embassy_mspm0::dma::{Channel, Transfer, TransferMode, TransferOptions, Word}; use embassy_mspm0::Peri; +use embassy_mspm0::dma::{Channel, Transfer, TransferMode, TransferOptions, Word}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 8acf27ce7..3a9b86cef 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml index c426fdd74..3756046fa 100644 --- a/tests/perf-client/Cargo.toml +++ b/tests/perf-client/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "perf-client" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/tests/perf-client/src/lib.rs b/tests/perf-client/src/lib.rs index 4bd9e5674..1ba071e8d 100644 --- a/tests/perf-client/src/lib.rs +++ b/tests/perf-client/src/lib.rs @@ -4,7 +4,7 @@ use defmt::{assert, *}; use embassy_futures::join::join; use embassy_net::tcp::TcpSocket; use embassy_net::{Ipv4Address, Stack}; -use embassy_time::{with_timeout, Duration, Timer}; +use embassy_time::{Duration, Timer, with_timeout}; pub struct Expected { pub down_kbps: usize, diff --git a/tests/perf-server/Cargo.toml b/tests/perf-server/Cargo.toml index f048eade2..72f92ed8d 100644 --- a/tests/perf-server/Cargo.toml +++ b/tests/perf-server/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "perf-server" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml index c441e8ed3..935c6a2ee 100644 --- a/tests/riscv32/Cargo.toml +++ b/tests/riscv32/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-riscv-tests" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 19461520a..640e58f11 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-rp-tests" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index 555134ffd..9487f5e1a 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -3,7 +3,7 @@ teleprobe_meta::target!(b"rpi-pico"); use cyw43::JoinOptions; -use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; +use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_net::{Config, StackResources}; diff --git a/tests/rp/src/bin/gpio_multicore.rs b/tests/rp/src/bin/gpio_multicore.rs index f48dd207b..6abcba590 100644 --- a/tests/rp/src/bin/gpio_multicore.rs +++ b/tests/rp/src/bin/gpio_multicore.rs @@ -7,10 +7,10 @@ teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{info, unwrap}; use embassy_executor::Executor; +use embassy_rp::Peri; use embassy_rp::gpio::{Input, Level, Output, Pull}; -use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_rp::multicore::{Stack, spawn_core1}; use embassy_rp::peripherals::{PIN_0, PIN_1}; -use embassy_rp::Peri; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use static_cell::StaticCell; diff --git a/tests/rp/src/bin/multicore.rs b/tests/rp/src/bin/multicore.rs index 11b03cfea..7e34bc778 100644 --- a/tests/rp/src/bin/multicore.rs +++ b/tests/rp/src/bin/multicore.rs @@ -7,7 +7,7 @@ teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{info, unwrap}; use embassy_executor::Executor; -use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_rp::multicore::{Stack, spawn_core1}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use static_cell::StaticCell; diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs index 167a26eb2..87a03b5e2 100644 --- a/tests/rp/src/bin/overclock.rs +++ b/tests/rp/src/bin/overclock.rs @@ -8,7 +8,7 @@ teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::info; use embassy_executor::Spawner; -use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage}; +use embassy_rp::clocks::{ClockConfig, CoreVoltage, clk_sys_freq, core_voltage}; use embassy_rp::config::Config; use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; diff --git a/tests/rp/src/bin/pio_multi_load.rs b/tests/rp/src/bin/pio_multi_load.rs index aca476d56..82bbab272 100644 --- a/tests/rp/src/bin/pio_multi_load.rs +++ b/tests/rp/src/bin/pio_multi_load.rs @@ -57,7 +57,9 @@ async fn main(_spawner: Spawner) { assert_eq!(loaded2.wrap.target, 14); // wrapping around the end of program space automatically works - let prg3 = pio_asm!("nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "irq 2",); + let prg3 = pio_asm!( + "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "irq 2", + ); let loaded3 = common.load_program(&prg3.program); assert_eq!(loaded3.origin, 24); assert_eq!(loaded3.wrap.source, 3); diff --git a/tests/rp/src/bin/rtc.rs b/tests/rp/src/bin/rtc.rs index c66981d95..e1def7b5b 100644 --- a/tests/rp/src/bin/rtc.rs +++ b/tests/rp/src/bin/rtc.rs @@ -5,7 +5,7 @@ teleprobe_meta::target!(b"rpi-pico"); use defmt::{assert, *}; use embassy_executor::Spawner; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_rp::bind_interrupts; use embassy_rp::rtc::{DateTime, DateTimeFilter, DayOfWeek, Rtc}; use embassy_time::{Duration, Instant, Timer}; diff --git a/tests/rp/src/bin/spinlock_mutex_multicore.rs b/tests/rp/src/bin/spinlock_mutex_multicore.rs index c56d43ade..25c4faf37 100644 --- a/tests/rp/src/bin/spinlock_mutex_multicore.rs +++ b/tests/rp/src/bin/spinlock_mutex_multicore.rs @@ -7,7 +7,7 @@ teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{info, unwrap}; use embassy_executor::Executor; -use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_rp::multicore::{Stack, spawn_core1}; use embassy_rp::spinlock_mutex::SpinlockRawMutex; use embassy_sync::channel::Channel; use static_cell::StaticCell; diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 891ec93fd..1161e827b 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32-tests" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/tests/stm32/src/bin/afio.rs b/tests/stm32/src/bin/afio.rs index 81d50874b..d88765717 100644 --- a/tests/stm32/src/bin/afio.rs +++ b/tests/stm32/src/bin/afio.rs @@ -16,7 +16,7 @@ use embassy_stm32::timer::qei::Qei; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; use embassy_stm32::timer::{Ch1, Ch2}; use embassy_stm32::usart::{Uart, UartRx, UartTx}; -use embassy_stm32::{bind_interrupts, Peripherals}; +use embassy_stm32::{Peripherals, bind_interrupts}; #[cfg(not(feature = "afio-connectivity-line"))] bind_interrupts!(struct Irqs { diff --git a/tests/stm32/src/bin/cryp.rs b/tests/stm32/src/bin/cryp.rs index f54c99cc3..640de50e3 100644 --- a/tests/stm32/src/bin/cryp.rs +++ b/tests/stm32/src/bin/cryp.rs @@ -5,9 +5,9 @@ #[path = "../common.rs"] mod common; +use aes_gcm::Aes128Gcm; use aes_gcm::aead::heapless::Vec; use aes_gcm::aead::{AeadInPlace, KeyInit}; -use aes_gcm::Aes128Gcm; use common::*; use embassy_executor::Spawner; use embassy_stm32::cryp::{self, *}; diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index c2a1a7bb8..d97f493df 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs @@ -8,7 +8,7 @@ mod common; use common::*; use embassy_executor::Spawner; use embassy_stm32::peripherals::*; -use embassy_stm32::{bind_interrupts, can, Config}; +use embassy_stm32::{Config, bind_interrupts, can}; use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs index 8119c1f39..833ca05d0 100644 --- a/tests/stm32/src/bin/stop.rs +++ b/tests/stm32/src/bin/stop.rs @@ -9,10 +9,10 @@ use chrono::NaiveDate; use common::*; use cortex_m_rt::entry; use embassy_executor::Spawner; -use embassy_stm32::low_power::{stop_ready, stop_with_rtc, Executor, StopMode}; +use embassy_stm32::Config; +use embassy_stm32::low_power::{Executor, StopMode, stop_ready, stop_with_rtc}; use embassy_stm32::rcc::LsConfig; use embassy_stm32::rtc::{Rtc, RtcConfig}; -use embassy_stm32::Config; use embassy_time::Timer; use static_cell::StaticCell; diff --git a/tests/stm32/src/bin/ucpd.rs b/tests/stm32/src/bin/ucpd.rs index 97aefe1a0..c794afff8 100644 --- a/tests/stm32/src/bin/ucpd.rs +++ b/tests/stm32/src/bin/ucpd.rs @@ -9,7 +9,7 @@ use defmt::{assert, assert_eq}; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, RxError, Ucpd}; -use embassy_stm32::{bind_interrupts, peripherals, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals}; use embassy_time::Timer; bind_interrupts!(struct Irqs { diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index 129c7b692..0b98d3eeb 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs @@ -7,7 +7,7 @@ use common::*; use defmt::{assert, assert_eq, unreachable}; use embassy_executor::Spawner; use embassy_stm32::usart::{Config, ConfigError, Error, Uart}; -use embassy_time::{block_for, Duration, Instant}; +use embassy_time::{Duration, Instant, block_for}; #[embassy_executor::main] async fn main(_spawner: Spawner) { diff --git a/tests/stm32/src/bin/wpan_ble.rs b/tests/stm32/src/bin/wpan_ble.rs index 8957bfc04..0f396b848 100644 --- a/tests/stm32/src/bin/wpan_ble.rs +++ b/tests/stm32/src/bin/wpan_ble.rs @@ -12,16 +12,16 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32_wpan::TlMbox; +use embassy_stm32_wpan::hci::BdAddr; use embassy_stm32_wpan::hci::host::uart::UartHci; use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; use embassy_stm32_wpan::hci::types::AdvertisingType; use embassy_stm32_wpan::hci::vendor::command::gap::{AdvertisingDataType, DiscoverableParameters, GapCommands, Role}; use embassy_stm32_wpan::hci::vendor::command::gatt::GattCommands; use embassy_stm32_wpan::hci::vendor::command::hal::{ConfigData, HalCommands, PowerLevel}; -use embassy_stm32_wpan::hci::BdAddr; use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp; use embassy_stm32_wpan::sub::mm; -use embassy_stm32_wpan::TlMbox; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/tests/stm32/src/bin/wpan_mac.rs b/tests/stm32/src/bin/wpan_mac.rs index 79e13d524..f27146c44 100644 --- a/tests/stm32/src/bin/wpan_mac.rs +++ b/tests/stm32/src/bin/wpan_mac.rs @@ -10,13 +10,13 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32_wpan::TlMbox; use embassy_stm32_wpan::mac::commands::{AssociateRequest, GetRequest, ResetRequest, SetRequest}; use embassy_stm32_wpan::mac::event::MacEvent; use embassy_stm32_wpan::mac::typedefs::{ AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel, }; use embassy_stm32_wpan::sub::mm; -use embassy_stm32_wpan::TlMbox; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index f800769ab..2bd934d6f 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -1,11 +1,11 @@ #![macro_use] pub use defmt::*; +use embassy_stm32::Config; #[allow(unused)] use embassy_stm32::rcc::*; #[allow(unused)] use embassy_stm32::time::Hertz; -use embassy_stm32::Config; use {defmt_rtt as _, panic_probe as _}; #[cfg(feature = "stm32f103c8")] diff --git a/tests/utils/Cargo.toml b/tests/utils/Cargo.toml index ddb990e0f..da04a1f5d 100644 --- a/tests/utils/Cargo.toml +++ b/tests/utils/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "test-utils" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/tests/utils/src/bin/saturate_serial.rs b/tests/utils/src/bin/saturate_serial.rs index 85676b106..1c8a8b322 100644 --- a/tests/utils/src/bin/saturate_serial.rs +++ b/tests/utils/src/bin/saturate_serial.rs @@ -2,7 +2,7 @@ use std::path::Path; use std::time::Duration; use std::{env, io, process, thread}; -use rand::{rng, Rng}; +use rand::{Rng, rng}; use serial::SerialPort; pub fn main() { -- cgit From 3949a8601f293856df326ccc21252cb5f1518c5c Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Thu, 30 Oct 2025 11:52:53 +0100 Subject: embassy-nrf: add gpiote::InputChannel::wait_for_high/low() Also catch GPIOTE events directly when wait() is called, even before polling the future. --- embassy-nrf/CHANGELOG.md | 3 ++ embassy-nrf/src/gpiote.rs | 68 ++++++++++++++++++++++++++--- examples/nrf52840/src/bin/gpiote_channel.rs | 8 ++-- examples/nrf5340/src/bin/gpiote_channel.rs | 8 ++-- examples/nrf54l15/src/bin/gpiote_channel.rs | 8 ++-- 5 files changed, 77 insertions(+), 18 deletions(-) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index a0668c495..98f40f9a9 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -22,6 +22,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - bugfix: Do not write to UICR from non-secure code on nrf53 - bugfix: Add delay to uart init anomaly fix - changed: `BufferedUarte::read_ready` now uses the same definition for 'empty' so following read calls will not block when true is returned +- added: add `gpiote::InputChannel::wait_for_high()` and `wait_for_low()` to wait for specific signal level +- changed: `gpiote::InputChannel::wait()` now takes a mutable reference to `self` to avoid interference from concurrent calls +- changed: `gpiote::InputChannel::wait()` now ensures events are seen as soon as the function is called, even if the future is not polled ## 0.8.0 - 2025-09-30 diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 91944d8cd..d4f6668f3 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -349,16 +349,73 @@ impl<'d> InputChannel<'d> { } /// Asynchronously wait for an event in this channel. - pub async fn wait(&self) { - let g = self.ch.regs(); - let num = self.ch.number(); - let waker = self.ch.waker(); + /// + /// It is possible to call this function and await the returned future later. + /// If an even occurs in the mean time, the future will immediately report ready. + pub fn wait(&mut self) -> impl Future { + // NOTE: This is `-> impl Future` and not an `async fn` on purpose. + // Otherwise, events will only be detected starting at the first poll of the returned future. + Self::wait_internal(&mut self.ch) + } + + /// Asynchronously wait for the pin to become high. + /// + /// The channel must be configured with [`InputChannelPolarity::LoToHi`] or [`InputChannelPolarity::Toggle`]. + /// If the channel is not configured to detect rising edges, it is unspecified when the returned future completes. + /// + /// It is possible to call this function and await the returned future later. + /// If an even occurs in the mean time, the future will immediately report ready. + pub fn wait_for_high(&mut self) -> impl Future { + // NOTE: This is `-> impl Future` and not an `async fn` on purpose. + // Otherwise, events will only be detected starting at the first poll of the returned future. + + // Subscribe to the event before checking the pin level. + let wait = Self::wait_internal(&mut self.ch); + let pin = &self.pin; + async move { + if pin.is_high() { + return; + } + wait.await; + } + } + + /// Asynchronously wait for the pin to become low. + /// + /// The channel must be configured with [`InputChannelPolarity::HiToLo`] or [`InputChannelPolarity::Toggle`]. + /// If the channel is not configured to detect falling edges, it is unspecified when the returned future completes. + /// + /// It is possible to call this function and await the returned future later. + /// If an even occurs in the mean time, the future will immediately report ready. + pub fn wait_for_low(&mut self) -> impl Future { + // NOTE: This is `-> impl Future` and not an `async fn` on purpose. + // Otherwise, events will only be detected starting at the first poll of the returned future. + + // Subscribe to the event before checking the pin level. + let wait = Self::wait_internal(&mut self.ch); + let pin = &self.pin; + async move { + if pin.is_low() { + return; + } + wait.await; + } + } + + /// Internal implementation for `wait()` and friends. + fn wait_internal(channel: &mut Peri<'_, AnyChannel>) -> impl Future { + // NOTE: This is `-> impl Future` and not an `async fn` on purpose. + // Otherwise, events will only be detected starting at the first poll of the returned future. + + let g = channel.regs(); + let num = channel.number(); + let waker = channel.waker(); // Enable interrupt g.events_in(num).write_value(0); g.intenset(INTNUM).write(|w| w.0 = 1 << num); - poll_fn(|cx| { + poll_fn(move |cx| { CHANNEL_WAKERS[waker].register(cx.waker()); if g.events_in(num).read() != 0 { @@ -367,7 +424,6 @@ impl<'d> InputChannel<'d> { Poll::Pending } }) - .await; } /// Get the associated input pin. diff --git a/examples/nrf52840/src/bin/gpiote_channel.rs b/examples/nrf52840/src/bin/gpiote_channel.rs index c7ddc1d8d..e358779b2 100644 --- a/examples/nrf52840/src/bin/gpiote_channel.rs +++ b/examples/nrf52840/src/bin/gpiote_channel.rs @@ -12,10 +12,10 @@ async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); info!("Starting!"); - let ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_11, Pull::Up, InputChannelPolarity::HiToLo); - let ch2 = InputChannel::new(p.GPIOTE_CH1, p.P0_12, Pull::Up, InputChannelPolarity::LoToHi); - let ch3 = InputChannel::new(p.GPIOTE_CH2, p.P0_24, Pull::Up, InputChannelPolarity::Toggle); - let ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_25, Pull::Up, InputChannelPolarity::Toggle); + let mut ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_11, Pull::Up, InputChannelPolarity::HiToLo); + let mut ch2 = InputChannel::new(p.GPIOTE_CH1, p.P0_12, Pull::Up, InputChannelPolarity::LoToHi); + let mut ch3 = InputChannel::new(p.GPIOTE_CH2, p.P0_24, Pull::Up, InputChannelPolarity::Toggle); + let mut ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_25, Pull::Up, InputChannelPolarity::Toggle); let button1 = async { loop { diff --git a/examples/nrf5340/src/bin/gpiote_channel.rs b/examples/nrf5340/src/bin/gpiote_channel.rs index a085310ce..41ee732c3 100644 --- a/examples/nrf5340/src/bin/gpiote_channel.rs +++ b/examples/nrf5340/src/bin/gpiote_channel.rs @@ -12,10 +12,10 @@ async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); info!("Starting!"); - let ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_23, Pull::Up, InputChannelPolarity::HiToLo); - let ch2 = InputChannel::new(p.GPIOTE_CH1, p.P0_24, Pull::Up, InputChannelPolarity::LoToHi); - let ch3 = InputChannel::new(p.GPIOTE_CH2, p.P0_08, Pull::Up, InputChannelPolarity::Toggle); - let ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_09, Pull::Up, InputChannelPolarity::Toggle); + let mut ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_23, Pull::Up, InputChannelPolarity::HiToLo); + let mut ch2 = InputChannel::new(p.GPIOTE_CH1, p.P0_24, Pull::Up, InputChannelPolarity::LoToHi); + let mut ch3 = InputChannel::new(p.GPIOTE_CH2, p.P0_08, Pull::Up, InputChannelPolarity::Toggle); + let mut ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_09, Pull::Up, InputChannelPolarity::Toggle); let button1 = async { loop { diff --git a/examples/nrf54l15/src/bin/gpiote_channel.rs b/examples/nrf54l15/src/bin/gpiote_channel.rs index 6333250ba..cac8823f8 100644 --- a/examples/nrf54l15/src/bin/gpiote_channel.rs +++ b/examples/nrf54l15/src/bin/gpiote_channel.rs @@ -12,10 +12,10 @@ async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); info!("Starting!"); - let ch1 = InputChannel::new(p.GPIOTE20_CH0, p.P1_13, Pull::Up, InputChannelPolarity::HiToLo); - let ch2 = InputChannel::new(p.GPIOTE20_CH1, p.P1_09, Pull::Up, InputChannelPolarity::LoToHi); - let ch3 = InputChannel::new(p.GPIOTE20_CH2, p.P1_08, Pull::Up, InputChannelPolarity::Toggle); - let ch4 = InputChannel::new(p.GPIOTE30_CH0, p.P0_04, Pull::Up, InputChannelPolarity::Toggle); + let mut ch1 = InputChannel::new(p.GPIOTE20_CH0, p.P1_13, Pull::Up, InputChannelPolarity::HiToLo); + let mut ch2 = InputChannel::new(p.GPIOTE20_CH1, p.P1_09, Pull::Up, InputChannelPolarity::LoToHi); + let mut ch3 = InputChannel::new(p.GPIOTE20_CH2, p.P1_08, Pull::Up, InputChannelPolarity::Toggle); + let mut ch4 = InputChannel::new(p.GPIOTE30_CH0, p.P0_04, Pull::Up, InputChannelPolarity::Toggle); let button1 = async { loop { -- cgit From f440a3e19584aa8c1c5df742b964ae417cf705a1 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Mon, 3 Nov 2025 23:08:15 +0200 Subject: stm32/timer/simplepwm: Fix docs formatting and clarify timer usage --- embassy-stm32/src/timer/simple_pwm.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 06315d7f3..7597c0eee 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -309,7 +309,9 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// Generate a sequence of PWM waveform /// /// Note: - /// you will need to provide corresponding TIMx_UP DMA channel to use this method. + /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. + /// Also be aware that embassy timers use one of timers internally. It is possible to + /// switch this timer by using `time-driver-timX` feature. pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma>, channel: Channel, duty: &[u16]) { #[allow(clippy::let_unit_value)] // eg. stm32f334 let req = dma.request(); @@ -378,18 +380,23 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like: /// + /// ```rust,ignore /// let dma_buf: [u16; 16] = [ /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4 /// ]; + /// ``` /// - /// Each group of N values (where N = number of channels) is transferred on one update event, + /// Each group of `N` values (where `N` is number of channels) is transferred on one update event, /// updating the duty cycles of all selected channels simultaneously. /// /// Note: - /// you will need to provide corresponding TIMx_UP DMA channel to use this method. + /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. + /// Also be aware that embassy timers use one of timers internally. It is possible to + /// switch this timer by using `time-driver-timX` feature. + /// pub async fn waveform_up_multi_channel( &mut self, dma: Peri<'_, impl super::UpDma>, -- cgit From b584624b18d1070a589eca4a9fce9abd76413bfd Mon Sep 17 00:00:00 2001 From: pkj Date: Mon, 10 Nov 2025 20:48:37 +0800 Subject: feat: update CHANGELOG --- embassy-stm32/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index f85fd82ef..595778748 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- feat: timer: Add 32-bit timer support to SimplePwm waveform_up method following waveform pattern ([#4717](https://github.com/embassy-rs/embassy/pull/4717)) - feat: Add support for injected ADC measurements for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840)) - feat: Implement into_ring_buffered for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840)) - feat: Add support for 13-bit address and 16-bit data SDRAM chips -- cgit From 12b59dc610fb659a4d51ccc364865a7e154379d6 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 10 Nov 2025 09:56:42 -0600 Subject: adc: remove sample_time from struct --- embassy-stm32/src/adc/adc4.rs | 18 ++++---------- embassy-stm32/src/adc/c0.rs | 15 ++++-------- embassy-stm32/src/adc/f1.rs | 13 +++------- embassy-stm32/src/adc/f3.rs | 13 +++------- embassy-stm32/src/adc/f3_v1_1.rs | 5 ++-- embassy-stm32/src/adc/g4.rs | 22 +++++------------ embassy-stm32/src/adc/mod.rs | 2 -- embassy-stm32/src/adc/v1.rs | 13 +++------- embassy-stm32/src/adc/v2.rs | 17 ++++--------- embassy-stm32/src/adc/v3.rs | 36 ++++++++-------------------- embassy-stm32/src/adc/v4.rs | 23 ++++-------------- embassy-stm32/src/adc/watchdog_v1.rs | 6 ++--- examples/stm32c0/src/bin/adc.rs | 8 +++---- examples/stm32f0/src/bin/adc-watchdog.rs | 6 ++--- examples/stm32f0/src/bin/adc.rs | 5 ++-- examples/stm32f1/src/bin/adc.rs | 6 ++--- examples/stm32f334/src/bin/adc.rs | 8 +++---- examples/stm32f334/src/bin/opamp.rs | 8 +++---- examples/stm32f4/src/bin/adc.rs | 10 ++++---- examples/stm32f4/src/bin/adc_dma.rs | 8 +++---- examples/stm32f7/src/bin/adc.rs | 6 ++--- examples/stm32g0/src/bin/adc.rs | 5 ++-- examples/stm32g0/src/bin/adc_oversampling.rs | 3 +-- examples/stm32g4/src/bin/adc.rs | 3 +-- examples/stm32g4/src/bin/adc_differential.rs | 3 +-- examples/stm32g4/src/bin/adc_oversampling.rs | 3 +-- examples/stm32h5/src/bin/adc.rs | 6 ++--- examples/stm32h7/src/bin/adc.rs | 6 ++--- examples/stm32l0/src/bin/adc.rs | 5 ++-- examples/stm32l4/src/bin/adc.rs | 4 ++-- examples/stm32l4/src/bin/adc_dma.rs | 10 +++----- examples/stm32u0/src/bin/adc.rs | 4 ++-- examples/stm32u5/src/bin/adc.rs | 18 ++++++-------- examples/stm32wba/src/bin/adc.rs | 6 ++--- examples/stm32wba6/src/bin/adc.rs | 5 ++-- examples/stm32wl/src/bin/adc.rs | 6 ++--- examples/stm32wle5/src/bin/adc.rs | 5 ++-- tests/stm32/src/bin/dac.rs | 9 ++++--- tests/stm32/src/bin/dac_l1.rs | 11 ++++++--- 39 files changed, 131 insertions(+), 229 deletions(-) diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs index 2608160a3..befa8ed4a 100644 --- a/embassy-stm32/src/adc/adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs @@ -327,18 +327,6 @@ impl<'d, T: Instance> Adc4<'d, T> { Dac {} } - /// Set the ADC sample time. - pub fn set_sample_time(&mut self, sample_time: SampleTime) { - T::regs().smpr().modify(|w| { - w.set_smp(0, sample_time); - }); - } - - /// Get the ADC sample time. - pub fn sample_time(&self) -> SampleTime { - T::regs().smpr().read().smp(0) - } - /// Set the ADC resolution. pub fn set_resolution(&mut self, resolution: Resolution) { T::regs().cfgr1().modify(|w| w.set_res(resolution.into())); @@ -387,7 +375,11 @@ impl<'d, T: Instance> Adc4<'d, T> { } /// Read an ADC channel. - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { + T::regs().smpr().modify(|w| { + w.set_smp(0, sample_time); + }); + channel.setup(); // Select channel diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index fc28df346..70302ef96 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs @@ -156,7 +156,7 @@ pub enum Averaging { impl<'d, T: Instance> Adc<'d, T> { /// Create a new ADC driver. - pub fn new(adc: Peri<'d, T>, sample_time: SampleTime, resolution: Resolution) -> Self { + pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self { rcc::enable_and_reset::(); T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK)); @@ -174,10 +174,7 @@ impl<'d, T: Instance> Adc<'d, T> { ); } - let mut s = Self { - adc, - sample_time: SampleTime::from_bits(0), - }; + let mut s = Self { adc }; s.power_up(); @@ -189,8 +186,6 @@ impl<'d, T: Instance> Adc<'d, T> { s.configure_default(); - s.set_sample_time_all_channels(sample_time); - s } @@ -258,8 +253,6 @@ impl<'d, T: Instance> Adc<'d, T> { /// Set the ADC sample time. /// Shall only be called when ADC is not converting. pub fn set_sample_time_all_channels(&mut self, sample_time: SampleTime) { - self.sample_time = sample_time; - // Set all channels to use SMP1 field as source. T::regs().smpr().modify(|w| { w.smpsel(0); @@ -288,7 +281,9 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().dr().read().data() as u16 } - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { + self.set_sample_time_all_channels(sample_time); + Self::configure_channel(channel); T::regs().cfgr1().write(|reg| { reg.set_chselrmod(false); diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index f9c23d72b..32e330d76 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -71,10 +71,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - Self { - adc, - sample_time: SampleTime::from_bits(0), - } + Self { adc } } fn freq() -> Hertz { @@ -108,10 +105,6 @@ impl<'d, T: Instance> Adc<'d, T> { Temperature {} } - pub fn set_sample_time(&mut self, sample_time: SampleTime) { - self.sample_time = sample_time; - } - /// Perform a single conversion. async fn convert(&mut self) -> u16 { T::regs().cr2().modify(|reg| { @@ -134,8 +127,8 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().dr().read().0 as u16 } - pub async fn read(&mut self, channel: &mut impl AdcChannel) -> u16 { - Self::set_channel_sample_time(channel.channel(), self.sample_time); + pub async fn read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { + Self::set_channel_sample_time(channel.channel(), sample_time); T::regs().cr1().modify(|reg| { reg.set_scan(false); reg.set_discen(false); diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 73ceb087a..cf31aa81b 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -90,10 +90,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::Interrupt::enable(); } - Self { - adc, - sample_time: SampleTime::from_bits(0), - } + Self { adc } } fn freq() -> Hertz { @@ -124,10 +121,6 @@ impl<'d, T: Instance> Adc<'d, T> { Temperature {} } - pub fn set_sample_time(&mut self, sample_time: SampleTime) { - self.sample_time = sample_time; - } - /// Perform a single conversion. async fn convert(&mut self) -> u16 { T::regs().isr().write(|_| {}); @@ -150,8 +143,8 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().dr().read().rdata() } - pub async fn read(&mut self, channel: &mut impl AdcChannel) -> u16 { - Self::set_channel_sample_time(channel.channel(), self.sample_time); + pub async fn read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { + Self::set_channel_sample_time(channel.channel(), sample_time); // Configure the channel to sample T::regs().sqr1().write(|w| w.set_sq(0, channel.channel())); diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs index cd5de54f5..919ac3cc0 100644 --- a/embassy-stm32/src/adc/f3_v1_1.rs +++ b/embassy-stm32/src/adc/f3_v1_1.rs @@ -79,7 +79,7 @@ impl Vref { } pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration { - let vref_val = adc.read(self).await; + let vref_val = adc.read(self, SampleTime::from(0)).await; Calibration { vref_cal: self.calibrated_value(), vref_val, @@ -270,7 +270,8 @@ impl<'d, T: Instance> Adc<'d, T> { } } - pub async fn read(&mut self, channel: &mut impl AdcChannel) -> u16 { + pub async fn read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { + self.set_sample_time(channel, sample_time).await; self.set_sample_sequence(&[channel.channel()]).await; self.convert().await } diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 3767820cf..5066aeec0 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -168,10 +168,7 @@ impl<'d, T: Instance> Adc<'d, T> { ); } - let mut s = Self { - adc, - sample_time: SampleTime::from_bits(0), - }; + let mut s = Self { adc }; s.power_up(); s.configure_differential_inputs(); @@ -297,7 +294,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// channel on the other ADC unusable. The only exception is when ADC master and the slave /// operate in interleaved mode. #[cfg(stm32g4)] - pub fn set_differential_channel(&mut self, ch: usize, enable: bool) { + fn set_differential_channel(&mut self, ch: usize, enable: bool) { T::regs().cr().modify(|w| w.set_aden(false)); // disable adc T::regs().difsel().modify(|w| { w.set_difsel( @@ -350,11 +347,6 @@ impl<'d, T: Instance> Adc<'d, T> { // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); // } - /// Set the ADC sample time. - pub fn set_sample_time(&mut self, sample_time: SampleTime) { - self.sample_time = sample_time; - } - /// Set the ADC resolution. pub fn set_resolution(&mut self, resolution: Resolution) { T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); @@ -380,10 +372,10 @@ impl<'d, T: Instance> Adc<'d, T> { } /// Read an ADC pin. - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { channel.setup(); - self.read_channel(channel) + self.read_channel(channel, sample_time) } /// Start regular adc conversion @@ -755,12 +747,10 @@ impl<'d, T: Instance> Adc<'d, T> { ( Self { adc: self.adc.clone_unchecked(), - sample_time: self.sample_time, } .into_ring_buffered(dma, dma_buf, regular_sequence, regular_conversion_mode), Self { adc: self.adc.clone_unchecked(), - sample_time: self.sample_time, } .setup_injected_conversions(injected_sequence, injected_trigger, injected_interrupt), ) @@ -805,8 +795,8 @@ impl<'d, T: Instance> Adc<'d, T> { Self::set_channel_sample_time(channel.channel(), sample_time); } - fn read_channel(&mut self, channel: &mut impl AdcChannel) -> u16 { - Self::configure_channel(channel, self.sample_time); + fn read_channel(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { + Self::configure_channel(channel, sample_time); #[cfg(stm32h7)] { T::regs().cfgr2().modify(|w| w.set_lshift(0)); diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index ea7341f75..a6b796fb9 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -47,8 +47,6 @@ dma_trait!(RxDma4, adc4::Instance); pub struct Adc<'d, T: Instance> { #[allow(unused)] adc: crate::Peri<'d, T>, - #[cfg(not(any(adc_f3v3, adc_f3v2, adc_wba)))] - sample_time: SampleTime, } #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index a5869d110..3838cc12a 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -114,10 +114,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::Interrupt::enable(); } - Self { - adc, - sample_time: SampleTime::from_bits(0), - } + Self { adc } } #[cfg(not(adc_l0))] @@ -149,10 +146,6 @@ impl<'d, T: Instance> Adc<'d, T> { Temperature } - pub fn set_sample_time(&mut self, sample_time: SampleTime) { - self.sample_time = sample_time; - } - pub fn set_resolution(&mut self, resolution: Resolution) { T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); } @@ -163,12 +156,13 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cfgr2().modify(|reg| reg.set_ckmode(ckmode)); } - pub async fn read(&mut self, channel: &mut impl AdcChannel) -> u16 { + pub async fn read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { let ch_num = channel.channel(); channel.setup(); // A.7.5 Single conversion sequence code example - Software trigger T::regs().chselr().write(|reg| reg.set_chsel_x(ch_num as usize, true)); + T::regs().smpr().modify(|reg| reg.set_smp(sample_time.into())); self.convert().await } @@ -179,7 +173,6 @@ impl<'d, T: Instance> Adc<'d, T> { reg.set_eosmp(true); }); - T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into())); T::regs().ier().modify(|w| w.set_eocie(true)); T::regs().cr().modify(|reg| reg.set_adstart(true)); diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 90c6294d2..67721770a 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -117,10 +117,7 @@ where blocking_delay_us(3); - Self { - adc, - sample_time: SampleTime::from_bits(0), - } + Self { adc } } /// Configures the ADC to use a DMA ring buffer for continuous data acquisition. @@ -137,7 +134,7 @@ where self, dma: Peri<'d, impl RxDma>, dma_buf: &'d mut [u16], - sequence: impl ExactSizeIterator, SampleTime)>, + sequence: impl ExactSizeIterator, SampleTime)>, ) -> RingBufferedAdc<'d, T> { assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); @@ -150,7 +147,7 @@ where r.set_l((sequence.len() - 1).try_into().unwrap()); }); - for (i, (channel, sample_time)) in sequence.enumerate() { + for (i, (mut channel, sample_time)) in sequence.enumerate() { // Set this GPIO as an analog input. channel.setup(); @@ -215,10 +212,6 @@ where }); } - pub fn set_sample_time(&mut self, sample_time: SampleTime) { - self.sample_time = sample_time; - } - pub fn set_resolution(&mut self, resolution: Resolution) { T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); } @@ -278,7 +271,7 @@ where T::regs().dr().read().0 as u16 } - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { channel.setup(); // Configure ADC @@ -288,7 +281,7 @@ where T::regs().sqr3().write(|reg| reg.set_sq(0, channel)); // Configure channel - Self::set_channel_sample_time(channel, self.sample_time); + Self::set_channel_sample_time(channel, sample_time); self.convert() } diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 170b08a25..bbbaf73c8 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -218,10 +218,7 @@ impl<'d, T: Instance> Adc<'d, T> { pub fn new(adc: Peri<'d, T>) -> Self { Self::init_regulator(); Self::init_calibrate(); - Self { - adc, - sample_time: SampleTime::from_bits(0), - } + Self { adc } } #[cfg(adc_g0)] @@ -257,10 +254,7 @@ impl<'d, T: Instance> Adc<'d, T> { Self::init_calibrate(); - Self { - adc, - sample_time: SampleTime::from_bits(0), - } + Self { adc } } // Enable ADC only when it is not already running. @@ -342,16 +336,6 @@ impl<'d, T: Instance> Adc<'d, T> { Vbat {} } - /// Set the ADC sample time. - pub fn set_sample_time(&mut self, sample_time: SampleTime) { - self.sample_time = sample_time; - } - - /// Get the ADC sample time. - pub fn sample_time(&self) -> SampleTime { - self.sample_time - } - /// Set the ADC resolution. pub fn set_resolution(&mut self, resolution: Resolution) { #[cfg(not(any(adc_g0, adc_u0)))] @@ -413,8 +397,8 @@ impl<'d, T: Instance> Adc<'d, T> { } /// Read an ADC channel. - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { - self.read_channel(channel) + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { + self.read_channel(channel, sample_time) } /// Read one or multiple ADC channels using DMA. @@ -616,7 +600,7 @@ impl<'d, T: Instance> Adc<'d, T> { &mut self, dma: Peri<'a, impl RxDma>, dma_buf: &'a mut [u16], - sequence: impl ExactSizeIterator, SampleTime)>, + sequence: impl ExactSizeIterator, SampleTime)>, ) -> RingBufferedAdc<'a, T> { assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); @@ -665,8 +649,8 @@ impl<'d, T: Instance> Adc<'d, T> { let mut channel_mask = 0; // Configure channels and ranks - for (_i, (channel, sample_time)) in sequence.enumerate() { - Self::configure_channel(channel, sample_time); + for (_i, (mut channel, sample_time)) in sequence.enumerate() { + Self::configure_channel(&mut channel, sample_time); // Each channel is sampled according to sequence #[cfg(not(any(adc_g0, adc_u0)))] @@ -745,13 +729,13 @@ impl<'d, T: Instance> Adc<'d, T> { Self::set_channel_sample_time(channel.channel(), sample_time); } - fn read_channel(&mut self, channel: &mut impl AdcChannel) -> u16 { + fn read_channel(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { self.enable(); #[cfg(not(adc_g0))] - Self::configure_channel(channel, self.sample_time); + Self::configure_channel(channel, sample_time); #[cfg(adc_g0)] T::regs().smpr().write(|reg| { - reg.set_sample_time(0, self.sample_time); + reg.set_sample_time(0, sample_time); reg.set_smpsel(channel.channel().into(), Smpsel::SMP1); }); // Select channel diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index c7d0103a6..cc3f8b34e 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -190,10 +190,7 @@ impl<'d, T: Instance> Adc<'d, T> { }; T::regs().cr().modify(|w| w.set_boost(boost)); } - let mut s = Self { - adc, - sample_time: SampleTime::from_bits(0), - }; + let mut s = Self { adc }; s.power_up(); s.configure_differential_inputs(); @@ -277,16 +274,6 @@ impl<'d, T: Instance> Adc<'d, T> { Vbat {} } - /// Set the ADC sample time. - pub fn set_sample_time(&mut self, sample_time: SampleTime) { - self.sample_time = sample_time; - } - - /// Get the ADC sample time. - pub fn sample_time(&self) -> SampleTime { - self.sample_time - } - /// Set the ADC resolution. pub fn set_resolution(&mut self, resolution: Resolution) { T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); @@ -335,8 +322,8 @@ impl<'d, T: Instance> Adc<'d, T> { } /// Read an ADC channel. - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { - self.read_channel(channel) + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { + self.read_channel(channel, sample_time) } /// Read one or multiple ADC channels using DMA. @@ -472,8 +459,8 @@ impl<'d, T: Instance> Adc<'d, T> { } } - fn read_channel(&mut self, channel: &mut impl AdcChannel) -> u16 { - Self::configure_channel(channel, self.sample_time); + fn read_channel(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { + Self::configure_channel(channel, sample_time); T::regs().sqr1().modify(|reg| { reg.set_sq(0, channel.channel()); diff --git a/embassy-stm32/src/adc/watchdog_v1.rs b/embassy-stm32/src/adc/watchdog_v1.rs index bbe8e1971..b12e0d333 100644 --- a/embassy-stm32/src/adc/watchdog_v1.rs +++ b/embassy-stm32/src/adc/watchdog_v1.rs @@ -1,7 +1,7 @@ use core::future::poll_fn; use core::task::Poll; -use stm32_metapac::adc::vals::{Align, Awdsgl, Res}; +use stm32_metapac::adc::vals::{Align, Awdsgl, Res, SampleTime}; use crate::adc::{Adc, AdcChannel, Instance}; @@ -67,7 +67,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// let v_high = adc.monitor_watchdog().await; /// info!("ADC sample is high {}", v_high); /// ``` - pub async fn monitor_watchdog(&mut self) -> u16 { + pub async fn monitor_watchdog(&mut self, sample_time: SampleTime) -> u16 { assert!( match T::regs().cfgr1().read().awdsgl() { Awdsgl::SINGLE_CHANNEL => T::regs().cfgr1().read().awdch() != 0, @@ -76,7 +76,7 @@ impl<'d, T: Instance> Adc<'d, T> { "`set_channel` should be called before `monitor`", ); assert!(T::regs().chselr().read().0 != 0); - T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into())); + T::regs().smpr().modify(|reg| reg.set_smp(sample_time.into())); Self::start_awd(); let sample = poll_fn(|cx| { diff --git a/examples/stm32c0/src/bin/adc.rs b/examples/stm32c0/src/bin/adc.rs index 1f54b0b18..b52c9e7f8 100644 --- a/examples/stm32c0/src/bin/adc.rs +++ b/examples/stm32c0/src/bin/adc.rs @@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) { info!("ADC STM32C0 example."); // We need to set certain sample time to be able to read temp sensor. - let mut adc = Adc::new(p.ADC1, SampleTime::CYCLES12_5, Resolution::BITS12); + let mut adc = Adc::new(p.ADC1, Resolution::BITS12); let mut temp = adc.enable_temperature().degrade_adc(); let mut vref = adc.enable_vrefint().degrade_adc(); let mut pin0 = p.PA0.degrade_adc(); @@ -27,9 +27,9 @@ async fn main(_spawner: Spawner) { loop { info!("============================"); - let blocking_temp = adc.blocking_read(&mut temp); - let blocking_vref = adc.blocking_read(&mut vref); - let blocing_pin0 = adc.blocking_read(&mut pin0); + let blocking_temp = adc.blocking_read(&mut temp, SampleTime::CYCLES12_5); + let blocking_vref = adc.blocking_read(&mut vref, SampleTime::CYCLES12_5); + let blocing_pin0 = adc.blocking_read(&mut pin0, SampleTime::CYCLES12_5); info!( "Blocking ADC read: vref = {}, temp = {}, pin0 = {}.", blocking_vref, blocking_temp, blocing_pin0 diff --git a/examples/stm32f0/src/bin/adc-watchdog.rs b/examples/stm32f0/src/bin/adc-watchdog.rs index ff98aac8e..6879dd10a 100644 --- a/examples/stm32f0/src/bin/adc-watchdog.rs +++ b/examples/stm32f0/src/bin/adc-watchdog.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{self, Adc, WatchdogChannels}; +use embassy_stm32::adc::{self, Adc, SampleTime, WatchdogChannels}; use embassy_stm32::bind_interrupts; use embassy_stm32::peripherals::ADC1; use {defmt_rtt as _, panic_probe as _}; @@ -23,12 +23,12 @@ async fn main(_spawner: Spawner) { loop { // Wait for pin to go high adc.init_watchdog(WatchdogChannels::from_channel(&pin), 0, 0x07F); - let v_high = adc.monitor_watchdog().await; + let v_high = adc.monitor_watchdog(SampleTime::CYCLES13_5).await; info!("ADC sample is high {}", v_high); // Wait for pin to go low adc.init_watchdog(WatchdogChannels::from_channel(&pin), 0x01f, 0xFFF); - let v_low = adc.monitor_watchdog().await; + let v_low = adc.monitor_watchdog(SampleTime::CYCLES13_5).await; info!("ADC sample is low {}", v_low); } } diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs index 8825e2687..fafeeffaf 100644 --- a/examples/stm32f0/src/bin/adc.rs +++ b/examples/stm32f0/src/bin/adc.rs @@ -19,11 +19,10 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut adc = Adc::new(p.ADC1, Irqs); - adc.set_sample_time(SampleTime::CYCLES71_5); let mut pin = p.PA1; let mut vrefint = adc.enable_vref(); - let vrefint_sample = adc.read(&mut vrefint).await; + let vrefint_sample = adc.read(&mut vrefint, SampleTime::CYCLES13_5).await; let convert_to_millivolts = |sample| { // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf // 6.3.4 Embedded reference voltage @@ -33,7 +32,7 @@ async fn main(_spawner: Spawner) { }; loop { - let v = adc.read(&mut pin).await; + let v = adc.read(&mut pin, SampleTime::CYCLES13_5).await; info!("--> {} - {} mV", v, convert_to_millivolts(v)); Timer::after_millis(100).await; } diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs index 541ff159e..2451aee3d 100644 --- a/examples/stm32f1/src/bin/adc.rs +++ b/examples/stm32f1/src/bin/adc.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::Adc; +use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC1; use embassy_stm32::{adc, bind_interrupts}; use embassy_time::Timer; @@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) { let mut pin = p.PB1; let mut vrefint = adc.enable_vref(); - let vrefint_sample = adc.read(&mut vrefint).await; + let vrefint_sample = adc.read(&mut vrefint, SampleTime::CYCLES13_5).await; let convert_to_millivolts = |sample| { // From http://www.st.com/resource/en/datasheet/CD00161566.pdf // 5.3.4 Embedded reference voltage @@ -32,7 +32,7 @@ async fn main(_spawner: Spawner) { }; loop { - let v = adc.read(&mut pin).await; + let v = adc.read(&mut pin, SampleTime::CYCLES13_5).await; info!("--> {} - {} mV", v, convert_to_millivolts(v)); Timer::after_millis(100).await; } diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index a993b00ca..a420c8876 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs @@ -40,21 +40,19 @@ async fn main(_spawner: Spawner) -> ! { let mut adc = Adc::new(p.ADC1, Irqs); - adc.set_sample_time(SampleTime::CYCLES601_5); - info!("enable vrefint..."); let mut vrefint = adc.enable_vref(); let mut temperature = adc.enable_temperature(); loop { - let vref = adc.read(&mut vrefint).await; + let vref = adc.read(&mut vrefint, SampleTime::CYCLES601_5).await; info!("read vref: {} (should be {})", vref, vrefint.value()); - let temp = adc.read(&mut temperature).await; + let temp = adc.read(&mut temperature, SampleTime::CYCLES601_5).await; info!("read temperature: {}", temp); - let pin = adc.read(&mut p.PA0).await; + let pin = adc.read(&mut p.PA0, SampleTime::CYCLES601_5).await; info!("read pin: {}", pin); let pin_mv = (pin as u32 * vrefint.value() as u32 / vref as u32) * 3300 / 4095; diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs index 3e621f2a1..ddefdd03d 100644 --- a/examples/stm32f334/src/bin/opamp.rs +++ b/examples/stm32f334/src/bin/opamp.rs @@ -42,8 +42,6 @@ async fn main(_spawner: Spawner) -> ! { let mut adc = Adc::new(p.ADC2, Irqs); let mut opamp = OpAmp::new(p.OPAMP2); - adc.set_sample_time(SampleTime::CYCLES601_5); - info!("enable vrefint..."); let mut vrefint = adc.enable_vref(); @@ -51,13 +49,13 @@ async fn main(_spawner: Spawner) -> ! { let mut buffer = opamp.buffer_ext(p.PA7.reborrow(), p.PA6.reborrow()); loop { - let vref = adc.read(&mut vrefint).await; + let vref = adc.read(&mut vrefint, SampleTime::CYCLES601_5).await; info!("read vref: {} (should be {})", vref, vrefint.value()); - let temp = adc.read(&mut temperature).await; + let temp = adc.read(&mut temperature, SampleTime::CYCLES601_5).await; info!("read temperature: {}", temp); - let buffer = adc.read(&mut buffer).await; + let buffer = adc.read(&mut buffer, SampleTime::CYCLES601_5).await; info!("read buffer: {}", buffer); let pin_mv = (buffer as u32 * vrefint.value() as u32 / vref as u32) * 3300 / 4095; diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs index 423d29225..5628cb827 100644 --- a/examples/stm32f4/src/bin/adc.rs +++ b/examples/stm32f4/src/bin/adc.rs @@ -4,7 +4,7 @@ use cortex_m::prelude::_embedded_hal_blocking_delay_DelayUs; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, Temperature, VrefInt}; +use embassy_stm32::adc::{Adc, SampleTime, Temperature, VrefInt}; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) { // Startup delay can be combined to the maximum of either delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us())); - let vrefint_sample = adc.blocking_read(&mut vrefint); + let vrefint_sample = adc.blocking_read(&mut vrefint, SampleTime::CYCLES112); let convert_to_millivolts = |sample| { // From http://www.st.com/resource/en/datasheet/DM00071990.pdf @@ -50,16 +50,16 @@ async fn main(_spawner: Spawner) { loop { // Read pin - let v = adc.blocking_read(&mut pin); + let v = adc.blocking_read(&mut pin, SampleTime::CYCLES112); info!("PC1: {} ({} mV)", v, convert_to_millivolts(v)); // Read internal temperature - let v = adc.blocking_read(&mut temp); + let v = adc.blocking_read(&mut temp, SampleTime::CYCLES112); let celcius = convert_to_celcius(v); info!("Internal temp: {} ({} C)", v, celcius); // Read internal voltage reference - let v = adc.blocking_read(&mut vrefint); + let v = adc.blocking_read(&mut vrefint, SampleTime::CYCLES112); info!("VrefInt: {}", v); Timer::after_millis(100).await; diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs index f8da91336..01b881c79 100644 --- a/examples/stm32f4/src/bin/adc_dma.rs +++ b/examples/stm32f4/src/bin/adc_dma.rs @@ -27,8 +27,8 @@ async fn adc_task(p: Peripherals) { p.DMA2_CH0, adc_data, [ - (&mut p.PA0.degrade_adc(), SampleTime::CYCLES112), - (&mut p.PA2.degrade_adc(), SampleTime::CYCLES112), + (p.PA0.degrade_adc(), SampleTime::CYCLES112), + (p.PA2.degrade_adc(), SampleTime::CYCLES112), ] .into_iter(), ); @@ -36,8 +36,8 @@ async fn adc_task(p: Peripherals) { p.DMA2_CH2, adc_data2, [ - (&mut p.PA1.degrade_adc(), SampleTime::CYCLES112), - (&mut p.PA3.degrade_adc(), SampleTime::CYCLES112), + (p.PA1.degrade_adc(), SampleTime::CYCLES112), + (p.PA3.degrade_adc(), SampleTime::CYCLES112), ] .into_iter(), ); diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs index 6689e3b5d..0f226d34e 100644 --- a/examples/stm32f7/src/bin/adc.rs +++ b/examples/stm32f7/src/bin/adc.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::Adc; +use embassy_stm32::adc::{Adc, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -16,7 +16,7 @@ async fn main(_spawner: Spawner) { let mut pin = p.PA3; let mut vrefint = adc.enable_vrefint(); - let vrefint_sample = adc.blocking_read(&mut vrefint); + let vrefint_sample = adc.blocking_read(&mut vrefint, SampleTime::CYCLES112); let convert_to_millivolts = |sample| { // From http://www.st.com/resource/en/datasheet/DM00273119.pdf // 6.3.27 Reference voltage @@ -26,7 +26,7 @@ async fn main(_spawner: Spawner) { }; loop { - let v = adc.blocking_read(&mut pin); + let v = adc.blocking_read(&mut pin, SampleTime::CYCLES112); info!("--> {} - {} mV", v, convert_to_millivolts(v)); Timer::after_millis(100).await; } diff --git a/examples/stm32g0/src/bin/adc.rs b/examples/stm32g0/src/bin/adc.rs index 7d8653ef2..972e43b55 100644 --- a/examples/stm32g0/src/bin/adc.rs +++ b/examples/stm32g0/src/bin/adc.rs @@ -13,11 +13,10 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut adc = Adc::new_with_clock(p.ADC1, Clock::Async { div: Presc::DIV1 }); - adc.set_sample_time(SampleTime::CYCLES79_5); let mut pin = p.PA1; let mut vrefint = adc.enable_vrefint(); - let vrefint_sample = adc.blocking_read(&mut vrefint); + let vrefint_sample = adc.blocking_read(&mut vrefint, SampleTime::CYCLES79_5); let convert_to_millivolts = |sample| { // From https://www.st.com/resource/en/datasheet/stm32g031g8.pdf // 6.3.3 Embedded internal reference voltage @@ -27,7 +26,7 @@ async fn main(_spawner: Spawner) { }; loop { - let v = adc.blocking_read(&mut pin); + let v = adc.blocking_read(&mut pin, SampleTime::CYCLES79_5); info!("--> {} - {} mV", v, convert_to_millivolts(v)); Timer::after_millis(100).await; } diff --git a/examples/stm32g0/src/bin/adc_oversampling.rs b/examples/stm32g0/src/bin/adc_oversampling.rs index 834d1cd4a..f6979889d 100644 --- a/examples/stm32g0/src/bin/adc_oversampling.rs +++ b/examples/stm32g0/src/bin/adc_oversampling.rs @@ -17,7 +17,6 @@ async fn main(_spawner: Spawner) { info!("Adc oversample test"); let mut adc = Adc::new_with_clock(p.ADC1, Clock::Async { div: Presc::DIV1 }); - adc.set_sample_time(SampleTime::CYCLES1_5); let mut pin = p.PA1; adc.set_oversampling_ratio(Ovsr::MUL16); @@ -25,7 +24,7 @@ async fn main(_spawner: Spawner) { adc.oversampling_enable(true); loop { - let v = adc.blocking_read(&mut pin); + let v = adc.blocking_read(&mut pin, SampleTime::CYCLES1_5); info!("--> {} ", v); //max 65520 = 0xFFF0 Timer::after_millis(100).await; } diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index 920142a18..695f37115 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -29,10 +29,9 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut adc = Adc::new(p.ADC2); - adc.set_sample_time(SampleTime::CYCLES24_5); loop { - let measured = adc.blocking_read(&mut p.PA7); + let measured = adc.blocking_read(&mut p.PA7, SampleTime::CYCLES24_5); info!("measured: {}", measured); Timer::after_millis(500).await; } diff --git a/examples/stm32g4/src/bin/adc_differential.rs b/examples/stm32g4/src/bin/adc_differential.rs index 301f0da84..a6e2f7d33 100644 --- a/examples/stm32g4/src/bin/adc_differential.rs +++ b/examples/stm32g4/src/bin/adc_differential.rs @@ -33,14 +33,13 @@ async fn main(_spawner: Spawner) { let mut p = embassy_stm32::init(config); let mut adc = Adc::new(p.ADC1); - adc.set_sample_time(SampleTime::CYCLES247_5); adc.set_differential(&mut p.PA0, true); //p:pa0,n:pa1 // can also use // adc.set_differential_channel(1, true); info!("adc initialized"); loop { - let measured = adc.blocking_read(&mut p.PA0); + let measured = adc.blocking_read(&mut p.PA0, SampleTime::CYCLES247_5); info!("data: {}", measured); Timer::after_millis(500).await; } diff --git a/examples/stm32g4/src/bin/adc_oversampling.rs b/examples/stm32g4/src/bin/adc_oversampling.rs index 1e464183a..cb99ab2a7 100644 --- a/examples/stm32g4/src/bin/adc_oversampling.rs +++ b/examples/stm32g4/src/bin/adc_oversampling.rs @@ -33,7 +33,6 @@ async fn main(_spawner: Spawner) { let mut p = embassy_stm32::init(config); let mut adc = Adc::new(p.ADC1); - adc.set_sample_time(SampleTime::CYCLES6_5); // From https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf // page652 Oversampler // Table 172. Maximum output results vs N and M. Grayed values indicates truncation @@ -50,7 +49,7 @@ async fn main(_spawner: Spawner) { adc.enable_regular_oversampling_mode(Rovsm::RESUMED, Trovs::AUTOMATIC, true); loop { - let measured = adc.blocking_read(&mut p.PA0); + let measured = adc.blocking_read(&mut p.PA0, SampleTime::CYCLES6_5); info!("data: 0x{:X}", measured); //max 0xFFF0 -> 65520 Timer::after_millis(500).await; } diff --git a/examples/stm32h5/src/bin/adc.rs b/examples/stm32h5/src/bin/adc.rs index 0566320d4..c919b1a95 100644 --- a/examples/stm32h5/src/bin/adc.rs +++ b/examples/stm32h5/src/bin/adc.rs @@ -45,14 +45,12 @@ async fn main(_spawner: Spawner) { let mut adc = Adc::new(p.ADC1); - adc.set_sample_time(SampleTime::CYCLES24_5); - let mut vrefint_channel = adc.enable_vrefint(); loop { - let vrefint = adc.blocking_read(&mut vrefint_channel); + let vrefint = adc.blocking_read(&mut vrefint_channel, SampleTime::CYCLES24_5); info!("vrefint: {}", vrefint); - let measured = adc.blocking_read(&mut p.PA0); + let measured = adc.blocking_read(&mut p.PA0, SampleTime::CYCLES24_5); info!("measured: {}", measured); Timer::after_millis(500).await; } diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs index a53c9d8d5..fc45541bf 100644 --- a/examples/stm32h7/src/bin/adc.rs +++ b/examples/stm32h7/src/bin/adc.rs @@ -46,14 +46,12 @@ async fn main(_spawner: Spawner) { let mut adc = Adc::new(p.ADC3); - adc.set_sample_time(SampleTime::CYCLES32_5); - let mut vrefint_channel = adc.enable_vrefint(); loop { - let vrefint = adc.blocking_read(&mut vrefint_channel); + let vrefint = adc.blocking_read(&mut vrefint_channel, SampleTime::CYCLES32_5); info!("vrefint: {}", vrefint); - let measured = adc.blocking_read(&mut p.PC0); + let measured = adc.blocking_read(&mut p.PC0, SampleTime::CYCLES32_5); info!("measured: {}", measured); Timer::after_millis(500).await; } diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs index 9dd09bc45..83be74ed9 100644 --- a/examples/stm32l0/src/bin/adc.rs +++ b/examples/stm32l0/src/bin/adc.rs @@ -19,11 +19,10 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut adc = Adc::new(p.ADC1, Irqs); - adc.set_sample_time(SampleTime::CYCLES79_5); let mut pin = p.PA1; let mut vrefint = adc.enable_vref(); - let vrefint_sample = adc.read(&mut vrefint).await; + let vrefint_sample = adc.read(&mut vrefint, SampleTime::CYCLES79_5).await; let convert_to_millivolts = |sample| { // From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf // 6.3.3 Embedded internal reference voltage @@ -33,7 +32,7 @@ async fn main(_spawner: Spawner) { }; loop { - let v = adc.read(&mut pin).await; + let v = adc.read(&mut pin, SampleTime::CYCLES79_5).await; info!("--> {} - {} mV", v, convert_to_millivolts(v)); Timer::after_millis(100).await; } diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs index 40e907940..835bf5411 100644 --- a/examples/stm32l4/src/bin/adc.rs +++ b/examples/stm32l4/src/bin/adc.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_stm32::Config; -use embassy_stm32::adc::{Adc, Resolution}; +use embassy_stm32::adc::{Adc, Resolution, SampleTime}; use {defmt_rtt as _, panic_probe as _}; #[cortex_m_rt::entry] @@ -23,7 +23,7 @@ fn main() -> ! { let mut channel = p.PC0; loop { - let v = adc.blocking_read(&mut channel); + let v = adc.blocking_read(&mut channel, SampleTime::from_bits(0)); info!("--> {}", v); } } diff --git a/examples/stm32l4/src/bin/adc_dma.rs b/examples/stm32l4/src/bin/adc_dma.rs index 7a9200edd..ab1e9d2e9 100644 --- a/examples/stm32l4/src/bin/adc_dma.rs +++ b/examples/stm32l4/src/bin/adc_dma.rs @@ -21,18 +21,14 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); let mut adc = Adc::new(p.ADC1); - let mut adc_pin0 = p.PA0.degrade_adc(); - let mut adc_pin1 = p.PA1.degrade_adc(); + let adc_pin0 = p.PA0.degrade_adc(); + let adc_pin1 = p.PA1.degrade_adc(); let mut adc_dma_buf = [0u16; DMA_BUF_LEN]; let mut measurements = [0u16; DMA_BUF_LEN / 2]; let mut ring_buffered_adc = adc.into_ring_buffered( p.DMA1_CH1, &mut adc_dma_buf, - [ - (&mut adc_pin0, SampleTime::CYCLES640_5), - (&mut adc_pin1, SampleTime::CYCLES640_5), - ] - .into_iter(), + [(adc_pin0, SampleTime::CYCLES640_5), (adc_pin1, SampleTime::CYCLES640_5)].into_iter(), ); info!("starting measurement loop"); diff --git a/examples/stm32u0/src/bin/adc.rs b/examples/stm32u0/src/bin/adc.rs index 32a54299d..4fbc6f17f 100644 --- a/examples/stm32u0/src/bin/adc.rs +++ b/examples/stm32u0/src/bin/adc.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_stm32::Config; -use embassy_stm32::adc::{Adc, Resolution}; +use embassy_stm32::adc::{Adc, Resolution, SampleTime}; use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; @@ -23,7 +23,7 @@ fn main() -> ! { let mut channel = p.PC0; loop { - let v = adc.blocking_read(&mut channel); + let v = adc.blocking_read(&mut channel, SampleTime::CYCLES12_5); info!("--> {}", v); embassy_time::block_for(Duration::from_millis(200)); } diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs index 91e33053e..99944f7c7 100644 --- a/examples/stm32u5/src/bin/adc.rs +++ b/examples/stm32u5/src/bin/adc.rs @@ -2,8 +2,7 @@ #![no_main] use defmt::*; -use embassy_stm32::adc; -use embassy_stm32::adc::{AdcChannel, adc4}; +use embassy_stm32::adc::{self, AdcChannel, SampleTime, adc4}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -18,7 +17,6 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut adc1_pin2 = p.PA2; // A1 adc1.set_resolution(adc::Resolution::BITS14); adc1.set_averaging(adc::Averaging::Samples1024); - adc1.set_sample_time(adc::SampleTime::CYCLES160_5); let max1 = adc::resolution_to_max_count(adc::Resolution::BITS14); // **** ADC2 init **** @@ -27,7 +25,6 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut adc2_pin2 = p.PB0; // A3 adc2.set_resolution(adc::Resolution::BITS14); adc2.set_averaging(adc::Averaging::Samples1024); - adc2.set_sample_time(adc::SampleTime::CYCLES160_5); let max2 = adc::resolution_to_max_count(adc::Resolution::BITS14); // **** ADC4 init **** @@ -36,33 +33,32 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut adc4_pin2 = p.PC0; // A5 adc4.set_resolution(adc4::Resolution::BITS12); adc4.set_averaging(adc4::Averaging::Samples256); - adc4.set_sample_time(adc4::SampleTime::CYCLES1_5); let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); // **** ADC1 blocking read **** - let raw: u16 = adc1.blocking_read(&mut adc1_pin1); + let raw: u16 = adc1.blocking_read(&mut adc1_pin1, SampleTime::CYCLES160_5); let volt: f32 = 3.3 * raw as f32 / max1 as f32; info!("Read adc1 pin 1 {}", volt); - let raw: u16 = adc1.blocking_read(&mut adc1_pin2); + let raw: u16 = adc1.blocking_read(&mut adc1_pin2, SampleTime::CYCLES160_5); let volt: f32 = 3.3 * raw as f32 / max1 as f32; info!("Read adc1 pin 2 {}", volt); // **** ADC2 blocking read **** - let raw: u16 = adc2.blocking_read(&mut adc2_pin1); + let raw: u16 = adc2.blocking_read(&mut adc2_pin1, SampleTime::CYCLES160_5); let volt: f32 = 3.3 * raw as f32 / max2 as f32; info!("Read adc2 pin 1 {}", volt); - let raw: u16 = adc2.blocking_read(&mut adc2_pin2); + let raw: u16 = adc2.blocking_read(&mut adc2_pin2, SampleTime::CYCLES160_5); let volt: f32 = 3.3 * raw as f32 / max2 as f32; info!("Read adc2 pin 2 {}", volt); // **** ADC4 blocking read **** - let raw: u16 = adc4.blocking_read(&mut adc4_pin1); + let raw: u16 = adc4.blocking_read(&mut adc4_pin1, adc4::SampleTime::CYCLES1_5); let volt: f32 = 3.3 * raw as f32 / max4 as f32; info!("Read adc4 pin 1 {}", volt); - let raw: u16 = adc4.blocking_read(&mut adc4_pin2); + let raw: u16 = adc4.blocking_read(&mut adc4_pin2, adc4::SampleTime::CYCLES1_5); let volt: f32 = 3.3 * raw as f32 / max4 as f32; info!("Read adc4 pin 2 {}", volt); diff --git a/examples/stm32wba/src/bin/adc.rs b/examples/stm32wba/src/bin/adc.rs index 8c80470b8..177aab3f3 100644 --- a/examples/stm32wba/src/bin/adc.rs +++ b/examples/stm32wba/src/bin/adc.rs @@ -17,15 +17,15 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut adc4_pin2 = p.PA1; // A5 adc4.set_resolution(adc4::Resolution::BITS12); adc4.set_averaging(adc4::Averaging::Samples256); - adc4.set_sample_time(adc4::SampleTime::CYCLES1_5); + let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); // **** ADC4 blocking read **** - let raw: u16 = adc4.blocking_read(&mut adc4_pin1); + let raw: u16 = adc4.blocking_read(&mut adc4_pin1, adc4::SampleTime::CYCLES1_5); let volt: f32 = 3.0 * raw as f32 / max4 as f32; info!("Read adc4 pin 1 {}", volt); - let raw: u16 = adc4.blocking_read(&mut adc4_pin2); + let raw: u16 = adc4.blocking_read(&mut adc4_pin2, adc4::SampleTime::CYCLES1_5); let volt: f32 = 3.3 * raw as f32 / max4 as f32; info!("Read adc4 pin 2 {}", volt); diff --git a/examples/stm32wba6/src/bin/adc.rs b/examples/stm32wba6/src/bin/adc.rs index 8c80470b8..0887e124c 100644 --- a/examples/stm32wba6/src/bin/adc.rs +++ b/examples/stm32wba6/src/bin/adc.rs @@ -17,15 +17,14 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut adc4_pin2 = p.PA1; // A5 adc4.set_resolution(adc4::Resolution::BITS12); adc4.set_averaging(adc4::Averaging::Samples256); - adc4.set_sample_time(adc4::SampleTime::CYCLES1_5); let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); // **** ADC4 blocking read **** - let raw: u16 = adc4.blocking_read(&mut adc4_pin1); + let raw: u16 = adc4.blocking_read(&mut adc4_pin1, adc4::SampleTime::CYCLES1_5); let volt: f32 = 3.0 * raw as f32 / max4 as f32; info!("Read adc4 pin 1 {}", volt); - let raw: u16 = adc4.blocking_read(&mut adc4_pin2); + let raw: u16 = adc4.blocking_read(&mut adc4_pin2, adc4::SampleTime::CYCLES1_5); let volt: f32 = 3.3 * raw as f32 / max4 as f32; info!("Read adc4 pin 2 {}", volt); diff --git a/examples/stm32wl/src/bin/adc.rs b/examples/stm32wl/src/bin/adc.rs index 6b21b086b..adabe0df8 100644 --- a/examples/stm32wl/src/bin/adc.rs +++ b/examples/stm32wl/src/bin/adc.rs @@ -18,11 +18,11 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut adc = Adc::new_with_clock(p.ADC1, Clock::Sync { div: CkModePclk::DIV1 }); - adc.set_sample_time(SampleTime::CYCLES79_5); + let mut pin = p.PB2; let mut vrefint = adc.enable_vrefint(); - let vrefint_sample = adc.blocking_read(&mut vrefint); + let vrefint_sample = adc.blocking_read(&mut vrefint, SampleTime::CYCLES79_5); let convert_to_millivolts = |sample| { // From https://www.st.com/resource/en/datasheet/stm32g031g8.pdf // 6.3.3 Embedded internal reference voltage @@ -32,7 +32,7 @@ async fn main(_spawner: Spawner) { }; loop { - let v = adc.blocking_read(&mut pin); + let v = adc.blocking_read(&mut pin, SampleTime::CYCLES79_5); info!("--> {} - {} mV", v, convert_to_millivolts(v)); Timer::after_millis(100).await; } diff --git a/examples/stm32wle5/src/bin/adc.rs b/examples/stm32wle5/src/bin/adc.rs index 8b830a1e6..4e0574d97 100644 --- a/examples/stm32wle5/src/bin/adc.rs +++ b/examples/stm32wle5/src/bin/adc.rs @@ -73,11 +73,10 @@ async fn async_main(_spawner: Spawner) { info!("Hello World!"); let mut adc = Adc::new(p.ADC1); - adc.set_sample_time(SampleTime::CYCLES79_5); let mut pin = p.PA10; let mut vrefint = adc.enable_vrefint(); - let vrefint_sample = adc.blocking_read(&mut vrefint); + let vrefint_sample = adc.blocking_read(&mut vrefint, SampleTime::CYCLES79_5); let convert_to_millivolts = |sample| { // From https://www.st.com/resource/en/datasheet/stm32g031g8.pdf // 6.3.3 Embedded internal reference voltage @@ -87,7 +86,7 @@ async fn async_main(_spawner: Spawner) { }; loop { - let v = adc.blocking_read(&mut pin); + let v = adc.blocking_read(&mut pin, SampleTime::CYCLES79_5); info!("--> {} - {} mV", v, convert_to_millivolts(v)); Timer::after_secs(1).await; } diff --git a/tests/stm32/src/bin/dac.rs b/tests/stm32/src/bin/dac.rs index d34bbb255..747b11e7f 100644 --- a/tests/stm32/src/bin/dac.rs +++ b/tests/stm32/src/bin/dac.rs @@ -10,7 +10,7 @@ use core::f32::consts::PI; use common::*; use defmt::assert; use embassy_executor::Spawner; -use embassy_stm32::adc::Adc; +use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::dac::{DacCh1, Value}; use embassy_time::Timer; use micromath::F32Ext; @@ -37,7 +37,7 @@ async fn main(_spawner: Spawner) { dac.set(Value::Bit8(0)); // Now wait a little to obtain a stable value Timer::after_millis(30).await; - let offset = adc.blocking_read(&mut adc_pin); + let offset = adc.blocking_read(&mut adc_pin, SampleTime::from_bits(0)); for v in 0..=255 { // First set the DAC output value @@ -48,7 +48,10 @@ async fn main(_spawner: Spawner) { Timer::after_millis(30).await; // Need to steal the peripherals here because PA4 is obviously in use already - let measured = adc.blocking_read(&mut unsafe { embassy_stm32::Peripherals::steal() }.PA4); + let measured = adc.blocking_read( + &mut unsafe { embassy_stm32::Peripherals::steal() }.PA4, + SampleTime::from_bits(0), + ); // Calibrate and normalize the measurement to get close to the dac_output_val let measured_normalized = ((measured as i32 - offset as i32) / normalization_factor) as i16; diff --git a/tests/stm32/src/bin/dac_l1.rs b/tests/stm32/src/bin/dac_l1.rs index e6400f28e..2fe0cf1f1 100644 --- a/tests/stm32/src/bin/dac_l1.rs +++ b/tests/stm32/src/bin/dac_l1.rs @@ -10,7 +10,7 @@ use core::f32::consts::PI; use common::*; use defmt::assert; use embassy_executor::Spawner; -use embassy_stm32::adc::Adc; +use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::dac::{DacCh1, Value}; use embassy_stm32::{bind_interrupts, peripherals}; use embassy_time::Timer; @@ -47,7 +47,7 @@ async fn main(_spawner: Spawner) { dac.set(Value::Bit8(0)); // Now wait a little to obtain a stable value Timer::after_millis(30).await; - let offset = adc.read(&mut adc_pin).await; + let offset = adc.read(&mut adc_pin, SampleTime::from_bits(0)).await; for v in 0..=255 { // First set the DAC output value @@ -58,7 +58,12 @@ async fn main(_spawner: Spawner) { Timer::after_millis(30).await; // Need to steal the peripherals here because PA4 is obviously in use already - let measured = adc.read(&mut unsafe { embassy_stm32::Peripherals::steal() }.PA4).await; + let measured = adc + .read( + &mut unsafe { embassy_stm32::Peripherals::steal() }.PA4, + SampleTime::from_bits(0), + ) + .await; // Calibrate and normalize the measurement to get close to the dac_output_val let measured_normalized = ((measured as i32 - offset as i32) / normalization_factor) as i16; -- cgit From c90e4b3135283070bddc6a8e64df3139909ac8ce Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 10 Nov 2025 12:37:38 -0600 Subject: adc: use common vref scheme --- embassy-stm32/src/adc/c0.rs | 32 ++++---------- embassy-stm32/src/adc/f1.rs | 24 ++++------ embassy-stm32/src/adc/f3.rs | 26 ++++------- embassy-stm32/src/adc/g4.rs | 85 ++++++++++-------------------------- embassy-stm32/src/adc/mod.rs | 41 ++++++++++++++++++ embassy-stm32/src/adc/v1.rs | 40 +++++++---------- embassy-stm32/src/adc/v2.rs | 47 ++++++++------------ embassy-stm32/src/adc/v3.rs | 101 +++++++++++++++++++++---------------------- embassy-stm32/src/adc/v4.rs | 61 +++++++++++--------------- 9 files changed, 195 insertions(+), 262 deletions(-) diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index 70302ef96..1869993a5 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs @@ -19,33 +19,17 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(25); const TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US: u32 = 20; -const TEMP_CHANNEL: u8 = 9; -const VREF_CHANNEL: u8 = 10; - const NUM_HW_CHANNELS: u8 = 22; const CHSELR_SQ_SIZE: usize = 8; const CHSELR_SQ_MAX_CHANNEL: u8 = 14; const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111; -// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, -// this currently cannot be modeled with stm32-data, -// so these are available from the software on all ADCs. -/// Internal voltage reference channel. -pub struct VrefInt; -impl AdcChannel for VrefInt {} -impl SealedAdcChannel for VrefInt { - fn channel(&self) -> u8 { - VREF_CHANNEL - } +impl super::VrefConverter for T { + const CHANNEL: u8 = 10; } -/// Internal temperature channel. -pub struct Temperature; -impl AdcChannel for Temperature {} -impl SealedAdcChannel for Temperature { - fn channel(&self) -> u8 { - TEMP_CHANNEL - } +impl super::TemperatureConverter for T { + const CHANNEL: u8 = 9; } #[derive(Copy, Clone, Debug)] @@ -232,22 +216,22 @@ impl<'d, T: Instance> Adc<'d, T> { } /// Enable reading the voltage reference internal channel. - pub fn enable_vrefint(&self) -> VrefInt { + pub fn enable_vrefint(&self) -> super::VrefInt { T::common_regs().ccr().modify(|reg| { reg.set_vrefen(true); }); - VrefInt {} + super::VrefInt {} } /// Enable reading the temperature internal channel. - pub fn enable_temperature(&self) -> Temperature { + pub fn enable_temperature(&self) -> super::Temperature { debug!("Ensure that sample time is set to more than temperature sensor T_start from the datasheet!"); T::common_regs().ccr().modify(|reg| { reg.set_tsen(true); }); - Temperature {} + super::Temperature {} } /// Set the ADC sample time. diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index 32e330d76..835cc8c63 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -28,20 +28,12 @@ impl interrupt::typelevel::Handler for InterruptHandl } } -pub struct Vref; -impl AdcChannel for Vref {} -impl super::SealedAdcChannel for Vref { - fn channel(&self) -> u8 { - 17 - } +impl super::VrefConverter for T { + const CHANNEL: u8 = 17; } -pub struct Temperature; -impl AdcChannel for Temperature {} -impl super::SealedAdcChannel for Temperature { - fn channel(&self) -> u8 { - 16 - } +impl super::TemperatureConverter for T { + const CHANNEL: u8 = 16; } impl<'d, T: Instance> Adc<'d, T> { @@ -91,18 +83,18 @@ impl<'d, T: Instance> Adc<'d, T> { } } - pub fn enable_vref(&self) -> Vref { + pub fn enable_vref(&self) -> super::VrefInt { T::regs().cr2().modify(|reg| { reg.set_tsvrefe(true); }); - Vref {} + super::VrefInt {} } - pub fn enable_temperature(&self) -> Temperature { + pub fn enable_temperature(&self) -> super::Temperature { T::regs().cr2().modify(|reg| { reg.set_tsvrefe(true); }); - Temperature {} + super::Temperature {} } /// Perform a single conversion. diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index cf31aa81b..da185e875 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -29,27 +29,19 @@ impl interrupt::typelevel::Handler for InterruptHandl } } -pub struct Vref; -impl AdcChannel for Vref {} -impl super::SealedAdcChannel for Vref { - fn channel(&self) -> u8 { - 18 - } +impl super::VrefConverter for T { + const CHANNEL: u8 = 18; } -impl Vref { +impl super::VrefInt { /// The value that vref would be if vdda was at 3300mv pub fn value(&self) -> u16 { crate::pac::VREFINTCAL.data().read() } } -pub struct Temperature; -impl AdcChannel for Temperature {} -impl super::SealedAdcChannel for Temperature { - fn channel(&self) -> u8 { - 16 - } +impl super::TemperatureConverter for T { + const CHANNEL: u8 = 16; } impl<'d, T: Instance> Adc<'d, T> { @@ -109,16 +101,16 @@ impl<'d, T: Instance> Adc<'d, T> { } } - pub fn enable_vref(&self) -> Vref { + pub fn enable_vref(&self) -> super::VrefInt { T::common_regs().ccr().modify(|w| w.set_vrefen(true)); - Vref {} + super::VrefInt {} } - pub fn enable_temperature(&self) -> Temperature { + pub fn enable_temperature(&self) -> super::Temperature { T::common_regs().ccr().modify(|w| w.set_tsen(true)); - Temperature {} + super::Temperature {} } /// Perform a single conversion. diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 5066aeec0..2138a82b4 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -35,34 +35,6 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); #[cfg(stm32h7)] const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); -// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs -/// Internal voltage reference channel. -pub struct VrefInt; -impl AdcChannel for VrefInt {} -impl super::SealedAdcChannel for VrefInt { - fn channel(&self) -> u8 { - T::CHANNEL - } -} - -/// Internal temperature channel. -pub struct Temperature; -impl AdcChannel for Temperature {} -impl super::SealedAdcChannel for Temperature { - fn channel(&self) -> u8 { - T::CHANNEL - } -} - -/// Internal battery voltage channel. -pub struct Vbat; -impl AdcChannel for Vbat {} -impl super::SealedAdcChannel for Vbat { - fn channel(&self) -> u8 { - T::CHANNEL - } -} - // NOTE (unused): The prescaler enum closely copies the hardware capabilities, // but high prescaling doesn't make a lot of sense in the current implementation and is ommited. #[allow(unused)] @@ -250,39 +222,39 @@ impl<'d, T: Instance> Adc<'d, T> { } /// Enable reading the voltage reference internal channel. - pub fn enable_vrefint(&self) -> VrefInt + pub fn enable_vrefint(&self) -> super::VrefInt where - T: VrefChannel, + T: super::VrefConverter, { T::common_regs().ccr().modify(|reg| { reg.set_vrefen(true); }); - VrefInt {} + super::VrefInt {} } /// Enable reading the temperature internal channel. - pub fn enable_temperature(&self) -> Temperature + pub fn enable_temperature(&self) -> super::Temperature where - T: TemperatureChannel, + T: super::TemperatureConverter, { T::common_regs().ccr().modify(|reg| { reg.set_vsenseen(true); }); - Temperature {} + super::Temperature {} } /// Enable reading the vbat internal channel. - pub fn enable_vbat(&self) -> Vbat + pub fn enable_vbat(&self) -> super::Vbat where - T: VBatChannel, + T: super::VBatConverter, { T::common_regs().ccr().modify(|reg| { reg.set_vbaten(true); }); - Vbat {} + super::Vbat {} } /// Enable differential channel. @@ -850,62 +822,49 @@ impl InjectedAdc { } } -/// Implemented for ADCs that have a Temperature channel -pub trait TemperatureChannel { - const CHANNEL: u8; -} -/// Implemented for ADCs that have a Vref channel -pub trait VrefChannel { - const CHANNEL: u8; -} -/// Implemented for ADCs that have a VBat channel -pub trait VBatChannel { - const CHANNEL: u8; -} - #[cfg(stm32g4)] mod g4 { - pub use super::*; + use crate::adc::{TemperatureConverter, VBatConverter, VrefConverter}; - impl TemperatureChannel for crate::peripherals::ADC1 { + impl TemperatureConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 16; } - impl VrefChannel for crate::peripherals::ADC1 { + impl VrefConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 18; } - impl VBatChannel for crate::peripherals::ADC1 { + impl VBatConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 17; } #[cfg(peri_adc3_common)] - impl VrefChannel for crate::peripherals::ADC3 { + impl VrefConverter for crate::peripherals::ADC3 { const CHANNEL: u8 = 18; } #[cfg(peri_adc3_common)] - impl VBatChannel for crate::peripherals::ADC3 { + impl VBatConverter for crate::peripherals::ADC3 { const CHANNEL: u8 = 17; } #[cfg(not(stm32g4x1))] - impl VrefChannel for crate::peripherals::ADC4 { + impl VrefConverter for crate::peripherals::ADC4 { const CHANNEL: u8 = 18; } #[cfg(not(stm32g4x1))] - impl TemperatureChannel for crate::peripherals::ADC5 { + impl TemperatureConverter for crate::peripherals::ADC5 { const CHANNEL: u8 = 4; } #[cfg(not(stm32g4x1))] - impl VrefChannel for crate::peripherals::ADC5 { + impl VrefConverter for crate::peripherals::ADC5 { const CHANNEL: u8 = 18; } #[cfg(not(stm32g4x1))] - impl VBatChannel for crate::peripherals::ADC5 { + impl VBatConverter for crate::peripherals::ADC5 { const CHANNEL: u8 = 17; } } @@ -913,13 +872,13 @@ mod g4 { // TODO this should look at each ADC individually and impl the correct channels #[cfg(stm32h7)] mod h7 { - impl TemperatureChannel for T { + impl TemperatureConverter for T { const CHANNEL: u8 = 18; } - impl VrefChannel for T { + impl VrefConverter for T { const CHANNEL: u8 = 19; } - impl VBatChannel for T { + impl VBatConverter for T { // TODO this should be 14 for H7a/b/35 const CHANNEL: u8 = 17; } diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index a6b796fb9..a5ca6277f 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -100,6 +100,47 @@ pub(crate) fn blocking_delay_us(us: u32) { } } +/// Implemented for ADCs that have a Temperature channel +pub trait TemperatureConverter { + const CHANNEL: u8; +} +/// Implemented for ADCs that have a Vref channel +pub trait VrefConverter { + const CHANNEL: u8; +} +/// Implemented for ADCs that have a VBat channel +pub trait VBatConverter { + const CHANNEL: u8; +} + +// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs +/// Internal voltage reference channel. +pub struct VrefInt; +impl AdcChannel for VrefInt {} +impl SealedAdcChannel for VrefInt { + fn channel(&self) -> u8 { + T::CHANNEL + } +} + +/// Internal temperature channel. +pub struct Temperature; +impl AdcChannel for Temperature {} +impl SealedAdcChannel for Temperature { + fn channel(&self) -> u8 { + T::CHANNEL + } +} + +/// Internal battery voltage channel. +pub struct Vbat; +impl AdcChannel for Vbat {} +impl SealedAdcChannel for Vbat { + fn channel(&self) -> u8 { + T::CHANNEL + } +} + /// ADC instance. #[cfg(not(any( adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_g4, adc_f3v1, adc_f3v2, adc_g0, adc_u0, adc_h5, adc_h7rs, diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 3838cc12a..97557ee8a 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -5,10 +5,11 @@ use core::task::Poll; #[cfg(adc_l0)] use stm32_metapac::adc::vals::Ckmode; -use super::blocking_delay_us; +#[cfg(not(adc_l0))] +use super::Vbat; +use super::{Temperature, VrefInt, blocking_delay_us}; use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; use crate::interrupt::typelevel::Interrupt; -use crate::peripherals::ADC1; use crate::{Peri, interrupt, rcc}; mod watchdog_v1; @@ -42,32 +43,23 @@ impl interrupt::typelevel::Handler for InterruptHandl } #[cfg(not(adc_l0))] -pub struct Vbat; - -#[cfg(not(adc_l0))] -impl AdcChannel for Vbat {} +impl super::VBatConverter for crate::peripherals::ADC1 { + const CHANNEL: u8 = 18; +} #[cfg(not(adc_l0))] -impl super::SealedAdcChannel for Vbat { - fn channel(&self) -> u8 { - 18 - } +impl super::VrefConverter for crate::peripherals::ADC1 { + const CHANNEL: u8 = 17; } -pub struct Vref; -impl AdcChannel for Vref {} -impl super::SealedAdcChannel for Vref { - fn channel(&self) -> u8 { - 17 - } +#[cfg(adc_l0)] +impl super::VrefConverter for crate::peripherals::ADC1 { + const CHANNEL: u8 = 18; } -pub struct Temperature; -impl AdcChannel for Temperature {} -impl super::SealedAdcChannel for Temperature { - fn channel(&self) -> u8 { - if cfg!(adc_l0) { 18 } else { 16 } - } +#[cfg(not(adc_l0))] +impl super::TemperatureConverter for crate::peripherals::ADC1 { + const CHANNEL: u8 = 16; } impl<'d, T: Instance> Adc<'d, T> { @@ -127,12 +119,12 @@ impl<'d, T: Instance> Adc<'d, T> { Vbat } - pub fn enable_vref(&self) -> Vref { + pub fn enable_vref(&self) -> VrefInt { // Table 28. Embedded internal reference voltage // tstart = 10μs T::regs().ccr().modify(|reg| reg.set_vrefen(true)); blocking_delay_us(10); - Vref + VrefInt } pub fn enable_temperature(&self) -> Temperature { diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 67721770a..af5d486d9 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -1,10 +1,9 @@ use core::mem; use core::sync::atomic::{Ordering, compiler_fence}; -use super::blocking_delay_us; +use super::{Temperature, Vbat, VrefInt, blocking_delay_us}; use crate::adc::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel}; use crate::pac::adc::vals; -use crate::peripherals::ADC1; use crate::time::Hertz; use crate::{Peri, rcc}; @@ -23,12 +22,22 @@ pub const VREF_DEFAULT_MV: u32 = 3300; /// VREF voltage used for factory calibration of VREFINTCAL register. pub const VREF_CALIB_MV: u32 = 3300; -pub struct VrefInt; -impl AdcChannel for VrefInt {} -impl super::SealedAdcChannel for VrefInt { - fn channel(&self) -> u8 { - 17 - } +impl super::VrefConverter for crate::peripherals::ADC1 { + const CHANNEL: u8 = 17; +} + +#[cfg(any(stm32f2, stm32f40x, stm32f41x))] +impl super::TemperatureConverter for crate::peripherals::ADC1 { + const CHANNEL: u8 = 16; +} + +#[cfg(not(any(stm32f2, stm32f40x, stm32f41x)))] +impl super::TemperatureConverter for crate::peripherals::ADC1 { + const CHANNEL: u8 = 18; +} + +impl super::VBatConverter for crate::peripherals::ADC1 { + const CHANNEL: u8 = 18; } impl VrefInt { @@ -38,20 +47,6 @@ impl VrefInt { } } -pub struct Temperature; -impl AdcChannel for Temperature {} -impl super::SealedAdcChannel for Temperature { - fn channel(&self) -> u8 { - cfg_if::cfg_if! { - if #[cfg(any(stm32f2, stm32f40x, stm32f41x))] { - 16 - } else { - 18 - } - } - } -} - impl Temperature { /// Time needed for temperature sensor readings to stabilize pub fn start_time_us() -> u32 { @@ -59,14 +54,6 @@ impl Temperature { } } -pub struct Vbat; -impl AdcChannel for Vbat {} -impl super::SealedAdcChannel for Vbat { - fn channel(&self) -> u8 { - 18 - } -} - enum Prescaler { Div2, Div4, diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index bbbaf73c8..0822fbb69 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -9,8 +9,11 @@ use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs}; #[cfg(adc_g0)] pub use pac::adc::vals::{Ovsr, Ovss, Presc}; +#[allow(unused_imports)] +use super::SealedAdcChannel; use super::{ - Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, + Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, Temperature, Vbat, VrefInt, + blocking_delay_us, }; #[cfg(any(adc_v3, adc_g0, adc_u0))] @@ -32,61 +35,55 @@ pub const VREF_CALIB_MV: u32 = 3000; // TODO: Use [#![feature(variant_count)]](https://github.com/rust-lang/rust/issues/73662) when stable const SAMPLE_TIMES_CAPACITY: usize = 2; -pub struct VrefInt; -impl AdcChannel for VrefInt {} -impl SealedAdcChannel for VrefInt { - fn channel(&self) -> u8 { - cfg_if! { - if #[cfg(adc_g0)] { - let val = 13; - } else if #[cfg(any(adc_h5, adc_h7rs))] { - let val = 17; - } else if #[cfg(adc_u0)] { - let val = 12; - } else { - let val = 0; - } - } - val - } +#[cfg(adc_g0)] +impl super::VrefConverter for T { + const CHANNEL: u8 = 13; +} +#[cfg(any(adc_h5, adc_h7rs))] +impl super::VrefConverter for T { + const CHANNEL: u8 = 17; +} +#[cfg(adc_u0)] +impl super::VrefConverter for T { + const CHANNEL: u8 = 12; +} +#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))] +impl super::VrefConverter for T { + const CHANNEL: u8 = 0; } -pub struct Temperature; -impl AdcChannel for Temperature {} -impl SealedAdcChannel for Temperature { - fn channel(&self) -> u8 { - cfg_if! { - if #[cfg(adc_g0)] { - let val = 12; - } else if #[cfg(any(adc_h5, adc_h7rs))] { - let val = 16; - } else if #[cfg(adc_u0)] { - let val = 11; - } else { - let val = 17; - } - } - val - } +#[cfg(adc_g0)] +impl super::TemperatureConverter for T { + const CHANNEL: u8 = 12; +} +#[cfg(any(adc_h5, adc_h7rs))] +impl super::TemperatureConverter for T { + const CHANNEL: u8 = 16; +} +#[cfg(adc_u0)] +impl super::TemperatureConverter for T { + const CHANNEL: u8 = 11; +} +#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))] +impl super::TemperatureConverter for T { + const CHANNEL: u8 = 17; } -pub struct Vbat; -impl AdcChannel for Vbat {} -impl SealedAdcChannel for Vbat { - fn channel(&self) -> u8 { - cfg_if! { - if #[cfg(adc_g0)] { - let val = 14; - } else if #[cfg(any(adc_h5, adc_h7rs))] { - let val = 2; - } else if #[cfg(any(adc_h5, adc_h7rs))] { - let val = 13; - } else { - let val = 18; - } - } - val - } +#[cfg(adc_g0)] +impl super::VBatConverter for T { + const CHANNEL: u8 = 14; +} +#[cfg(any(adc_h5, adc_h7rs))] +impl super::VBatConverter for T { + const CHANNEL: u8 = 2; +} +#[cfg(adc_u0)] +impl super::VBatConverter for T { + const CHANNEL: u8 = 13; +} +#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))] +impl super::VBatConverter for T { + const CHANNEL: u8 = 18; } cfg_if! { diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index cc3f8b34e..2f7baf3bf 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -5,7 +5,8 @@ use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; use pac::adccommon::vals::Presc; use super::{ - Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, + Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, Temperature, Vbat, + VrefInt, blocking_delay_us, }; use crate::dma::Transfer; use crate::time::Hertz; @@ -25,52 +26,40 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); #[cfg(stm32g4)] -const VREF_CHANNEL: u8 = 18; +impl super::VrefConverter for T { + const CHANNEL: u8 = 18; +} #[cfg(stm32g4)] -const TEMP_CHANNEL: u8 = 16; +impl super::TemperatureConverter for T { + const CHANNEL: u8 = 16; +} #[cfg(stm32h7)] -const VREF_CHANNEL: u8 = 19; +impl super::VrefConverter for T { + const CHANNEL: u8 = 19; +} #[cfg(stm32h7)] -const TEMP_CHANNEL: u8 = 18; +impl super::TemperatureConverter for T { + const CHANNEL: u8 = 18; +} // TODO this should be 14 for H7a/b/35 #[cfg(not(stm32u5))] -const VBAT_CHANNEL: u8 = 17; +impl super::VBatConverter for T { + const CHANNEL: u8 = 17; +} #[cfg(stm32u5)] -const VREF_CHANNEL: u8 = 0; -#[cfg(stm32u5)] -const TEMP_CHANNEL: u8 = 19; -#[cfg(stm32u5)] -const VBAT_CHANNEL: u8 = 18; - -// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs -/// Internal voltage reference channel. -pub struct VrefInt; -impl AdcChannel for VrefInt {} -impl SealedAdcChannel for VrefInt { - fn channel(&self) -> u8 { - VREF_CHANNEL - } +impl super::VrefConverter for T { + const CHANNEL: u8 = 0; } - -/// Internal temperature channel. -pub struct Temperature; -impl AdcChannel for Temperature {} -impl SealedAdcChannel for Temperature { - fn channel(&self) -> u8 { - TEMP_CHANNEL - } +#[cfg(stm32u5)] +impl super::TemperatureConverter for T { + const CHANNEL: u8 = 19; } - -/// Internal battery voltage channel. -pub struct Vbat; -impl AdcChannel for Vbat {} -impl SealedAdcChannel for Vbat { - fn channel(&self) -> u8 { - VBAT_CHANNEL - } +#[cfg(stm32u5)] +impl super::VBatConverter for T { + const CHANNEL: u8 = 18; } // NOTE (unused): The prescaler enum closely copies the hardware capabilities, -- cgit From ff1fb2dd6b9ebc0dd3c7b642f70fbb80a1fd030d Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 10 Nov 2025 12:49:23 -0600 Subject: adc: exact cal --- embassy-stm32/src/adc/f3.rs | 7 ------- embassy-stm32/src/adc/mod.rs | 8 ++++++++ examples/stm32f334/src/bin/adc.rs | 4 ++-- examples/stm32f334/src/bin/opamp.rs | 4 ++-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index da185e875..f6a4e1209 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -33,13 +33,6 @@ impl super::VrefConverter for T { const CHANNEL: u8 = 18; } -impl super::VrefInt { - /// The value that vref would be if vdda was at 3300mv - pub fn value(&self) -> u16 { - crate::pac::VREFINTCAL.data().read() - } -} - impl super::TemperatureConverter for T { const CHANNEL: u8 = 16; } diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index a5ca6277f..3bf893a35 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -123,6 +123,14 @@ impl SealedAdcChannel for VrefInt { } } +impl VrefInt { + #[cfg(any(adc_f3v1, adc_f3v2))] + /// The value that vref would be if vdda was at 3300mv + pub fn calibrated_value(&self) -> u16 { + crate::pac::VREFINTCAL.data().read() + } +} + /// Internal temperature channel. pub struct Temperature; impl AdcChannel for Temperature {} diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index a420c8876..486f160ec 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs @@ -47,7 +47,7 @@ async fn main(_spawner: Spawner) -> ! { loop { let vref = adc.read(&mut vrefint, SampleTime::CYCLES601_5).await; - info!("read vref: {} (should be {})", vref, vrefint.value()); + info!("read vref: {} (should be {})", vref, vrefint.calibrated_value()); let temp = adc.read(&mut temperature, SampleTime::CYCLES601_5).await; info!("read temperature: {}", temp); @@ -55,7 +55,7 @@ async fn main(_spawner: Spawner) -> ! { let pin = adc.read(&mut p.PA0, SampleTime::CYCLES601_5).await; info!("read pin: {}", pin); - let pin_mv = (pin as u32 * vrefint.value() as u32 / vref as u32) * 3300 / 4095; + let pin_mv = (pin as u32 * vrefint.calibrated_value() as u32 / vref as u32) * 3300 / 4095; info!("computed pin mv: {}", pin_mv); Timer::after_millis(500).await; diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs index ddefdd03d..9555fd35d 100644 --- a/examples/stm32f334/src/bin/opamp.rs +++ b/examples/stm32f334/src/bin/opamp.rs @@ -50,7 +50,7 @@ async fn main(_spawner: Spawner) -> ! { loop { let vref = adc.read(&mut vrefint, SampleTime::CYCLES601_5).await; - info!("read vref: {} (should be {})", vref, vrefint.value()); + info!("read vref: {} (should be {})", vref, vrefint.calibrated_value()); let temp = adc.read(&mut temperature, SampleTime::CYCLES601_5).await; info!("read temperature: {}", temp); @@ -58,7 +58,7 @@ async fn main(_spawner: Spawner) -> ! { let buffer = adc.read(&mut buffer, SampleTime::CYCLES601_5).await; info!("read buffer: {}", buffer); - let pin_mv = (buffer as u32 * vrefint.value() as u32 / vref as u32) * 3300 / 4095; + let pin_mv = (buffer as u32 * vrefint.calibrated_value() as u32 / vref as u32) * 3300 / 4095; info!("computed pin mv: {}", pin_mv); Timer::after_millis(500).await; -- cgit From d89d8d9e2bb201fe5f1d8212d317abb12a91666f Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 10 Nov 2025 13:48:24 -0600 Subject: adc: consolidate functions --- embassy-stm32/src/adc/g4.rs | 125 ++++++++++++-------------- embassy-stm32/src/adc/injected.rs | 2 +- embassy-stm32/src/adc/ringbuffered.rs | 2 +- embassy-stm32/src/adc/v2.rs | 164 +++++++++++++++++----------------- embassy-stm32/src/adc/v3.rs | 2 +- 5 files changed, 140 insertions(+), 155 deletions(-) diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 2138a82b4..5d9c6ff74 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -147,7 +147,7 @@ impl<'d, T: Instance> Adc<'d, T> { s.calibrate(); blocking_delay_us(1); - s.enable(); + Self::enable(); s.configure(); s @@ -192,7 +192,7 @@ impl<'d, T: Instance> Adc<'d, T> { blocking_delay_us(20); } - fn enable(&mut self) { + fn enable() { // Make sure bits are off while T::regs().cr().read().addis() { // spin @@ -363,7 +363,7 @@ impl<'d, T: Instance> Adc<'d, T> { } /// Teardown method for stopping regular ADC conversions - pub(super) fn teardown_adc() { + pub(super) fn teardown_dma() { Self::stop_regular_conversions(); // Disable dma control @@ -418,39 +418,13 @@ impl<'d, T: Instance> Adc<'d, T> { // Ensure no conversions are ongoing and ADC is enabled. Self::stop_regular_conversions(); - self.enable(); + Self::enable(); - // Set sequence length - T::regs().sqr1().modify(|w| { - w.set_l(sequence.len() as u8 - 1); - }); - // Configure channels and ranks - for (_i, (channel, sample_time)) in sequence.enumerate() { - Self::configure_channel(channel, sample_time); - match _i { - 0..=3 => { - T::regs().sqr1().modify(|w| { - w.set_sq(_i, channel.channel()); - }); - } - 4..=8 => { - T::regs().sqr2().modify(|w| { - w.set_sq(_i - 4, channel.channel()); - }); - } - 9..=13 => { - T::regs().sqr3().modify(|w| { - w.set_sq(_i - 9, channel.channel()); - }); - } - 14..=15 => { - T::regs().sqr4().modify(|w| { - w.set_sq(_i - 14, channel.channel()); - }); - } - _ => unreachable!(), - } - } + Self::configure_sequence(sequence.map(|(channel, sample_time)| { + channel.setup(); + + (channel.channel, sample_time) + })); // Set continuous mode with oneshot dma. // Clear overrun flag before starting transfer. @@ -493,6 +467,47 @@ impl<'d, T: Instance> Adc<'d, T> { }); } + pub(super) fn configure_sequence(sequence: impl ExactSizeIterator) { + // Set sequence length + T::regs().sqr1().modify(|w| { + w.set_l(sequence.len() as u8 - 1); + }); + + // Configure channels and ranks + for (_i, (ch, sample_time)) in sequence.enumerate() { + let sample_time = sample_time.into(); + if ch <= 9 { + T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time)); + } else { + T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); + } + + match _i { + 0..=3 => { + T::regs().sqr1().modify(|w| { + w.set_sq(_i, ch); + }); + } + 4..=8 => { + T::regs().sqr2().modify(|w| { + w.set_sq(_i - 4, ch); + }); + } + 9..=13 => { + T::regs().sqr3().modify(|w| { + w.set_sq(_i - 9, ch); + }); + } + 14..=15 => { + T::regs().sqr4().modify(|w| { + w.set_sq(_i - 14, ch); + }); + } + _ => unreachable!(), + } + } + } + /// Set external trigger for regular conversion sequence fn set_regular_conversion_trigger(&mut self, trigger: ConversionTrigger) { T::regs().cfgr().modify(|r| { @@ -546,43 +561,15 @@ impl<'d, T: Instance> Adc<'d, T> { ); // reset conversions and enable the adc Self::stop_regular_conversions(); - self.enable(); + Self::enable(); //adc side setup - // Set sequence length - T::regs().sqr1().modify(|w| { - w.set_l(sequence.len() as u8 - 1); - }); - - // Configure channels and ranks - for (_i, (mut channel, sample_time)) in sequence.enumerate() { - Self::configure_channel(&mut channel, sample_time); + Self::configure_sequence(sequence.map(|(mut channel, sample_time)| { + channel.setup(); - match _i { - 0..=3 => { - T::regs().sqr1().modify(|w| { - w.set_sq(_i, channel.channel()); - }); - } - 4..=8 => { - T::regs().sqr2().modify(|w| { - w.set_sq(_i - 4, channel.channel()); - }); - } - 9..=13 => { - T::regs().sqr3().modify(|w| { - w.set_sq(_i - 9, channel.channel()); - }); - } - 14..=15 => { - T::regs().sqr4().modify(|w| { - w.set_sq(_i - 14, channel.channel()); - }); - } - _ => unreachable!(), - } - } + (channel.channel, sample_time) + })); // Clear overrun flag before starting transfer. T::regs().isr().modify(|reg| { @@ -655,7 +642,7 @@ impl<'d, T: Instance> Adc<'d, T> { ); Self::stop_regular_conversions(); - self.enable(); + Self::enable(); T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); diff --git a/embassy-stm32/src/adc/injected.rs b/embassy-stm32/src/adc/injected.rs index 0e4fe5847..f9f1bba2a 100644 --- a/embassy-stm32/src/adc/injected.rs +++ b/embassy-stm32/src/adc/injected.rs @@ -38,7 +38,7 @@ impl InjectedAdc { impl Drop for InjectedAdc { fn drop(&mut self) { - Adc::::teardown_adc(); + Adc::::teardown_dma(); compiler_fence(Ordering::SeqCst); } } diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs index 971c8195c..024c6acdc 100644 --- a/embassy-stm32/src/adc/ringbuffered.rs +++ b/embassy-stm32/src/adc/ringbuffered.rs @@ -172,7 +172,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { impl Drop for RingBufferedAdc<'_, T> { fn drop(&mut self) { - Adc::::teardown_adc(); + Adc::::teardown_dma(); compiler_fence(Ordering::SeqCst); diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index af5d486d9..88a8b96ed 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -125,57 +125,14 @@ where ) -> RingBufferedAdc<'d, T> { assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); - T::regs().cr2().modify(|reg| { - reg.set_adon(true); - }); - - // Check the sequence is long enough - T::regs().sqr1().modify(|r| { - r.set_l((sequence.len() - 1).try_into().unwrap()); - }); - - for (i, (mut channel, sample_time)) in sequence.enumerate() { - // Set this GPIO as an analog input. + Self::configure_sequence(sequence.map(|(mut channel, sample_time)| { channel.setup(); - // Set the channel in the right sequence field. - T::regs().sqr3().modify(|w| w.set_sq(i, channel.channel())); - - Self::set_channel_sample_time(channel.channel(), sample_time); - } - + (channel.channel, sample_time) + })); compiler_fence(Ordering::SeqCst); - let r = T::regs(); - - // Clear all interrupts - r.sr().modify(|regs| { - regs.set_eoc(false); - regs.set_ovr(false); - regs.set_strt(false); - }); - - r.cr1().modify(|w| { - // Enable interrupt for end of conversion - w.set_eocie(true); - // Enable interrupt for overrun - w.set_ovrie(true); - // Scanning converisons of multiple channels - w.set_scan(true); - // Continuous conversion mode - w.set_discen(false); - }); - - r.cr2().modify(|w| { - // Enable DMA mode - w.set_dma(true); - // Enable continuous conversions - w.set_cont(true); - // DMA requests are issues as long as DMA=1 and data are converted. - w.set_dds(vals::Dds::CONTINUOUS); - // EOC flag is set at the end of each conversion. - w.set_eocs(vals::Eocs::EACH_CONVERSION); - }); + Self::setup_dma(); // Don't disable the clock mem::forget(self); @@ -183,24 +140,14 @@ where RingBufferedAdc::new(dma, dma_buf) } - pub(super) fn start() { - // Begin ADC conversions - T::regs().cr2().modify(|reg| { - reg.set_adon(true); - reg.set_swstart(true); - }); - } + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { + channel.setup(); - pub(super) fn stop() { - // Stop ADC - T::regs().cr2().modify(|reg| { - // Stop ADC - reg.set_swstart(false); - }); - } + // Configure ADC + let channel = channel.channel(); - pub fn set_resolution(&mut self, resolution: Resolution) { - T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); + Self::configure_sequence([(channel, sample_time)].into_iter()); + Self::blocking_convert() } /// Enables internal voltage reference and returns [VrefInt], which can be used in @@ -236,8 +183,27 @@ where Vbat {} } - /// Perform a single conversion. - fn convert(&mut self) -> u16 { + pub(super) fn start() { + // Begin ADC conversions + T::regs().cr2().modify(|reg| { + reg.set_adon(true); + reg.set_swstart(true); + }); + } + + pub(super) fn stop() { + // Stop ADC + T::regs().cr2().modify(|reg| { + // Stop ADC + reg.set_swstart(false); + }); + } + + pub fn set_resolution(&mut self, resolution: Resolution) { + T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); + } + + pub(super) fn blocking_convert() -> u16 { // clear end of conversion flag T::regs().sr().modify(|reg| { reg.set_eoc(false); @@ -258,31 +224,63 @@ where T::regs().dr().read().0 as u16 } - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { - channel.setup(); + pub(super) fn configure_sequence(sequence: impl ExactSizeIterator) { + T::regs().cr2().modify(|reg| { + reg.set_adon(true); + }); - // Configure ADC - let channel = channel.channel(); + // Check the sequence is long enough + T::regs().sqr1().modify(|r| { + r.set_l((sequence.len() - 1).try_into().unwrap()); + }); - // Select channel - T::regs().sqr3().write(|reg| reg.set_sq(0, channel)); + for (i, (ch, sample_time)) in sequence.enumerate() { + // Set the channel in the right sequence field. + T::regs().sqr3().modify(|w| w.set_sq(i, ch)); + + let sample_time = sample_time.into(); + if ch <= 9 { + T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); + } else { + T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); + } + } + } - // Configure channel - Self::set_channel_sample_time(channel, sample_time); + pub(super) fn setup_dma() { + let r = T::regs(); - self.convert() - } + // Clear all interrupts + r.sr().modify(|regs| { + regs.set_eoc(false); + regs.set_ovr(false); + regs.set_strt(false); + }); - fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { - let sample_time = sample_time.into(); - if ch <= 9 { - T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); - } else { - T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); - } + r.cr1().modify(|w| { + // Enable interrupt for end of conversion + w.set_eocie(true); + // Enable interrupt for overrun + w.set_ovrie(true); + // Scanning converisons of multiple channels + w.set_scan(true); + // Continuous conversion mode + w.set_discen(false); + }); + + r.cr2().modify(|w| { + // Enable DMA mode + w.set_dma(true); + // Enable continuous conversions + w.set_cont(true); + // DMA requests are issues as long as DMA=1 and data are converted. + w.set_dds(vals::Dds::CONTINUOUS); + // EOC flag is set at the end of each conversion. + w.set_eocs(vals::Eocs::EACH_CONVERSION); + }); } - pub(super) fn teardown_adc() { + pub(super) fn teardown_dma() { let r = T::regs(); // Stop ADC diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 0822fbb69..e816907d1 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -198,7 +198,7 @@ impl<'d, T: Instance> Adc<'d, T> { } #[cfg(any(adc_v3, adc_g0, adc_u0))] - pub(super) fn teardown_adc() { + pub(super) fn teardown_dma() { //disable dma control #[cfg(not(any(adc_g0, adc_u0)))] T::regs().cfgr().modify(|reg| { -- cgit From b806d7a98d7bd01a8038573748fbc03c587ba62b Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 10 Nov 2025 14:00:05 -0600 Subject: changelog --- embassy-stm32/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 595778748..8a53c9f03 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -52,6 +52,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - feat: stm32/dsi support zero parameter commands in `write_cmd` ([#4847](https://github.com/embassy-rs/embassy/pull/4847)) - feat: stm32/spi: added support for slave mode ([#4388](https://github.com/embassy-rs/embassy/pull/4388)) - chore: Updated stm32-metapac and stm32-data dependencies +- adc: reogranize and cleanup somewhat. require sample_time to be passed on conversion ## 0.4.0 - 2025-08-26 -- cgit From a3b037ff9d328eb92e0ded1320466f6e1b59e893 Mon Sep 17 00:00:00 2001 From: WillaWillNot Date: Mon, 10 Nov 2025 17:03:50 -0500 Subject: Added TXDR flush via TXE set to the drop guard for write_dma_internal_slave; factored in remaining DMA transfers for the return values for write_dma_internal_slave and read_dma_internal_slave --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/src/i2c/v2.rs | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 8a53c9f03..33c7b5da5 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -53,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - feat: stm32/spi: added support for slave mode ([#4388](https://github.com/embassy-rs/embassy/pull/4388)) - chore: Updated stm32-metapac and stm32-data dependencies - adc: reogranize and cleanup somewhat. require sample_time to be passed on conversion +- fix: stm32/i2c v2 slave: prevent misaligned reads, error false positives, and incorrect counts of bytes read/written ## 0.4.0 - 2025-08-26 diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 57a7acee7..4527e55b9 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -1235,6 +1235,7 @@ impl<'d> I2c<'d, Async, MultiMaster> { regs.cr1().modify(|w| w.set_tcie(true)); Poll::Pending } else if isr.stopf() { + remaining_len = remaining_len.saturating_add(dma_transfer.get_remaining_transfers() as usize); regs.icr().write(|reg| reg.set_stopcf(true)); let poll = Poll::Ready(Ok(total_len - remaining_len)); poll @@ -1274,7 +1275,8 @@ impl<'d> I2c<'d, Async, MultiMaster> { w.set_txdmaen(false); w.set_stopie(false); w.set_tcie(false); - }) + }); + regs.isr().write(|w| w.set_txe(true)); }); let state = self.state; @@ -1297,6 +1299,11 @@ impl<'d> I2c<'d, Async, MultiMaster> { self.info.regs.cr1().modify(|w| w.set_tcie(true)); Poll::Pending } else if isr.stopf() { + let mut leftover_bytes = dma_transfer.get_remaining_transfers(); + if !self.info.regs.isr().read().txe() { + leftover_bytes = leftover_bytes.saturating_add(1); + } + remaining_len = remaining_len.saturating_add(leftover_bytes as usize); self.info.regs.icr().write(|reg| reg.set_stopcf(true)); if remaining_len > 0 { dma_transfer.request_pause(); -- cgit From 0528e3daa386dc2ee7bb9e4a4ee3e1c979e6c479 Mon Sep 17 00:00:00 2001 From: everdrone Date: Tue, 11 Nov 2025 15:21:37 +0100 Subject: enable peripherals low power mode --- embassy-stm32/src/rcc/n6.rs | 185 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs index 5d2003325..5e66e1e86 100644 --- a/embassy-stm32/src/rcc/n6.rs +++ b/embassy-stm32/src/rcc/n6.rs @@ -329,6 +329,14 @@ fn init_clocks(config: Config, input: &ClocksInput) -> ClocksOutput { let ppre4 = periph_prescaler_to_value(config.apb4.to_bits()); let ppre5 = periph_prescaler_to_value(config.apb5.to_bits()); + // enable all peripherals in sleep mode + enable_low_power_peripherals(); + + // enable interrupts + unsafe { + core::arch::asm!("cpsie i"); + } + ClocksOutput { sysclk, cpuclk, @@ -341,6 +349,183 @@ fn init_clocks(config: Config, input: &ClocksInput) -> ClocksOutput { } } +fn enable_low_power_peripherals() { + // AHB1-5 + RCC.ahb1lpenr().modify(|w| { + w.set_adc12lpen(true); + w.set_gpdma1lpen(true); + }); + RCC.ahb2lpenr().modify(|w| { + w.set_adf1lpen(true); + w.set_mdf1lpen(true); + w.set_ramcfglpen(true); + }); + RCC.ahb3lpenr().modify(|w| { + w.set_risaflpen(true); + w.set_iaclpen(true); + w.set_rifsclpen(true); + w.set_pkalpen(true); + w.set_saeslpen(true); + w.set_cryplpen(true); + w.set_hashlpen(true); + w.set_rnglpen(true); + }); + RCC.ahb4lpenr().modify(|w| { + w.set_crclpen(true); + w.set_pwrlpen(true); + w.set_gpioqlpen(true); + w.set_gpioplpen(true); + w.set_gpioolpen(true); + w.set_gpionlpen(true); + w.set_gpiohlpen(true); + w.set_gpioglpen(true); + w.set_gpioflpen(true); + w.set_gpioelpen(true); + w.set_gpiodlpen(true); + w.set_gpioclpen(true); + w.set_gpioblpen(true); + w.set_gpioalpen(true); + }); + RCC.ahb5lpenr().modify(|w| { + w.set_npulpen(true); + w.set_npucachelpen(true); + w.set_otg2lpen(true); + w.set_otgphy2lpen(true); + w.set_otgphy1lpen(true); + w.set_otg1lpen(true); + w.set_eth1lpen(true); + w.set_eth1rxlpen(true); + w.set_eth1txlpen(true); + w.set_eth1maclpen(true); + w.set_gpulpen(true); + w.set_gfxmmulpen(true); + w.set_mce4lpen(true); + w.set_xspi3lpen(true); + w.set_mce3lpen(true); + w.set_mce2lpen(true); + w.set_mce1lpen(true); + w.set_xspimlpen(true); + w.set_xspi2lpen(true); + w.set_sdmmc1lpen(true); + w.set_sdmmc2lpen(true); + w.set_pssilpen(true); + w.set_xspi1lpen(true); + w.set_fmclpen(true); + w.set_jpeglpen(true); + w.set_dma2dlpen(true); + w.set_hpdma1lpen(true); + }); + + // APB1-5 + RCC.apb1llpenr().modify(|w| { + w.set_uart8lpen(true); + w.set_uart7lpen(true); + w.set_i3c2lpen(true); + w.set_i3c1lpen(true); + w.set_i2c3lpen(true); + w.set_i2c2lpen(true); + w.set_i2c1lpen(true); + w.set_uart5lpen(true); + w.set_uart4lpen(true); + w.set_usart3lpen(true); + w.set_usart2lpen(true); + w.set_spdifrx1lpen(true); + w.set_spi3lpen(true); + w.set_spi2lpen(true); + w.set_tim11lpen(true); + w.set_tim10lpen(true); + w.set_wwdglpen(true); + w.set_lptim1lpen(true); + w.set_tim14lpen(true); + w.set_tim13lpen(true); + w.set_tim12lpen(true); + w.set_tim7lpen(true); + w.set_tim6lpen(true); + w.set_tim5lpen(true); + w.set_tim4lpen(true); + w.set_tim3lpen(true); + w.set_tim2lpen(true); + }); + RCC.apb1hlpenr().modify(|w| { + w.set_ucpd1lpen(true); + w.set_fdcanlpen(true); + w.set_mdioslpen(true); + }); + RCC.apb2lpenr().modify(|w| { + w.set_sai2lpen(true); + w.set_sai1lpen(true); + w.set_spi5lpen(true); + w.set_tim9lpen(true); + w.set_tim17lpen(true); + w.set_tim16lpen(true); + w.set_tim15lpen(true); + w.set_tim18lpen(true); + w.set_spi4lpen(true); + w.set_spi1lpen(true); + w.set_usart10lpen(true); + w.set_uart9lpen(true); + w.set_usart6lpen(true); + w.set_usart1lpen(true); + w.set_tim8lpen(true); + w.set_tim1lpen(true); + }); + RCC.apb3lpenr().modify(|w| { + w.set_dftlpen(true); + }); + RCC.apb4llpenr().modify(|w| { + w.set_rtcapblpen(true); + w.set_rtclpen(true); + w.set_vrefbuflpen(true); + w.set_lptim5lpen(true); + w.set_lptim4lpen(true); + w.set_lptim3lpen(true); + w.set_lptim2lpen(true); + w.set_i2c4lpen(true); + w.set_spi6lpen(true); + w.set_lpuart1lpen(true); + w.set_hdplpen(true); + }); + RCC.apb4hlpenr().modify(|w| { + w.set_dtslpen(true); + w.set_bseclpen(true); + w.set_syscfglpen(true); + }); + RCC.apb5lpenr().modify(|w| { + w.set_csilpen(true); + w.set_venclpen(true); + w.set_gfxtimlpen(true); + w.set_dcmilpen(true); + w.set_ltdclpen(true); + }); + + RCC.buslpenr().modify(|w| { + w.set_aclknclpen(true); + w.set_aclknlpen(true); + }); + + RCC.memlpenr().modify(|w| { + w.set_bootromlpen(true); + w.set_vencramlpen(true); + w.set_npucacheramlpen(true); + w.set_flexramlpen(true); + w.set_axisram2lpen(true); + w.set_axisram1lpen(true); + w.set_bkpsramlpen(true); + w.set_ahbsram2lpen(true); + w.set_ahbsram1lpen(true); + w.set_axisram6lpen(true); + w.set_axisram5lpen(true); + w.set_axisram4lpen(true); + w.set_axisram3lpen(true); + }); + + RCC.misclpenr().modify(|w| { + w.set_perlpen(true); + w.set_xspiphycomplpen(true); + w.set_dbglpen(true); + }); +} + const fn periph_prescaler_to_value(bits: u8) -> u8 { match bits { 0 => 1, -- cgit From cf55b39f9a54cf3ed01f52c0565a36a444174235 Mon Sep 17 00:00:00 2001 From: everdrone Date: Tue, 11 Nov 2025 15:28:00 +0100 Subject: restore metapac dependency --- embassy-stm32/Cargo.toml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index fb4bc70b7..fabfa8342 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -174,8 +174,7 @@ cortex-m = "0.7.6" futures-util = { version = "0.3.30", default-features = false } sdio-host = "0.9.0" critical-section = "1.1" -stm32-metapac = { path = "../../stm32-data/build/stm32-metapac" } -# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7" } vcell = "0.1.3" nb = "1.0.0" @@ -204,8 +203,7 @@ proptest-state-machine = "0.3.0" proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { path = "../../stm32-data/build/stm32-metapac", default-features = false, features = ["metadata"]} -# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7", default-features = false, features = ["metadata"] } [features] default = ["rt"] -- cgit From aea23ee19ea06bde6a8e7bd6cfcdcebaeb518e35 Mon Sep 17 00:00:00 2001 From: everdrone Date: Tue, 11 Nov 2025 15:50:12 +0100 Subject: update changelog --- embassy-stm32/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 33c7b5da5..3431848d3 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- feat: Add support for STM32N657X0 - feat: timer: Add 32-bit timer support to SimplePwm waveform_up method following waveform pattern ([#4717](https://github.com/embassy-rs/embassy/pull/4717)) - feat: Add support for injected ADC measurements for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840)) - feat: Implement into_ring_buffered for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840)) -- cgit From ce9a9078a694d96800823577a6541ceb539b4aee Mon Sep 17 00:00:00 2001 From: everdrone Date: Tue, 11 Nov 2025 15:56:09 +0100 Subject: rustfmt --- embassy-stm32/src/exti.rs | 6 +++--- embassy-stm32/src/rcc/n6.rs | 12 +++++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 83e0ecf88..cb46d362c 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -5,13 +5,13 @@ use core::marker::PhantomData; use core::pin::Pin; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_hal_internal::{PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, PinNumber, Pull}; -use crate::pac::exti::regs::Lines; use crate::pac::EXTI; -use crate::{interrupt, pac, peripherals, Peri}; +use crate::pac::exti::regs::Lines; +use crate::{Peri, interrupt, pac, peripherals}; const EXTI_COUNT: usize = 16; static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [const { AtomicWaker::new() }; EXTI_COUNT]; diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs index 5e66e1e86..c9c874e75 100644 --- a/embassy-stm32/src/rcc/n6.rs +++ b/embassy-stm32/src/rcc/n6.rs @@ -770,7 +770,9 @@ fn init_osc(config: Config) -> OscOutput { || (pll3_src == Pllsel::HSE && rcc_sr.pllrdy(2)) || (pll4_src == Pllsel::HSE && rcc_sr.pllrdy(3)) { - panic!("When the HSE is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"); + panic!( + "When the HSE is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled" + ); } else { debug!("HSE off"); @@ -806,7 +808,9 @@ fn init_osc(config: Config) -> OscOutput { || (pll3_src == Pllsel::HSI && rcc_sr.pllrdy(2)) || (pll4_src == Pllsel::HSI && rcc_sr.pllrdy(3)) { - panic!("When the HSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"); + panic!( + "When the HSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled" + ); } else { debug!("HSI off"); @@ -835,7 +839,9 @@ fn init_osc(config: Config) -> OscOutput { || (pll3_src == Pllsel::MSI && rcc_sr.pllrdy(2)) || (pll4_src == Pllsel::MSI && rcc_sr.pllrdy(3)) { - panic!("When the MSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"); + panic!( + "When the MSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled" + ); } else { RCC.ccr().write(|w| w.set_msionc(true)); while RCC.sr().read().msirdy() {} -- cgit From 16f2aaca61df2e708e78a12051365034281c95a4 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 11 Nov 2025 09:01:09 -0600 Subject: adc: impl. differential channels --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/build.rs | 37 ++++++++++++++++++++++++++++++------- embassy-stm32/src/adc/g4.rs | 36 ++++++++++-------------------------- embassy-stm32/src/adc/mod.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 35 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 108321d0a..86c995ec2 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -197,11 +197,11 @@ aligned = "0.4.1" heapless = "0.9.1" #stm32-metapac = { version = "18" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-22374e3344a2c9150b9b3d4da45c03f398fdc54e" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b77c8d968f53b18d6bdcd052e354b5070ec2bbc2" } [build-dependencies] #stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-22374e3344a2c9150b9b3d4da45c03f398fdc54e", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b77c8d968f53b18d6bdcd052e354b5070ec2bbc2", default-features = false, features = ["metadata"] } proc-macro2 = "1.0.36" quote = "1.0.15" diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 940e29417..017b0f196 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1346,6 +1346,8 @@ fn main() { for p in METADATA.peripherals { if let Some(regs) = &p.registers { + let mut adc_pairs: BTreeMap, Option)> = BTreeMap::new(); + for pin in p.pins { let key = (regs.kind, pin.signal); if let Some(tr) = signals.get(&key) { @@ -1467,25 +1469,29 @@ fn main() { }; // H7 has differential voltage measurements - let ch: Option = if pin.signal.starts_with("INP") { - Some(pin.signal.strip_prefix("INP").unwrap().parse().unwrap()) + let ch: Option<(u8, bool)> = if pin.signal.starts_with("INP") { + Some((pin.signal.strip_prefix("INP").unwrap().parse().unwrap(), false)) } else if pin.signal.starts_with("INN") { - // TODO handle in the future when embassy supports differential measurements - None + Some((pin.signal.strip_prefix("INN").unwrap().parse().unwrap(), true)) } else if pin.signal.starts_with("IN") && pin.signal.ends_with('b') { // we number STM32L1 ADC bank 1 as 0..=31, bank 2 as 32..=63 let signal = pin.signal.strip_prefix("IN").unwrap().strip_suffix('b').unwrap(); - Some(32u8 + signal.parse::().unwrap()) + Some((32u8 + signal.parse::().unwrap(), false)) } else if pin.signal.starts_with("IN") { - Some(pin.signal.strip_prefix("IN").unwrap().parse().unwrap()) + Some((pin.signal.strip_prefix("IN").unwrap().parse().unwrap(), false)) } else { None }; - if let Some(ch) = ch { + if let Some((ch, false)) = ch { + adc_pairs.entry(ch).or_insert((None, None)).0.replace(pin_name.clone()); + g.extend(quote! { impl_adc_pin!( #peri, #pin_name, #ch); }) } + if let Some((ch, true)) = ch { + adc_pairs.entry(ch).or_insert((None, None)).1.replace(pin_name.clone()); + } } if regs.kind == "opamp" { @@ -1524,6 +1530,23 @@ fn main() { }) } } + + { + let peri = format_ident!("{}", p.name); + + for (ch, (pin, npin)) in adc_pairs { + let (pin_name, npin_name) = match (pin, npin) { + (Some(pin), Some(npin)) => (pin, npin), + _ => { + continue; + } + }; + + g.extend(quote! { + impl_adc_pair!( #peri, #pin_name, #npin_name, #ch); + }) + } + } } } diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 5d9c6ff74..c0fb7c733 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -140,37 +140,19 @@ impl<'d, T: Instance> Adc<'d, T> { ); } - let mut s = Self { adc }; - s.power_up(); - s.configure_differential_inputs(); - - s.calibrate(); - blocking_delay_us(1); - - Self::enable(); - s.configure(); - - s - } - - fn power_up(&mut self) { T::regs().cr().modify(|reg| { reg.set_deeppwd(false); reg.set_advregen(true); }); blocking_delay_us(20); - } - fn configure_differential_inputs(&mut self) { T::regs().difsel().modify(|w| { for n in 0..18 { w.set_difsel(n, Difsel::SINGLE_ENDED); } }); - } - fn calibrate(&mut self) { T::regs().cr().modify(|w| { w.set_adcaldif(Adcaldif::SINGLE_ENDED); }); @@ -190,6 +172,16 @@ impl<'d, T: Instance> Adc<'d, T> { while T::regs().cr().read().adcal() {} blocking_delay_us(20); + + Self::enable(); + + // single conversion mode, software trigger + T::regs().cfgr().modify(|w| { + w.set_cont(false); + w.set_exten(Exten::DISABLED); + }); + + Self { adc } } fn enable() { @@ -213,14 +205,6 @@ impl<'d, T: Instance> Adc<'d, T> { } } - fn configure(&mut self) { - // single conversion mode, software trigger - T::regs().cfgr().modify(|w| { - w.set_cont(false); - w.set_exten(Exten::DISABLED); - }); - } - /// Enable reading the voltage reference internal channel. pub fn enable_vrefint(&self) -> super::VrefInt where diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 3bf893a35..a11e0c1b4 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -80,6 +80,11 @@ pub(crate) trait SealedAdcChannel { #[allow(unused)] fn channel(&self) -> u8; + + #[allow(unused)] + fn is_differential(&self) -> bool { + false + } } /// Performs a busy-wait delay for a specified number of microseconds. @@ -178,6 +183,7 @@ pub trait AdcChannel: SealedAdcChannel + Sized { AnyAdcChannel { channel: self.channel(), + is_differential: self.is_differential(), _phantom: PhantomData, } } @@ -189,6 +195,7 @@ pub trait AdcChannel: SealedAdcChannel + Sized { /// storing them in an array. pub struct AnyAdcChannel { channel: u8, + is_differential: bool, _phantom: PhantomData, } impl_peripheral!(AnyAdcChannel); @@ -197,6 +204,10 @@ impl SealedAdcChannel for AnyAdcChannel { fn channel(&self) -> u8 { self.channel } + + fn is_differential(&self) -> bool { + self.is_differential + } } impl AnyAdcChannel { @@ -315,6 +326,39 @@ macro_rules! impl_adc_pin { }; } +#[allow(unused_macros)] +macro_rules! impl_adc_pair { + ($inst:ident, $pin:ident, $npin:ident, $ch:expr) => { + impl crate::adc::AdcChannel + for ( + crate::Peri<'_, crate::peripherals::$pin>, + crate::Peri<'_, crate::peripherals::$npin>, + ) + { + } + impl crate::adc::SealedAdcChannel + for ( + crate::Peri<'_, crate::peripherals::$pin>, + crate::Peri<'_, crate::peripherals::$npin>, + ) + { + #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] + fn setup(&mut self) { + ::set_as_analog(&mut self.0); + ::set_as_analog(&mut self.1); + } + + fn channel(&self) -> u8 { + $ch + } + + fn is_differential(&self) -> bool { + true + } + } + }; +} + /// Get the maximum reading value for this resolution. /// /// This is `2**n - 1`. -- cgit From 6e7855d84e3bfd724ac0eacc20db34c1eee0761b Mon Sep 17 00:00:00 2001 From: everdrone Date: Tue, 11 Nov 2025 16:12:49 +0100 Subject: add docs for PinNumber --- embassy-stm32/src/gpio.rs | 5 +++++ embassy-stm32/src/rcc/n6.rs | 3 +++ 2 files changed, 8 insertions(+) diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 1813a887b..17c5a9962 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -804,6 +804,11 @@ pub(crate) trait SealedPin { /// is needed to hold the total pin number `(ports * number)`. #[cfg(not(stm32n6))] pub type PinNumber = u8; + +/// GPIO pin number type. +/// +/// Some chips have a total number of ports that exceeds 8, a larger integer +/// is needed to hold the total pin number `(ports * number)`. #[cfg(stm32n6)] pub type PinNumber = u16; diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs index c9c874e75..866851bbd 100644 --- a/embassy-stm32/src/rcc/n6.rs +++ b/embassy-stm32/src/rcc/n6.rs @@ -167,6 +167,7 @@ impl Config { } } +#[allow(dead_code)] struct ClocksOutput { cpuclk: Hertz, sysclk: Hertz, @@ -580,6 +581,7 @@ struct PllInput { } #[derive(Clone, Copy, Default)] +#[allow(dead_code)] struct PllOutput { divm: Option, divn: Option, @@ -707,6 +709,7 @@ fn init_pll(pll_config: Option, pll_index: usize, input: &PllInput) -> PllO } } +#[allow(dead_code)] struct OscOutput { hsi: Option, hse: Option, -- cgit From aecff11b662c8232e7c848962c6c9ccda0cd9bf3 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 11 Nov 2025 09:37:20 -0600 Subject: adc: cleanup g4 --- embassy-stm32/src/adc/g4.rs | 125 ++++++++++----------------- examples/stm32g4/src/bin/adc_differential.rs | 6 +- 2 files changed, 51 insertions(+), 80 deletions(-) diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index c0fb7c733..e622e2a23 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -241,35 +241,6 @@ impl<'d, T: Instance> Adc<'d, T> { super::Vbat {} } - /// Enable differential channel. - /// Caution: - /// : When configuring the channel “i” in differential input mode, its negative input voltage VINN[i] - /// is connected to another channel. As a consequence, this channel is no longer usable in - /// single-ended mode or in differential mode and must never be configured to be converted. - /// Some channels are shared between ADC1/ADC2/ADC3/ADC4/ADC5: this can make the - /// channel on the other ADC unusable. The only exception is when ADC master and the slave - /// operate in interleaved mode. - #[cfg(stm32g4)] - fn set_differential_channel(&mut self, ch: usize, enable: bool) { - T::regs().cr().modify(|w| w.set_aden(false)); // disable adc - T::regs().difsel().modify(|w| { - w.set_difsel( - ch, - if enable { - Difsel::DIFFERENTIAL - } else { - Difsel::SINGLE_ENDED - }, - ); - }); - T::regs().cr().modify(|w| w.set_aden(true)); - } - - #[cfg(stm32g4)] - pub fn set_differential(&mut self, channel: &mut impl AdcChannel, enable: bool) { - self.set_differential_channel(channel.channel() as usize, enable); - } - /// Set oversampling shift. #[cfg(stm32g4)] pub fn set_oversampling_shift(&mut self, shift: u8) { @@ -331,7 +302,17 @@ impl<'d, T: Instance> Adc<'d, T> { pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { channel.setup(); - self.read_channel(channel, sample_time) + Self::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); + + #[cfg(stm32h7)] + { + T::regs().cfgr2().modify(|w| w.set_lshift(0)); + T::regs() + .pcsel() + .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED)); + } + + self.convert() } /// Start regular adc conversion @@ -404,11 +385,9 @@ impl<'d, T: Instance> Adc<'d, T> { Self::stop_regular_conversions(); Self::enable(); - Self::configure_sequence(sequence.map(|(channel, sample_time)| { - channel.setup(); - - (channel.channel, sample_time) - })); + Self::configure_sequence( + sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), + ); // Set continuous mode with oneshot dma. // Clear overrun flag before starting transfer. @@ -451,14 +430,14 @@ impl<'d, T: Instance> Adc<'d, T> { }); } - pub(super) fn configure_sequence(sequence: impl ExactSizeIterator) { + pub(super) fn configure_sequence(sequence: impl ExactSizeIterator) { // Set sequence length T::regs().sqr1().modify(|w| { w.set_l(sequence.len() as u8 - 1); }); // Configure channels and ranks - for (_i, (ch, sample_time)) in sequence.enumerate() { + for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() { let sample_time = sample_time.into(); if ch <= 9 { T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time)); @@ -489,6 +468,24 @@ impl<'d, T: Instance> Adc<'d, T> { } _ => unreachable!(), } + + #[cfg(stm32g4)] + { + T::regs().cr().modify(|w| w.set_aden(false)); // disable adc + + T::regs().difsel().modify(|w| { + w.set_difsel( + ch.into(), + if is_differential { + Difsel::DIFFERENTIAL + } else { + Difsel::SINGLE_ENDED + }, + ); + }); + + T::regs().cr().modify(|w| w.set_aden(true)); // enable adc + } } } @@ -548,12 +545,9 @@ impl<'d, T: Instance> Adc<'d, T> { Self::enable(); //adc side setup - - Self::configure_sequence(sequence.map(|(mut channel, sample_time)| { - channel.setup(); - - (channel.channel, sample_time) - })); + Self::configure_sequence( + sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), + ); // Clear overrun flag before starting transfer. T::regs().isr().modify(|reg| { @@ -630,8 +624,17 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); - for (n, (mut channel, sample_time)) in sequence.into_iter().enumerate() { - Self::configure_channel(&mut channel, sample_time); + for (n, (channel, sample_time)) in sequence.into_iter().enumerate() { + let sample_time = sample_time.into(); + if channel.channel() <= 9 { + T::regs() + .smpr() + .modify(|reg| reg.set_smp(channel.channel() as _, sample_time)); + } else { + T::regs() + .smpr2() + .modify(|reg| reg.set_smp((channel.channel() - 10) as _, sample_time)); + } let idx = match n { 0..=3 => n, @@ -733,38 +736,6 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().ier().modify(|r| r.set_jeosie(enable)); } - fn configure_channel(channel: &mut impl AdcChannel, sample_time: SampleTime) { - // Configure channel - Self::set_channel_sample_time(channel.channel(), sample_time); - } - - fn read_channel(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { - Self::configure_channel(channel, sample_time); - #[cfg(stm32h7)] - { - T::regs().cfgr2().modify(|w| w.set_lshift(0)); - T::regs() - .pcsel() - .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED)); - } - - T::regs().sqr1().write(|reg| { - reg.set_sq(0, channel.channel()); - reg.set_l(0); - }); - - self.convert() - } - - fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { - let sample_time = sample_time.into(); - if ch <= 9 { - T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time)); - } else { - T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); - } - } - // Stop regular conversions fn stop_regular_conversions() { if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { diff --git a/examples/stm32g4/src/bin/adc_differential.rs b/examples/stm32g4/src/bin/adc_differential.rs index a6e2f7d33..2773723e9 100644 --- a/examples/stm32g4/src/bin/adc_differential.rs +++ b/examples/stm32g4/src/bin/adc_differential.rs @@ -30,16 +30,16 @@ async fn main(_spawner: Spawner) { config.rcc.mux.adc12sel = mux::Adcsel::SYS; config.rcc.sys = Sysclk::PLL1_R; } - let mut p = embassy_stm32::init(config); + let p = embassy_stm32::init(config); let mut adc = Adc::new(p.ADC1); - adc.set_differential(&mut p.PA0, true); //p:pa0,n:pa1 + let mut differential_channel = (p.PA0, p.PA1); // can also use // adc.set_differential_channel(1, true); info!("adc initialized"); loop { - let measured = adc.blocking_read(&mut p.PA0, SampleTime::CYCLES247_5); + let measured = adc.blocking_read(&mut differential_channel, SampleTime::CYCLES247_5); info!("data: {}", measured); Timer::after_millis(500).await; } -- cgit From 94c4cd8500b131bbfb0ed22176c35dc4df5ff009 Mon Sep 17 00:00:00 2001 From: everdrone Date: Tue, 11 Nov 2025 17:00:41 +0100 Subject: cfg out unused items --- embassy-stm32/src/dma/gpdma/mod.rs | 1 + embassy-stm32/src/dma/mod.rs | 4 ++++ embassy-stm32/src/lib.rs | 2 +- embassy-stm32/src/rcc/bd.rs | 8 ++++++-- embassy-stm32/src/ucpd.rs | 3 ++- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/dma/gpdma/mod.rs b/embassy-stm32/src/dma/gpdma/mod.rs index 3e117c331..106558d20 100644 --- a/embassy-stm32/src/dma/gpdma/mod.rs +++ b/embassy-stm32/src/dma/gpdma/mod.rs @@ -136,6 +136,7 @@ pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: c impl AnyChannel { /// Safety: Must be called with a matching set of parameters for a valid dma channel + #[cfg(not(stm32n6))] pub(crate) unsafe fn on_irq(&self) { let info = self.info(); #[cfg(feature = "_dual-core")] diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 297fa3674..de7a2c175 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -46,9 +46,11 @@ pub type Request = u8; pub type Request = (); pub(crate) trait SealedChannel { + #[cfg(not(stm32n6))] fn id(&self) -> u8; } +#[cfg(not(stm32n6))] pub(crate) trait ChannelInterrupt { #[cfg_attr(not(feature = "rt"), allow(unused))] unsafe fn on_irq(); @@ -58,6 +60,7 @@ pub(crate) trait ChannelInterrupt { #[allow(private_bounds)] pub trait Channel: SealedChannel + PeripheralType + Into + 'static {} +#[cfg(not(stm32n6))] macro_rules! dma_channel_impl { ($channel_peri:ident, $index:expr) => { impl crate::dma::SealedChannel for crate::peripherals::$channel_peri { @@ -96,6 +99,7 @@ impl AnyChannel { } impl SealedChannel for AnyChannel { + #[cfg(not(stm32n6))] fn id(&self) -> u8 { self.id } diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 5b338a28b..680edf433 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -615,7 +615,7 @@ fn init_hw(config: Config) -> Peripherals { #[cfg(ucpd)] ucpd::init( cs, - #[cfg(peri_ucpd1)] + #[cfg(all(peri_ucpd1, not(stm32n6)))] config.enable_ucpd1_dead_battery, #[cfg(peri_ucpd2)] config.enable_ucpd2_dead_battery, diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 9cad03227..219be208f 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -1,5 +1,7 @@ +#[cfg(not(stm32n6))] use core::sync::atomic::{Ordering, compiler_fence}; +#[cfg(not(stm32n6))] use crate::pac::common::{RW, Reg}; #[cfg(backup_sram)] use crate::pac::pwr::vals::Retention; @@ -54,7 +56,7 @@ impl From for crate::pac::rcc::vals::Lsedrv { } } -#[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0)))] +#[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0, stm32n6)))] type Bdcr = crate::pac::rcc::regs::Bdcr; #[cfg(any(rtc_v2_l0, rtc_v2_l1))] type Bdcr = crate::pac::rcc::regs::Csr; @@ -64,7 +66,7 @@ type Bdcr = crate::pac::rcc::regs::Csr1; #[cfg(any(stm32c0))] fn unlock() {} -#[cfg(not(any(stm32c0)))] +#[cfg(not(any(stm32c0, stm32n6)))] fn unlock() { #[cfg(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1))] let cr = crate::pac::PWR.cr(); @@ -79,6 +81,7 @@ fn unlock() { while !cr.read().dbp() {} } +#[cfg(not(stm32n6))] fn bdcr() -> Reg { #[cfg(any(rtc_v2_l0, rtc_v2_l1))] return crate::pac::RCC.csr(); @@ -152,6 +155,7 @@ impl Default for LsConfig { } impl LsConfig { + #[cfg(not(stm32n6))] pub(crate) fn init(&self) -> Option { let rtc_clk = match self.rtc { RtcClockSource::LSI => { diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 8f259a917..ae86d28f0 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -32,7 +32,7 @@ use crate::{Peri, interrupt}; pub(crate) fn init( _cs: critical_section::CriticalSection, - #[cfg(peri_ucpd1)] ucpd1_db_enable: bool, + #[cfg(all(peri_ucpd1, not(stm32n6)))] ucpd1_db_enable: bool, #[cfg(peri_ucpd2)] ucpd2_db_enable: bool, ) { #[cfg(stm32g0x1)] @@ -349,6 +349,7 @@ impl<'d, T: Instance> CcPhy<'d, T> { critical_section::with(|cs| { init( cs, + #[cfg(not(stm32n6))] false, #[cfg(peri_ucpd2)] false, -- cgit From 769941980442ada1524ee4f60f1d003735caff4b Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 11 Nov 2025 11:14:21 -0600 Subject: adc: seal special channels --- embassy-stm32/src/adc/c0.rs | 4 ++-- embassy-stm32/src/adc/f1.rs | 6 +++--- embassy-stm32/src/adc/f3.rs | 6 +++--- embassy-stm32/src/adc/g4.rs | 32 +++++++++++++++--------------- embassy-stm32/src/adc/mod.rs | 43 +++++++++++++++-------------------------- embassy-stm32/src/adc/v1.rs | 8 ++++---- embassy-stm32/src/adc/v2.rs | 8 ++++---- embassy-stm32/src/adc/v3.rs | 24 +++++++++++------------ embassy-stm32/src/adc/v4.rs | 16 +++++++-------- examples/stm32g4/src/bin/adc.rs | 5 +++++ 10 files changed, 73 insertions(+), 79 deletions(-) diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index 1869993a5..bc97a7c4b 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs @@ -24,11 +24,11 @@ const CHSELR_SQ_SIZE: usize = 8; const CHSELR_SQ_MAX_CHANNEL: u8 = 14; const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111; -impl super::VrefConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 10; } -impl super::TemperatureConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 9; } diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index 835cc8c63..f6220de78 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use core::task::Poll; use super::blocking_delay_us; -use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; +use crate::adc::{Adc, AdcChannel, Instance, SampleTime, VrefInt}; use crate::interrupt::typelevel::Interrupt; use crate::interrupt::{self}; use crate::time::Hertz; @@ -28,11 +28,11 @@ impl interrupt::typelevel::Handler for InterruptHandl } } -impl super::VrefConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 17; } -impl super::TemperatureConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 16; } diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index f6a4e1209..4a77f3c5b 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use core::task::Poll; use super::blocking_delay_us; -use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; +use crate::adc::{Adc, AdcChannel, Instance, SampleTime, VrefInt}; use crate::interrupt::typelevel::Interrupt; use crate::time::Hertz; use crate::{Peri, interrupt, rcc}; @@ -29,11 +29,11 @@ impl interrupt::typelevel::Handler for InterruptHandl } } -impl super::VrefConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 18; } -impl super::TemperatureConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 16; } diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index e622e2a23..6430b0243 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -208,7 +208,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// Enable reading the voltage reference internal channel. pub fn enable_vrefint(&self) -> super::VrefInt where - T: super::VrefConverter, + T: super::SpecialConverter, { T::common_regs().ccr().modify(|reg| { reg.set_vrefen(true); @@ -220,7 +220,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// Enable reading the temperature internal channel. pub fn enable_temperature(&self) -> super::Temperature where - T: super::TemperatureConverter, + T: super::SpecialConverter, { T::common_regs().ccr().modify(|reg| { reg.set_vsenseen(true); @@ -232,7 +232,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// Enable reading the vbat internal channel. pub fn enable_vbat(&self) -> super::Vbat where - T: super::VBatConverter, + T: super::SpecialConverter, { T::common_regs().ccr().modify(|reg| { reg.set_vbaten(true); @@ -766,47 +766,47 @@ impl InjectedAdc { #[cfg(stm32g4)] mod g4 { - use crate::adc::{TemperatureConverter, VBatConverter, VrefConverter}; + use crate::adc::{SealedSpecialConverter, Temperature, Vbat, VrefInt}; - impl TemperatureConverter for crate::peripherals::ADC1 { + impl SealedSpecialConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 16; } - impl VrefConverter for crate::peripherals::ADC1 { + impl SealedSpecialConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 18; } - impl VBatConverter for crate::peripherals::ADC1 { + impl SealedSpecialConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 17; } #[cfg(peri_adc3_common)] - impl VrefConverter for crate::peripherals::ADC3 { + impl SealedSpecialConverter for crate::peripherals::ADC3 { const CHANNEL: u8 = 18; } #[cfg(peri_adc3_common)] - impl VBatConverter for crate::peripherals::ADC3 { + impl SealedSpecialConverter for crate::peripherals::ADC3 { const CHANNEL: u8 = 17; } #[cfg(not(stm32g4x1))] - impl VrefConverter for crate::peripherals::ADC4 { + impl SealedSpecialConverter for crate::peripherals::ADC4 { const CHANNEL: u8 = 18; } #[cfg(not(stm32g4x1))] - impl TemperatureConverter for crate::peripherals::ADC5 { + impl SealedSpecialConverter for crate::peripherals::ADC5 { const CHANNEL: u8 = 4; } #[cfg(not(stm32g4x1))] - impl VrefConverter for crate::peripherals::ADC5 { + impl SealedSpecialConverter for crate::peripherals::ADC5 { const CHANNEL: u8 = 18; } #[cfg(not(stm32g4x1))] - impl VBatConverter for crate::peripherals::ADC5 { + impl SealedSpecialConverter for crate::peripherals::ADC5 { const CHANNEL: u8 = 17; } } @@ -814,13 +814,13 @@ mod g4 { // TODO this should look at each ADC individually and impl the correct channels #[cfg(stm32h7)] mod h7 { - impl TemperatureConverter for T { + impl SealedSpecialConverter for T { const CHANNEL: u8 = 18; } - impl VrefConverter for T { + impl SealedSpecialConverter for T { const CHANNEL: u8 = 19; } - impl VBatConverter for T { + impl SealedSpecialConverter for T { // TODO this should be 14 for H7a/b/35 const CHANNEL: u8 = 17; } diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index a11e0c1b4..e321c4fa1 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -105,29 +105,28 @@ pub(crate) fn blocking_delay_us(us: u32) { } } -/// Implemented for ADCs that have a Temperature channel -pub trait TemperatureConverter { - const CHANNEL: u8; -} -/// Implemented for ADCs that have a Vref channel -pub trait VrefConverter { - const CHANNEL: u8; -} -/// Implemented for ADCs that have a VBat channel -pub trait VBatConverter { +pub(self) trait SpecialChannel {} + +/// Implemented for ADCs that have a special channel +trait SealedSpecialConverter { const CHANNEL: u8; } -// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs -/// Internal voltage reference channel. -pub struct VrefInt; -impl AdcChannel for VrefInt {} -impl SealedAdcChannel for VrefInt { +#[allow(private_bounds)] +pub trait SpecialConverter: SealedSpecialConverter {} + +impl> SpecialConverter for T {} + +impl> AdcChannel for C {} +impl> SealedAdcChannel for C { fn channel(&self) -> u8 { T::CHANNEL } } +pub struct VrefInt; +impl SpecialChannel for VrefInt {} + impl VrefInt { #[cfg(any(adc_f3v1, adc_f3v2))] /// The value that vref would be if vdda was at 3300mv @@ -138,21 +137,11 @@ impl VrefInt { /// Internal temperature channel. pub struct Temperature; -impl AdcChannel for Temperature {} -impl SealedAdcChannel for Temperature { - fn channel(&self) -> u8 { - T::CHANNEL - } -} +impl SpecialChannel for Temperature {} /// Internal battery voltage channel. pub struct Vbat; -impl AdcChannel for Vbat {} -impl SealedAdcChannel for Vbat { - fn channel(&self) -> u8 { - T::CHANNEL - } -} +impl SpecialChannel for Vbat {} /// ADC instance. #[cfg(not(any( diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 97557ee8a..58c30935f 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -43,22 +43,22 @@ impl interrupt::typelevel::Handler for InterruptHandl } #[cfg(not(adc_l0))] -impl super::VBatConverter for crate::peripherals::ADC1 { +impl super::SealedSpecialConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 18; } #[cfg(not(adc_l0))] -impl super::VrefConverter for crate::peripherals::ADC1 { +impl super::SealedSpecialConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 17; } #[cfg(adc_l0)] -impl super::VrefConverter for crate::peripherals::ADC1 { +impl super::SealedSpecialConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 18; } #[cfg(not(adc_l0))] -impl super::TemperatureConverter for crate::peripherals::ADC1 { +impl super::SealedSpecialConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 16; } diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 88a8b96ed..efa1cc68c 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -22,21 +22,21 @@ pub const VREF_DEFAULT_MV: u32 = 3300; /// VREF voltage used for factory calibration of VREFINTCAL register. pub const VREF_CALIB_MV: u32 = 3300; -impl super::VrefConverter for crate::peripherals::ADC1 { +impl super::SealedSpecialConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 17; } #[cfg(any(stm32f2, stm32f40x, stm32f41x))] -impl super::TemperatureConverter for crate::peripherals::ADC1 { +impl super::SealedSpecialConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 16; } #[cfg(not(any(stm32f2, stm32f40x, stm32f41x)))] -impl super::TemperatureConverter for crate::peripherals::ADC1 { +impl super::SealedSpecialConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 18; } -impl super::VBatConverter for crate::peripherals::ADC1 { +impl super::SealedSpecialConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 18; } diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index e816907d1..cbc217545 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -36,53 +36,53 @@ pub const VREF_CALIB_MV: u32 = 3000; const SAMPLE_TIMES_CAPACITY: usize = 2; #[cfg(adc_g0)] -impl super::VrefConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 13; } #[cfg(any(adc_h5, adc_h7rs))] -impl super::VrefConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 17; } #[cfg(adc_u0)] -impl super::VrefConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 12; } #[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))] -impl super::VrefConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 0; } #[cfg(adc_g0)] -impl super::TemperatureConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 12; } #[cfg(any(adc_h5, adc_h7rs))] -impl super::TemperatureConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 16; } #[cfg(adc_u0)] -impl super::TemperatureConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 11; } #[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))] -impl super::TemperatureConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 17; } #[cfg(adc_g0)] -impl super::VBatConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 14; } #[cfg(any(adc_h5, adc_h7rs))] -impl super::VBatConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 2; } #[cfg(adc_u0)] -impl super::VBatConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 13; } #[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))] -impl super::VBatConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 18; } diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 2f7baf3bf..1d5d3fb92 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -26,39 +26,39 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); #[cfg(stm32g4)] -impl super::VrefConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 18; } #[cfg(stm32g4)] -impl super::TemperatureConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 16; } #[cfg(stm32h7)] -impl super::VrefConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 19; } #[cfg(stm32h7)] -impl super::TemperatureConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 18; } // TODO this should be 14 for H7a/b/35 #[cfg(not(stm32u5))] -impl super::VBatConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 17; } #[cfg(stm32u5)] -impl super::VrefConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 0; } #[cfg(stm32u5)] -impl super::TemperatureConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 19; } #[cfg(stm32u5)] -impl super::VBatConverter for T { +impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 18; } diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index 695f37115..94315141c 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -30,9 +30,14 @@ async fn main(_spawner: Spawner) { let mut adc = Adc::new(p.ADC2); + let mut adc_temp = Adc::new(p.ADC1); + let mut temperature = adc_temp.enable_temperature(); + loop { let measured = adc.blocking_read(&mut p.PA7, SampleTime::CYCLES24_5); + let temperature = adc_temp.blocking_read(&mut temperature, SampleTime::CYCLES24_5); info!("measured: {}", measured); + info!("temperature: {}", temperature); Timer::after_millis(500).await; } } -- cgit From 5e76be83cf693d2de4608fec4ef11fbeb32722d4 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Tue, 11 Nov 2025 20:33:00 +0100 Subject: stm32/i2c_v2: Add initial transaction implementation --- embassy-stm32/src/i2c/v2.rs | 502 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 474 insertions(+), 28 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 4527e55b9..061f4ff3a 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -172,20 +172,23 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { length: usize, stop: Stop, reload: bool, + restart: bool, timeout: Timeout, ) -> Result<(), Error> { assert!(length < 256); - // Wait for any previous address sequence to end - // automatically. This could be up to 50% of a bus - // cycle (ie. up to 0.5/freq) - while info.regs.cr2().read().start() { - timeout.check()?; - } + if !restart { + // Wait for any previous address sequence to end + // automatically. This could be up to 50% of a bus + // cycle (ie. up to 0.5/freq) + while info.regs.cr2().read().start() { + timeout.check()?; + } - // Wait for the bus to be free - while info.regs.isr().read().busy() { - timeout.check()?; + // Wait for the bus to be free + while info.regs.isr().read().busy() { + timeout.check()?; + } } let reload = if reload { @@ -210,7 +213,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { Ok(()) } - fn reload(info: &'static Info, length: usize, will_reload: bool, timeout: Timeout) -> Result<(), Error> { + fn reload(info: &'static Info, length: usize, will_reload: bool, stop: Stop, timeout: Timeout) -> Result<(), Error> { assert!(length < 256 && length > 0); while !info.regs.isr().read().tcr() { @@ -226,6 +229,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { info.regs.cr2().modify(|w| { w.set_nbytes(length as u8); w.set_reload(will_reload); + w.set_autoend(stop.autoend()); }); Ok(()) @@ -403,7 +407,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { for (number, chunk) in read.chunks_mut(255).enumerate() { if number != 0 { - Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; + Self::reload(self.info, chunk.len(), number != last_chunk_idx, Stop::Automatic, timeout)?; } for byte in chunk { @@ -441,6 +445,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { write.len().min(255), Stop::Software, last_chunk_idx != 0, + false, // restart timeout, ) { if send_stop { @@ -451,7 +456,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { for (number, chunk) in write.chunks(255).enumerate() { if number != 0 { - Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; + Self::reload(self.info, chunk.len(), number != last_chunk_idx, Stop::Software, timeout)?; } for byte in chunk { @@ -507,9 +512,219 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { /// /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { - let _ = addr; - let _ = operations; - todo!() + if operations.is_empty() { + return Err(Error::ZeroLengthTransfer); + } + + let address = addr.into(); + let timeout = self.timeout(); + + // Group consecutive operations of the same type + let mut op_idx = 0; + let mut is_first_group = true; + + while op_idx < operations.len() { + // Determine the type of current group and find all consecutive operations of same type + let is_read = matches!(operations[op_idx], Operation::Read(_)); + let group_start = op_idx; + + // Find end of this group (consecutive operations of same type) + while op_idx < operations.len() && matches!(operations[op_idx], Operation::Read(_)) == is_read { + op_idx += 1; + } + let group_end = op_idx; + let is_last_group = op_idx >= operations.len(); + + // Execute this group of operations + if is_read { + self.execute_read_group( + address, + &mut operations[group_start..group_end], + is_first_group, + is_last_group, + timeout, + )?; + } else { + self.execute_write_group( + address, + &operations[group_start..group_end], + is_first_group, + is_last_group, + timeout, + )?; + } + + is_first_group = false; + } + + Ok(()) + } + + fn execute_write_group( + &mut self, + address: Address, + operations: &[Operation<'_>], + is_first_group: bool, + is_last_group: bool, + timeout: Timeout, + ) -> Result<(), Error> { + // Calculate total bytes across all operations in this group + let total_bytes: usize = operations + .iter() + .map(|op| match op { + Operation::Write(buf) => buf.len(), + _ => 0, + }) + .sum(); + + if total_bytes == 0 { + // Handle empty write group - just send address + if is_first_group { + Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?; + } + if is_last_group { + self.master_stop(); + } + return Ok(()); + } + + let mut total_remaining = total_bytes; + let mut first_chunk = true; + + for operation in operations { + if let Operation::Write(buffer) = operation { + for chunk in buffer.chunks(255) { + let chunk_len = chunk.len(); + total_remaining -= chunk_len; + let is_last_chunk = total_remaining == 0; + let will_reload = !is_last_chunk; + + if first_chunk { + // First chunk: initiate transfer + // If not first group, use RESTART instead of START + Self::master_write(self.info, address, chunk_len, Stop::Software, will_reload, !is_first_group, timeout)?; + first_chunk = false; + } else { + // Subsequent chunks: use reload + // Always use Software stop for writes + Self::reload(self.info, chunk_len, will_reload, Stop::Software, timeout)?; + } + + // Send data bytes + for byte in chunk { + self.wait_txis(timeout)?; + self.info.regs.txdr().write(|w| w.set_txdata(*byte)); + } + } + } + } + + // Wait for transfer to complete + if is_last_group { + self.wait_tc(timeout)?; + self.master_stop(); + self.wait_stop(timeout)?; + } else { + // Wait for TC before next group (enables RESTART) + self.wait_tc(timeout)?; + } + + Ok(()) + } + + fn execute_read_group( + &mut self, + address: Address, + operations: &mut [Operation<'_>], + is_first_group: bool, + is_last_group: bool, + timeout: Timeout, + ) -> Result<(), Error> { + // Calculate total bytes across all operations in this group + let total_bytes: usize = operations + .iter() + .map(|op| match op { + Operation::Read(buf) => buf.len(), + _ => 0, + }) + .sum(); + + if total_bytes == 0 { + // Handle empty read group + if is_first_group { + Self::master_read( + self.info, + address, + 0, + if is_last_group { Stop::Automatic } else { Stop::Software }, + false, + !is_first_group, + timeout, + )?; + } + if is_last_group { + self.wait_stop(timeout)?; + } + return Ok(()); + } + + let mut total_remaining = total_bytes; + let mut first_chunk = true; + + for operation in operations { + if let Operation::Read(buffer) = operation { + for chunk in buffer.chunks_mut(255) { + let chunk_len = chunk.len(); + total_remaining -= chunk_len; + let is_last_chunk = total_remaining == 0; + let will_reload = !is_last_chunk; + + if first_chunk { + // First chunk: initiate transfer + let stop = if is_last_group && is_last_chunk { + Stop::Automatic + } else { + Stop::Software + }; + + Self::master_read( + self.info, + address, + chunk_len, + stop, + will_reload, + !is_first_group, // restart if not first group + timeout, + )?; + first_chunk = false; + } else { + // Subsequent chunks: use reload + let stop = if is_last_group && is_last_chunk { + Stop::Automatic + } else { + Stop::Software + }; + Self::reload(self.info, chunk_len, will_reload, stop, timeout)?; + } + + // Receive data bytes + for byte in chunk { + self.wait_rxne(timeout)?; + *byte = self.info.regs.rxdr().read().rxdata(); + } + } + } + } + + // Wait for transfer to complete + if is_last_group { + self.wait_stop(timeout)?; + } + // For non-last read groups, don't wait for TC - the peripheral may hold SCL low + // in Software AUTOEND mode until the next START is issued. Just proceed directly + // to the next group which will issue RESTART and release the clock. + + Ok(()) } /// Blocking write multiple buffers. @@ -531,6 +746,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { first_length.min(255), Stop::Software, (first_length > 255) || (last_slice_index != 0), + false, // restart timeout, ) { self.master_stop(); @@ -552,6 +768,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { self.info, slice_len.min(255), (idx != last_slice_index) || (slice_len > 255), + Stop::Software, timeout, ) { if err != Error::Nack { @@ -567,6 +784,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { self.info, chunk.len(), (number != last_chunk_idx) || (idx != last_slice_index), + Stop::Software, timeout, ) { if err != Error::Nack { @@ -610,6 +828,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { first_slice: bool, last_slice: bool, send_stop: bool, + restart: bool, timeout: Timeout, ) -> Result<(), Error> { let total_len = write.len(); @@ -676,10 +895,11 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { total_len.min(255), Stop::Software, (total_len > 255) || !last_slice, + restart, timeout, )?; } else { - Self::reload(self.info, total_len.min(255), (total_len > 255) || !last_slice, timeout)?; + Self::reload(self.info, total_len.min(255), (total_len > 255) || !last_slice, Stop::Software, timeout)?; self.info.regs.cr1().modify(|w| w.set_tcie(true)); } } else if !(isr.tcr() || isr.tc()) { @@ -690,7 +910,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { } else { let last_piece = (remaining_len <= 255) && last_slice; - if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { + if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, Stop::Software, timeout) { return Poll::Ready(Err(e)); } self.info.regs.cr1().modify(|w| w.set_tcie(true)); @@ -793,7 +1013,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { } else { let last_piece = remaining_len <= 255; - if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { + if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, Stop::Automatic, timeout) { return Poll::Ready(Err(e)); } // Return here if we are on last chunk, @@ -826,7 +1046,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { self.write_internal(address.into(), write, true, timeout) } else { timeout - .with(self.write_dma_internal(address.into(), write, true, true, true, timeout)) + .with(self.write_dma_internal(address.into(), write, true, true, true, false, timeout)) .await } } @@ -850,7 +1070,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { let next = iter.next(); let is_last = next.is_none(); - let fut = self.write_dma_internal(address, c, first, is_last, is_last, timeout); + let fut = self.write_dma_internal(address, c, first, is_last, is_last, false, timeout); timeout.with(fut).await?; first = false; current = next; @@ -881,7 +1101,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { if write.is_empty() { self.write_internal(address.into(), write, false, timeout)?; } else { - let fut = self.write_dma_internal(address.into(), write, true, true, false, timeout); + let fut = self.write_dma_internal(address.into(), write, true, true, false, false, timeout); timeout.with(fut).await?; } @@ -903,9 +1123,235 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { #[cfg(all(feature = "low-power", stm32wlex))] let _device_busy = crate::low_power::DeviceBusy::new_stop1(); - let _ = addr; - let _ = operations; - todo!() + + if operations.is_empty() { + return Err(Error::ZeroLengthTransfer); + } + + let address = addr.into(); + let timeout = self.timeout(); + + // Group consecutive operations of the same type + let mut op_idx = 0; + let mut is_first_group = true; + + while op_idx < operations.len() { + // Determine the type of current group and find all consecutive operations of same type + let is_read = matches!(operations[op_idx], Operation::Read(_)); + let group_start = op_idx; + + // Find end of this group (consecutive operations of same type) + while op_idx < operations.len() && matches!(operations[op_idx], Operation::Read(_)) == is_read { + op_idx += 1; + } + let group_end = op_idx; + let is_last_group = op_idx >= operations.len(); + + // Execute this group of operations + if is_read { + self.execute_read_group_async( + address, + &mut operations[group_start..group_end], + is_first_group, + is_last_group, + timeout, + ) + .await?; + } else { + self.execute_write_group_async( + address, + &operations[group_start..group_end], + is_first_group, + is_last_group, + timeout, + ) + .await?; + } + + is_first_group = false; + } + + Ok(()) + } + + async fn execute_write_group_async( + &mut self, + address: Address, + operations: &[Operation<'_>], + is_first_group: bool, + is_last_group: bool, + timeout: Timeout, + ) -> Result<(), Error> { + // Calculate total bytes across all operations in this group + let total_bytes: usize = operations + .iter() + .map(|op| match op { + Operation::Write(buf) => buf.len(), + _ => 0, + }) + .sum(); + + if total_bytes == 0 { + // Handle empty write group using blocking call + if is_first_group { + Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?; + } + if is_last_group { + self.master_stop(); + } + return Ok(()); + } + + let send_stop = is_last_group; + + // Use DMA for each operation in the group + let mut first_in_group = true; + let mut remaining_operations = operations.len(); + + for operation in operations { + if let Operation::Write(buffer) = operation { + remaining_operations -= 1; + let is_last_in_group = remaining_operations == 0; + + if buffer.is_empty() { + // Skip empty buffers + continue; + } + + let fut = self.write_dma_internal( + address, + buffer, + first_in_group && is_first_group, // first_slice + is_last_in_group && is_last_group, // last_slice + send_stop && is_last_in_group, // send_stop + !is_first_group && first_in_group, // restart + timeout, + ); + timeout.with(fut).await?; + first_in_group = false; + } + } + + // If not last group, wait for TC to enable RESTART + if !is_last_group { + self.wait_tc(timeout)?; + } + + Ok(()) + } + + async fn execute_read_group_async( + &mut self, + address: Address, + operations: &mut [Operation<'_>], + is_first_group: bool, + is_last_group: bool, + timeout: Timeout, + ) -> Result<(), Error> { + // Calculate total bytes across all operations in this group + let total_bytes: usize = operations + .iter() + .map(|op| match op { + Operation::Read(buf) => buf.len(), + _ => 0, + }) + .sum(); + + if total_bytes == 0 { + // Handle empty read group using blocking call + if is_first_group { + Self::master_read( + self.info, + address, + 0, + if is_last_group { Stop::Automatic } else { Stop::Software }, + false, + !is_first_group, + timeout, + )?; + } + if is_last_group { + self.wait_stop(timeout)?; + } + return Ok(()); + } + + // For read operations, we need to handle them differently since read_dma_internal + // expects a single buffer. We'll iterate through operations and use DMA for each. + let mut total_remaining = total_bytes; + let restart = !is_first_group; + + for operation in operations { + if let Operation::Read(buffer) = operation { + if buffer.is_empty() { + // Skip empty buffers + continue; + } + + let is_first_read = total_remaining == total_bytes; + let buf_len = buffer.len(); + total_remaining -= buf_len; + let is_last_read = total_remaining == 0; + + if is_first_read { + // First read in the group + let completed_chunks = buf_len / 255; + let total_chunks = if completed_chunks * 255 == buf_len { + completed_chunks + } else { + completed_chunks + 1 + }; + let last_chunk_idx = total_chunks.saturating_sub(1); + + // Use master_read to initiate, then DMA for data + Self::master_read( + self.info, + address, + buf_len.min(255), + if is_last_group && is_last_read { + Stop::Automatic + } else { + Stop::Software + }, + last_chunk_idx != 0 || !is_last_read, + restart, + timeout, + )?; + } + + // Use the existing read_dma_internal, but we need to handle the reload logic ourselves + // For simplicity with consecutive reads, fall back to blocking for now + // This maintains correctness while keeping complexity manageable + for (chunk_idx, chunk) in buffer.chunks_mut(255).enumerate() { + let chunk_len = chunk.len(); + let is_very_last = total_remaining == 0 && chunk_len == chunk.len(); + + if !is_first_read || chunk_idx != 0 { + let stop = if is_last_group && is_very_last { + Stop::Automatic + } else { + Stop::Software + }; + Self::reload(self.info, chunk_len, !(is_last_group && is_very_last), stop, timeout)?; + } + + for byte in chunk { + self.wait_rxne(timeout)?; + *byte = self.info.regs.rxdr().read().rxdata(); + } + } + } + } + + // Wait for transfer to complete + if is_last_group { + self.wait_stop(timeout)?; + } + // For non-last read groups, don't wait for TC - the peripheral may hold SCL low + // in Software AUTOEND mode until the next START is issued. Just proceed directly + // to the next group which will issue RESTART and release the clock. + + Ok(()) } } @@ -1043,7 +1489,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { if number == 0 { Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); } else { - Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; + Self::reload(self.info, chunk.len(), number != last_chunk_idx, Stop::Software, timeout)?; } let mut index = 0; @@ -1092,7 +1538,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { if number == 0 { Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); } else { - Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; + Self::reload(self.info, chunk.len(), number != last_chunk_idx, Stop::Software, timeout)?; } let mut index = 0; @@ -1228,7 +1674,7 @@ impl<'d> I2c<'d, Async, MultiMaster> { Poll::Pending } else if isr.tcr() { let is_last_slice = remaining_len <= 255; - if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { + if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, Stop::Software, timeout) { return Poll::Ready(Err(e)); } remaining_len = remaining_len.saturating_sub(255); @@ -1292,7 +1738,7 @@ impl<'d> I2c<'d, Async, MultiMaster> { Poll::Pending } else if isr.tcr() { let is_last_slice = remaining_len <= 255; - if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { + if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, Stop::Software, timeout) { return Poll::Ready(Err(e)); } remaining_len = remaining_len.saturating_sub(255); -- cgit From aa5c0c02425104fceea9e5dc773e3f5c346e9656 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Wed, 12 Nov 2025 09:49:25 +0100 Subject: stm32/i2c_v2: Add transaction test --- examples/stm32f0/Cargo.toml | 1 + examples/stm32f0/src/bin/i2c_transaction_test.rs | 219 +++++++++++++++++++++++ 2 files changed, 220 insertions(+) create mode 100644 examples/stm32f0/src/bin/i2c_transaction_test.rs diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index a78873d21..177dd0ac2 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -16,6 +16,7 @@ panic-probe = { version = "1.0.0", features = ["print-defmt"] } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } static_cell = "2" portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } diff --git a/examples/stm32f0/src/bin/i2c_transaction_test.rs b/examples/stm32f0/src/bin/i2c_transaction_test.rs new file mode 100644 index 000000000..0ecc3e8b1 --- /dev/null +++ b/examples/stm32f0/src/bin/i2c_transaction_test.rs @@ -0,0 +1,219 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::i2c::{Config, I2c, Master}; +use embassy_stm32::mode::Blocking; +use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, i2c, peripherals}; +use embassy_time::Timer; +use embedded_hal_1::i2c::Operation; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + I2C1 => i2c::EventInterruptHandler, i2c::ErrorInterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + // For STM32F072RB on NUCLEO board + let p = embassy_stm32::init(Default::default()); + + info!("I2C Transaction Test Starting..."); + + // Initialize I2C1: PB6=SCL, PB7=SDA + let mut config = Config::default(); + config.frequency = Hertz(100_000); + let mut i2c = I2c::new_blocking( + p.I2C1, + p.PB8, // SCL + p.PB9, // SDA + config, + ); + + let slave_addr = 0x50u8; + + // Wait for devices to initialize + Timer::after_millis(100).await; + + info!("=== Test 1: Consecutive Writes (Should Merge) ==="); + test_consecutive_writes(&mut i2c, slave_addr); + Timer::after_millis(500).await; + + info!("=== Test 2: Consecutive Reads (Should Merge) ==="); + test_consecutive_reads(&mut i2c, slave_addr); + Timer::after_millis(500).await; + + info!("=== Test 3: Write then Read (RESTART) ==="); + test_write_then_read(&mut i2c, slave_addr); + Timer::after_millis(500).await; + + info!("=== Test 4: Read then Write (RESTART) ==="); + test_read_then_write(&mut i2c, slave_addr); + Timer::after_millis(500).await; + + info!("=== Test 5: Complex Mixed Sequence ==="); + test_mixed_sequence(&mut i2c, slave_addr); + Timer::after_millis(500).await; + + info!("=== Test 6: Single Operations ==="); + test_single_operations(&mut i2c, slave_addr); + + info!("All tests complete!"); + + loop { + Timer::after_secs(1).await; + } +} + +fn test_consecutive_writes(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { + // Expected on bus: START, ADDR+W, data1, data2, data3, STOP + // NO intermediate RESTART/STOP between writes + let data1 = [0x10, 0x11, 0x12]; + let data2 = [0x20, 0x21]; + let data3 = [0x30, 0x31, 0x32, 0x33]; + + let mut ops = [ + Operation::Write(&data1), + Operation::Write(&data2), + Operation::Write(&data3), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => info!("✓ Consecutive writes succeeded"), + Err(e) => warn!("✗ Consecutive writes failed: {:?}", e), + } + + info!("Expected: START, ADDR+W, [9 bytes], STOP"); + info!("Check Analog Discovery: No RESTART between writes"); +} + +fn test_consecutive_reads(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { + // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP + // NO intermediate RESTART/STOP between reads + let mut buf1 = [0u8; 4]; + let mut buf2 = [0u8; 3]; + let mut buf3 = [0u8; 2]; + + let mut ops = [ + Operation::Read(&mut buf1), + Operation::Read(&mut buf2), + Operation::Read(&mut buf3), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Consecutive reads succeeded"); + info!(" buf1: {:02x}", buf1); + info!(" buf2: {:02x}", buf2); + info!(" buf3: {:02x}", buf3); + } + Err(e) => warn!("✗ Consecutive reads failed: {:?}", e), + } + + info!("Expected: START, ADDR+R, [9 bytes], NACK on last, STOP"); + info!("Check Analog Discovery: No RESTART between reads"); +} + +fn test_write_then_read(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { + // Expected: START, ADDR+W, data, RESTART, ADDR+R, data, NACK, STOP + let write_data = [0xAA, 0xBB]; + let mut read_buf = [0u8; 4]; + + let mut ops = [ + Operation::Write(&write_data), + Operation::Read(&mut read_buf), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Write-then-read succeeded"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => warn!("✗ Write-then-read failed: {:?}", e), + } + + info!("Expected: START, ADDR+W, [2 bytes], RESTART, ADDR+R, [4 bytes], NACK, STOP"); + info!("Check Analog Discovery: RESTART between write and read"); +} + +fn test_read_then_write(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { + // Expected: START, ADDR+R, data, NACK, RESTART, ADDR+W, data, STOP + let mut read_buf = [0u8; 3]; + let write_data = [0xCC, 0xDD, 0xEE]; + + let mut ops = [ + Operation::Read(&mut read_buf), + Operation::Write(&write_data), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Read-then-write succeeded"); + info!(" Read: {:02x}", read_buf); + info!(" Written: {:02x}", write_data); + } + Err(e) => warn!("✗ Read-then-write failed: {:?}", e), + } + + info!("Expected: START, ADDR+R, [3 bytes], NACK, RESTART, ADDR+W, [3 bytes], STOP"); + info!("Check Analog Discovery: RESTART between read and write"); +} + +fn test_mixed_sequence(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { + // Complex: W, W, R, R, W, R + // Groups: [W,W] RESTART [R,R] RESTART [W] RESTART [R] + let w1 = [0x01, 0x02]; + let w2 = [0x03, 0x04]; + let mut r1 = [0u8; 2]; + let mut r2 = [0u8; 2]; + let w3 = [0x05]; + let mut r3 = [0u8; 1]; + + let mut ops = [ + Operation::Write(&w1), + Operation::Write(&w2), + Operation::Read(&mut r1), + Operation::Read(&mut r2), + Operation::Write(&w3), + Operation::Read(&mut r3), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Mixed sequence succeeded"); + info!(" r1: {:02x}", r1); + info!(" r2: {:02x}", r2); + info!(" r3: {:02x}", r3); + } + Err(e) => warn!("✗ Mixed sequence failed: {:?}", e), + } + + info!("Expected sequence:"); + info!(" START, ADDR+W, [4 bytes merged], RESTART,"); + info!(" ADDR+R, [4 bytes merged], NACK, RESTART,"); + info!(" ADDR+W, [1 byte], RESTART,"); + info!(" ADDR+R, [1 byte], NACK, STOP"); +} + +fn test_single_operations(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { + // Test single write + let write_data = [0xFF]; + let mut ops = [Operation::Write(&write_data)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => info!("✓ Single write succeeded"), + Err(e) => warn!("✗ Single write failed: {:?}", e), + } + + // Test single read + let mut read_buf = [0u8; 1]; + let mut ops = [Operation::Read(&mut read_buf)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), + Err(e) => warn!("✗ Single read failed: {:?}", e), + } +} -- cgit From d4e2caab31c1e9802120141cebc0a00b04471c16 Mon Sep 17 00:00:00 2001 From: Valentin Trophime Date: Wed, 12 Nov 2025 13:19:42 +0100 Subject: Add docs for embassy-rp::pio::get_x assumption about autopush. --- embassy-rp/CHANGELOG.md | 2 ++ embassy-rp/src/pio/instr.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index 3b3cb5351..4b0d738a7 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- Add documentation for pio `get_x` about autopush. - Fix several minor typos in documentation - Add PIO SPI - Add PIO I2S input @@ -114,3 +115,4 @@ Small release fixing a few gnarly bugs, upgrading is strongly recommended. - rename the Channel trait to Slice and the PwmPin to PwmChannel - i2c: Fix race condition that appears on fast repeated transfers. - Add a basic "read to break" function + diff --git a/embassy-rp/src/pio/instr.rs b/embassy-rp/src/pio/instr.rs index b15d507de..304ddb20a 100644 --- a/embassy-rp/src/pio/instr.rs +++ b/embassy-rp/src/pio/instr.rs @@ -5,6 +5,10 @@ use crate::pio::{Instance, StateMachine}; impl<'d, PIO: Instance, const SM: usize> StateMachine<'d, PIO, SM> { /// Set value of scratch register X. + /// + /// SAFETY: autopull enabled else it will write undefined data. + /// Make sure to have setup the according configuration see + /// [shift_out](crate::pio::Config::shift_out) and [auto_fill](crate::pio::ShiftConfig::auto_fill). pub unsafe fn set_x(&mut self, value: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::X, @@ -16,6 +20,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachine<'d, PIO, SM> { } /// Get value of scratch register X. + /// + /// SAFETY: autopush enabled else it will read undefined data. + /// Make sure to have setup the according configurations see + /// [shift_in](crate::pio::Config::shift_in) and [auto_fill](crate::pio::ShiftConfig::auto_fill). pub unsafe fn get_x(&mut self) -> u32 { const IN: u16 = InstructionOperands::IN { source: InSource::X, @@ -27,6 +35,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachine<'d, PIO, SM> { } /// Set value of scratch register Y. + /// + /// SAFETY: autopull enabled else it will write undefined data. + /// Make sure to have setup the according configuration see + /// [shift_out](crate::pio::Config::shift_out) and [auto_fill](crate::pio::ShiftConfig::auto_fill). pub unsafe fn set_y(&mut self, value: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::Y, @@ -38,6 +50,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachine<'d, PIO, SM> { } /// Get value of scratch register Y. + /// + /// SAFETY: autopush enabled else it will read undefined data. + /// Make sure to have setup the according configurations see + /// [shift_in](crate::pio::Config::shift_in) and [auto_fill](crate::pio::ShiftConfig::auto_fill). pub unsafe fn get_y(&mut self) -> u32 { const IN: u16 = InstructionOperands::IN { source: InSource::Y, -- cgit From 2d73fe88935bcc42452907b42a7de5a9fa5ab1f8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 12 Nov 2025 13:49:17 +0100 Subject: stm32: add all N6 chips, add N6 to docs build. --- embassy-stm32/Cargo.toml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index a722d2379..ec49924a2 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -139,6 +139,7 @@ flavors = [ { regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" }, { regex_feature = "stm32wba.*", target = "thumbv8m.main-none-eabihf" }, { regex_feature = "stm32wl.*", target = "thumbv7em-none-eabi" }, + { regex_feature = "stm32n6.*", target = "thumbv8m.main-none-eabihf" }, ] [package.metadata.docs.rs] @@ -1642,7 +1643,30 @@ stm32l562qe = [ "stm32-metapac/stm32l562qe" ] stm32l562re = [ "stm32-metapac/stm32l562re" ] stm32l562ve = [ "stm32-metapac/stm32l562ve" ] stm32l562ze = [ "stm32-metapac/stm32l562ze" ] +stm32n645a0 = [ "stm32-metapac/stm32n645a0" ] +stm32n645b0 = [ "stm32-metapac/stm32n645b0" ] +stm32n645i0 = [ "stm32-metapac/stm32n645i0" ] +stm32n645l0 = [ "stm32-metapac/stm32n645l0" ] +stm32n645x0 = [ "stm32-metapac/stm32n645x0" ] +stm32n645z0 = [ "stm32-metapac/stm32n645z0" ] +stm32n647a0 = [ "stm32-metapac/stm32n647a0" ] +stm32n647b0 = [ "stm32-metapac/stm32n647b0" ] +stm32n647i0 = [ "stm32-metapac/stm32n647i0" ] +stm32n647l0 = [ "stm32-metapac/stm32n647l0" ] +stm32n647x0 = [ "stm32-metapac/stm32n647x0" ] +stm32n647z0 = [ "stm32-metapac/stm32n647z0" ] +stm32n655a0 = [ "stm32-metapac/stm32n655a0" ] +stm32n655b0 = [ "stm32-metapac/stm32n655b0" ] +stm32n655i0 = [ "stm32-metapac/stm32n655i0" ] +stm32n655l0 = [ "stm32-metapac/stm32n655l0" ] +stm32n655x0 = [ "stm32-metapac/stm32n655x0" ] +stm32n655z0 = [ "stm32-metapac/stm32n655z0" ] +stm32n657a0 = [ "stm32-metapac/stm32n657a0" ] +stm32n657b0 = [ "stm32-metapac/stm32n657b0" ] +stm32n657i0 = [ "stm32-metapac/stm32n657i0" ] +stm32n657l0 = [ "stm32-metapac/stm32n657l0" ] stm32n657x0 = [ "stm32-metapac/stm32n657x0" ] +stm32n657z0 = [ "stm32-metapac/stm32n657z0" ] stm32u031c6 = [ "stm32-metapac/stm32u031c6" ] stm32u031c8 = [ "stm32-metapac/stm32u031c8" ] stm32u031f4 = [ "stm32-metapac/stm32u031f4" ] -- cgit From 74b5f14ede9a6b4349932bff41dac077afc47fa2 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Wed, 12 Nov 2025 19:31:21 +0100 Subject: stm32/i2c_v2: Refactor transaction implementation --- embassy-stm32/src/i2c/v2.rs | 87 +++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 54 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 061f4ff3a..3c43887c0 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -98,6 +98,27 @@ pub(crate) unsafe fn on_interrupt() { } impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { + #[inline] + fn to_reload(reload: bool) -> i2c::vals::Reload { + if reload { + i2c::vals::Reload::NOT_COMPLETED + } else { + i2c::vals::Reload::COMPLETED + } + } + + /// Calculate total bytes in a group of operations + #[inline] + fn total_operation_bytes(operations: &[Operation<'_>]) -> usize { + operations + .iter() + .map(|op| match op { + Operation::Write(buf) => buf.len(), + Operation::Read(buf) => buf.len(), + }) + .sum() + } + pub(crate) fn init(&mut self, config: Config) { self.info.regs.cr1().modify(|reg| { reg.set_pe(false); @@ -147,12 +168,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { // `buffer`. The START bit can be set even if the bus // is BUSY or I2C is in slave mode. - let reload = if reload { - i2c::vals::Reload::NOT_COMPLETED - } else { - i2c::vals::Reload::COMPLETED - }; - info.regs.cr2().modify(|w| { w.set_sadd(address.addr() << 1); w.set_add10(address.add_mode()); @@ -160,7 +175,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { w.set_nbytes(length as u8); w.set_start(true); w.set_autoend(stop.autoend()); - w.set_reload(reload); + w.set_reload(Self::to_reload(reload)); }); Ok(()) @@ -191,12 +206,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { } } - let reload = if reload { - i2c::vals::Reload::NOT_COMPLETED - } else { - i2c::vals::Reload::COMPLETED - }; - // Set START and prepare to send `bytes`. The // START bit can be set even if the bus is BUSY or // I2C is in slave mode. @@ -207,7 +216,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { w.set_nbytes(length as u8); w.set_start(true); w.set_autoend(stop.autoend()); - w.set_reload(reload); + w.set_reload(Self::to_reload(reload)); }); Ok(()) @@ -220,15 +229,9 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { timeout.check()?; } - let will_reload = if will_reload { - i2c::vals::Reload::NOT_COMPLETED - } else { - i2c::vals::Reload::COMPLETED - }; - info.regs.cr2().modify(|w| { w.set_nbytes(length as u8); - w.set_reload(will_reload); + w.set_reload(Self::to_reload(will_reload)); w.set_autoend(stop.autoend()); }); @@ -400,7 +403,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { address, read.len().min(255), Stop::Automatic, - last_chunk_idx != 0, + last_chunk_idx != 0, // reload restart, timeout, )?; @@ -569,13 +572,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { timeout: Timeout, ) -> Result<(), Error> { // Calculate total bytes across all operations in this group - let total_bytes: usize = operations - .iter() - .map(|op| match op { - Operation::Write(buf) => buf.len(), - _ => 0, - }) - .sum(); + let total_bytes = Self::total_operation_bytes(operations); if total_bytes == 0 { // Handle empty write group - just send address @@ -641,13 +638,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { timeout: Timeout, ) -> Result<(), Error> { // Calculate total bytes across all operations in this group - let total_bytes: usize = operations - .iter() - .map(|op| match op { - Operation::Read(buf) => buf.len(), - _ => 0, - }) - .sum(); + let total_bytes = Self::total_operation_bytes(operations); if total_bytes == 0 { // Handle empty read group @@ -657,7 +648,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { address, 0, if is_last_group { Stop::Automatic } else { Stop::Software }, - false, + false, // reload !is_first_group, timeout, )?; @@ -1000,7 +991,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { address, total_len.min(255), Stop::Automatic, - total_len > 255, + total_len > 255, // reload restart, timeout, )?; @@ -1183,13 +1174,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { timeout: Timeout, ) -> Result<(), Error> { // Calculate total bytes across all operations in this group - let total_bytes: usize = operations - .iter() - .map(|op| match op { - Operation::Write(buf) => buf.len(), - _ => 0, - }) - .sum(); + let total_bytes = Self::total_operation_bytes(operations); if total_bytes == 0 { // Handle empty write group using blocking call @@ -1249,13 +1234,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { timeout: Timeout, ) -> Result<(), Error> { // Calculate total bytes across all operations in this group - let total_bytes: usize = operations - .iter() - .map(|op| match op { - Operation::Read(buf) => buf.len(), - _ => 0, - }) - .sum(); + let total_bytes = Self::total_operation_bytes(operations); if total_bytes == 0 { // Handle empty read group using blocking call @@ -1265,7 +1244,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { address, 0, if is_last_group { Stop::Automatic } else { Stop::Software }, - false, + false, // reload !is_first_group, timeout, )?; @@ -1313,7 +1292,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { } else { Stop::Software }, - last_chunk_idx != 0 || !is_last_read, + last_chunk_idx != 0 || !is_last_read, // reload restart, timeout, )?; -- cgit From 1c94d27a147035dfe40d33bae85be0308394dc53 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Wed, 12 Nov 2025 20:13:48 +0100 Subject: stm32: Add entry about i2c v2 transaction implementation --- embassy-stm32/CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 3431848d3..666ee1714 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -43,7 +43,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - fix: sdmmc: don't wait for DBCKEND flag on sdmmc_v2 devices as it never fires (Fixes #4723) - fix: usart: fix race condition in ringbuffered usart - feat: Add backup_sram::init() for H5 devices to access BKPSRAM -- feat: Add I2C MultiMaster (Slave) support for I2C v1 +- feat: stm32/i2c v1: Add I2C MultiMaster (Slave) support +- feat: stm32/i2c v2: Add transaction() and blocking_transaction() methods with contract-compliant operation merging - feat: stm32/fdcan: add ability to control automatic recovery from bus off ([#4821](https://github.com/embassy-rs/embassy/pull/4821)) - low-power: update rtc api to allow reconfig - adc: consolidate ringbuffer -- cgit From e32f78fde6f8130f1eb3effa131e42b7ca153ba6 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 12 Nov 2025 13:14:15 -0600 Subject: stm32/adc: extract into common add common low-level interface for adc --- embassy-stm32/src/adc/adc4.rs | 110 +-- embassy-stm32/src/adc/g4.rs | 459 ++++--------- embassy-stm32/src/adc/injected.rs | 2 +- embassy-stm32/src/adc/mod.rs | 173 +++++ embassy-stm32/src/adc/ringbuffered.rs | 2 +- embassy-stm32/src/adc/v2.rs | 233 +++---- embassy-stm32/src/adc/v3.rs | 738 +++++++-------------- embassy-stm32/src/adc/v4.rs | 327 ++++----- examples/stm32f4/src/bin/adc.rs | 2 +- examples/stm32f4/src/bin/adc_dma.rs | 8 +- examples/stm32g0/src/bin/adc_oversampling.rs | 14 +- examples/stm32g4/src/bin/adc.rs | 4 +- examples/stm32g4/src/bin/adc_differential.rs | 2 +- examples/stm32g4/src/bin/adc_dma.rs | 2 +- .../stm32g4/src/bin/adc_injected_and_regular.rs | 2 +- examples/stm32g4/src/bin/adc_oversampling.rs | 13 +- examples/stm32l4/src/bin/adc.rs | 9 +- examples/stm32l4/src/bin/adc_dma.rs | 5 +- examples/stm32u0/src/bin/adc.rs | 7 +- examples/stm32u5/src/bin/adc.rs | 16 +- 20 files changed, 869 insertions(+), 1259 deletions(-) diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs index befa8ed4a..04d976513 100644 --- a/embassy-stm32/src/adc/adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs @@ -4,7 +4,7 @@ use pac::adc::vals::{Adc4Dmacfg as Dmacfg, Adc4Exten as Exten, Adc4OversamplingR #[cfg(stm32wba)] use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel}; -use super::{AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel, blocking_delay_us}; +use super::{AdcChannel, AnyAdcChannel, RxDma4, blocking_delay_us}; use crate::dma::Transfer; #[cfg(stm32u5)] pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; @@ -24,56 +24,24 @@ pub const VREF_DEFAULT_MV: u32 = 3300; /// VREF voltage used for factory calibration of VREFINTCAL register. pub const VREF_CALIB_MV: u32 = 3300; -const VREF_CHANNEL: u8 = 0; -const VCORE_CHANNEL: u8 = 12; -const TEMP_CHANNEL: u8 = 13; -const VBAT_CHANNEL: u8 = 14; -const DAC_CHANNEL: u8 = 21; - -// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs -/// Internal voltage reference channel. -pub struct VrefInt; -impl AdcChannel for VrefInt {} -impl SealedAdcChannel for VrefInt { - fn channel(&self) -> u8 { - VREF_CHANNEL - } +impl<'d, T: Instance> super::SealedSpecialConverter for Adc4<'d, T> { + const CHANNEL: u8 = 0; } -/// Internal temperature channel. -pub struct Temperature; -impl AdcChannel for Temperature {} -impl SealedAdcChannel for Temperature { - fn channel(&self) -> u8 { - TEMP_CHANNEL - } +impl<'d, T: Instance> super::SealedSpecialConverter for Adc4<'d, T> { + const CHANNEL: u8 = 13; } -/// Internal battery voltage channel. -pub struct Vbat; -impl AdcChannel for Vbat {} -impl SealedAdcChannel for Vbat { - fn channel(&self) -> u8 { - VBAT_CHANNEL - } +impl<'d, T: Instance> super::SealedSpecialConverter for Adc4<'d, T> { + const CHANNEL: u8 = 12; } -/// Internal DAC channel. -pub struct Dac; -impl AdcChannel for Dac {} -impl SealedAdcChannel for Dac { - fn channel(&self) -> u8 { - DAC_CHANNEL - } +impl<'d, T: Instance> super::SealedSpecialConverter for Adc4<'d, T> { + const CHANNEL: u8 = 14; } -/// Internal Vcore channel. -pub struct Vcore; -impl AdcChannel for Vcore {} -impl SealedAdcChannel for Vcore { - fn channel(&self) -> u8 { - VCORE_CHANNEL - } +impl<'d, T: Instance> super::SealedSpecialConverter for Adc4<'d, T> { + const CHANNEL: u8 = 21; } #[derive(Copy, Clone)] @@ -214,20 +182,6 @@ impl<'d, T: Instance> Adc4<'d, T> { ); } - let mut s = Self { adc }; - - s.power_up(); - - s.calibrate(); - blocking_delay_us(1); - - s.enable(); - s.configure(); - - s - } - - fn power_up(&mut self) { T::regs().isr().modify(|w| { w.set_ldordy(true); }); @@ -239,22 +193,15 @@ impl<'d, T: Instance> Adc4<'d, T> { T::regs().isr().modify(|w| { w.set_ldordy(true); }); - } - fn calibrate(&mut self) { T::regs().cr().modify(|w| w.set_adcal(true)); while T::regs().cr().read().adcal() {} T::regs().isr().modify(|w| w.set_eocal(true)); - } - fn enable(&mut self) { - T::regs().isr().write(|w| w.set_adrdy(true)); - T::regs().cr().modify(|w| w.set_aden(true)); - while !T::regs().isr().read().adrdy() {} - T::regs().isr().write(|w| w.set_adrdy(true)); - } + blocking_delay_us(1); + + Self::enable(); - fn configure(&mut self) { // single conversion mode, software trigger T::regs().cfgr1().modify(|w| { #[cfg(stm32u5)] @@ -280,51 +227,60 @@ impl<'d, T: Instance> Adc4<'d, T> { w.set_smpsel(i, Smpsel::SMP1); } }); + + Self { adc } + } + + fn enable() { + T::regs().isr().write(|w| w.set_adrdy(true)); + T::regs().cr().modify(|w| w.set_aden(true)); + while !T::regs().isr().read().adrdy() {} + T::regs().isr().write(|w| w.set_adrdy(true)); } /// Enable reading the voltage reference internal channel. - pub fn enable_vrefint(&self) -> VrefInt { + pub fn enable_vrefint(&self) -> super::VrefInt { T::regs().ccr().modify(|w| { w.set_vrefen(true); }); - VrefInt {} + super::VrefInt {} } /// Enable reading the temperature internal channel. - pub fn enable_temperature(&self) -> Temperature { + pub fn enable_temperature(&self) -> super::Temperature { T::regs().ccr().modify(|w| { w.set_vsensesel(true); }); - Temperature {} + super::Temperature {} } /// Enable reading the vbat internal channel. #[cfg(stm32u5)] - pub fn enable_vbat(&self) -> Vbat { + pub fn enable_vbat(&self) -> super::Vbat { T::regs().ccr().modify(|w| { w.set_vbaten(true); }); - Vbat {} + super::Vbat {} } /// Enable reading the vbat internal channel. - pub fn enable_vcore(&self) -> Vcore { - Vcore {} + pub fn enable_vcore(&self) -> super::Vcore { + super::Vcore {} } /// Enable reading the vbat internal channel. #[cfg(stm32u5)] - pub fn enable_dac_channel(&self, dac: DacChannel) -> Dac { + pub fn enable_dac_channel(&self, dac: DacChannel) -> super::Dac { let mux; match dac { DacChannel::OUT1 => mux = false, DacChannel::OUT2 => mux = true, } T::regs().or().modify(|w| w.set_chn21sel(mux)); - Dac {} + super::Dac {} } /// Set the ADC resolution. diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 6430b0243..0a9f35a5b 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -1,5 +1,3 @@ -use core::mem; - #[allow(unused)] #[cfg(stm32h7)] use pac::adc::vals::{Adcaldif, Difsel, Exten}; @@ -10,15 +8,14 @@ pub use pac::adccommon::vals::Presc; pub use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen}; pub use stm32_metapac::adccommon::vals::Dual; -use super::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, blocking_delay_us}; +use super::{ + Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime, + blocking_delay_us, +}; use crate::adc::SealedAdcChannel; -use crate::dma::Transfer; use crate::time::Hertz; use crate::{Peri, pac, rcc}; -mod ringbuffered; -pub use ringbuffered::RingBufferedAdc; - mod injected; pub use injected::InjectedAdc; @@ -103,6 +100,19 @@ impl Prescaler { } } +/// ADC configuration +#[derive(Default)] +pub struct AdcConfig { + pub dual_mode: Option, + pub resolution: Option, + #[cfg(stm32g4)] + pub oversampling_shift: Option, + #[cfg(stm32g4)] + pub oversampling_ratio: Option, + #[cfg(stm32g4)] + pub oversampling_mode: Option<(Rovsm, Trovs, bool)>, +} + // Trigger source for ADC conversions¨ #[derive(Copy, Clone)] pub struct ConversionTrigger { @@ -112,18 +122,9 @@ pub struct ConversionTrigger { pub edge: Exten, } -// Conversion mode for regular ADC channels -#[derive(Copy, Clone)] -pub enum RegularConversionMode { - // Samples as fast as possible - Continuous, - // Sample at rate determined by external trigger - Triggered(ConversionTrigger), -} - impl<'d, T: Instance> Adc<'d, T> { /// Create a new ADC driver. - pub fn new(adc: Peri<'d, T>) -> Self { + pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self { rcc::enable_and_reset::(); let prescaler = Prescaler::from_ker_ck(T::frequency()); @@ -181,10 +182,38 @@ impl<'d, T: Instance> Adc<'d, T> { w.set_exten(Exten::DISABLED); }); + if let Some(dual) = config.dual_mode { + T::common_regs().ccr().modify(|reg| { + reg.set_dual(dual); + }) + } + + if let Some(resolution) = config.resolution { + T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); + } + + #[cfg(stm32g4)] + if let Some(shift) = config.oversampling_shift { + T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); + } + + #[cfg(stm32g4)] + if let Some(ratio) = config.oversampling_ratio { + T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); + } + + #[cfg(stm32g4)] + if let Some((mode, trig_mode, enable)) = config.oversampling_mode { + T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); + T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); + T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); + } + Self { adc } } - fn enable() { + /// Enable the ADC + pub(super) fn enable() { // Make sure bits are off while T::regs().cr().read().addis() { // spin @@ -205,82 +234,33 @@ impl<'d, T: Instance> Adc<'d, T> { } } - /// Enable reading the voltage reference internal channel. - pub fn enable_vrefint(&self) -> super::VrefInt - where - T: super::SpecialConverter, - { - T::common_regs().ccr().modify(|reg| { - reg.set_vrefen(true); + /// Start regular adc conversion + pub(super) fn start() { + T::regs().cr().modify(|reg| { + reg.set_adstart(true); }); - - super::VrefInt {} } - /// Enable reading the temperature internal channel. - pub fn enable_temperature(&self) -> super::Temperature - where - T: super::SpecialConverter, - { - T::common_regs().ccr().modify(|reg| { - reg.set_vsenseen(true); - }); - - super::Temperature {} - } + /// Stop regular conversions and disable DMA + pub(super) fn stop() { + if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { + T::regs().cr().modify(|reg| { + reg.set_adstp(Adstp::STOP); + }); + // The software must poll ADSTART until the bit is reset before assuming the + // ADC is completely stopped + while T::regs().cr().read().adstart() {} + } - /// Enable reading the vbat internal channel. - pub fn enable_vbat(&self) -> super::Vbat - where - T: super::SpecialConverter, - { - T::common_regs().ccr().modify(|reg| { - reg.set_vbaten(true); + // Disable dma control and continuous conversion, if enabled + T::regs().cfgr().modify(|reg| { + reg.set_cont(false); + reg.set_dmaen(Dmaen::DISABLE); }); - - super::Vbat {} - } - - /// Set oversampling shift. - #[cfg(stm32g4)] - pub fn set_oversampling_shift(&mut self, shift: u8) { - T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); - } - - /// Set oversampling ratio. - #[cfg(stm32g4)] - pub fn set_oversampling_ratio(&mut self, ratio: u8) { - T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); - } - - /// Enable oversampling in regular mode. - #[cfg(stm32g4)] - pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) { - T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); - T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); - T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); - } - - // Reads that are not implemented as INJECTED in "blocking_read" - // #[cfg(stm32g4)] - // pub fn enalble_injected_oversampling_mode(&mut self, enable: bool) { - // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); - // } - - // #[cfg(stm32g4)] - // pub fn enable_oversampling_regular_injected_mode(&mut self, enable: bool) { - // // the regularoversampling mode is forced to resumed mode (ROVSM bit ignored), - // T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); - // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); - // } - - /// Set the ADC resolution. - pub fn set_resolution(&mut self, resolution: Resolution) { - T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); } /// Perform a single conversion. - fn convert(&mut self) -> u16 { + pub(super) fn convert() -> u16 { T::regs().isr().modify(|reg| { reg.set_eos(true); reg.set_eoc(true); @@ -298,136 +278,42 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().dr().read().0 as u16 } - /// Read an ADC pin. - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { - channel.setup(); - - Self::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); - - #[cfg(stm32h7)] - { - T::regs().cfgr2().modify(|w| w.set_lshift(0)); - T::regs() - .pcsel() - .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED)); - } - - self.convert() - } - - /// Start regular adc conversion - pub(super) fn start() { - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); - } - - /// Stop regular conversions - pub(super) fn stop() { - Self::stop_regular_conversions(); - } - - /// Teardown method for stopping regular ADC conversions - pub(super) fn teardown_dma() { - Self::stop_regular_conversions(); - - // Disable dma control - T::regs().cfgr().modify(|reg| { - reg.set_dmaen(Dmaen::DISABLE); - }); - } - - /// Read one or multiple ADC regular channels using DMA. - /// - /// `sequence` iterator and `readings` must have the same length. - /// - /// Example - /// ```rust,ignore - /// use embassy_stm32::adc::{Adc, AdcChannel} - /// - /// let mut adc = Adc::new(p.ADC1); - /// let mut adc_pin0 = p.PA0.into(); - /// let mut adc_pin1 = p.PA1.into(); - /// let mut measurements = [0u16; 2]; - /// - /// adc.read( - /// p.DMA1_CH2.reborrow(), - /// [ - /// (&mut *adc_pin0, SampleTime::CYCLES160_5), - /// (&mut *adc_pin1, SampleTime::CYCLES160_5), - /// ] - /// .into_iter(), - /// &mut measurements, - /// ) - /// .await; - /// defmt::info!("measurements: {}", measurements); - /// ``` - /// - /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use - /// `into_ring_buffered`, `into_ring_buffered_and_injected` - pub async fn read( - &mut self, - rx_dma: Peri<'_, impl RxDma>, - sequence: impl ExactSizeIterator, SampleTime)>, - readings: &mut [u16], - ) { - assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); - assert!( - sequence.len() == readings.len(), - "Sequence length must be equal to readings length" - ); - assert!( - sequence.len() <= 16, - "Asynchronous read sequence cannot be more than 16 in length" - ); - - // Ensure no conversions are ongoing and ADC is enabled. - Self::stop_regular_conversions(); - Self::enable(); - - Self::configure_sequence( - sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), - ); - - // Set continuous mode with oneshot dma. - // Clear overrun flag before starting transfer. + pub(super) fn configure_dma(conversion_mode: ConversionMode) { T::regs().isr().modify(|reg| { reg.set_ovr(true); }); T::regs().cfgr().modify(|reg| { - reg.set_discen(false); - reg.set_cont(true); - reg.set_dmacfg(Dmacfg::ONE_SHOT); + reg.set_discen(false); // Convert all channels for each trigger + reg.set_dmacfg(match conversion_mode { + ConversionMode::Singular => Dmacfg::ONE_SHOT, + ConversionMode::Repeated(_) => Dmacfg::CIRCULAR, + }); reg.set_dmaen(Dmaen::ENABLE); }); - let request = rx_dma.request(); - let transfer = unsafe { - Transfer::new_read( - rx_dma, - request, - T::regs().dr().as_ptr() as *mut u16, - readings, - Default::default(), - ) - }; - - // Start conversion - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); - - // Wait for conversion sequence to finish. - transfer.await; + if let ConversionMode::Repeated(mode) = conversion_mode { + match mode { + RegularConversionMode::Continuous => { + T::regs().cfgr().modify(|reg| { + reg.set_cont(true); + }); + } + RegularConversionMode::Triggered(trigger) => { + T::regs().cfgr().modify(|r| { + r.set_cont(false); // New trigger is neede for each sample to be read + }); - // Ensure conversions are finished. - Self::stop_regular_conversions(); + T::regs().cfgr().modify(|r| { + r.set_extsel(trigger.channel); + r.set_exten(trigger.edge); + }); - // Reset configuration. - T::regs().cfgr().modify(|reg| { - reg.set_cont(false); - }); + // Regular conversions uses DMA so no need to generate interrupt + T::regs().ier().modify(|r| r.set_eosie(false)); + } + } + } } pub(super) fn configure_sequence(sequence: impl ExactSizeIterator) { @@ -489,95 +375,54 @@ impl<'d, T: Instance> Adc<'d, T> { } } - /// Set external trigger for regular conversion sequence - fn set_regular_conversion_trigger(&mut self, trigger: ConversionTrigger) { - T::regs().cfgr().modify(|r| { - r.set_extsel(trigger.channel); - r.set_exten(trigger.edge); + /// Enable reading the voltage reference internal channel. + pub fn enable_vrefint(&self) -> super::VrefInt + where + T: super::SpecialConverter, + { + T::common_regs().ccr().modify(|reg| { + reg.set_vrefen(true); }); - // Regular conversions uses DMA so no need to generate interrupt - T::regs().ier().modify(|r| r.set_eosie(false)); - } - // Dual ADC mode selection - pub fn configure_dual_mode(&mut self, val: Dual) { - T::common_regs().ccr().modify(|reg| { - reg.set_dual(val); - }) + super::VrefInt {} } - /// Configures the ADC to use a DMA ring buffer for continuous data acquisition. - /// - /// Use the [`read`] method to retrieve measurements from the DMA ring buffer. The read buffer - /// should be exactly half the size of `dma_buf`. When using triggered mode, it is recommended - /// to configure `dma_buf` as a double buffer so that one half can be read while the other half - /// is being filled by the DMA, preventing data loss. The trigger period of the ADC effectively - /// defines the period at which the buffer should be read. - /// - /// If continous conversion mode is selected, the provided `dma_buf` must be large enough to prevent - /// DMA buffer overruns. Its length should be a multiple of the number of ADC channels being measured. - /// For example, if 3 channels are measured and you want to store 40 samples per channel, - /// the buffer length should be `3 * 40 = 120`. - /// - /// # Parameters - /// - `dma`: The DMA peripheral used to transfer ADC data into the buffer. - /// - `dma_buf`: The buffer where DMA stores ADC samples. - /// - `regular_sequence`: Sequence of channels and sample times for regular ADC conversions. - /// - `regular_conversion_mode`: Mode for regular conversions (continuous or triggered). - /// - /// # Returns - /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling. - pub fn into_ring_buffered<'a>( - mut self, - dma: Peri<'a, impl RxDma>, - dma_buf: &'a mut [u16], - sequence: impl ExactSizeIterator, SampleTime)>, - mode: RegularConversionMode, - ) -> RingBufferedAdc<'a, T> { - assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); - assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); - assert!( - sequence.len() <= 16, - "Asynchronous read sequence cannot be more than 16 in length" - ); - // reset conversions and enable the adc - Self::stop_regular_conversions(); - Self::enable(); - - //adc side setup - Self::configure_sequence( - sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), - ); - - // Clear overrun flag before starting transfer. - T::regs().isr().modify(|reg| { - reg.set_ovr(true); + /// Enable reading the temperature internal channel. + pub fn enable_temperature(&self) -> super::Temperature + where + T: super::SpecialConverter, + { + T::common_regs().ccr().modify(|reg| { + reg.set_vsenseen(true); }); - T::regs().cfgr().modify(|reg| { - reg.set_discen(false); // Convert all channels for each trigger - reg.set_dmacfg(Dmacfg::CIRCULAR); - reg.set_dmaen(Dmaen::ENABLE); + super::Temperature {} + } + + /// Enable reading the vbat internal channel. + pub fn enable_vbat(&self) -> super::Vbat + where + T: super::SpecialConverter, + { + T::common_regs().ccr().modify(|reg| { + reg.set_vbaten(true); }); - match mode { - RegularConversionMode::Continuous => { - T::regs().cfgr().modify(|reg| { - reg.set_cont(true); - }); - } - RegularConversionMode::Triggered(trigger) => { - T::regs().cfgr().modify(|r| { - r.set_cont(false); // New trigger is neede for each sample to be read - }); - self.set_regular_conversion_trigger(trigger); - } - } + super::Vbat {} + } - mem::forget(self); + // Reads that are not implemented as INJECTED in "blocking_read" + // #[cfg(stm32g4)] + // pub fn enalble_injected_oversampling_mode(&mut self, enable: bool) { + // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); + // } - RingBufferedAdc::new(dma, dma_buf) - } + // #[cfg(stm32g4)] + // pub fn enable_oversampling_regular_injected_mode(&mut self, enable: bool) { + // // the regularoversampling mode is forced to resumed mode (ROVSM bit ignored), + // T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); + // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); + // } /// Configures the ADC for injected conversions. /// @@ -607,7 +452,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// - Accessing samples beyond `N` will result in a panic; use the returned type /// `InjectedAdc` to enforce bounds at compile time. pub fn setup_injected_conversions<'a, const N: usize>( - mut self, + self, sequence: [(AnyAdcChannel, SampleTime); N], trigger: ConversionTrigger, interrupt: bool, @@ -619,7 +464,7 @@ impl<'d, T: Instance> Adc<'d, T> { NR_INJECTED_RANKS ); - Self::stop_regular_conversions(); + Self::stop(); Self::enable(); T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); @@ -649,8 +494,16 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cfgr().modify(|reg| reg.set_jdiscen(false)); - self.set_injected_conversion_trigger(trigger); - self.enable_injected_eos_interrupt(interrupt); + // Set external trigger for injected conversion sequence + // Possible trigger values are seen in Table 167 in RM0440 Rev 9 + T::regs().jsqr().modify(|r| { + r.set_jextsel(trigger.channel); + r.set_jexten(trigger.edge); + }); + + // Enable end of injected sequence interrupt + T::regs().ier().modify(|r| r.set_jeosie(interrupt)); + Self::start_injected_conversions(); InjectedAdc::new(sequence) // InjectedAdc<'a, T, N> now borrows the channels @@ -688,7 +541,7 @@ impl<'d, T: Instance> Adc<'d, T> { injected_sequence: [(AnyAdcChannel, SampleTime); N], injected_trigger: ConversionTrigger, injected_interrupt: bool, - ) -> (RingBufferedAdc<'a, T>, InjectedAdc) { + ) -> (super::RingBufferedAdc<'a, T>, InjectedAdc) { unsafe { ( Self { @@ -721,32 +574,6 @@ impl<'d, T: Instance> Adc<'d, T> { reg.set_jadstart(true); }); } - - /// Set external trigger for injected conversion sequence - /// Possible trigger values are seen in Table 167 in RM0440 Rev 9 - fn set_injected_conversion_trigger(&mut self, trigger: ConversionTrigger) { - T::regs().jsqr().modify(|r| { - r.set_jextsel(trigger.channel); - r.set_jexten(trigger.edge); - }); - } - - /// Enable end of injected sequence interrupt - fn enable_injected_eos_interrupt(&mut self, enable: bool) { - T::regs().ier().modify(|r| r.set_jeosie(enable)); - } - - // Stop regular conversions - fn stop_regular_conversions() { - if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { - T::regs().cr().modify(|reg| { - reg.set_adstp(Adstp::STOP); - }); - // The software must poll ADSTART until the bit is reset before assuming the - // ADC is completely stopped - while T::regs().cr().read().adstart() {} - } - } } impl InjectedAdc { diff --git a/embassy-stm32/src/adc/injected.rs b/embassy-stm32/src/adc/injected.rs index f9f1bba2a..7bb3a541c 100644 --- a/embassy-stm32/src/adc/injected.rs +++ b/embassy-stm32/src/adc/injected.rs @@ -38,7 +38,7 @@ impl InjectedAdc { impl Drop for InjectedAdc { fn drop(&mut self) { - Adc::::teardown_dma(); + Adc::::stop(); compiler_fence(Ordering::SeqCst); } } diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index e321c4fa1..bf404d6ef 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -17,6 +17,9 @@ #[cfg_attr(adc_c0, path = "c0.rs")] mod _version; +#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] +mod ringbuffered; + use core::marker::PhantomData; #[allow(unused)] @@ -25,6 +28,8 @@ pub use _version::*; use embassy_hal_internal::{PeripheralType, impl_peripheral}; #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] use embassy_sync::waitqueue::AtomicWaker; +#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] +pub use ringbuffered::RingBufferedAdc; #[cfg(any(adc_u5, adc_wba))] #[path = "adc4.rs"] @@ -105,6 +110,166 @@ pub(crate) fn blocking_delay_us(us: u32) { } } +#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] +pub(self) enum ConversionMode { + #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] + Singular, + #[allow(dead_code)] + Repeated(RegularConversionMode), +} + +#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] +// Conversion mode for regular ADC channels +#[derive(Copy, Clone)] +pub enum RegularConversionMode { + // Samples as fast as possible + Continuous, + #[cfg(adc_g4)] + // Sample at rate determined by external trigger + Triggered(ConversionTrigger), +} + +impl<'d, T: Instance> Adc<'d, T> { + #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4))] + /// Read an ADC pin. + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { + #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] + channel.setup(); + + #[cfg(not(adc_v4))] + Self::enable(); + Self::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); + + Self::convert() + } + + #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] + /// Read one or multiple ADC regular channels using DMA. + /// + /// `sequence` iterator and `readings` must have the same length. + /// + /// Example + /// ```rust,ignore + /// use embassy_stm32::adc::{Adc, AdcChannel} + /// + /// let mut adc = Adc::new(p.ADC1); + /// let mut adc_pin0 = p.PA0.into(); + /// let mut adc_pin1 = p.PA1.into(); + /// let mut measurements = [0u16; 2]; + /// + /// adc.read( + /// p.DMA1_CH2.reborrow(), + /// [ + /// (&mut *adc_pin0, SampleTime::CYCLES160_5), + /// (&mut *adc_pin1, SampleTime::CYCLES160_5), + /// ] + /// .into_iter(), + /// &mut measurements, + /// ) + /// .await; + /// defmt::info!("measurements: {}", measurements); + /// ``` + /// + /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use + /// `into_ring_buffered`, `into_ring_buffered_and_injected` + pub async fn read( + &mut self, + rx_dma: embassy_hal_internal::Peri<'_, impl RxDma>, + sequence: impl ExactSizeIterator, SampleTime)>, + readings: &mut [u16], + ) { + assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); + assert!( + sequence.len() == readings.len(), + "Sequence length must be equal to readings length" + ); + assert!( + sequence.len() <= 16, + "Asynchronous read sequence cannot be more than 16 in length" + ); + + // Ensure no conversions are ongoing and ADC is enabled. + Self::stop(); + Self::enable(); + + Self::configure_sequence( + sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), + ); + + Self::configure_dma(ConversionMode::Singular); + + let request = rx_dma.request(); + let transfer = unsafe { + crate::dma::Transfer::new_read( + rx_dma, + request, + T::regs().dr().as_ptr() as *mut u16, + readings, + Default::default(), + ) + }; + + Self::start(); + + // Wait for conversion sequence to finish. + transfer.await; + + // Ensure conversions are finished. + Self::stop(); + } + + #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] + /// Configures the ADC to use a DMA ring buffer for continuous data acquisition. + /// + /// Use the [`read`] method to retrieve measurements from the DMA ring buffer. The read buffer + /// should be exactly half the size of `dma_buf`. When using triggered mode, it is recommended + /// to configure `dma_buf` as a double buffer so that one half can be read while the other half + /// is being filled by the DMA, preventing data loss. The trigger period of the ADC effectively + /// defines the period at which the buffer should be read. + /// + /// If continous conversion mode is selected, the provided `dma_buf` must be large enough to prevent + /// DMA buffer overruns. Its length should be a multiple of the number of ADC channels being measured. + /// For example, if 3 channels are measured and you want to store 40 samples per channel, + /// the buffer length should be `3 * 40 = 120`. + /// + /// # Parameters + /// - `dma`: The DMA peripheral used to transfer ADC data into the buffer. + /// - `dma_buf`: The buffer where DMA stores ADC samples. + /// - `regular_sequence`: Sequence of channels and sample times for regular ADC conversions. + /// - `regular_conversion_mode`: Mode for regular conversions (continuous or triggered). + /// + /// # Returns + /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling. + pub fn into_ring_buffered<'a>( + self, + dma: embassy_hal_internal::Peri<'a, impl RxDma>, + dma_buf: &'a mut [u16], + sequence: impl ExactSizeIterator, SampleTime)>, + mode: RegularConversionMode, + ) -> RingBufferedAdc<'a, T> { + assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); + assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); + assert!( + sequence.len() <= 16, + "Asynchronous read sequence cannot be more than 16 in length" + ); + // reset conversions and enable the adc + Self::stop(); + Self::enable(); + + //adc side setup + Self::configure_sequence( + sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), + ); + + Self::configure_dma(ConversionMode::Repeated(mode)); + + core::mem::forget(self); + + RingBufferedAdc::new(dma, dma_buf) + } +} + pub(self) trait SpecialChannel {} /// Implemented for ADCs that have a special channel @@ -143,6 +308,14 @@ impl SpecialChannel for Temperature {} pub struct Vbat; impl SpecialChannel for Vbat {} +/// Vcore channel. +pub struct Vcore; +impl SpecialChannel for Vcore {} + +/// Internal dac channel. +pub struct Dac; +impl SpecialChannel for Dac {} + /// ADC instance. #[cfg(not(any( adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_g4, adc_f3v1, adc_f3v2, adc_g0, adc_u0, adc_h5, adc_h7rs, diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs index 024c6acdc..62ea0d3a2 100644 --- a/embassy-stm32/src/adc/ringbuffered.rs +++ b/embassy-stm32/src/adc/ringbuffered.rs @@ -172,7 +172,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { impl Drop for RingBufferedAdc<'_, T> { fn drop(&mut self) { - Adc::::teardown_dma(); + Adc::::stop(); compiler_fence(Ordering::SeqCst); diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index efa1cc68c..2f9fabafb 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -1,15 +1,11 @@ -use core::mem; use core::sync::atomic::{Ordering, compiler_fence}; -use super::{Temperature, Vbat, VrefInt, blocking_delay_us}; -use crate::adc::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel}; +use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us}; +use crate::adc::{Adc, Instance, Resolution, SampleTime}; use crate::pac::adc::vals; use crate::time::Hertz; use crate::{Peri, rcc}; -mod ringbuffered; -pub use ringbuffered::RingBufferedAdc; - fn clear_interrupt_flags(r: crate::pac::adc::Adc) { r.sr().modify(|regs| { regs.set_eoc(false); @@ -89,11 +85,21 @@ impl Prescaler { } } +/// ADC configuration +#[derive(Default)] +pub struct AdcConfig { + resolution: Option, +} + impl<'d, T> Adc<'d, T> where T: Instance, { pub fn new(adc: Peri<'d, T>) -> Self { + Self::new_with_config(adc, Default::default()) + } + + pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { rcc::enable_and_reset::(); let presc = Prescaler::from_pclk2(T::frequency()); @@ -104,84 +110,14 @@ where blocking_delay_us(3); - Self { adc } - } - - /// Configures the ADC to use a DMA ring buffer for continuous data acquisition. - /// - /// The `dma_buf` should be large enough to prevent DMA buffer overrun. - /// The length of the `dma_buf` should be a multiple of the ADC channel count. - /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements. - /// - /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length. - /// It is critical to call `read` frequently to prevent DMA buffer overrun. - /// - /// [`read`]: #method.read - pub fn into_ring_buffered<'a>( - self, - dma: Peri<'d, impl RxDma>, - dma_buf: &'d mut [u16], - sequence: impl ExactSizeIterator, SampleTime)>, - ) -> RingBufferedAdc<'d, T> { - assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); - - Self::configure_sequence(sequence.map(|(mut channel, sample_time)| { - channel.setup(); - - (channel.channel, sample_time) - })); - compiler_fence(Ordering::SeqCst); - - Self::setup_dma(); - - // Don't disable the clock - mem::forget(self); - - RingBufferedAdc::new(dma, dma_buf) - } - - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { - channel.setup(); - - // Configure ADC - let channel = channel.channel(); - - Self::configure_sequence([(channel, sample_time)].into_iter()); - Self::blocking_convert() - } - - /// Enables internal voltage reference and returns [VrefInt], which can be used in - /// [Adc::read_internal()] to perform conversion. - pub fn enable_vrefint(&self) -> VrefInt { - T::common_regs().ccr().modify(|reg| { - reg.set_tsvrefe(true); - }); - - VrefInt {} - } - - /// Enables internal temperature sensor and returns [Temperature], which can be used in - /// [Adc::read_internal()] to perform conversion. - /// - /// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled, - /// temperature sensor will return vbat value. - pub fn enable_temperature(&self) -> Temperature { - T::common_regs().ccr().modify(|reg| { - reg.set_tsvrefe(true); - }); + if let Some(resolution) = config.resolution { + T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); + } - Temperature {} + Self { adc } } - /// Enables vbat input and returns [Vbat], which can be used in - /// [Adc::read_internal()] to perform conversion. - pub fn enable_vbat(&self) -> Vbat { - T::common_regs().ccr().modify(|reg| { - reg.set_vbate(true); - }); - - Vbat {} - } + pub(super) fn enable() {} pub(super) fn start() { // Begin ADC conversions @@ -192,18 +128,31 @@ where } pub(super) fn stop() { + let r = T::regs(); + // Stop ADC - T::regs().cr2().modify(|reg| { + r.cr2().modify(|reg| { // Stop ADC reg.set_swstart(false); + // Stop ADC + reg.set_adon(false); + // Stop DMA + reg.set_dma(false); }); - } - pub fn set_resolution(&mut self, resolution: Resolution) { - T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); + r.cr1().modify(|w| { + // Disable interrupt for end of conversion + w.set_eocie(false); + // Disable interrupt for overrun + w.set_ovrie(false); + }); + + clear_interrupt_flags(r); + + compiler_fence(Ordering::SeqCst); } - pub(super) fn blocking_convert() -> u16 { + pub(super) fn convert() -> u16 { // clear end of conversion flag T::regs().sr().modify(|reg| { reg.set_eoc(false); @@ -224,7 +173,44 @@ where T::regs().dr().read().0 as u16 } - pub(super) fn configure_sequence(sequence: impl ExactSizeIterator) { + pub(super) fn configure_dma(conversion_mode: ConversionMode) { + match conversion_mode { + ConversionMode::Repeated(_) => { + let r = T::regs(); + + // Clear all interrupts + r.sr().modify(|regs| { + regs.set_eoc(false); + regs.set_ovr(false); + regs.set_strt(false); + }); + + r.cr1().modify(|w| { + // Enable interrupt for end of conversion + w.set_eocie(true); + // Enable interrupt for overrun + w.set_ovrie(true); + // Scanning converisons of multiple channels + w.set_scan(true); + // Continuous conversion mode + w.set_discen(false); + }); + + r.cr2().modify(|w| { + // Enable DMA mode + w.set_dma(true); + // Enable continuous conversions + w.set_cont(true); + // DMA requests are issues as long as DMA=1 and data are converted. + w.set_dds(vals::Dds::CONTINUOUS); + // EOC flag is set at the end of each conversion. + w.set_eocs(vals::Eocs::EACH_CONVERSION); + }); + } + } + } + + pub(super) fn configure_sequence(sequence: impl ExactSizeIterator) { T::regs().cr2().modify(|reg| { reg.set_adon(true); }); @@ -234,7 +220,7 @@ where r.set_l((sequence.len() - 1).try_into().unwrap()); }); - for (i, (ch, sample_time)) in sequence.enumerate() { + for (i, ((ch, _), sample_time)) in sequence.enumerate() { // Set the channel in the right sequence field. T::regs().sqr3().modify(|w| w.set_sq(i, ch)); @@ -247,62 +233,37 @@ where } } - pub(super) fn setup_dma() { - let r = T::regs(); - - // Clear all interrupts - r.sr().modify(|regs| { - regs.set_eoc(false); - regs.set_ovr(false); - regs.set_strt(false); - }); - - r.cr1().modify(|w| { - // Enable interrupt for end of conversion - w.set_eocie(true); - // Enable interrupt for overrun - w.set_ovrie(true); - // Scanning converisons of multiple channels - w.set_scan(true); - // Continuous conversion mode - w.set_discen(false); + /// Enables internal voltage reference and returns [VrefInt], which can be used in + /// [Adc::read_internal()] to perform conversion. + pub fn enable_vrefint(&self) -> VrefInt { + T::common_regs().ccr().modify(|reg| { + reg.set_tsvrefe(true); }); - r.cr2().modify(|w| { - // Enable DMA mode - w.set_dma(true); - // Enable continuous conversions - w.set_cont(true); - // DMA requests are issues as long as DMA=1 and data are converted. - w.set_dds(vals::Dds::CONTINUOUS); - // EOC flag is set at the end of each conversion. - w.set_eocs(vals::Eocs::EACH_CONVERSION); - }); + VrefInt {} } - pub(super) fn teardown_dma() { - let r = T::regs(); - - // Stop ADC - r.cr2().modify(|reg| { - // Stop ADC - reg.set_swstart(false); - // Stop ADC - reg.set_adon(false); - // Stop DMA - reg.set_dma(false); + /// Enables internal temperature sensor and returns [Temperature], which can be used in + /// [Adc::read_internal()] to perform conversion. + /// + /// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled, + /// temperature sensor will return vbat value. + pub fn enable_temperature(&self) -> Temperature { + T::common_regs().ccr().modify(|reg| { + reg.set_tsvrefe(true); }); - r.cr1().modify(|w| { - // Disable interrupt for end of conversion - w.set_eocie(false); - // Disable interrupt for overrun - w.set_ovrie(false); - }); + Temperature {} + } - clear_interrupt_flags(r); + /// Enables vbat input and returns [Vbat], which can be used in + /// [Adc::read_internal()] to perform conversion. + pub fn enable_vbat(&self) -> Vbat { + T::common_regs().ccr().modify(|reg| { + reg.set_vbate(true); + }); - compiler_fence(Ordering::SeqCst); + Vbat {} } } diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index cbc217545..62b5043ee 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -1,9 +1,9 @@ use cfg_if::cfg_if; #[cfg(adc_g0)] use heapless::Vec; -use pac::adc::vals::Dmacfg; #[cfg(adc_g0)] -use pac::adc::vals::{Ckmode, Smpsel}; +use pac::adc::vals::Ckmode; +use pac::adc::vals::Dmacfg; #[cfg(adc_v3)] use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs}; #[cfg(adc_g0)] @@ -11,18 +11,8 @@ pub use pac::adc::vals::{Ovsr, Ovss, Presc}; #[allow(unused_imports)] use super::SealedAdcChannel; -use super::{ - Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, Temperature, Vbat, VrefInt, - blocking_delay_us, -}; - -#[cfg(any(adc_v3, adc_g0, adc_u0))] -mod ringbuffered; - -#[cfg(any(adc_v3, adc_g0, adc_u0))] -use ringbuffered::RingBufferedAdc; - -use crate::dma::Transfer; +use super::{Adc, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; +use crate::adc::ConversionMode; use crate::{Peri, pac, rcc}; /// Default VREF voltage used for sample conversion to millivolts. @@ -89,7 +79,7 @@ impl super::SealedSpecialConverter for T { cfg_if! { if #[cfg(any(adc_h5, adc_h7rs))] { pub struct VddCore; - impl AdcChannel for VddCore {} + impl super::AdcChannel for VddCore {} impl super::SealedAdcChannel for VddCore { fn channel(&self) -> u8 { 6 @@ -101,7 +91,7 @@ cfg_if! { cfg_if! { if #[cfg(adc_u0)] { pub struct DacOut; - impl AdcChannel for DacOut {} + impl super::AdcChannel for DacOut {} impl super::SealedAdcChannel for DacOut { fn channel(&self) -> u8 { 19 @@ -145,6 +135,32 @@ pub enum Clock { }} +#[cfg(adc_u0)] +type Ovss = u8; +#[cfg(adc_u0)] +type Ovsr = u8; +#[cfg(adc_v3)] +type Ovss = OversamplingShift; +#[cfg(adc_v3)] +type Ovsr = OversamplingRatio; + +/// Adc configuration +#[derive(Default)] +pub struct AdcConfig { + #[cfg(any(adc_u0, adc_g0, adc_v3))] + pub oversampling_shift: Option, + #[cfg(any(adc_u0, adc_g0, adc_v3))] + pub oversampling_ratio: Option, + #[cfg(any(adc_u0, adc_g0))] + pub oversampling_enable: Option, + #[cfg(adc_v3)] + pub oversampling_mode: Option<(Rovsm, Trovs, bool)>, + #[cfg(adc_g0)] + pub clock: Option, + pub resolution: Option, + pub averaging: Option, +} + impl<'d, T: Instance> Adc<'d, T> { /// Enable the voltage regulator fn init_regulator() { @@ -178,38 +194,6 @@ impl<'d, T: Instance> Adc<'d, T> { blocking_delay_us(1); } - #[cfg(any(adc_v3, adc_g0, adc_u0))] - pub(super) fn start() { - // Start adc conversion - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); - } - - #[cfg(any(adc_v3, adc_g0, adc_u0))] - pub(super) fn stop() { - // Stop adc conversion - if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { - T::regs().cr().modify(|reg| { - reg.set_adstp(true); - }); - while T::regs().cr().read().adstart() {} - } - } - - #[cfg(any(adc_v3, adc_g0, adc_u0))] - pub(super) fn teardown_dma() { - //disable dma control - #[cfg(not(any(adc_g0, adc_u0)))] - T::regs().cfgr().modify(|reg| { - reg.set_dmaen(false); - }); - #[cfg(any(adc_g0, adc_u0))] - T::regs().cfgr1().modify(|reg| { - reg.set_dmaen(false); - }); - } - /// Initialize the ADC leaving any analog clock at reset value. /// For G0 and WL, this is the async clock without prescaler. pub fn new(adc: Peri<'d, T>) -> Self { @@ -218,6 +202,73 @@ impl<'d, T: Instance> Adc<'d, T> { Self { adc } } + pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { + #[cfg(not(adc_g0))] + let s = Self::new(adc); + + #[cfg(adc_g0)] + let s = match config.clock { + Some(clock) => Self::new_with_clock(adc, clock), + None => Self::new(adc), + }; + + #[cfg(any(adc_g0, adc_u0, adc_v3))] + if let Some(shift) = config.oversampling_shift { + T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); + } + + #[cfg(any(adc_g0, adc_u0, adc_v3))] + if let Some(ratio) = config.oversampling_ratio { + T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); + } + + #[cfg(any(adc_g0, adc_u0))] + if let Some(enable) = config.oversampling_enable { + T::regs().cfgr2().modify(|reg| reg.set_ovse(enable)); + } + + #[cfg(adc_v3)] + if let Some((mode, trig_mode, enable)) = config.oversampling_mode { + T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); + T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); + T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); + } + + if let Some(resolution) = config.resolution { + #[cfg(not(any(adc_g0, adc_u0)))] + T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); + #[cfg(any(adc_g0, adc_u0))] + T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); + } + + if let Some(averaging) = config.averaging { + let (enable, samples, right_shift) = match averaging { + Averaging::Disabled => (false, 0, 0), + Averaging::Samples2 => (true, 0, 1), + Averaging::Samples4 => (true, 1, 2), + Averaging::Samples8 => (true, 2, 3), + Averaging::Samples16 => (true, 3, 4), + Averaging::Samples32 => (true, 4, 5), + Averaging::Samples64 => (true, 5, 6), + Averaging::Samples128 => (true, 6, 7), + Averaging::Samples256 => (true, 7, 8), + }; + T::regs().cfgr2().modify(|reg| { + #[cfg(not(any(adc_g0, adc_u0)))] + reg.set_rovse(enable); + #[cfg(any(adc_g0, adc_u0))] + reg.set_ovse(enable); + #[cfg(any(adc_h5, adc_h7rs))] + reg.set_ovsr(samples.into()); + #[cfg(not(any(adc_h5, adc_h7rs)))] + reg.set_ovsr(samples.into()); + reg.set_ovss(right_shift.into()); + }) + } + + s + } + #[cfg(adc_g0)] /// Initialize ADC with explicit clock for the analog ADC pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self { @@ -255,7 +306,7 @@ impl<'d, T: Instance> Adc<'d, T> { } // Enable ADC only when it is not already running. - fn enable(&mut self) { + pub(super) fn enable() { // Make sure bits are off while T::regs().cr().read().addis() { // spin @@ -276,258 +327,75 @@ impl<'d, T: Instance> Adc<'d, T> { } } - pub fn enable_vrefint(&self) -> VrefInt { - #[cfg(not(any(adc_g0, adc_u0)))] - T::common_regs().ccr().modify(|reg| { - reg.set_vrefen(true); - }); - #[cfg(any(adc_g0, adc_u0))] - T::regs().ccr().modify(|reg| { - reg.set_vrefen(true); - }); - - // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us - // to stabilize the internal voltage reference. - blocking_delay_us(15); - - VrefInt {} - } - - pub fn enable_temperature(&self) -> Temperature { - cfg_if! { - if #[cfg(any(adc_g0, adc_u0))] { - T::regs().ccr().modify(|reg| { - reg.set_tsen(true); - }); - } else if #[cfg(any(adc_h5, adc_h7rs))] { - T::common_regs().ccr().modify(|reg| { - reg.set_tsen(true); - }); - } else { - T::common_regs().ccr().modify(|reg| { - reg.set_ch17sel(true); - }); - } + pub(super) fn start() { + #[cfg(any(adc_v3, adc_g0, adc_u0))] + { + // Start adc conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); } - - Temperature {} } - pub fn enable_vbat(&self) -> Vbat { - cfg_if! { - if #[cfg(any(adc_g0, adc_u0))] { - T::regs().ccr().modify(|reg| { - reg.set_vbaten(true); - }); - } else if #[cfg(any(adc_h5, adc_h7rs))] { - T::common_regs().ccr().modify(|reg| { - reg.set_vbaten(true); - }); - } else { - T::common_regs().ccr().modify(|reg| { - reg.set_ch18sel(true); + pub(super) fn stop() { + #[cfg(any(adc_v3, adc_g0, adc_u0))] + { + // Ensure conversions are finished. + if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { + T::regs().cr().modify(|reg| { + reg.set_adstp(true); }); + while T::regs().cr().read().adstart() {} } - } - - Vbat {} - } - - /// Set the ADC resolution. - pub fn set_resolution(&mut self, resolution: Resolution) { - #[cfg(not(any(adc_g0, adc_u0)))] - T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); - #[cfg(any(adc_g0, adc_u0))] - T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); - } - pub fn set_averaging(&mut self, averaging: Averaging) { - let (enable, samples, right_shift) = match averaging { - Averaging::Disabled => (false, 0, 0), - Averaging::Samples2 => (true, 0, 1), - Averaging::Samples4 => (true, 1, 2), - Averaging::Samples8 => (true, 2, 3), - Averaging::Samples16 => (true, 3, 4), - Averaging::Samples32 => (true, 4, 5), - Averaging::Samples64 => (true, 5, 6), - Averaging::Samples128 => (true, 6, 7), - Averaging::Samples256 => (true, 7, 8), - }; - T::regs().cfgr2().modify(|reg| { + // Reset configuration. #[cfg(not(any(adc_g0, adc_u0)))] - reg.set_rovse(enable); + T::regs().cfgr().modify(|reg| { + reg.set_cont(false); + reg.set_dmaen(false); + }); #[cfg(any(adc_g0, adc_u0))] - reg.set_ovse(enable); - #[cfg(any(adc_h5, adc_h7rs))] - reg.set_ovsr(samples.into()); - #[cfg(not(any(adc_h5, adc_h7rs)))] - reg.set_ovsr(samples.into()); - reg.set_ovss(right_shift.into()); - }) - } - /* - /// Convert a raw sample from the `Temperature` to deg C - pub fn to_degrees_centigrade(sample: u16) -> f32 { - (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32) - * (sample as f32 - VtempCal30::get().read() as f32) - + 30.0 - } - */ - - /// Perform a single conversion. - fn convert(&mut self) -> u16 { - T::regs().isr().modify(|reg| { - reg.set_eos(true); - reg.set_eoc(true); - }); - - // Start conversion - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); - - while !T::regs().isr().read().eos() { - // spin + T::regs().cfgr1().modify(|reg| { + reg.set_cont(false); + reg.set_dmaen(false); + }); } - - T::regs().dr().read().0 as u16 } - /// Read an ADC channel. - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { - self.read_channel(channel, sample_time) - } - - /// Read one or multiple ADC channels using DMA. - /// - /// `readings` must have a length that is a multiple of the length of the - /// `sequence` iterator. - /// - /// Note: The order of values in `readings` is defined by the pin ADC - /// channel number and not the pin order in `sequence`. - /// - /// Example - /// ```rust,ignore - /// use embassy_stm32::adc::{Adc, AdcChannel} - /// - /// let mut adc = Adc::new(p.ADC1); - /// let mut adc_pin0 = p.PA0.degrade_adc(); - /// let mut adc_pin1 = p.PA1.degrade_adc(); - /// let mut measurements = [0u16; 2]; - /// - /// adc.read( - /// p.DMA1_CH2.reborrow(), - /// [ - /// (&mut *adc_pin0, SampleTime::CYCLES160_5), - /// (&mut *adc_pin1, SampleTime::CYCLES160_5), - /// ] - /// .into_iter(), - /// &mut measurements, - /// ) - /// .await; - /// defmt::info!("measurements: {}", measurements); - /// ``` - pub async fn read( - &mut self, - rx_dma: Peri<'_, impl RxDma>, - sequence: impl ExactSizeIterator, SampleTime)>, - readings: &mut [u16], - ) { - assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); - assert!( - readings.len() % sequence.len() == 0, - "Readings length must be a multiple of sequence length" - ); - assert!( - sequence.len() <= 16, - "Asynchronous read sequence cannot be more than 16 in length" - ); - - #[cfg(all(feature = "low-power", stm32wlex))] - let _device_busy = crate::low_power::DeviceBusy::new_stop1(); - - // Ensure no conversions are ongoing and ADC is enabled. - Self::cancel_conversions(); - self.enable(); + /// Perform a single conversion. + pub(super) fn convert() -> u16 { + // Some models are affected by an erratum: + // If we perform conversions slower than 1 kHz, the first read ADC value can be + // corrupted, so we discard it and measure again. + // + // STM32L471xx: Section 2.7.3 + // STM32G4: Section 2.7.3 + #[cfg(any(rcc_l4, rcc_g4))] + let len = 2; - // Set sequence length - #[cfg(not(any(adc_g0, adc_u0)))] - T::regs().sqr1().modify(|w| { - w.set_l(sequence.len() as u8 - 1); - }); + #[cfg(not(any(rcc_l4, rcc_g4)))] + let len = 1; - #[cfg(adc_g0)] - { - let mut sample_times = Vec::::new(); - - T::regs().chselr().write(|chselr| { - T::regs().smpr().write(|smpr| { - for (channel, sample_time) in sequence { - chselr.set_chsel(channel.channel.into(), true); - if let Some(i) = sample_times.iter().position(|&t| t == sample_time) { - smpr.set_smpsel(channel.channel.into(), (i as u8).into()); - } else { - smpr.set_sample_time(sample_times.len(), sample_time); - if let Err(_) = sample_times.push(sample_time) { - panic!( - "Implementation is limited to {} unique sample times among all channels.", - SAMPLE_TIMES_CAPACITY - ); - } - } - } - }) + for _ in 0..len { + T::regs().isr().modify(|reg| { + reg.set_eos(true); + reg.set_eoc(true); }); - } - #[cfg(not(adc_g0))] - { - #[cfg(adc_u0)] - let mut channel_mask = 0; - - // Configure channels and ranks - for (_i, (channel, sample_time)) in sequence.enumerate() { - Self::configure_channel(channel, sample_time); - // Each channel is sampled according to sequence - #[cfg(not(any(adc_g0, adc_u0)))] - match _i { - 0..=3 => { - T::regs().sqr1().modify(|w| { - w.set_sq(_i, channel.channel()); - }); - } - 4..=8 => { - T::regs().sqr2().modify(|w| { - w.set_sq(_i - 4, channel.channel()); - }); - } - 9..=13 => { - T::regs().sqr3().modify(|w| { - w.set_sq(_i - 9, channel.channel()); - }); - } - 14..=15 => { - T::regs().sqr4().modify(|w| { - w.set_sq(_i - 14, channel.channel()); - }); - } - _ => unreachable!(), - } + // Start conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); - #[cfg(adc_u0)] - { - channel_mask |= 1 << channel.channel(); - } + while !T::regs().isr().read().eos() { + // spin } - - // On G0 and U0 enabled channels are sampled from 0 to last channel. - // It is possible to add up to 8 sequences if CHSELRMOD = 1. - // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. - #[cfg(adc_u0)] - T::regs().chselr().modify(|reg| { - reg.set_chsel(channel_mask); - }); } + + T::regs().dr().read().0 as u16 + } + + pub(super) fn configure_dma(conversion_mode: ConversionMode) { // Set continuous mode with oneshot dma. // Clear overrun flag before starting transfer. T::regs().isr().modify(|reg| { @@ -535,82 +403,23 @@ impl<'d, T: Instance> Adc<'d, T> { }); #[cfg(not(any(adc_g0, adc_u0)))] - T::regs().cfgr().modify(|reg| { - reg.set_discen(false); - reg.set_cont(true); - reg.set_dmacfg(Dmacfg::ONE_SHOT); - reg.set_dmaen(true); - }); + let regs = T::regs().cfgr(); + #[cfg(any(adc_g0, adc_u0))] - T::regs().cfgr1().modify(|reg| { + let regs = T::regs().cfgr1(); + + regs.modify(|reg| { reg.set_discen(false); reg.set_cont(true); - reg.set_dmacfg(Dmacfg::ONE_SHOT); + reg.set_dmacfg(match conversion_mode { + ConversionMode::Singular => Dmacfg::ONE_SHOT, + ConversionMode::Repeated(_) => Dmacfg::CIRCULAR, + }); reg.set_dmaen(true); }); - - let request = rx_dma.request(); - let transfer = unsafe { - Transfer::new_read( - rx_dma, - request, - T::regs().dr().as_ptr() as *mut u16, - readings, - Default::default(), - ) - }; - - // Start conversion - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); - - // Wait for conversion sequence to finish. - transfer.await; - - // Ensure conversions are finished. - Self::cancel_conversions(); - - // Reset configuration. - #[cfg(not(any(adc_g0, adc_u0)))] - T::regs().cfgr().modify(|reg| { - reg.set_cont(false); - }); - #[cfg(any(adc_g0, adc_u0))] - T::regs().cfgr1().modify(|reg| { - reg.set_cont(false); - }); } - /// Configures the ADC to use a DMA ring buffer for continuous data acquisition. - /// - /// The `dma_buf` should be large enough to prevent DMA buffer overrun. - /// The length of the `dma_buf` should be a multiple of the ADC channel count. - /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements. - /// - /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length. - /// It is critical to call `read` frequently to prevent DMA buffer overrun. - /// - /// [`read`]: #method.read - #[cfg(any(adc_v3, adc_g0, adc_u0))] - pub fn into_ring_buffered<'a>( - &mut self, - dma: Peri<'a, impl RxDma>, - dma_buf: &'a mut [u16], - sequence: impl ExactSizeIterator, SampleTime)>, - ) -> RingBufferedAdc<'a, T> { - assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); - assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); - assert!( - sequence.len() <= 16, - "Asynchronous read sequence cannot be more than 16 in length" - ); - // reset conversions and enable the adc - Self::cancel_conversions(); - self.enable(); - - //adc side setup - + pub(super) fn configure_sequence(sequence: impl ExactSizeIterator) { // Set sequence length #[cfg(not(any(adc_g0, adc_u0)))] T::regs().sqr1().modify(|w| { @@ -623,10 +432,10 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().chselr().write(|chselr| { T::regs().smpr().write(|smpr| { - for (channel, sample_time) in sequence { - chselr.set_chsel(channel.channel.into(), true); + for ((channel, _), sample_time) in sequence { + chselr.set_chsel(channel.into(), true); if let Some(i) = sample_times.iter().position(|&t| t == sample_time) { - smpr.set_smpsel(channel.channel.into(), (i as u8).into()); + smpr.set_smpsel(channel.into(), (i as u8).into()); } else { smpr.set_sample_time(sample_times.len(), sample_time); if let Err(_) = sample_times.push(sample_time) { @@ -646,30 +455,63 @@ impl<'d, T: Instance> Adc<'d, T> { let mut channel_mask = 0; // Configure channels and ranks - for (_i, (mut channel, sample_time)) in sequence.enumerate() { - Self::configure_channel(&mut channel, sample_time); + for (_i, ((channel, _), sample_time)) in sequence.enumerate() { + // RM0492, RM0481, etc. + // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." + #[cfg(any(adc_h5, adc_h7rs))] + if channel == 0 { + T::regs().or().modify(|reg| reg.set_op0(true)); + } + + // Configure channel + cfg_if! { + if #[cfg(adc_u0)] { + // On G0 and U6 all channels use the same sampling time. + T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); + } else if #[cfg(any(adc_h5, adc_h7rs))] { + match channel { + 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())), + _ => T::regs().smpr2().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())), + } + } else { + let sample_time = sample_time.into(); + T::regs() + .smpr(channel as usize / 10) + .modify(|reg| reg.set_smp(channel as usize % 10, sample_time)); + } + } + + #[cfg(stm32h7)] + { + use crate::pac::adc::vals::Pcsel; + + T::regs().cfgr2().modify(|w| w.set_lshift(0)); + T::regs() + .pcsel() + .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED)); + } // Each channel is sampled according to sequence #[cfg(not(any(adc_g0, adc_u0)))] match _i { 0..=3 => { T::regs().sqr1().modify(|w| { - w.set_sq(_i, channel.channel()); + w.set_sq(_i, channel); }); } 4..=8 => { T::regs().sqr2().modify(|w| { - w.set_sq(_i - 4, channel.channel()); + w.set_sq(_i - 4, channel); }); } 9..=13 => { T::regs().sqr3().modify(|w| { - w.set_sq(_i - 9, channel.channel()); + w.set_sq(_i - 9, channel); }); } 14..=15 => { T::regs().sqr4().modify(|w| { - w.set_sq(_i - 14, channel.channel()); + w.set_sq(_i - 14, channel); }); } _ => unreachable!(), @@ -677,7 +519,7 @@ impl<'d, T: Instance> Adc<'d, T> { #[cfg(adc_u0)] { - channel_mask |= 1 << channel.channel(); + channel_mask |= 1 << channel; } } @@ -689,151 +531,71 @@ impl<'d, T: Instance> Adc<'d, T> { reg.set_chsel(channel_mask); }); } - // Set continuous mode with Circular dma. - // Clear overrun flag before starting transfer. - T::regs().isr().modify(|reg| { - reg.set_ovr(true); - }); + } + pub fn enable_vrefint(&self) -> VrefInt { #[cfg(not(any(adc_g0, adc_u0)))] - T::regs().cfgr().modify(|reg| { - reg.set_discen(false); - reg.set_cont(true); - reg.set_dmacfg(Dmacfg::CIRCULAR); - reg.set_dmaen(true); + T::common_regs().ccr().modify(|reg| { + reg.set_vrefen(true); }); #[cfg(any(adc_g0, adc_u0))] - T::regs().cfgr1().modify(|reg| { - reg.set_discen(false); - reg.set_cont(true); - reg.set_dmacfg(Dmacfg::CIRCULAR); - reg.set_dmaen(true); + T::regs().ccr().modify(|reg| { + reg.set_vrefen(true); }); - RingBufferedAdc::new(dma, dma_buf) - } - - #[cfg(not(adc_g0))] - fn configure_channel(channel: &mut impl AdcChannel, sample_time: SampleTime) { - // RM0492, RM0481, etc. - // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." - #[cfg(any(adc_h5, adc_h7rs))] - if channel.channel() == 0 { - T::regs().or().modify(|reg| reg.set_op0(true)); - } + // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us + // to stabilize the internal voltage reference. + blocking_delay_us(15); - // Configure channel - Self::set_channel_sample_time(channel.channel(), sample_time); + VrefInt {} } - fn read_channel(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { - self.enable(); - #[cfg(not(adc_g0))] - Self::configure_channel(channel, sample_time); - #[cfg(adc_g0)] - T::regs().smpr().write(|reg| { - reg.set_sample_time(0, sample_time); - reg.set_smpsel(channel.channel().into(), Smpsel::SMP1); - }); - // Select channel - #[cfg(not(any(adc_g0, adc_u0)))] - T::regs().sqr1().write(|reg| reg.set_sq(0, channel.channel())); - #[cfg(any(adc_g0, adc_u0))] - T::regs().chselr().write(|reg| { - #[cfg(adc_g0)] - reg.set_chsel(channel.channel().into(), true); - #[cfg(adc_u0)] - reg.set_chsel(1 << channel.channel()); - }); - - // Some models are affected by an erratum: - // If we perform conversions slower than 1 kHz, the first read ADC value can be - // corrupted, so we discard it and measure again. - // - // STM32L471xx: Section 2.7.3 - // STM32G4: Section 2.7.3 - #[cfg(any(rcc_l4, rcc_g4))] - let _ = self.convert(); - let val = self.convert(); - - T::regs().cr().modify(|reg| reg.set_addis(true)); - - // RM0492, RM0481, etc. - // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." - #[cfg(any(adc_h5, adc_h7rs))] - if channel.channel() == 0 { - T::regs().or().modify(|reg| reg.set_op0(false)); + pub fn enable_temperature(&self) -> Temperature { + cfg_if! { + if #[cfg(any(adc_g0, adc_u0))] { + T::regs().ccr().modify(|reg| { + reg.set_tsen(true); + }); + } else if #[cfg(any(adc_h5, adc_h7rs))] { + T::common_regs().ccr().modify(|reg| { + reg.set_tsen(true); + }); + } else { + T::common_regs().ccr().modify(|reg| { + reg.set_ch17sel(true); + }); + } } - val - } - - #[cfg(adc_g0)] - pub fn set_oversampling_shift(&mut self, shift: Ovss) { - T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); - } - #[cfg(adc_u0)] - pub fn set_oversampling_shift(&mut self, shift: u8) { - T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); - } - - #[cfg(adc_g0)] - pub fn set_oversampling_ratio(&mut self, ratio: Ovsr) { - T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); - } - #[cfg(adc_u0)] - pub fn set_oversampling_ratio(&mut self, ratio: u8) { - T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); - } - - #[cfg(any(adc_g0, adc_u0))] - pub fn oversampling_enable(&mut self, enable: bool) { - T::regs().cfgr2().modify(|reg| reg.set_ovse(enable)); - } - - #[cfg(adc_v3)] - pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) { - T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); - T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); - T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); - } - - #[cfg(adc_v3)] - pub fn set_oversampling_ratio(&mut self, ratio: OversamplingRatio) { - T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); - } - - #[cfg(adc_v3)] - pub fn set_oversampling_shift(&mut self, shift: OversamplingShift) { - T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); + Temperature {} } - #[cfg(not(adc_g0))] - fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { + pub fn enable_vbat(&self) -> Vbat { cfg_if! { - if #[cfg(adc_u0)] { - // On G0 and U6 all channels use the same sampling time. - T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); + if #[cfg(any(adc_g0, adc_u0))] { + T::regs().ccr().modify(|reg| { + reg.set_vbaten(true); + }); } else if #[cfg(any(adc_h5, adc_h7rs))] { - match _ch { - 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), - _ => T::regs().smpr2().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), - } + T::common_regs().ccr().modify(|reg| { + reg.set_vbaten(true); + }); } else { - let sample_time = sample_time.into(); - T::regs() - .smpr(_ch as usize / 10) - .modify(|reg| reg.set_smp(_ch as usize % 10, sample_time)); + T::common_regs().ccr().modify(|reg| { + reg.set_ch18sel(true); + }); } } + + Vbat {} } - fn cancel_conversions() { - if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { - T::regs().cr().modify(|reg| { - reg.set_adstp(true); - }); - while T::regs().cr().read().adstart() {} - } + /* + /// Convert a raw sample from the `Temperature` to deg C + pub fn to_degrees_centigrade(sample: u16) -> f32 { + (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32) + * (sample as f32 - VtempCal30::get().read() as f32) + + 30.0 } + */ } diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 1d5d3fb92..9be6bcd0b 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -4,11 +4,8 @@ use pac::adc::vals::{Adcaldif, Boost}; use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; use pac::adccommon::vals::Presc; -use super::{ - Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, Temperature, Vbat, - VrefInt, blocking_delay_us, -}; -use crate::dma::Transfer; +use super::{Adc, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; +use crate::adc::ConversionMode; use crate::time::Hertz; use crate::{Peri, pac, rcc}; @@ -147,7 +144,48 @@ pub enum Averaging { Samples1024, } +/// Adc configuration +#[derive(Default)] +pub struct AdcConfig { + pub resolution: Option, + pub averaging: Option, +} + impl<'d, T: Instance> Adc<'d, T> { + pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { + let s = Self::new(adc); + + // Set the ADC resolution. + if let Some(resolution) = config.resolution { + T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); + } + + // Set hardware averaging. + if let Some(averaging) = config.averaging { + let (enable, samples, right_shift) = match averaging { + Averaging::Disabled => (false, 0, 0), + Averaging::Samples2 => (true, 1, 1), + Averaging::Samples4 => (true, 3, 2), + Averaging::Samples8 => (true, 7, 3), + Averaging::Samples16 => (true, 15, 4), + Averaging::Samples32 => (true, 31, 5), + Averaging::Samples64 => (true, 63, 6), + Averaging::Samples128 => (true, 127, 7), + Averaging::Samples256 => (true, 255, 8), + Averaging::Samples512 => (true, 511, 9), + Averaging::Samples1024 => (true, 1023, 10), + }; + + T::regs().cfgr2().modify(|reg| { + reg.set_rovse(enable); + reg.set_ovsr(samples); + reg.set_ovss(right_shift); + }) + } + + s + } + /// Create a new ADC driver. pub fn new(adc: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); @@ -179,37 +217,20 @@ impl<'d, T: Instance> Adc<'d, T> { }; T::regs().cr().modify(|w| w.set_boost(boost)); } - let mut s = Self { adc }; - s.power_up(); - s.configure_differential_inputs(); - - s.calibrate(); - blocking_delay_us(1); - - s.enable(); - s.configure(); - - s - } - fn power_up(&mut self) { T::regs().cr().modify(|reg| { reg.set_deeppwd(false); reg.set_advregen(true); }); blocking_delay_us(10); - } - fn configure_differential_inputs(&mut self) { T::regs().difsel().modify(|w| { for n in 0..20 { w.set_difsel(n, Difsel::SINGLE_ENDED); } }); - } - fn calibrate(&mut self) { T::regs().cr().modify(|w| { #[cfg(not(adc_u5))] w.set_adcaldif(Adcaldif::SINGLE_ENDED); @@ -219,80 +240,50 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cr().modify(|w| w.set_adcal(true)); while T::regs().cr().read().adcal() {} - } - fn enable(&mut self) { - T::regs().isr().write(|w| w.set_adrdy(true)); - T::regs().cr().modify(|w| w.set_aden(true)); - while !T::regs().isr().read().adrdy() {} - T::regs().isr().write(|w| w.set_adrdy(true)); - } + blocking_delay_us(1); + + Self::enable(); - fn configure(&mut self) { // single conversion mode, software trigger T::regs().cfgr().modify(|w| { w.set_cont(false); w.set_exten(Exten::DISABLED); }); - } - /// Enable reading the voltage reference internal channel. - pub fn enable_vrefint(&self) -> VrefInt { - T::common_regs().ccr().modify(|reg| { - reg.set_vrefen(true); - }); - - VrefInt {} + Self { adc } } - /// Enable reading the temperature internal channel. - pub fn enable_temperature(&self) -> Temperature { - T::common_regs().ccr().modify(|reg| { - reg.set_vsenseen(true); - }); - - Temperature {} + pub(super) fn enable() { + T::regs().isr().write(|w| w.set_adrdy(true)); + T::regs().cr().modify(|w| w.set_aden(true)); + while !T::regs().isr().read().adrdy() {} + T::regs().isr().write(|w| w.set_adrdy(true)); } - /// Enable reading the vbat internal channel. - pub fn enable_vbat(&self) -> Vbat { - T::common_regs().ccr().modify(|reg| { - reg.set_vbaten(true); + pub(super) fn start() { + // Start conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); }); - - Vbat {} } - /// Set the ADC resolution. - pub fn set_resolution(&mut self, resolution: Resolution) { - T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); - } + pub(super) fn stop() { + if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { + T::regs().cr().modify(|reg| { + reg.set_adstp(Adstp::STOP); + }); + while T::regs().cr().read().adstart() {} + } - /// Set hardware averaging. - pub fn set_averaging(&mut self, averaging: Averaging) { - let (enable, samples, right_shift) = match averaging { - Averaging::Disabled => (false, 0, 0), - Averaging::Samples2 => (true, 1, 1), - Averaging::Samples4 => (true, 3, 2), - Averaging::Samples8 => (true, 7, 3), - Averaging::Samples16 => (true, 15, 4), - Averaging::Samples32 => (true, 31, 5), - Averaging::Samples64 => (true, 63, 6), - Averaging::Samples128 => (true, 127, 7), - Averaging::Samples256 => (true, 255, 8), - Averaging::Samples512 => (true, 511, 9), - Averaging::Samples1024 => (true, 1023, 10), - }; - - T::regs().cfgr2().modify(|reg| { - reg.set_rovse(enable); - reg.set_ovsr(samples); - reg.set_ovss(right_shift); - }) + // Reset configuration. + T::regs().cfgr().modify(|reg| { + reg.set_cont(false); + reg.set_dmngt(Dmngt::from_bits(0)); + }); } - /// Perform a single conversion. - fn convert(&mut self) -> u16 { + pub(super) fn convert() -> u16 { T::regs().isr().modify(|reg| { reg.set_eos(true); reg.set_eoc(true); @@ -310,170 +301,96 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().dr().read().0 as u16 } - /// Read an ADC channel. - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { - self.read_channel(channel, sample_time) + pub(super) fn configure_dma(conversion_mode: ConversionMode) { + match conversion_mode { + ConversionMode::Singular => { + T::regs().isr().modify(|reg| { + reg.set_ovr(true); + }); + T::regs().cfgr().modify(|reg| { + reg.set_cont(true); + reg.set_dmngt(Dmngt::DMA_ONE_SHOT); + }); + } + _ => unreachable!(), + } } - /// Read one or multiple ADC channels using DMA. - /// - /// `sequence` iterator and `readings` must have the same length. - /// - /// Example - /// ```rust,ignore - /// use embassy_stm32::adc::{Adc, AdcChannel} - /// - /// let mut adc = Adc::new(p.ADC1); - /// let mut adc_pin0 = p.PA0.into(); - /// let mut adc_pin2 = p.PA2.into(); - /// let mut measurements = [0u16; 2]; - /// - /// adc.read( - /// p.DMA2_CH0.reborrow(), - /// [ - /// (&mut *adc_pin0, SampleTime::CYCLES112), - /// (&mut *adc_pin2, SampleTime::CYCLES112), - /// ] - /// .into_iter(), - /// &mut measurements, - /// ) - /// .await; - /// defmt::info!("measurements: {}", measurements); - /// ``` - pub async fn read( - &mut self, - rx_dma: Peri<'_, impl RxDma>, - sequence: impl ExactSizeIterator, SampleTime)>, - readings: &mut [u16], - ) { - assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); - assert!( - sequence.len() == readings.len(), - "Sequence length must be equal to readings length" - ); - assert!( - sequence.len() <= 16, - "Asynchronous read sequence cannot be more than 16 in length" - ); - - // Ensure no conversions are ongoing - Self::cancel_conversions(); - + pub(super) fn configure_sequence(sequence: impl ExactSizeIterator) { // Set sequence length T::regs().sqr1().modify(|w| { w.set_l(sequence.len() as u8 - 1); }); // Configure channels and ranks - for (i, (channel, sample_time)) in sequence.enumerate() { - Self::configure_channel(channel, sample_time); + for (i, ((channel, _), sample_time)) in sequence.enumerate() { + let sample_time = sample_time.into(); + if channel <= 9 { + T::regs().smpr(0).modify(|reg| reg.set_smp(channel as _, sample_time)); + } else { + T::regs() + .smpr(1) + .modify(|reg| reg.set_smp((channel - 10) as _, sample_time)); + } + + #[cfg(any(stm32h7, stm32u5))] + { + T::regs().cfgr2().modify(|w| w.set_lshift(0)); + T::regs() + .pcsel() + .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); + } + match i { 0..=3 => { T::regs().sqr1().modify(|w| { - w.set_sq(i, channel.channel()); + w.set_sq(i, channel); }); } 4..=8 => { T::regs().sqr2().modify(|w| { - w.set_sq(i - 4, channel.channel()); + w.set_sq(i - 4, channel); }); } 9..=13 => { T::regs().sqr3().modify(|w| { - w.set_sq(i - 9, channel.channel()); + w.set_sq(i - 9, channel); }); } 14..=15 => { T::regs().sqr4().modify(|w| { - w.set_sq(i - 14, channel.channel()); + w.set_sq(i - 14, channel); }); } _ => unreachable!(), } } - - // Set continuous mode with oneshot dma. - // Clear overrun flag before starting transfer. - - T::regs().isr().modify(|reg| { - reg.set_ovr(true); - }); - T::regs().cfgr().modify(|reg| { - reg.set_cont(true); - reg.set_dmngt(Dmngt::DMA_ONE_SHOT); - }); - - let request = rx_dma.request(); - let transfer = unsafe { - Transfer::new_read( - rx_dma, - request, - T::regs().dr().as_ptr() as *mut u16, - readings, - Default::default(), - ) - }; - - // Start conversion - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); - - // Wait for conversion sequence to finish. - transfer.await; - - // Ensure conversions are finished. - Self::cancel_conversions(); - - // Reset configuration. - T::regs().cfgr().modify(|reg| { - reg.set_cont(false); - reg.set_dmngt(Dmngt::from_bits(0)); - }); } - fn configure_channel(channel: &mut impl AdcChannel, sample_time: SampleTime) { - channel.setup(); - - let channel = channel.channel(); - - Self::set_channel_sample_time(channel, sample_time); + /// Enable reading the voltage reference internal channel. + pub fn enable_vrefint(&self) -> VrefInt { + T::common_regs().ccr().modify(|reg| { + reg.set_vrefen(true); + }); - #[cfg(any(stm32h7, stm32u5))] - { - T::regs().cfgr2().modify(|w| w.set_lshift(0)); - T::regs() - .pcsel() - .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); - } + VrefInt {} } - fn read_channel(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { - Self::configure_channel(channel, sample_time); - - T::regs().sqr1().modify(|reg| { - reg.set_sq(0, channel.channel()); - reg.set_l(0); + /// Enable reading the temperature internal channel. + pub fn enable_temperature(&self) -> Temperature { + T::common_regs().ccr().modify(|reg| { + reg.set_vsenseen(true); }); - self.convert() + Temperature {} } - fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { - let sample_time = sample_time.into(); - if ch <= 9 { - T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time)); - } else { - T::regs().smpr(1).modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); - } - } + /// Enable reading the vbat internal channel. + pub fn enable_vbat(&self) -> Vbat { + T::common_regs().ccr().modify(|reg| { + reg.set_vbaten(true); + }); - fn cancel_conversions() { - if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { - T::regs().cr().modify(|reg| { - reg.set_adstp(Adstp::STOP); - }); - while T::regs().cr().read().adstart() {} - } + Vbat {} } } diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs index 5628cb827..694e85657 100644 --- a/examples/stm32f4/src/bin/adc.rs +++ b/examples/stm32f4/src/bin/adc.rs @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut delay = Delay; - let mut adc = Adc::new(p.ADC1); + let mut adc = Adc::new_with_config(p.ADC1, Default::default()); let mut pin = p.PC1; let mut vrefint = adc.enable_vrefint(); diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs index 01b881c79..d61b1b2eb 100644 --- a/examples/stm32f4/src/bin/adc_dma.rs +++ b/examples/stm32f4/src/bin/adc_dma.rs @@ -4,7 +4,7 @@ use cortex_m::singleton; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::Peripherals; -use embassy_stm32::adc::{Adc, AdcChannel, RingBufferedAdc, SampleTime}; +use embassy_stm32::adc::{Adc, AdcChannel, RegularConversionMode, RingBufferedAdc, SampleTime}; use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; @@ -20,8 +20,8 @@ async fn adc_task(p: Peripherals) { let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); let adc_data2: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT2 : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); - let adc = Adc::new(p.ADC1); - let adc2 = Adc::new(p.ADC2); + let adc = Adc::new_with_config(p.ADC1, Default::default()); + let adc2 = Adc::new_with_config(p.ADC2, Default::default()); let mut adc: RingBufferedAdc = adc.into_ring_buffered( p.DMA2_CH0, @@ -31,6 +31,7 @@ async fn adc_task(p: Peripherals) { (p.PA2.degrade_adc(), SampleTime::CYCLES112), ] .into_iter(), + RegularConversionMode::Continuous, ); let mut adc2: RingBufferedAdc = adc2.into_ring_buffered( p.DMA2_CH2, @@ -40,6 +41,7 @@ async fn adc_task(p: Peripherals) { (p.PA3.degrade_adc(), SampleTime::CYCLES112), ] .into_iter(), + RegularConversionMode::Continuous, ); // Note that overrun is a big consideration in this implementation. Whatever task is running the adc.read() calls absolutely must circle back around diff --git a/examples/stm32g0/src/bin/adc_oversampling.rs b/examples/stm32g0/src/bin/adc_oversampling.rs index f6979889d..aa8b1771b 100644 --- a/examples/stm32g0/src/bin/adc_oversampling.rs +++ b/examples/stm32g0/src/bin/adc_oversampling.rs @@ -7,7 +7,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, Clock, Ovsr, Ovss, Presc, SampleTime}; +use embassy_stm32::adc::{Adc, AdcConfig, Clock, Ovsr, Ovss, Presc, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -16,12 +16,14 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Adc oversample test"); - let mut adc = Adc::new_with_clock(p.ADC1, Clock::Async { div: Presc::DIV1 }); - let mut pin = p.PA1; + let mut config = AdcConfig::default(); + config.clock = Some(Clock::Async { div: Presc::DIV1 }); + config.oversampling_ratio = Some(Ovsr::MUL16); + config.oversampling_shift = Some(Ovss::NO_SHIFT); + config.oversampling_enable = Some(true); - adc.set_oversampling_ratio(Ovsr::MUL16); - adc.set_oversampling_shift(Ovss::NO_SHIFT); - adc.oversampling_enable(true); + let mut adc = Adc::new_with_config(p.ADC1, config); + let mut pin = p.PA1; loop { let v = adc.blocking_read(&mut pin, SampleTime::CYCLES1_5); diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index 94315141c..2149e0748 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -28,9 +28,9 @@ async fn main(_spawner: Spawner) { let mut p = embassy_stm32::init(config); info!("Hello World!"); - let mut adc = Adc::new(p.ADC2); + let mut adc = Adc::new(p.ADC2, Default::default()); - let mut adc_temp = Adc::new(p.ADC1); + let mut adc_temp = Adc::new(p.ADC1, Default::default()); let mut temperature = adc_temp.enable_temperature(); loop { diff --git a/examples/stm32g4/src/bin/adc_differential.rs b/examples/stm32g4/src/bin/adc_differential.rs index 2773723e9..6dedf88d6 100644 --- a/examples/stm32g4/src/bin/adc_differential.rs +++ b/examples/stm32g4/src/bin/adc_differential.rs @@ -32,7 +32,7 @@ async fn main(_spawner: Spawner) { } let p = embassy_stm32::init(config); - let mut adc = Adc::new(p.ADC1); + let mut adc = Adc::new(p.ADC1, Default::default()); let mut differential_channel = (p.PA0, p.PA1); // can also use diff --git a/examples/stm32g4/src/bin/adc_dma.rs b/examples/stm32g4/src/bin/adc_dma.rs index ef8b0c3c2..478b6b2ca 100644 --- a/examples/stm32g4/src/bin/adc_dma.rs +++ b/examples/stm32g4/src/bin/adc_dma.rs @@ -33,7 +33,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); - let mut adc = Adc::new(p.ADC1); + let mut adc = Adc::new(p.ADC1, Default::default()); let mut dma = p.DMA1_CH1; let mut vrefint_channel = adc.enable_vrefint().degrade_adc(); diff --git a/examples/stm32g4/src/bin/adc_injected_and_regular.rs b/examples/stm32g4/src/bin/adc_injected_and_regular.rs index 3ae2ff064..1e97fa925 100644 --- a/examples/stm32g4/src/bin/adc_injected_and_regular.rs +++ b/examples/stm32g4/src/bin/adc_injected_and_regular.rs @@ -77,7 +77,7 @@ async fn main(_spawner: embassy_executor::Spawner) { pwm.set_mms2(Mms2::UPDATE); // Configure regular conversions with DMA - let adc1 = Adc::new(p.ADC1); + let adc1 = Adc::new(p.ADC1, Default::default()); let vrefint_channel = adc1.enable_vrefint().degrade_adc(); let pa0 = p.PC1.degrade_adc(); diff --git a/examples/stm32g4/src/bin/adc_oversampling.rs b/examples/stm32g4/src/bin/adc_oversampling.rs index cb99ab2a7..87ffea4be 100644 --- a/examples/stm32g4/src/bin/adc_oversampling.rs +++ b/examples/stm32g4/src/bin/adc_oversampling.rs @@ -9,7 +9,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::Config; use embassy_stm32::adc::vals::{Rovsm, Trovs}; -use embassy_stm32::adc::{Adc, SampleTime}; +use embassy_stm32::adc::{Adc, AdcConfig, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -32,7 +32,8 @@ async fn main(_spawner: Spawner) { } let mut p = embassy_stm32::init(config); - let mut adc = Adc::new(p.ADC1); + let mut config = AdcConfig::default(); + // From https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf // page652 Oversampler // Table 172. Maximum output results vs N and M. Grayed values indicates truncation @@ -44,9 +45,11 @@ async fn main(_spawner: Spawner) { // 0x05 oversampling ratio X64 // 0x06 oversampling ratio X128 // 0x07 oversampling ratio X256 - adc.set_oversampling_ratio(0x03); // ratio X3 - adc.set_oversampling_shift(0b0000); // no shift - adc.enable_regular_oversampling_mode(Rovsm::RESUMED, Trovs::AUTOMATIC, true); + config.oversampling_ratio = Some(0x03); // ratio X3 + config.oversampling_shift = Some(0b0000); // no shift + config.oversampling_mode = Some((Rovsm::RESUMED, Trovs::AUTOMATIC, true)); + + let mut adc = Adc::new(p.ADC1, config); loop { let measured = adc.blocking_read(&mut p.PA0, SampleTime::CYCLES6_5); diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs index 835bf5411..42766a5e3 100644 --- a/examples/stm32l4/src/bin/adc.rs +++ b/examples/stm32l4/src/bin/adc.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_stm32::Config; -use embassy_stm32::adc::{Adc, Resolution, SampleTime}; +use embassy_stm32::adc::{Adc, AdcConfig, Resolution, SampleTime}; use {defmt_rtt as _, panic_probe as _}; #[cortex_m_rt::entry] @@ -17,9 +17,12 @@ fn main() -> ! { } let p = embassy_stm32::init(config); - let mut adc = Adc::new(p.ADC1); + let mut config = AdcConfig::default(); + config.resolution = Some(Resolution::BITS8); + + let mut adc = Adc::new_with_config(p.ADC1, config); //adc.enable_vref(); - adc.set_resolution(Resolution::BITS8); + let mut channel = p.PC0; loop { diff --git a/examples/stm32l4/src/bin/adc_dma.rs b/examples/stm32l4/src/bin/adc_dma.rs index ab1e9d2e9..550da95a4 100644 --- a/examples/stm32l4/src/bin/adc_dma.rs +++ b/examples/stm32l4/src/bin/adc_dma.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::Config; -use embassy_stm32::adc::{Adc, AdcChannel, SampleTime}; +use embassy_stm32::adc::{Adc, AdcChannel, RegularConversionMode, SampleTime}; use {defmt_rtt as _, panic_probe as _}; const DMA_BUF_LEN: usize = 512; @@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) { } let p = embassy_stm32::init(config); - let mut adc = Adc::new(p.ADC1); + let adc = Adc::new(p.ADC1); let adc_pin0 = p.PA0.degrade_adc(); let adc_pin1 = p.PA1.degrade_adc(); let mut adc_dma_buf = [0u16; DMA_BUF_LEN]; @@ -29,6 +29,7 @@ async fn main(_spawner: Spawner) { p.DMA1_CH1, &mut adc_dma_buf, [(adc_pin0, SampleTime::CYCLES640_5), (adc_pin1, SampleTime::CYCLES640_5)].into_iter(), + RegularConversionMode::Continuous, ); info!("starting measurement loop"); diff --git a/examples/stm32u0/src/bin/adc.rs b/examples/stm32u0/src/bin/adc.rs index 4fbc6f17f..53bd37303 100644 --- a/examples/stm32u0/src/bin/adc.rs +++ b/examples/stm32u0/src/bin/adc.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_stm32::Config; -use embassy_stm32::adc::{Adc, Resolution, SampleTime}; +use embassy_stm32::adc::{Adc, AdcConfig, Resolution, SampleTime}; use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; @@ -18,8 +18,9 @@ fn main() -> ! { } let p = embassy_stm32::init(config); - let mut adc = Adc::new(p.ADC1); - adc.set_resolution(Resolution::BITS8); + let mut config = AdcConfig::default(); + config.resolution = Some(Resolution::BITS8); + let mut adc = Adc::new_with_config(p.ADC1, config); let mut channel = p.PC0; loop { diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs index 99944f7c7..6b9a91d6e 100644 --- a/examples/stm32u5/src/bin/adc.rs +++ b/examples/stm32u5/src/bin/adc.rs @@ -2,7 +2,7 @@ #![no_main] use defmt::*; -use embassy_stm32::adc::{self, AdcChannel, SampleTime, adc4}; +use embassy_stm32::adc::{self, AdcChannel, AdcConfig, SampleTime, adc4}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,19 +12,21 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut p = embassy_stm32::init(config); // **** ADC1 init **** - let mut adc1 = adc::Adc::new(p.ADC1); + let mut config = AdcConfig::default(); + config.averaging = Some(adc::Averaging::Samples1024); + config.resolution = Some(adc::Resolution::BITS14); + let mut adc1 = adc::Adc::new_with_config(p.ADC1, config); let mut adc1_pin1 = p.PA3; // A0 on nucleo u5a5 let mut adc1_pin2 = p.PA2; // A1 - adc1.set_resolution(adc::Resolution::BITS14); - adc1.set_averaging(adc::Averaging::Samples1024); let max1 = adc::resolution_to_max_count(adc::Resolution::BITS14); // **** ADC2 init **** - let mut adc2 = adc::Adc::new(p.ADC2); + let mut config = AdcConfig::default(); + config.averaging = Some(adc::Averaging::Samples1024); + config.resolution = Some(adc::Resolution::BITS14); + let mut adc2 = adc::Adc::new_with_config(p.ADC2, config); let mut adc2_pin1 = p.PC3; // A2 let mut adc2_pin2 = p.PB0; // A3 - adc2.set_resolution(adc::Resolution::BITS14); - adc2.set_averaging(adc::Averaging::Samples1024); let max2 = adc::resolution_to_max_count(adc::Resolution::BITS14); // **** ADC4 init **** -- cgit From 4efd9fccf4259779d96c5d1a4829a90bda1a5def Mon Sep 17 00:00:00 2001 From: Wouter Geraedts Date: Wed, 12 Nov 2025 20:48:03 +0100 Subject: Fix flash erase on dualbank STM32Gxxx --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/src/flash/g.rs | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 3431848d3..b418faee6 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- fix: flash erase on dual-bank STM32Gxxx - feat: Add support for STM32N657X0 - feat: timer: Add 32-bit timer support to SimplePwm waveform_up method following waveform pattern ([#4717](https://github.com/embassy-rs/embassy/pull/4717)) - feat: Add support for injected ADC measurements for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840)) diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index d026541a4..d7ba2f571 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs @@ -44,7 +44,6 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) } pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { - let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; wait_busy(); clear_all_err(); @@ -54,9 +53,9 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E #[cfg(any(flash_g0x0, flash_g0x1, flash_g4c3))] w.set_bker(sector.bank == crate::flash::FlashBank::Bank2); #[cfg(flash_g0x0)] - w.set_pnb(idx as u16); + w.set_pnb(sector.index_in_bank as u16); #[cfg(not(flash_g0x0))] - w.set_pnb(idx as u8); + w.set_pnb(sector.index_in_bank as u8); w.set_strt(true); }); }); -- cgit From 973fdb6b222a24e881c722b33767aab76ab92896 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Wed, 12 Nov 2025 21:02:10 +0100 Subject: stm32: Add i2c v2 transaction test --- examples/stm32f0/Cargo.toml | 1 - examples/stm32f0/src/bin/i2c_transaction_test.rs | 219 ---------------------- tests/stm32/Cargo.toml | 7 + tests/stm32/src/bin/i2c_v2.rs | 220 +++++++++++++++++++++++ tests/stm32/src/common.rs | 25 +++ 5 files changed, 252 insertions(+), 220 deletions(-) delete mode 100644 examples/stm32f0/src/bin/i2c_transaction_test.rs create mode 100644 tests/stm32/src/bin/i2c_v2.rs diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 177dd0ac2..a78873d21 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -16,7 +16,6 @@ panic-probe = { version = "1.0.0", features = ["print-defmt"] } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embedded-hal-1 = { package = "embedded-hal", version = "1.0" } static_cell = "2" portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } diff --git a/examples/stm32f0/src/bin/i2c_transaction_test.rs b/examples/stm32f0/src/bin/i2c_transaction_test.rs deleted file mode 100644 index 0ecc3e8b1..000000000 --- a/examples/stm32f0/src/bin/i2c_transaction_test.rs +++ /dev/null @@ -1,219 +0,0 @@ -#![no_std] -#![no_main] - -use defmt::*; -use embassy_executor::Spawner; -use embassy_stm32::i2c::{Config, I2c, Master}; -use embassy_stm32::mode::Blocking; -use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, i2c, peripherals}; -use embassy_time::Timer; -use embedded_hal_1::i2c::Operation; -use {defmt_rtt as _, panic_probe as _}; - -bind_interrupts!(struct Irqs { - I2C1 => i2c::EventInterruptHandler, i2c::ErrorInterruptHandler; -}); - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - // For STM32F072RB on NUCLEO board - let p = embassy_stm32::init(Default::default()); - - info!("I2C Transaction Test Starting..."); - - // Initialize I2C1: PB6=SCL, PB7=SDA - let mut config = Config::default(); - config.frequency = Hertz(100_000); - let mut i2c = I2c::new_blocking( - p.I2C1, - p.PB8, // SCL - p.PB9, // SDA - config, - ); - - let slave_addr = 0x50u8; - - // Wait for devices to initialize - Timer::after_millis(100).await; - - info!("=== Test 1: Consecutive Writes (Should Merge) ==="); - test_consecutive_writes(&mut i2c, slave_addr); - Timer::after_millis(500).await; - - info!("=== Test 2: Consecutive Reads (Should Merge) ==="); - test_consecutive_reads(&mut i2c, slave_addr); - Timer::after_millis(500).await; - - info!("=== Test 3: Write then Read (RESTART) ==="); - test_write_then_read(&mut i2c, slave_addr); - Timer::after_millis(500).await; - - info!("=== Test 4: Read then Write (RESTART) ==="); - test_read_then_write(&mut i2c, slave_addr); - Timer::after_millis(500).await; - - info!("=== Test 5: Complex Mixed Sequence ==="); - test_mixed_sequence(&mut i2c, slave_addr); - Timer::after_millis(500).await; - - info!("=== Test 6: Single Operations ==="); - test_single_operations(&mut i2c, slave_addr); - - info!("All tests complete!"); - - loop { - Timer::after_secs(1).await; - } -} - -fn test_consecutive_writes(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { - // Expected on bus: START, ADDR+W, data1, data2, data3, STOP - // NO intermediate RESTART/STOP between writes - let data1 = [0x10, 0x11, 0x12]; - let data2 = [0x20, 0x21]; - let data3 = [0x30, 0x31, 0x32, 0x33]; - - let mut ops = [ - Operation::Write(&data1), - Operation::Write(&data2), - Operation::Write(&data3), - ]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => info!("✓ Consecutive writes succeeded"), - Err(e) => warn!("✗ Consecutive writes failed: {:?}", e), - } - - info!("Expected: START, ADDR+W, [9 bytes], STOP"); - info!("Check Analog Discovery: No RESTART between writes"); -} - -fn test_consecutive_reads(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { - // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP - // NO intermediate RESTART/STOP between reads - let mut buf1 = [0u8; 4]; - let mut buf2 = [0u8; 3]; - let mut buf3 = [0u8; 2]; - - let mut ops = [ - Operation::Read(&mut buf1), - Operation::Read(&mut buf2), - Operation::Read(&mut buf3), - ]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Consecutive reads succeeded"); - info!(" buf1: {:02x}", buf1); - info!(" buf2: {:02x}", buf2); - info!(" buf3: {:02x}", buf3); - } - Err(e) => warn!("✗ Consecutive reads failed: {:?}", e), - } - - info!("Expected: START, ADDR+R, [9 bytes], NACK on last, STOP"); - info!("Check Analog Discovery: No RESTART between reads"); -} - -fn test_write_then_read(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { - // Expected: START, ADDR+W, data, RESTART, ADDR+R, data, NACK, STOP - let write_data = [0xAA, 0xBB]; - let mut read_buf = [0u8; 4]; - - let mut ops = [ - Operation::Write(&write_data), - Operation::Read(&mut read_buf), - ]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Write-then-read succeeded"); - info!(" Written: {:02x}", write_data); - info!(" Read: {:02x}", read_buf); - } - Err(e) => warn!("✗ Write-then-read failed: {:?}", e), - } - - info!("Expected: START, ADDR+W, [2 bytes], RESTART, ADDR+R, [4 bytes], NACK, STOP"); - info!("Check Analog Discovery: RESTART between write and read"); -} - -fn test_read_then_write(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { - // Expected: START, ADDR+R, data, NACK, RESTART, ADDR+W, data, STOP - let mut read_buf = [0u8; 3]; - let write_data = [0xCC, 0xDD, 0xEE]; - - let mut ops = [ - Operation::Read(&mut read_buf), - Operation::Write(&write_data), - ]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Read-then-write succeeded"); - info!(" Read: {:02x}", read_buf); - info!(" Written: {:02x}", write_data); - } - Err(e) => warn!("✗ Read-then-write failed: {:?}", e), - } - - info!("Expected: START, ADDR+R, [3 bytes], NACK, RESTART, ADDR+W, [3 bytes], STOP"); - info!("Check Analog Discovery: RESTART between read and write"); -} - -fn test_mixed_sequence(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { - // Complex: W, W, R, R, W, R - // Groups: [W,W] RESTART [R,R] RESTART [W] RESTART [R] - let w1 = [0x01, 0x02]; - let w2 = [0x03, 0x04]; - let mut r1 = [0u8; 2]; - let mut r2 = [0u8; 2]; - let w3 = [0x05]; - let mut r3 = [0u8; 1]; - - let mut ops = [ - Operation::Write(&w1), - Operation::Write(&w2), - Operation::Read(&mut r1), - Operation::Read(&mut r2), - Operation::Write(&w3), - Operation::Read(&mut r3), - ]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Mixed sequence succeeded"); - info!(" r1: {:02x}", r1); - info!(" r2: {:02x}", r2); - info!(" r3: {:02x}", r3); - } - Err(e) => warn!("✗ Mixed sequence failed: {:?}", e), - } - - info!("Expected sequence:"); - info!(" START, ADDR+W, [4 bytes merged], RESTART,"); - info!(" ADDR+R, [4 bytes merged], NACK, RESTART,"); - info!(" ADDR+W, [1 byte], RESTART,"); - info!(" ADDR+R, [1 byte], NACK, STOP"); -} - -fn test_single_operations(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { - // Test single write - let write_data = [0xFF]; - let mut ops = [Operation::Write(&write_data)]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => info!("✓ Single write succeeded"), - Err(e) => warn!("✗ Single write failed: {:?}", e), - } - - // Test single read - let mut read_buf = [0u8; 1]; - let mut ops = [Operation::Read(&mut read_buf)]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), - Err(e) => warn!("✗ Single read failed: {:?}", e), - } -} diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index b92b47be2..fa757e276 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -35,6 +35,7 @@ stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" stm32wba52cg = ["embassy-stm32/stm32wba52cg", "spi-v345", "chrono", "rng", "hash"] stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"] +stm32f072rb = ["embassy-stm32/stm32f072rb", "cm0", "not-gpdma", "chrono"] stm32h503rb = ["embassy-stm32/stm32h503rb", "spi-v345", "rng", "stop"] stm32h7s3l8 = ["embassy-stm32/stm32h7s3l8", "spi-v345", "rng", "cordic", "hash-v34"] # TODO: fdcan crashes, cryp dma hangs. stm32u083rc = ["embassy-stm32/stm32u083rc", "cm0", "rng", "chrono"] @@ -159,6 +160,11 @@ name = "hash" path = "src/bin/hash.rs" required-features = [ "hash",] +[[bin]] +name = "i2c_v2" +path = "src/bin/i2c_v2.rs" +required-features = [ "stm32f072rb",] + [[bin]] name = "rng" path = "src/bin/rng.rs" @@ -285,6 +291,7 @@ build = [ { target = "thumbv7em-none-eabi", features = ["stm32wl55jc"], artifact-dir = "out/tests/stm32wl55jc" }, { target = "thumbv7em-none-eabi", features = ["stm32h7s3l8"], artifact-dir = "out/tests/stm32h7s3l8" }, { target = "thumbv6m-none-eabi", features = ["stm32f091rc"], artifact-dir = "out/tests/stm32f091rc" }, + { target = "thumbv6m-none-eabi", features = ["stm32f072rb"], artifact-dir = "out/tests/stm32f072rb" }, { target = "thumbv8m.main-none-eabihf", features = ["stm32h503rb"], artifact-dir = "out/tests/stm32h503rb" }, { target = "thumbv6m-none-eabi", features = ["stm32u083rc"], artifact-dir = "out/tests/stm32u083rc" } ] diff --git a/tests/stm32/src/bin/i2c_v2.rs b/tests/stm32/src/bin/i2c_v2.rs new file mode 100644 index 000000000..9a23e28e1 --- /dev/null +++ b/tests/stm32/src/bin/i2c_v2.rs @@ -0,0 +1,220 @@ +#![no_std] +#![no_main] +// required-features: stm32f072rb +// +// Hardware Setup for NUCLEO-F072RB: +// - I2C1 pins: PB8 (SCL), PB9 (SDA) on CN5 connector +// - Connect to I2C slave device (e.g., Digilent Analog Discovery I2C slave, or EEPROM) +// - Default slave address: 0x50 +// - Pull-up resistors: 4.7kΩ on both SCL and SDA +// - CN5 Pin 5 (PB8/SCL) and CN5 Pin 9 (PB9/SDA) +// +// Analog Discovery Setup: +// - Configure as I2C Slave at address 0x50 +// - DIO 0: SCL +// - DIO 1: SDA +// - Enable pull-ups or use external 4.7kΩ pull-up resistors + +#[path = "../common.rs"] +mod common; + +use common::*; +use embassy_executor::Spawner; +use embassy_stm32::i2c::{Config, I2c, Master}; +use embassy_stm32::mode::Blocking; +use embassy_stm32::time::Hertz; +use embassy_time::block_for; +use embedded_hal_1::i2c::Operation; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = init(); + info!("I2C v2 Transaction Test Starting..."); + + let mut i2c_peri = peri!(p, I2C); + let mut scl = peri!(p, I2C_SCL); + let mut sda = peri!(p, I2C_SDA); + + let mut config = Config::default(); + config.frequency = Hertz(100_000); + + let mut i2c = I2c::new_blocking( + i2c_peri.reborrow(), + scl.reborrow(), + sda.reborrow(), + config, + ); + + // I2C slave address for Analog Discovery or test EEPROM + let slave_addr = 0x50u8; + + // Wait for slave device to be ready + block_for(embassy_time::Duration::from_millis(100)); + + info!("=== Test 1: Consecutive Writes (Should Merge) ==="); + test_consecutive_writes(&mut i2c, slave_addr); + + info!("=== Test 2: Consecutive Reads (Should Merge) ==="); + test_consecutive_reads(&mut i2c, slave_addr); + + info!("=== Test 3: Write then Read (RESTART) ==="); + test_write_then_read(&mut i2c, slave_addr); + + info!("=== Test 4: Read then Write (RESTART) ==="); + test_read_then_write(&mut i2c, slave_addr); + + info!("=== Test 5: Complex Mixed Sequence ==="); + test_mixed_sequence(&mut i2c, slave_addr); + + info!("=== Test 6: Single Operations ==="); + test_single_operations(&mut i2c, slave_addr); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} + +fn test_consecutive_writes(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected on bus: START, ADDR+W, data1, data2, data3, STOP + // NO intermediate RESTART/STOP between writes - they should be merged + let data1 = [0x10, 0x11, 0x12]; + let data2 = [0x20, 0x21]; + let data3 = [0x30, 0x31, 0x32, 0x33]; + + let mut ops = [ + Operation::Write(&data1), + Operation::Write(&data2), + Operation::Write(&data3), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"), + Err(e) => { + error!("✗ Consecutive writes failed: {:?}", e); + defmt::panic!("Test failed: consecutive writes"); + } + } +} + +fn test_consecutive_reads(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP + // NO intermediate RESTART/STOP between reads - they should be merged + let mut buf1 = [0u8; 4]; + let mut buf2 = [0u8; 3]; + let mut buf3 = [0u8; 2]; + + let mut ops = [ + Operation::Read(&mut buf1), + Operation::Read(&mut buf2), + Operation::Read(&mut buf3), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Consecutive reads succeeded (merged 9 bytes)"); + info!(" buf1: {:02x}", buf1); + info!(" buf2: {:02x}", buf2); + info!(" buf3: {:02x}", buf3); + } + Err(e) => { + error!("✗ Consecutive reads failed: {:?}", e); + defmt::panic!("Test failed: consecutive reads"); + } + } +} + +fn test_write_then_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected: START, ADDR+W, data, RESTART, ADDR+R, data, NACK, STOP + let write_data = [0xAA, 0xBB]; + let mut read_buf = [0u8; 4]; + + let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Write-then-read succeeded with RESTART"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => { + error!("✗ Write-then-read failed: {:?}", e); + defmt::panic!("Test failed: write-then-read"); + } + } +} + +fn test_read_then_write(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected: START, ADDR+R, data, NACK, RESTART, ADDR+W, data, STOP + let mut read_buf = [0u8; 3]; + let write_data = [0xCC, 0xDD, 0xEE]; + + let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Read-then-write succeeded with RESTART"); + info!(" Read: {:02x}", read_buf); + info!(" Written: {:02x}", write_data); + } + Err(e) => { + error!("✗ Read-then-write failed: {:?}", e); + defmt::panic!("Test failed: read-then-write"); + } + } +} + +fn test_mixed_sequence(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Complex: W, W, R, R, W, R + // Groups: [W,W] RESTART [R,R] RESTART [W] RESTART [R] + let w1 = [0x01, 0x02]; + let w2 = [0x03, 0x04]; + let mut r1 = [0u8; 2]; + let mut r2 = [0u8; 2]; + let w3 = [0x05]; + let mut r3 = [0u8; 1]; + + let mut ops = [ + Operation::Write(&w1), + Operation::Write(&w2), + Operation::Read(&mut r1), + Operation::Read(&mut r2), + Operation::Write(&w3), + Operation::Read(&mut r3), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Mixed sequence succeeded"); + info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]"); + } + Err(e) => { + error!("✗ Mixed sequence failed: {:?}", e); + defmt::panic!("Test failed: mixed sequence"); + } + } +} + +fn test_single_operations(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Test single write + let write_data = [0xFF]; + let mut ops = [Operation::Write(&write_data)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => info!("✓ Single write succeeded"), + Err(e) => { + error!("✗ Single write failed: {:?}", e); + defmt::panic!("Test failed: single write"); + } + } + + // Test single read + let mut read_buf = [0u8; 1]; + let mut ops = [Operation::Read(&mut read_buf)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), + Err(e) => { + error!("✗ Single read failed: {:?}", e); + defmt::panic!("Test failed: single read"); + } + } +} diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 096cce947..07b667ade 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -60,6 +60,8 @@ teleprobe_meta::target!(b"nucleo-stm32wl55jc"); teleprobe_meta::target!(b"nucleo-stm32wba52cg"); #[cfg(feature = "stm32f091rc")] teleprobe_meta::target!(b"nucleo-stm32f091rc"); +#[cfg(feature = "stm32f072rb")] +teleprobe_meta::target!(b"nucleo-stm32f072rb"); #[cfg(feature = "stm32h503rb")] teleprobe_meta::target!(b"nucleo-stm32h503rb"); #[cfg(feature = "stm32h7s3l8")] @@ -103,6 +105,14 @@ define_peris!( SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, ); +#[cfg(feature = "stm32f072rb")] +define_peris!( + UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, + I2C = I2C1, I2C_SCL = PB8, I2C_SDA = PB9, + @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, + @irq I2C = {I2C1 => embassy_stm32::i2c::EventInterruptHandler, embassy_stm32::i2c::ErrorInterruptHandler;}, +); #[cfg(any(feature = "stm32f100rd", feature = "stm32f103c8", feature = "stm32f107vc"))] define_peris!( UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5, @@ -325,6 +335,21 @@ pub fn config() -> Config { config.rcc.ahb_pre = AHBPrescaler::DIV1; config.rcc.apb1_pre = APBPrescaler::DIV1; } + #[cfg(feature = "stm32f072rb")] + { + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::Bypass, + }); + config.rcc.pll = Some(Pll { + src: PllSource::HSE, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL6, + }); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV1; + } #[cfg(feature = "stm32f103c8")] { config.rcc.hse = Some(Hse { -- cgit From 9e2a4161b32154f19963a222b3eb8f956b60d820 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Wed, 12 Nov 2025 21:55:20 +0100 Subject: stm32/i2c: Fix v2 async transaction implementation --- embassy-stm32/src/i2c/v2.rs | 261 +++++++++++++++++++++++++----------------- tests/stm32/build.rs | 1 + tests/stm32/src/bin/i2c_v2.rs | 238 +++++++++++++++++++++++++++++++++----- tests/stm32/src/common.rs | 2 +- 4 files changed, 363 insertions(+), 139 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 3c43887c0..c9656d2c2 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -225,7 +225,14 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { fn reload(info: &'static Info, length: usize, will_reload: bool, stop: Stop, timeout: Timeout) -> Result<(), Error> { assert!(length < 256 && length > 0); - while !info.regs.isr().read().tcr() { + // Wait for either TCR (Transfer Complete Reload) or TC (Transfer Complete) + // TCR occurs when RELOAD=1, TC occurs when RELOAD=0 + // Both indicate the peripheral is ready for the next transfer + loop { + let isr = info.regs.isr().read(); + if isr.tcr() || isr.tc() { + break; + } timeout.check()?; } @@ -885,12 +892,12 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { address, total_len.min(255), Stop::Software, - (total_len > 255) || !last_slice, + total_len > 255, restart, timeout, )?; } else { - Self::reload(self.info, total_len.min(255), (total_len > 255) || !last_slice, Stop::Software, timeout)?; + Self::reload(self.info, total_len.min(255), total_len > 255, Stop::Software, timeout)?; self.info.regs.cr1().modify(|w| w.set_tcie(true)); } } else if !(isr.tcr() || isr.tc()) { @@ -899,9 +906,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { } else if remaining_len == 0 { return Poll::Ready(Ok(())); } else { - let last_piece = (remaining_len <= 255) && last_slice; - - if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, Stop::Software, timeout) { + if let Err(e) = Self::reload(self.info, remaining_len.min(255), remaining_len > 255, Stop::Software, timeout) { return Poll::Ready(Err(e)); } self.info.regs.cr1().modify(|w| w.set_tcie(true)); @@ -913,10 +918,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { .await?; dma_transfer.await; - if last_slice { - // This should be done already - self.wait_tc(timeout)?; - } + + // Always wait for TC after DMA completes - needed for consecutive buffers + self.wait_tc(timeout)?; if last_slice & send_stop { self.master_stop(); @@ -1173,56 +1177,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { is_last_group: bool, timeout: Timeout, ) -> Result<(), Error> { - // Calculate total bytes across all operations in this group - let total_bytes = Self::total_operation_bytes(operations); - - if total_bytes == 0 { - // Handle empty write group using blocking call - if is_first_group { - Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?; - } - if is_last_group { - self.master_stop(); - } - return Ok(()); - } - - let send_stop = is_last_group; - - // Use DMA for each operation in the group - let mut first_in_group = true; - let mut remaining_operations = operations.len(); - - for operation in operations { - if let Operation::Write(buffer) = operation { - remaining_operations -= 1; - let is_last_in_group = remaining_operations == 0; - - if buffer.is_empty() { - // Skip empty buffers - continue; - } - - let fut = self.write_dma_internal( - address, - buffer, - first_in_group && is_first_group, // first_slice - is_last_in_group && is_last_group, // last_slice - send_stop && is_last_in_group, // send_stop - !is_first_group && first_in_group, // restart - timeout, - ); - timeout.with(fut).await?; - first_in_group = false; - } - } - - // If not last group, wait for TC to enable RESTART - if !is_last_group { - self.wait_tc(timeout)?; - } - - Ok(()) + // For now, use blocking implementation for write groups + // This avoids complexity of handling multiple non-contiguous buffers with DMA + self.execute_write_group(address, operations, is_first_group, is_last_group, timeout) } async fn execute_read_group_async( @@ -1255,10 +1212,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { return Ok(()); } - // For read operations, we need to handle them differently since read_dma_internal - // expects a single buffer. We'll iterate through operations and use DMA for each. - let mut total_remaining = total_bytes; + // Use DMA for read operations - need to handle multiple buffers let restart = !is_first_group; + let mut total_remaining = total_bytes; + let mut is_first_in_group = true; for operation in operations { if let Operation::Read(buffer) = operation { @@ -1267,57 +1224,46 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { continue; } - let is_first_read = total_remaining == total_bytes; let buf_len = buffer.len(); total_remaining -= buf_len; - let is_last_read = total_remaining == 0; - - if is_first_read { - // First read in the group - let completed_chunks = buf_len / 255; - let total_chunks = if completed_chunks * 255 == buf_len { - completed_chunks + let is_last_in_group = total_remaining == 0; + + // Perform DMA read + if is_first_in_group { + // First buffer: use read_dma_internal which handles restart properly + // Only use Automatic stop if this is the last buffer in the last group + let stop_mode = if is_last_group && is_last_in_group { + Stop::Automatic } else { - completed_chunks + 1 + Stop::Software }; - let last_chunk_idx = total_chunks.saturating_sub(1); - // Use master_read to initiate, then DMA for data - Self::master_read( - self.info, + // We need a custom DMA read that respects our stop mode + self.read_dma_group_internal( address, - buf_len.min(255), - if is_last_group && is_last_read { - Stop::Automatic - } else { - Stop::Software - }, - last_chunk_idx != 0 || !is_last_read, // reload + buffer, restart, + stop_mode, timeout, - )?; - } - - // Use the existing read_dma_internal, but we need to handle the reload logic ourselves - // For simplicity with consecutive reads, fall back to blocking for now - // This maintains correctness while keeping complexity manageable - for (chunk_idx, chunk) in buffer.chunks_mut(255).enumerate() { - let chunk_len = chunk.len(); - let is_very_last = total_remaining == 0 && chunk_len == chunk.len(); - - if !is_first_read || chunk_idx != 0 { - let stop = if is_last_group && is_very_last { - Stop::Automatic - } else { - Stop::Software - }; - Self::reload(self.info, chunk_len, !(is_last_group && is_very_last), stop, timeout)?; - } + ) + .await?; + is_first_in_group = false; + } else { + // Subsequent buffers: need to reload and continue + let stop_mode = if is_last_group && is_last_in_group { + Stop::Automatic + } else { + Stop::Software + }; - for byte in chunk { - self.wait_rxne(timeout)?; - *byte = self.info.regs.rxdr().read().rxdata(); - } + self.read_dma_group_internal( + address, + buffer, + false, // no restart for subsequent buffers in same group + stop_mode, + timeout, + ) + .await?; } } } @@ -1326,9 +1272,108 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { if is_last_group { self.wait_stop(timeout)?; } - // For non-last read groups, don't wait for TC - the peripheral may hold SCL low - // in Software AUTOEND mode until the next START is issued. Just proceed directly - // to the next group which will issue RESTART and release the clock. + + Ok(()) + } + + /// Internal DMA read helper for transaction groups + async fn read_dma_group_internal( + &mut self, + address: Address, + buffer: &mut [u8], + restart: bool, + stop_mode: Stop, + timeout: Timeout, + ) -> Result<(), Error> { + let total_len = buffer.len(); + + let dma_transfer = unsafe { + let regs = self.info.regs; + regs.cr1().modify(|w| { + w.set_rxdmaen(true); + w.set_tcie(true); + w.set_nackie(true); + w.set_errie(true); + }); + let src = regs.rxdr().as_ptr() as *mut u8; + + self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) + }; + + let mut remaining_len = total_len; + + let on_drop = OnDrop::new(|| { + let regs = self.info.regs; + regs.cr1().modify(|w| { + w.set_rxdmaen(false); + w.set_tcie(false); + w.set_nackie(false); + w.set_errie(false); + }); + regs.icr().write(|w| { + w.set_nackcf(true); + w.set_berrcf(true); + w.set_arlocf(true); + w.set_ovrcf(true); + }); + }); + + poll_fn(|cx| { + self.state.waker.register(cx.waker()); + + let isr = self.info.regs.isr().read(); + + if isr.nackf() { + return Poll::Ready(Err(Error::Nack)); + } + if isr.arlo() { + return Poll::Ready(Err(Error::Arbitration)); + } + if isr.berr() { + return Poll::Ready(Err(Error::Bus)); + } + if isr.ovr() { + return Poll::Ready(Err(Error::Overrun)); + } + + if remaining_len == total_len { + Self::master_read( + self.info, + address, + total_len.min(255), + stop_mode, + total_len > 255, // reload + restart, + timeout, + )?; + if total_len <= 255 { + return Poll::Ready(Ok(())); + } + } else if isr.tcr() { + // Transfer Complete Reload - need to set up next chunk + let last_piece = remaining_len <= 255; + + if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, stop_mode, timeout) { + return Poll::Ready(Err(e)); + } + // Return here if we are on last chunk, + // end of transfer will be awaited with the DMA below + if last_piece { + return Poll::Ready(Ok(())); + } + self.info.regs.cr1().modify(|w| w.set_tcie(true)); + } else { + // poll_fn was woken without TCR interrupt + return Poll::Pending; + } + + remaining_len = remaining_len.saturating_sub(255); + Poll::Pending + }) + .await?; + + dma_transfer.await; + drop(on_drop); Ok(()) } diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs index 556d77a20..34030c206 100644 --- a/tests/stm32/build.rs +++ b/tests/stm32/build.rs @@ -15,6 +15,7 @@ fn main() -> Result<(), Box> { feature = "stm32c071rb", // 24 kb feature = "stm32l073rz", // 20 kb feature = "stm32h503rb", // 32 kb + feature = "stm32f072rb", // 16 kb - I2C v2 test with async too large for RAM // no VTOR, so interrupts can't work when running from RAM feature = "stm32f091rc", )) { diff --git a/tests/stm32/src/bin/i2c_v2.rs b/tests/stm32/src/bin/i2c_v2.rs index 9a23e28e1..087b8bbd9 100644 --- a/tests/stm32/src/bin/i2c_v2.rs +++ b/tests/stm32/src/bin/i2c_v2.rs @@ -7,7 +7,7 @@ // - Connect to I2C slave device (e.g., Digilent Analog Discovery I2C slave, or EEPROM) // - Default slave address: 0x50 // - Pull-up resistors: 4.7kΩ on both SCL and SDA -// - CN5 Pin 5 (PB8/SCL) and CN5 Pin 9 (PB9/SDA) +// - CN5 Pin 10 (PB8/SCL) and CN5 Pin 9 (PB9/SDA) // // Analog Discovery Setup: // - Configure as I2C Slave at address 0x50 @@ -21,9 +21,9 @@ mod common; use common::*; use embassy_executor::Spawner; use embassy_stm32::i2c::{Config, I2c, Master}; -use embassy_stm32::mode::Blocking; +use embassy_stm32::mode::{Async, Blocking}; use embassy_stm32::time::Hertz; -use embassy_time::block_for; +use embassy_time::Timer; use embedded_hal_1::i2c::Operation; #[embassy_executor::main] @@ -38,42 +38,80 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.frequency = Hertz(100_000); - let mut i2c = I2c::new_blocking( - i2c_peri.reborrow(), - scl.reborrow(), - sda.reborrow(), - config, - ); - // I2C slave address for Analog Discovery or test EEPROM let slave_addr = 0x50u8; // Wait for slave device to be ready - block_for(embassy_time::Duration::from_millis(100)); + Timer::after_millis(100).await; + + // ========== BLOCKING TESTS ========== + info!("========== BLOCKING TRANSACTION TESTS =========="); + { + let mut i2c = I2c::new_blocking( + i2c_peri.reborrow(), + scl.reborrow(), + sda.reborrow(), + config, + ); + + info!("=== Test 1: Consecutive Writes (Should Merge) ==="); + test_consecutive_writes_blocking(&mut i2c, slave_addr); + + info!("=== Test 2: Consecutive Reads (Should Merge) ==="); + test_consecutive_reads_blocking(&mut i2c, slave_addr); + + info!("=== Test 3: Write then Read (RESTART) ==="); + test_write_then_read_blocking(&mut i2c, slave_addr); + + info!("=== Test 4: Read then Write (RESTART) ==="); + test_read_then_write_blocking(&mut i2c, slave_addr); + + info!("=== Test 5: Complex Mixed Sequence ==="); + test_mixed_sequence_blocking(&mut i2c, slave_addr); + + info!("=== Test 6: Single Operations ==="); + test_single_operations_blocking(&mut i2c, slave_addr); + + info!("Blocking tests OK"); + } + + Timer::after_millis(100).await; + + // ========== ASYNC TESTS ========== + info!("========== ASYNC TRANSACTION TESTS (DMA) =========="); + { + let tx_dma = peri!(p, I2C_TX_DMA); + let rx_dma = peri!(p, I2C_RX_DMA); + let irq = irqs!(I2C); - info!("=== Test 1: Consecutive Writes (Should Merge) ==="); - test_consecutive_writes(&mut i2c, slave_addr); + let mut i2c = I2c::new(i2c_peri, scl, sda, irq, tx_dma, rx_dma, config); - info!("=== Test 2: Consecutive Reads (Should Merge) ==="); - test_consecutive_reads(&mut i2c, slave_addr); + info!("=== Test 1: Consecutive Writes (Should Merge) ==="); + test_consecutive_writes_async(&mut i2c, slave_addr).await; - info!("=== Test 3: Write then Read (RESTART) ==="); - test_write_then_read(&mut i2c, slave_addr); + info!("=== Test 2: Consecutive Reads (Should Merge) ==="); + test_consecutive_reads_async(&mut i2c, slave_addr).await; - info!("=== Test 4: Read then Write (RESTART) ==="); - test_read_then_write(&mut i2c, slave_addr); + info!("=== Test 3: Write then Read (RESTART) ==="); + test_write_then_read_async(&mut i2c, slave_addr).await; - info!("=== Test 5: Complex Mixed Sequence ==="); - test_mixed_sequence(&mut i2c, slave_addr); + info!("=== Test 4: Read then Write (RESTART) ==="); + test_read_then_write_async(&mut i2c, slave_addr).await; - info!("=== Test 6: Single Operations ==="); - test_single_operations(&mut i2c, slave_addr); + info!("=== Test 5: Complex Mixed Sequence ==="); + test_mixed_sequence_async(&mut i2c, slave_addr).await; - info!("Test OK"); + info!("=== Test 6: Single Operations ==="); + test_single_operations_async(&mut i2c, slave_addr).await; + + info!("Async tests OK"); + } + + info!("All tests OK"); cortex_m::asm::bkpt(); } -fn test_consecutive_writes(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { +fn test_consecutive_writes_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { // Expected on bus: START, ADDR+W, data1, data2, data3, STOP // NO intermediate RESTART/STOP between writes - they should be merged let data1 = [0x10, 0x11, 0x12]; @@ -95,7 +133,7 @@ fn test_consecutive_writes(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { } } -fn test_consecutive_reads(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { +fn test_consecutive_reads_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP // NO intermediate RESTART/STOP between reads - they should be merged let mut buf1 = [0u8; 4]; @@ -122,7 +160,7 @@ fn test_consecutive_reads(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { } } -fn test_write_then_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { +fn test_write_then_read_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { // Expected: START, ADDR+W, data, RESTART, ADDR+R, data, NACK, STOP let write_data = [0xAA, 0xBB]; let mut read_buf = [0u8; 4]; @@ -142,7 +180,7 @@ fn test_write_then_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { } } -fn test_read_then_write(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { +fn test_read_then_write_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { // Expected: START, ADDR+R, data, NACK, RESTART, ADDR+W, data, STOP let mut read_buf = [0u8; 3]; let write_data = [0xCC, 0xDD, 0xEE]; @@ -162,7 +200,7 @@ fn test_read_then_write(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { } } -fn test_mixed_sequence(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { +fn test_mixed_sequence_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { // Complex: W, W, R, R, W, R // Groups: [W,W] RESTART [R,R] RESTART [W] RESTART [R] let w1 = [0x01, 0x02]; @@ -193,7 +231,7 @@ fn test_mixed_sequence(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { } } -fn test_single_operations(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { +fn test_single_operations_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { // Test single write let write_data = [0xFF]; let mut ops = [Operation::Write(&write_data)]; @@ -218,3 +256,143 @@ fn test_single_operations(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { } } } + +// ==================== ASYNC TEST FUNCTIONS ==================== + +async fn test_consecutive_writes_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let data1 = [0x10, 0x11, 0x12]; + let data2 = [0x20, 0x21]; + let data3 = [0x30, 0x31, 0x32, 0x33]; + + let mut ops = [ + Operation::Write(&data1), + Operation::Write(&data2), + Operation::Write(&data3), + ]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"), + Err(e) => { + error!("✗ Consecutive writes failed: {:?}", e); + defmt::panic!("Test failed: consecutive writes"); + } + } +} + +async fn test_consecutive_reads_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let mut buf1 = [0u8; 4]; + let mut buf2 = [0u8; 3]; + let mut buf3 = [0u8; 2]; + + let mut ops = [ + Operation::Read(&mut buf1), + Operation::Read(&mut buf2), + Operation::Read(&mut buf3), + ]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Consecutive reads succeeded (merged 9 bytes)"); + info!(" buf1: {:02x}", buf1); + info!(" buf2: {:02x}", buf2); + info!(" buf3: {:02x}", buf3); + } + Err(e) => { + error!("✗ Consecutive reads failed: {:?}", e); + defmt::panic!("Test failed: consecutive reads"); + } + } +} + +async fn test_write_then_read_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let write_data = [0xAA, 0xBB]; + let mut read_buf = [0u8; 4]; + + let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Write-then-read succeeded with RESTART"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => { + error!("✗ Write-then-read failed: {:?}", e); + defmt::panic!("Test failed: write-then-read"); + } + } +} + +async fn test_read_then_write_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let mut read_buf = [0u8; 3]; + let write_data = [0xCC, 0xDD, 0xEE]; + + let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Read-then-write succeeded with RESTART"); + info!(" Read: {:02x}", read_buf); + info!(" Written: {:02x}", write_data); + } + Err(e) => { + error!("✗ Read-then-write failed: {:?}", e); + defmt::panic!("Test failed: read-then-write"); + } + } +} + +async fn test_mixed_sequence_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let w1 = [0x01, 0x02]; + let w2 = [0x03, 0x04]; + let mut r1 = [0u8; 2]; + let mut r2 = [0u8; 2]; + let w3 = [0x05]; + let mut r3 = [0u8; 1]; + + let mut ops = [ + Operation::Write(&w1), + Operation::Write(&w2), + Operation::Read(&mut r1), + Operation::Read(&mut r2), + Operation::Write(&w3), + Operation::Read(&mut r3), + ]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Mixed sequence succeeded"); + info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]"); + } + Err(e) => { + error!("✗ Mixed sequence failed: {:?}", e); + defmt::panic!("Test failed: mixed sequence"); + } + } +} + +async fn test_single_operations_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + // Test single write + let write_data = [0xFF]; + let mut ops = [Operation::Write(&write_data)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => info!("✓ Single write succeeded"), + Err(e) => { + error!("✗ Single write failed: {:?}", e); + defmt::panic!("Test failed: single write"); + } + } + + // Test single read + let mut read_buf = [0u8; 1]; + let mut ops = [Operation::Read(&mut read_buf)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), + Err(e) => { + error!("✗ Single read failed: {:?}", e); + defmt::panic!("Test failed: single read"); + } + } +} diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 07b667ade..de06cb267 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -109,7 +109,7 @@ define_peris!( define_peris!( UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5, SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, - I2C = I2C1, I2C_SCL = PB8, I2C_SDA = PB9, + I2C = I2C1, I2C_SCL = PB8, I2C_SDA = PB9, I2C_TX_DMA = DMA1_CH6, I2C_RX_DMA = DMA1_CH7, @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, @irq I2C = {I2C1 => embassy_stm32::i2c::EventInterruptHandler, embassy_stm32::i2c::ErrorInterruptHandler;}, ); -- cgit From f0506252e21c96ce3b03e0d1c061a831d7dfe3c3 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 12 Nov 2025 20:06:00 -0600 Subject: stm32: extract adc4 extract adc4 into common adc system and add anyInstance trait to cover adc4 and not adc4 --- embassy-stm32/Cargo.toml | 1 + embassy-stm32/build.rs | 4 +- embassy-stm32/src/adc/adc4.rs | 312 ++++++++++++++-------------------- embassy-stm32/src/adc/g4.rs | 206 +++++++++++----------- embassy-stm32/src/adc/injected.rs | 6 +- embassy-stm32/src/adc/mod.rs | 111 +++++++----- embassy-stm32/src/adc/ringbuffered.rs | 12 +- embassy-stm32/src/adc/v2.rs | 66 +++---- embassy-stm32/src/adc/v3.rs | 302 ++++++++++++++++---------------- embassy-stm32/src/adc/v4.rs | 220 ++++++++++++------------ examples/stm32u5/src/bin/adc.rs | 21 ++- examples/stm32wba/src/bin/adc.rs | 17 +- examples/stm32wba6/src/bin/adc.rs | 17 +- 13 files changed, 651 insertions(+), 644 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ec49924a2..2f4f2ce51 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -188,6 +188,7 @@ embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } chrono = { version = "^0.4", default-features = false, optional = true } bit_field = "0.10.2" +trait-set = "0.3.0" document-features = "0.2.7" static_assertions = { version = "1.1" } diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 48da475df..ad6743f96 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1602,13 +1602,13 @@ fn main() { .into(); if chip_name.starts_with("stm32u5") { - signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma4)); + signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma)); } else { signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma)); } if chip_name.starts_with("stm32wba") { - signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma4)); + signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma)); } if chip_name.starts_with("stm32g4") { diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs index 04d976513..52678d1b6 100644 --- a/embassy-stm32/src/adc/adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs @@ -4,8 +4,8 @@ use pac::adc::vals::{Adc4Dmacfg as Dmacfg, Adc4Exten as Exten, Adc4OversamplingR #[cfg(stm32wba)] use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel}; -use super::{AdcChannel, AnyAdcChannel, RxDma4, blocking_delay_us}; -use crate::dma::Transfer; +use super::blocking_delay_us; +use crate::adc::ConversionMode; #[cfg(stm32u5)] pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; #[cfg(stm32wba)] @@ -153,6 +153,121 @@ pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeri type Interrupt: crate::interrupt::typelevel::Interrupt; } +foreach_adc!( + (ADC4, $common_inst:ident, $clock:ident) => { + use crate::peripherals::ADC4; + + impl super::BasicAnyInstance for ADC4 { + type SampleTime = SampleTime; + } + + impl super::SealedAnyInstance for ADC4 { + fn dr() -> *mut u16 { + ADC4::regs().dr().as_ptr() as *mut u16 + } + + fn enable() { + ADC4::regs().isr().write(|w| w.set_adrdy(true)); + ADC4::regs().cr().modify(|w| w.set_aden(true)); + while !ADC4::regs().isr().read().adrdy() {} + ADC4::regs().isr().write(|w| w.set_adrdy(true)); + } + + fn start() { + // Start conversion + ADC4::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + } + + fn stop() { + if ADC4::regs().cr().read().adstart() && !ADC4::regs().cr().read().addis() { + ADC4::regs().cr().modify(|reg| { + reg.set_adstp(true); + }); + while ADC4::regs().cr().read().adstart() {} + } + + // Reset configuration. + ADC4::regs().cfgr1().modify(|reg| { + reg.set_dmaen(false); + }); + } + + fn configure_dma(conversion_mode: ConversionMode) { + match conversion_mode { + ConversionMode::Singular => { + ADC4::regs().isr().modify(|reg| { + reg.set_ovr(true); + reg.set_eos(true); + reg.set_eoc(true); + }); + + ADC4::regs().cfgr1().modify(|reg| { + reg.set_dmaen(true); + reg.set_dmacfg(Dmacfg::ONE_SHOT); + #[cfg(stm32u5)] + reg.set_chselrmod(false); + #[cfg(stm32wba)] + reg.set_chselrmod(Chselrmod::ENABLE_INPUT) + }); + } + _ => unreachable!(), + } + } + + fn configure_sequence(sequence: impl ExactSizeIterator) { + let mut prev_channel: i16 = -1; + #[cfg(stm32wba)] + ADC4::regs().chselr().write_value(Chselr(0_u32)); + #[cfg(stm32u5)] + ADC4::regs().chselrmod0().write_value(Chselr(0_u32)); + for (_i, ((channel, _), sample_time)) in sequence.enumerate() { + ADC4::regs().smpr().modify(|w| { + w.set_smp(_i, sample_time); + }); + + let channel_num = channel; + if channel_num as i16 <= prev_channel { + return; + }; + prev_channel = channel_num as i16; + + #[cfg(stm32wba)] + ADC4::regs().chselr().modify(|w| { + w.set_chsel0(channel as usize, true); + }); + #[cfg(stm32u5)] + ADC4::regs().chselrmod0().modify(|w| { + w.set_chsel(channel as usize, true); + }); + } + } + + fn convert() -> u16 { + // Reset interrupts + ADC4::regs().isr().modify(|reg| { + reg.set_eos(true); + reg.set_eoc(true); + }); + + // Start conversion + ADC4::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + + while !ADC4::regs().isr().read().eos() { + // spin + } + + ADC4::regs().dr().read().0 as u16 + } + } + + impl super::AnyInstance for ADC4 {} + }; +); + pub struct Adc4<'d, T: Instance> { #[allow(unused)] adc: crate::Peri<'d, T>, @@ -164,9 +279,9 @@ pub enum Adc4Error { DMAError, } -impl<'d, T: Instance> Adc4<'d, T> { +impl<'d, T: Instance + super::AnyInstance> super::Adc<'d, T> { /// Create a new ADC driver. - pub fn new(adc: Peri<'d, T>) -> Self { + pub fn new_adc4(adc: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); let prescaler = Prescaler::from_ker_ck(T::frequency()); @@ -200,7 +315,7 @@ impl<'d, T: Instance> Adc4<'d, T> { blocking_delay_us(1); - Self::enable(); + T::enable(); // single conversion mode, software trigger T::regs().cfgr1().modify(|w| { @@ -231,15 +346,8 @@ impl<'d, T: Instance> Adc4<'d, T> { Self { adc } } - fn enable() { - T::regs().isr().write(|w| w.set_adrdy(true)); - T::regs().cr().modify(|w| w.set_aden(true)); - while !T::regs().isr().read().adrdy() {} - T::regs().isr().write(|w| w.set_adrdy(true)); - } - /// Enable reading the voltage reference internal channel. - pub fn enable_vrefint(&self) -> super::VrefInt { + pub fn enable_vrefint_adc4(&self) -> super::VrefInt { T::regs().ccr().modify(|w| { w.set_vrefen(true); }); @@ -248,7 +356,7 @@ impl<'d, T: Instance> Adc4<'d, T> { } /// Enable reading the temperature internal channel. - pub fn enable_temperature(&self) -> super::Temperature { + pub fn enable_temperature_adc4(&self) -> super::Temperature { T::regs().ccr().modify(|w| { w.set_vsensesel(true); }); @@ -258,7 +366,7 @@ impl<'d, T: Instance> Adc4<'d, T> { /// Enable reading the vbat internal channel. #[cfg(stm32u5)] - pub fn enable_vbat(&self) -> super::Vbat { + pub fn enable_vbat_adc4(&self) -> super::Vbat { T::regs().ccr().modify(|w| { w.set_vbaten(true); }); @@ -267,13 +375,13 @@ impl<'d, T: Instance> Adc4<'d, T> { } /// Enable reading the vbat internal channel. - pub fn enable_vcore(&self) -> super::Vcore { + pub fn enable_vcore_adc4(&self) -> super::Vcore { super::Vcore {} } /// Enable reading the vbat internal channel. #[cfg(stm32u5)] - pub fn enable_dac_channel(&self, dac: DacChannel) -> super::Dac { + pub fn enable_dac_channel_adc4(&self, dac: DacChannel) -> super::Dac { let mux; match dac { DacChannel::OUT1 => mux = false, @@ -284,13 +392,13 @@ impl<'d, T: Instance> Adc4<'d, T> { } /// Set the ADC resolution. - pub fn set_resolution(&mut self, resolution: Resolution) { + pub fn set_resolution_adc4(&mut self, resolution: Resolution) { T::regs().cfgr1().modify(|w| w.set_res(resolution.into())); } /// Set hardware averaging. #[cfg(stm32u5)] - pub fn set_averaging(&mut self, averaging: Averaging) { + pub fn set_averaging_adc4(&mut self, averaging: Averaging) { let (enable, samples, right_shift) = match averaging { Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, 0), Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, 1), @@ -310,7 +418,7 @@ impl<'d, T: Instance> Adc4<'d, T> { }) } #[cfg(stm32wba)] - pub fn set_averaging(&mut self, averaging: Averaging) { + pub fn set_averaging_adc4(&mut self, averaging: Averaging) { let (enable, samples, right_shift) = match averaging { Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT0), Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT1), @@ -329,168 +437,4 @@ impl<'d, T: Instance> Adc4<'d, T> { w.set_ovse(enable) }) } - - /// Read an ADC channel. - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { - T::regs().smpr().modify(|w| { - w.set_smp(0, sample_time); - }); - - channel.setup(); - - // Select channel - #[cfg(stm32wba)] - { - T::regs().chselr().write_value(Chselr(0_u32)); - T::regs().chselr().modify(|w| { - w.set_chsel0(channel.channel() as usize, true); - }); - } - #[cfg(stm32u5)] - { - T::regs().chselrmod0().write_value(Chselr(0_u32)); - T::regs().chselrmod0().modify(|w| { - w.set_chsel(channel.channel() as usize, true); - }); - } - - // Reset interrupts - T::regs().isr().modify(|reg| { - reg.set_eos(true); - reg.set_eoc(true); - }); - - // Start conversion - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); - - while !T::regs().isr().read().eos() { - // spin - } - - T::regs().dr().read().0 as u16 - } - - /// Read one or multiple ADC channels using DMA. - /// - /// `sequence` iterator and `readings` must have the same length. - /// The channels in `sequence` must be in ascending order. - /// - /// Example - /// ```rust,ignore - /// use embassy_stm32::adc::adc4; - /// use embassy_stm32::adc::AdcChannel; - /// - /// let mut adc4 = adc4::Adc4::new(p.ADC4); - /// let mut adc4_pin1 = p.PC1; - /// let mut adc4_pin2 = p.PC0; - /// let mut.into()d41 = adc4_pin1.into(); - /// let mut.into()d42 = adc4_pin2.into(); - /// let mut measurements = [0u16; 2]; - /// // not that the channels must be in ascending order - /// adc4.read( - /// &mut p.GPDMA1_CH1, - /// [ - /// &mut.into()d42, - /// &mut.into()d41, - /// ] - /// .into_iter(), - /// &mut measurements, - /// ).await.unwrap(); - /// ``` - pub async fn read( - &mut self, - rx_dma: Peri<'_, impl RxDma4>, - sequence: impl ExactSizeIterator>, - readings: &mut [u16], - ) -> Result<(), Adc4Error> { - assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); - assert!( - sequence.len() == readings.len(), - "Sequence length must be equal to readings length" - ); - - // Ensure no conversions are ongoing - Self::cancel_conversions(); - - T::regs().isr().modify(|reg| { - reg.set_ovr(true); - reg.set_eos(true); - reg.set_eoc(true); - }); - - T::regs().cfgr1().modify(|reg| { - reg.set_dmaen(true); - reg.set_dmacfg(Dmacfg::ONE_SHOT); - #[cfg(stm32u5)] - reg.set_chselrmod(false); - #[cfg(stm32wba)] - reg.set_chselrmod(Chselrmod::ENABLE_INPUT) - }); - - // Verify and activate sequence - let mut prev_channel: i16 = -1; - #[cfg(stm32wba)] - T::regs().chselr().write_value(Chselr(0_u32)); - #[cfg(stm32u5)] - T::regs().chselrmod0().write_value(Chselr(0_u32)); - for channel in sequence { - let channel_num = channel.channel; - if channel_num as i16 <= prev_channel { - return Err(Adc4Error::InvalidSequence); - }; - prev_channel = channel_num as i16; - - #[cfg(stm32wba)] - T::regs().chselr().modify(|w| { - w.set_chsel0(channel.channel as usize, true); - }); - #[cfg(stm32u5)] - T::regs().chselrmod0().modify(|w| { - w.set_chsel(channel.channel as usize, true); - }); - } - - let request = rx_dma.request(); - let transfer = unsafe { - Transfer::new_read( - rx_dma, - request, - T::regs().dr().as_ptr() as *mut u16, - readings, - Default::default(), - ) - }; - - // Start conversion - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); - - transfer.await; - - // Ensure conversions are finished. - Self::cancel_conversions(); - - // Reset configuration. - T::regs().cfgr1().modify(|reg| { - reg.set_dmaen(false); - }); - - if T::regs().isr().read().ovr() { - Err(Adc4Error::DMAError) - } else { - Ok(()) - } - } - - fn cancel_conversions() { - if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { - T::regs().cr().modify(|reg| { - reg.set_adstp(true); - }); - while T::regs().cr().read().adstart() {} - } - } } diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 0a9f35a5b..71dc8acc0 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -12,7 +12,7 @@ use super::{ Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime, blocking_delay_us, }; -use crate::adc::SealedAdcChannel; +use crate::adc::{AnyInstance, SealedAdcChannel}; use crate::time::Hertz; use crate::{Peri, pac, rcc}; @@ -122,98 +122,12 @@ pub struct ConversionTrigger { pub edge: Exten, } -impl<'d, T: Instance> Adc<'d, T> { - /// Create a new ADC driver. - pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self { - rcc::enable_and_reset::(); - - let prescaler = Prescaler::from_ker_ck(T::frequency()); - - T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); - - let frequency = Hertz(T::frequency().0 / prescaler.divisor()); - trace!("ADC frequency set to {}", frequency); - - if frequency > MAX_ADC_CLK_FREQ { - panic!( - "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", - MAX_ADC_CLK_FREQ.0 / 1_000_000 - ); - } - - T::regs().cr().modify(|reg| { - reg.set_deeppwd(false); - reg.set_advregen(true); - }); - - blocking_delay_us(20); - - T::regs().difsel().modify(|w| { - for n in 0..18 { - w.set_difsel(n, Difsel::SINGLE_ENDED); - } - }); - - T::regs().cr().modify(|w| { - w.set_adcaldif(Adcaldif::SINGLE_ENDED); - }); - - T::regs().cr().modify(|w| w.set_adcal(true)); - - while T::regs().cr().read().adcal() {} - - blocking_delay_us(20); - - T::regs().cr().modify(|w| { - w.set_adcaldif(Adcaldif::DIFFERENTIAL); - }); - - T::regs().cr().modify(|w| w.set_adcal(true)); - - while T::regs().cr().read().adcal() {} - - blocking_delay_us(20); - - Self::enable(); - - // single conversion mode, software trigger - T::regs().cfgr().modify(|w| { - w.set_cont(false); - w.set_exten(Exten::DISABLED); - }); - - if let Some(dual) = config.dual_mode { - T::common_regs().ccr().modify(|reg| { - reg.set_dual(dual); - }) - } - - if let Some(resolution) = config.resolution { - T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); - } - - #[cfg(stm32g4)] - if let Some(shift) = config.oversampling_shift { - T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); - } - - #[cfg(stm32g4)] - if let Some(ratio) = config.oversampling_ratio { - T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); - } - - #[cfg(stm32g4)] - if let Some((mode, trig_mode, enable)) = config.oversampling_mode { - T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); - T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); - T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); - } - - Self { adc } +impl super::SealedAnyInstance for T { + fn dr() -> *mut u16 { + T::regs().dr().as_ptr() as *mut u16 } - /// Enable the ADC - pub(super) fn enable() { + fn enable() { // Make sure bits are off while T::regs().cr().read().addis() { // spin @@ -234,15 +148,13 @@ impl<'d, T: Instance> Adc<'d, T> { } } - /// Start regular adc conversion - pub(super) fn start() { + fn start() { T::regs().cr().modify(|reg| { reg.set_adstart(true); }); } - /// Stop regular conversions and disable DMA - pub(super) fn stop() { + fn stop() { if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { T::regs().cr().modify(|reg| { reg.set_adstp(Adstp::STOP); @@ -259,8 +171,7 @@ impl<'d, T: Instance> Adc<'d, T> { }); } - /// Perform a single conversion. - pub(super) fn convert() -> u16 { + fn convert() -> u16 { T::regs().isr().modify(|reg| { reg.set_eos(true); reg.set_eoc(true); @@ -278,7 +189,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().dr().read().0 as u16 } - pub(super) fn configure_dma(conversion_mode: ConversionMode) { + fn configure_dma(conversion_mode: ConversionMode) { T::regs().isr().modify(|reg| { reg.set_ovr(true); }); @@ -316,7 +227,7 @@ impl<'d, T: Instance> Adc<'d, T> { } } - pub(super) fn configure_sequence(sequence: impl ExactSizeIterator) { + fn configure_sequence(sequence: impl ExactSizeIterator) { // Set sequence length T::regs().sqr1().modify(|w| { w.set_l(sequence.len() as u8 - 1); @@ -374,6 +285,97 @@ impl<'d, T: Instance> Adc<'d, T> { } } } +} + +impl<'d, T: Instance + AnyInstance> Adc<'d, T> { + /// Create a new ADC driver. + pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self { + rcc::enable_and_reset::(); + + let prescaler = Prescaler::from_ker_ck(T::frequency()); + + T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); + + let frequency = Hertz(T::frequency().0 / prescaler.divisor()); + trace!("ADC frequency set to {}", frequency); + + if frequency > MAX_ADC_CLK_FREQ { + panic!( + "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", + MAX_ADC_CLK_FREQ.0 / 1_000_000 + ); + } + + T::regs().cr().modify(|reg| { + reg.set_deeppwd(false); + reg.set_advregen(true); + }); + + blocking_delay_us(20); + + T::regs().difsel().modify(|w| { + for n in 0..18 { + w.set_difsel(n, Difsel::SINGLE_ENDED); + } + }); + + T::regs().cr().modify(|w| { + w.set_adcaldif(Adcaldif::SINGLE_ENDED); + }); + + T::regs().cr().modify(|w| w.set_adcal(true)); + + while T::regs().cr().read().adcal() {} + + blocking_delay_us(20); + + T::regs().cr().modify(|w| { + w.set_adcaldif(Adcaldif::DIFFERENTIAL); + }); + + T::regs().cr().modify(|w| w.set_adcal(true)); + + while T::regs().cr().read().adcal() {} + + blocking_delay_us(20); + + T::enable(); + + // single conversion mode, software trigger + T::regs().cfgr().modify(|w| { + w.set_cont(false); + w.set_exten(Exten::DISABLED); + }); + + if let Some(dual) = config.dual_mode { + T::common_regs().ccr().modify(|reg| { + reg.set_dual(dual); + }) + } + + if let Some(resolution) = config.resolution { + T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); + } + + #[cfg(stm32g4)] + if let Some(shift) = config.oversampling_shift { + T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); + } + + #[cfg(stm32g4)] + if let Some(ratio) = config.oversampling_ratio { + T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); + } + + #[cfg(stm32g4)] + if let Some((mode, trig_mode, enable)) = config.oversampling_mode { + T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); + T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); + T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); + } + + Self { adc } + } /// Enable reading the voltage reference internal channel. pub fn enable_vrefint(&self) -> super::VrefInt @@ -464,8 +466,8 @@ impl<'d, T: Instance> Adc<'d, T> { NR_INJECTED_RANKS ); - Self::stop(); - Self::enable(); + T::stop(); + T::enable(); T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); @@ -536,7 +538,7 @@ impl<'d, T: Instance> Adc<'d, T> { self, dma: Peri<'a, impl RxDma>, dma_buf: &'a mut [u16], - regular_sequence: impl ExactSizeIterator, SampleTime)>, + regular_sequence: impl ExactSizeIterator, T::SampleTime)>, regular_conversion_mode: RegularConversionMode, injected_sequence: [(AnyAdcChannel, SampleTime); N], injected_trigger: ConversionTrigger, diff --git a/embassy-stm32/src/adc/injected.rs b/embassy-stm32/src/adc/injected.rs index 7bb3a541c..ccaa5d1b2 100644 --- a/embassy-stm32/src/adc/injected.rs +++ b/embassy-stm32/src/adc/injected.rs @@ -5,9 +5,9 @@ use core::sync::atomic::{Ordering, compiler_fence}; use embassy_hal_internal::Peri; use super::{AnyAdcChannel, SampleTime}; -use crate::adc::Adc; #[allow(unused_imports)] use crate::adc::Instance; +use crate::adc::{Adc, AnyInstance}; /// Injected ADC sequence with owned channels. pub struct InjectedAdc { @@ -36,9 +36,9 @@ impl InjectedAdc { } } -impl Drop for InjectedAdc { +impl Drop for InjectedAdc { fn drop(&mut self) { - Adc::::stop(); + T::stop(); compiler_fence(Ordering::SeqCst); } } diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index bf404d6ef..856c2e61e 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -41,15 +41,10 @@ pub use crate::pac::adc::vals::Res as Resolution; pub use crate::pac::adc::vals::SampleTime; use crate::peripherals; -#[cfg(not(adc_wba))] -dma_trait!(RxDma, Instance); -#[cfg(adc_u5)] -dma_trait!(RxDma4, adc4::Instance); -#[cfg(adc_wba)] -dma_trait!(RxDma4, adc4::Instance); +dma_trait!(RxDma, AnyInstance); /// Analog to Digital driver. -pub struct Adc<'d, T: Instance> { +pub struct Adc<'d, T: AnyInstance> { #[allow(unused)] adc: crate::Peri<'d, T>, } @@ -92,6 +87,49 @@ pub(crate) trait SealedAdcChannel { } } +// Temporary patch for ADCs that have not implemented the standard iface yet +#[cfg(not(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4)))] +trait_set::trait_set! { + pub trait AnyInstance = Instance; +} + +#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] +#[allow(dead_code)] +pub trait BasicAnyInstance { + type SampleTime; +} + +#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] +#[allow(dead_code)] +pub(self) trait SealedAnyInstance: BasicAnyInstance { + fn enable(); + fn start(); + fn stop(); + fn convert() -> u16; + fn configure_dma(conversion_mode: ConversionMode); + fn configure_sequence(sequence: impl ExactSizeIterator); + fn dr() -> *mut u16; +} + +// On chips without ADC4, AnyInstance is an Instance +#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4))] +#[allow(private_bounds)] +pub trait AnyInstance: SealedAnyInstance + Instance {} + +// On chips with ADC4, AnyInstance is an Instance or adc4::Instance +#[cfg(any(adc_v4, adc_u5, adc_wba))] +#[allow(private_bounds)] +pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {} + +// Implement AnyInstance automatically for SealedAnyInstance +#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] +impl BasicAnyInstance for T { + type SampleTime = SampleTime; +} + +#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] +impl AnyInstance for T {} + /// Performs a busy-wait delay for a specified number of microseconds. #[allow(unused)] pub(crate) fn blocking_delay_us(us: u32) { @@ -110,16 +148,18 @@ pub(crate) fn blocking_delay_us(us: u32) { } } -#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] -pub(self) enum ConversionMode { - #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] +#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] +#[allow(dead_code)] +pub(crate) enum ConversionMode { + #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] Singular, #[allow(dead_code)] Repeated(RegularConversionMode), } -#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] +#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] // Conversion mode for regular ADC channels +#[allow(dead_code)] #[derive(Copy, Clone)] pub enum RegularConversionMode { // Samples as fast as possible @@ -129,21 +169,21 @@ pub enum RegularConversionMode { Triggered(ConversionTrigger), } -impl<'d, T: Instance> Adc<'d, T> { - #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4))] +impl<'d, T: AnyInstance> Adc<'d, T> { + #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba))] /// Read an ADC pin. - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: T::SampleTime) -> u16 { #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] channel.setup(); #[cfg(not(adc_v4))] - Self::enable(); - Self::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); + T::enable(); + T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); - Self::convert() + T::convert() } - #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] + #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] /// Read one or multiple ADC regular channels using DMA. /// /// `sequence` iterator and `readings` must have the same length. @@ -175,7 +215,7 @@ impl<'d, T: Instance> Adc<'d, T> { pub async fn read( &mut self, rx_dma: embassy_hal_internal::Peri<'_, impl RxDma>, - sequence: impl ExactSizeIterator, SampleTime)>, + sequence: impl ExactSizeIterator, T::SampleTime)>, readings: &mut [u16], ) { assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); @@ -189,33 +229,26 @@ impl<'d, T: Instance> Adc<'d, T> { ); // Ensure no conversions are ongoing and ADC is enabled. - Self::stop(); - Self::enable(); + T::stop(); + T::enable(); - Self::configure_sequence( + T::configure_sequence( sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), ); - Self::configure_dma(ConversionMode::Singular); + T::configure_dma(ConversionMode::Singular); let request = rx_dma.request(); - let transfer = unsafe { - crate::dma::Transfer::new_read( - rx_dma, - request, - T::regs().dr().as_ptr() as *mut u16, - readings, - Default::default(), - ) - }; + let transfer = + unsafe { crate::dma::Transfer::new_read(rx_dma, request, T::dr(), readings, Default::default()) }; - Self::start(); + T::start(); // Wait for conversion sequence to finish. transfer.await; // Ensure conversions are finished. - Self::stop(); + T::stop(); } #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] @@ -244,7 +277,7 @@ impl<'d, T: Instance> Adc<'d, T> { self, dma: embassy_hal_internal::Peri<'a, impl RxDma>, dma_buf: &'a mut [u16], - sequence: impl ExactSizeIterator, SampleTime)>, + sequence: impl ExactSizeIterator, T::SampleTime)>, mode: RegularConversionMode, ) -> RingBufferedAdc<'a, T> { assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); @@ -254,15 +287,15 @@ impl<'d, T: Instance> Adc<'d, T> { "Asynchronous read sequence cannot be more than 16 in length" ); // reset conversions and enable the adc - Self::stop(); - Self::enable(); + T::stop(); + T::enable(); //adc side setup - Self::configure_sequence( + T::configure_sequence( sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), ); - Self::configure_dma(ConversionMode::Repeated(mode)); + T::configure_dma(ConversionMode::Repeated(mode)); core::mem::forget(self); diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs index 62ea0d3a2..a56f8ca0b 100644 --- a/embassy-stm32/src/adc/ringbuffered.rs +++ b/embassy-stm32/src/adc/ringbuffered.rs @@ -4,7 +4,7 @@ use core::sync::atomic::{Ordering, compiler_fence}; #[allow(unused_imports)] use embassy_hal_internal::Peri; -use crate::adc::Adc; +use crate::adc::AnyInstance; #[allow(unused_imports)] use crate::adc::{Instance, RxDma}; #[allow(unused_imports)] @@ -19,7 +19,7 @@ pub struct RingBufferedAdc<'d, T: Instance> { ring_buf: ReadableRingBuffer<'d, u16>, } -impl<'d, T: Instance> RingBufferedAdc<'d, T> { +impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { pub(crate) fn new(dma: Peri<'d, impl RxDma>, dma_buf: &'d mut [u16]) -> Self { //dma side setup let opts = TransferOptions { @@ -45,11 +45,11 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { compiler_fence(Ordering::SeqCst); self.ring_buf.start(); - Adc::::start(); + T::start(); } pub fn stop(&mut self) { - Adc::::stop(); + T::stop(); self.ring_buf.request_pause(); @@ -170,9 +170,9 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { } } -impl Drop for RingBufferedAdc<'_, T> { +impl Drop for RingBufferedAdc<'_, T> { fn drop(&mut self) { - Adc::::stop(); + T::stop(); compiler_fence(Ordering::SeqCst); diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 2f9fabafb..4065f89a7 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -91,35 +91,14 @@ pub struct AdcConfig { resolution: Option, } -impl<'d, T> Adc<'d, T> -where - T: Instance, -{ - pub fn new(adc: Peri<'d, T>) -> Self { - Self::new_with_config(adc, Default::default()) - } - - pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { - rcc::enable_and_reset::(); - - let presc = Prescaler::from_pclk2(T::frequency()); - T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); - T::regs().cr2().modify(|reg| { - reg.set_adon(true); - }); - - blocking_delay_us(3); - - if let Some(resolution) = config.resolution { - T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); - } - - Self { adc } +impl super::SealedAnyInstance for T { + fn dr() -> *mut u16 { + T::regs().dr().as_ptr() as *mut u16 } - pub(super) fn enable() {} + fn enable() {} - pub(super) fn start() { + fn start() { // Begin ADC conversions T::regs().cr2().modify(|reg| { reg.set_adon(true); @@ -127,7 +106,7 @@ where }); } - pub(super) fn stop() { + fn stop() { let r = T::regs(); // Stop ADC @@ -152,7 +131,7 @@ where compiler_fence(Ordering::SeqCst); } - pub(super) fn convert() -> u16 { + fn convert() -> u16 { // clear end of conversion flag T::regs().sr().modify(|reg| { reg.set_eoc(false); @@ -173,7 +152,7 @@ where T::regs().dr().read().0 as u16 } - pub(super) fn configure_dma(conversion_mode: ConversionMode) { + fn configure_dma(conversion_mode: ConversionMode) { match conversion_mode { ConversionMode::Repeated(_) => { let r = T::regs(); @@ -210,7 +189,7 @@ where } } - pub(super) fn configure_sequence(sequence: impl ExactSizeIterator) { + fn configure_sequence(sequence: impl ExactSizeIterator) { T::regs().cr2().modify(|reg| { reg.set_adon(true); }); @@ -232,6 +211,33 @@ where } } } +} + +impl<'d, T> Adc<'d, T> +where + T: Instance, +{ + pub fn new(adc: Peri<'d, T>) -> Self { + Self::new_with_config(adc, Default::default()) + } + + pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { + rcc::enable_and_reset::(); + + let presc = Prescaler::from_pclk2(T::frequency()); + T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); + T::regs().cr2().modify(|reg| { + reg.set_adon(true); + }); + + blocking_delay_us(3); + + if let Some(resolution) = config.resolution { + T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); + } + + Self { adc } + } /// Enables internal voltage reference and returns [VrefInt], which can be used in /// [Adc::read_internal()] to perform conversion. diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 62b5043ee..4cce1dac3 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -161,152 +161,13 @@ pub struct AdcConfig { pub averaging: Option, } -impl<'d, T: Instance> Adc<'d, T> { - /// Enable the voltage regulator - fn init_regulator() { - rcc::enable_and_reset::(); - T::regs().cr().modify(|reg| { - #[cfg(not(any(adc_g0, adc_u0)))] - reg.set_deeppwd(false); - reg.set_advregen(true); - }); - - // If this is false then each ADC_CHSELR bit enables an input channel. - // This is the reset value, so has no effect. - #[cfg(any(adc_g0, adc_u0))] - T::regs().cfgr1().modify(|reg| { - reg.set_chselrmod(false); - }); - - blocking_delay_us(20); - } - - /// Calibrate to remove conversion offset - fn init_calibrate() { - T::regs().cr().modify(|reg| { - reg.set_adcal(true); - }); - - while T::regs().cr().read().adcal() { - // spin - } - - blocking_delay_us(1); - } - - /// Initialize the ADC leaving any analog clock at reset value. - /// For G0 and WL, this is the async clock without prescaler. - pub fn new(adc: Peri<'d, T>) -> Self { - Self::init_regulator(); - Self::init_calibrate(); - Self { adc } - } - - pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { - #[cfg(not(adc_g0))] - let s = Self::new(adc); - - #[cfg(adc_g0)] - let s = match config.clock { - Some(clock) => Self::new_with_clock(adc, clock), - None => Self::new(adc), - }; - - #[cfg(any(adc_g0, adc_u0, adc_v3))] - if let Some(shift) = config.oversampling_shift { - T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); - } - - #[cfg(any(adc_g0, adc_u0, adc_v3))] - if let Some(ratio) = config.oversampling_ratio { - T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); - } - - #[cfg(any(adc_g0, adc_u0))] - if let Some(enable) = config.oversampling_enable { - T::regs().cfgr2().modify(|reg| reg.set_ovse(enable)); - } - - #[cfg(adc_v3)] - if let Some((mode, trig_mode, enable)) = config.oversampling_mode { - T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); - T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); - T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); - } - - if let Some(resolution) = config.resolution { - #[cfg(not(any(adc_g0, adc_u0)))] - T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); - #[cfg(any(adc_g0, adc_u0))] - T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); - } - - if let Some(averaging) = config.averaging { - let (enable, samples, right_shift) = match averaging { - Averaging::Disabled => (false, 0, 0), - Averaging::Samples2 => (true, 0, 1), - Averaging::Samples4 => (true, 1, 2), - Averaging::Samples8 => (true, 2, 3), - Averaging::Samples16 => (true, 3, 4), - Averaging::Samples32 => (true, 4, 5), - Averaging::Samples64 => (true, 5, 6), - Averaging::Samples128 => (true, 6, 7), - Averaging::Samples256 => (true, 7, 8), - }; - T::regs().cfgr2().modify(|reg| { - #[cfg(not(any(adc_g0, adc_u0)))] - reg.set_rovse(enable); - #[cfg(any(adc_g0, adc_u0))] - reg.set_ovse(enable); - #[cfg(any(adc_h5, adc_h7rs))] - reg.set_ovsr(samples.into()); - #[cfg(not(any(adc_h5, adc_h7rs)))] - reg.set_ovsr(samples.into()); - reg.set_ovss(right_shift.into()); - }) - } - - s - } - - #[cfg(adc_g0)] - /// Initialize ADC with explicit clock for the analog ADC - pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self { - Self::init_regulator(); - - #[cfg(any(stm32wl5x))] - { - // Reset value 0 is actually _No clock selected_ in the STM32WL5x reference manual - let async_clock_available = pac::RCC.ccipr().read().adcsel() != pac::rcc::vals::Adcsel::_RESERVED_0; - match clock { - Clock::Async { div: _ } => { - assert!(async_clock_available); - } - Clock::Sync { div: _ } => { - if async_clock_available { - warn!("Not using configured ADC clock"); - } - } - } - } - match clock { - Clock::Async { div } => T::regs().ccr().modify(|reg| reg.set_presc(div)), - Clock::Sync { div } => T::regs().cfgr2().modify(|reg| { - reg.set_ckmode(match div { - CkModePclk::DIV1 => Ckmode::PCLK, - CkModePclk::DIV2 => Ckmode::PCLK_DIV2, - CkModePclk::DIV4 => Ckmode::PCLK_DIV4, - }) - }), - } - - Self::init_calibrate(); - - Self { adc } +impl super::SealedAnyInstance for T { + fn dr() -> *mut u16 { + T::regs().dr().as_ptr() as *mut u16 } // Enable ADC only when it is not already running. - pub(super) fn enable() { + fn enable() { // Make sure bits are off while T::regs().cr().read().addis() { // spin @@ -327,7 +188,7 @@ impl<'d, T: Instance> Adc<'d, T> { } } - pub(super) fn start() { + fn start() { #[cfg(any(adc_v3, adc_g0, adc_u0))] { // Start adc conversion @@ -337,7 +198,7 @@ impl<'d, T: Instance> Adc<'d, T> { } } - pub(super) fn stop() { + fn stop() { #[cfg(any(adc_v3, adc_g0, adc_u0))] { // Ensure conversions are finished. @@ -363,7 +224,7 @@ impl<'d, T: Instance> Adc<'d, T> { } /// Perform a single conversion. - pub(super) fn convert() -> u16 { + fn convert() -> u16 { // Some models are affected by an erratum: // If we perform conversions slower than 1 kHz, the first read ADC value can be // corrupted, so we discard it and measure again. @@ -395,7 +256,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().dr().read().0 as u16 } - pub(super) fn configure_dma(conversion_mode: ConversionMode) { + fn configure_dma(conversion_mode: ConversionMode) { // Set continuous mode with oneshot dma. // Clear overrun flag before starting transfer. T::regs().isr().modify(|reg| { @@ -419,7 +280,7 @@ impl<'d, T: Instance> Adc<'d, T> { }); } - pub(super) fn configure_sequence(sequence: impl ExactSizeIterator) { + fn configure_sequence(sequence: impl ExactSizeIterator) { // Set sequence length #[cfg(not(any(adc_g0, adc_u0)))] T::regs().sqr1().modify(|w| { @@ -532,6 +393,151 @@ impl<'d, T: Instance> Adc<'d, T> { }); } } +} + +impl<'d, T: Instance> Adc<'d, T> { + /// Enable the voltage regulator + fn init_regulator() { + rcc::enable_and_reset::(); + T::regs().cr().modify(|reg| { + #[cfg(not(any(adc_g0, adc_u0)))] + reg.set_deeppwd(false); + reg.set_advregen(true); + }); + + // If this is false then each ADC_CHSELR bit enables an input channel. + // This is the reset value, so has no effect. + #[cfg(any(adc_g0, adc_u0))] + T::regs().cfgr1().modify(|reg| { + reg.set_chselrmod(false); + }); + + blocking_delay_us(20); + } + + /// Calibrate to remove conversion offset + fn init_calibrate() { + T::regs().cr().modify(|reg| { + reg.set_adcal(true); + }); + + while T::regs().cr().read().adcal() { + // spin + } + + blocking_delay_us(1); + } + + /// Initialize the ADC leaving any analog clock at reset value. + /// For G0 and WL, this is the async clock without prescaler. + pub fn new(adc: Peri<'d, T>) -> Self { + Self::init_regulator(); + Self::init_calibrate(); + Self { adc } + } + + pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { + #[cfg(not(adc_g0))] + let s = Self::new(adc); + + #[cfg(adc_g0)] + let s = match config.clock { + Some(clock) => Self::new_with_clock(adc, clock), + None => Self::new(adc), + }; + + #[cfg(any(adc_g0, adc_u0, adc_v3))] + if let Some(shift) = config.oversampling_shift { + T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); + } + + #[cfg(any(adc_g0, adc_u0, adc_v3))] + if let Some(ratio) = config.oversampling_ratio { + T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); + } + + #[cfg(any(adc_g0, adc_u0))] + if let Some(enable) = config.oversampling_enable { + T::regs().cfgr2().modify(|reg| reg.set_ovse(enable)); + } + + #[cfg(adc_v3)] + if let Some((mode, trig_mode, enable)) = config.oversampling_mode { + T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); + T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); + T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); + } + + if let Some(resolution) = config.resolution { + #[cfg(not(any(adc_g0, adc_u0)))] + T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); + #[cfg(any(adc_g0, adc_u0))] + T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); + } + + if let Some(averaging) = config.averaging { + let (enable, samples, right_shift) = match averaging { + Averaging::Disabled => (false, 0, 0), + Averaging::Samples2 => (true, 0, 1), + Averaging::Samples4 => (true, 1, 2), + Averaging::Samples8 => (true, 2, 3), + Averaging::Samples16 => (true, 3, 4), + Averaging::Samples32 => (true, 4, 5), + Averaging::Samples64 => (true, 5, 6), + Averaging::Samples128 => (true, 6, 7), + Averaging::Samples256 => (true, 7, 8), + }; + T::regs().cfgr2().modify(|reg| { + #[cfg(not(any(adc_g0, adc_u0)))] + reg.set_rovse(enable); + #[cfg(any(adc_g0, adc_u0))] + reg.set_ovse(enable); + #[cfg(any(adc_h5, adc_h7rs))] + reg.set_ovsr(samples.into()); + #[cfg(not(any(adc_h5, adc_h7rs)))] + reg.set_ovsr(samples.into()); + reg.set_ovss(right_shift.into()); + }) + } + + s + } + + #[cfg(adc_g0)] + /// Initialize ADC with explicit clock for the analog ADC + pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self { + Self::init_regulator(); + + #[cfg(any(stm32wl5x))] + { + // Reset value 0 is actually _No clock selected_ in the STM32WL5x reference manual + let async_clock_available = pac::RCC.ccipr().read().adcsel() != pac::rcc::vals::Adcsel::_RESERVED_0; + match clock { + Clock::Async { div: _ } => { + assert!(async_clock_available); + } + Clock::Sync { div: _ } => { + if async_clock_available { + warn!("Not using configured ADC clock"); + } + } + } + } + match clock { + Clock::Async { div } => T::regs().ccr().modify(|reg| reg.set_presc(div)), + Clock::Sync { div } => T::regs().cfgr2().modify(|reg| { + reg.set_ckmode(match div { + CkModePclk::DIV1 => Ckmode::PCLK, + CkModePclk::DIV2 => Ckmode::PCLK_DIV2, + CkModePclk::DIV4 => Ckmode::PCLK_DIV4, + }) + }), + } + + Self::init_calibrate(); + + Self { adc } + } pub fn enable_vrefint(&self) -> VrefInt { #[cfg(not(any(adc_g0, adc_u0)))] diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 9be6bcd0b..43eb16fd5 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -151,124 +151,26 @@ pub struct AdcConfig { pub averaging: Option, } -impl<'d, T: Instance> Adc<'d, T> { - pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { - let s = Self::new(adc); - - // Set the ADC resolution. - if let Some(resolution) = config.resolution { - T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); - } - - // Set hardware averaging. - if let Some(averaging) = config.averaging { - let (enable, samples, right_shift) = match averaging { - Averaging::Disabled => (false, 0, 0), - Averaging::Samples2 => (true, 1, 1), - Averaging::Samples4 => (true, 3, 2), - Averaging::Samples8 => (true, 7, 3), - Averaging::Samples16 => (true, 15, 4), - Averaging::Samples32 => (true, 31, 5), - Averaging::Samples64 => (true, 63, 6), - Averaging::Samples128 => (true, 127, 7), - Averaging::Samples256 => (true, 255, 8), - Averaging::Samples512 => (true, 511, 9), - Averaging::Samples1024 => (true, 1023, 10), - }; - - T::regs().cfgr2().modify(|reg| { - reg.set_rovse(enable); - reg.set_ovsr(samples); - reg.set_ovss(right_shift); - }) - } - - s +impl super::SealedAnyInstance for T { + fn dr() -> *mut u16 { + T::regs().dr().as_ptr() as *mut u16 } - /// Create a new ADC driver. - pub fn new(adc: Peri<'d, T>) -> Self { - rcc::enable_and_reset::(); - - let prescaler = Prescaler::from_ker_ck(T::frequency()); - - T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); - - let frequency = Hertz(T::frequency().0 / prescaler.divisor()); - info!("ADC frequency set to {}", frequency); - - if frequency > MAX_ADC_CLK_FREQ { - panic!( - "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", - MAX_ADC_CLK_FREQ.0 / 1_000_000 - ); - } - - #[cfg(stm32h7)] - { - let boost = if frequency < Hertz::khz(6_250) { - Boost::LT6_25 - } else if frequency < Hertz::khz(12_500) { - Boost::LT12_5 - } else if frequency < Hertz::mhz(25) { - Boost::LT25 - } else { - Boost::LT50 - }; - T::regs().cr().modify(|w| w.set_boost(boost)); - } - - T::regs().cr().modify(|reg| { - reg.set_deeppwd(false); - reg.set_advregen(true); - }); - - blocking_delay_us(10); - - T::regs().difsel().modify(|w| { - for n in 0..20 { - w.set_difsel(n, Difsel::SINGLE_ENDED); - } - }); - - T::regs().cr().modify(|w| { - #[cfg(not(adc_u5))] - w.set_adcaldif(Adcaldif::SINGLE_ENDED); - w.set_adcallin(true); - }); - - T::regs().cr().modify(|w| w.set_adcal(true)); - - while T::regs().cr().read().adcal() {} - - blocking_delay_us(1); - - Self::enable(); - - // single conversion mode, software trigger - T::regs().cfgr().modify(|w| { - w.set_cont(false); - w.set_exten(Exten::DISABLED); - }); - - Self { adc } - } - - pub(super) fn enable() { + fn enable() { T::regs().isr().write(|w| w.set_adrdy(true)); T::regs().cr().modify(|w| w.set_aden(true)); while !T::regs().isr().read().adrdy() {} T::regs().isr().write(|w| w.set_adrdy(true)); } - pub(super) fn start() { + fn start() { // Start conversion T::regs().cr().modify(|reg| { reg.set_adstart(true); }); } - pub(super) fn stop() { + fn stop() { if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { T::regs().cr().modify(|reg| { reg.set_adstp(Adstp::STOP); @@ -283,7 +185,7 @@ impl<'d, T: Instance> Adc<'d, T> { }); } - pub(super) fn convert() -> u16 { + fn convert() -> u16 { T::regs().isr().modify(|reg| { reg.set_eos(true); reg.set_eoc(true); @@ -301,7 +203,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().dr().read().0 as u16 } - pub(super) fn configure_dma(conversion_mode: ConversionMode) { + fn configure_dma(conversion_mode: ConversionMode) { match conversion_mode { ConversionMode::Singular => { T::regs().isr().modify(|reg| { @@ -316,7 +218,7 @@ impl<'d, T: Instance> Adc<'d, T> { } } - pub(super) fn configure_sequence(sequence: impl ExactSizeIterator) { + fn configure_sequence(sequence: impl ExactSizeIterator) { // Set sequence length T::regs().sqr1().modify(|w| { w.set_l(sequence.len() as u8 - 1); @@ -366,6 +268,110 @@ impl<'d, T: Instance> Adc<'d, T> { } } } +} + +impl<'d, T: Instance + super::AnyInstance> Adc<'d, T> { + pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { + let s = Self::new(adc); + + // Set the ADC resolution. + if let Some(resolution) = config.resolution { + T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); + } + + // Set hardware averaging. + if let Some(averaging) = config.averaging { + let (enable, samples, right_shift) = match averaging { + Averaging::Disabled => (false, 0, 0), + Averaging::Samples2 => (true, 1, 1), + Averaging::Samples4 => (true, 3, 2), + Averaging::Samples8 => (true, 7, 3), + Averaging::Samples16 => (true, 15, 4), + Averaging::Samples32 => (true, 31, 5), + Averaging::Samples64 => (true, 63, 6), + Averaging::Samples128 => (true, 127, 7), + Averaging::Samples256 => (true, 255, 8), + Averaging::Samples512 => (true, 511, 9), + Averaging::Samples1024 => (true, 1023, 10), + }; + + T::regs().cfgr2().modify(|reg| { + reg.set_rovse(enable); + reg.set_ovsr(samples); + reg.set_ovss(right_shift); + }) + } + + s + } + + /// Create a new ADC driver. + pub fn new(adc: Peri<'d, T>) -> Self { + rcc::enable_and_reset::(); + + let prescaler = Prescaler::from_ker_ck(T::frequency()); + + T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); + + let frequency = Hertz(T::frequency().0 / prescaler.divisor()); + info!("ADC frequency set to {}", frequency); + + if frequency > MAX_ADC_CLK_FREQ { + panic!( + "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", + MAX_ADC_CLK_FREQ.0 / 1_000_000 + ); + } + + #[cfg(stm32h7)] + { + let boost = if frequency < Hertz::khz(6_250) { + Boost::LT6_25 + } else if frequency < Hertz::khz(12_500) { + Boost::LT12_5 + } else if frequency < Hertz::mhz(25) { + Boost::LT25 + } else { + Boost::LT50 + }; + T::regs().cr().modify(|w| w.set_boost(boost)); + } + + T::regs().cr().modify(|reg| { + reg.set_deeppwd(false); + reg.set_advregen(true); + }); + + blocking_delay_us(10); + + T::regs().difsel().modify(|w| { + for n in 0..20 { + w.set_difsel(n, Difsel::SINGLE_ENDED); + } + }); + + T::regs().cr().modify(|w| { + #[cfg(not(adc_u5))] + w.set_adcaldif(Adcaldif::SINGLE_ENDED); + w.set_adcallin(true); + }); + + T::regs().cr().modify(|w| w.set_adcal(true)); + + while T::regs().cr().read().adcal() {} + + blocking_delay_us(1); + + T::enable(); + + // single conversion mode, software trigger + T::regs().cfgr().modify(|w| { + w.set_cont(false); + w.set_exten(Exten::DISABLED); + }); + + Self { adc } + } /// Enable reading the voltage reference internal channel. pub fn enable_vrefint(&self) -> VrefInt { diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs index 6b9a91d6e..ad59c0bea 100644 --- a/examples/stm32u5/src/bin/adc.rs +++ b/examples/stm32u5/src/bin/adc.rs @@ -2,7 +2,7 @@ #![no_main] use defmt::*; -use embassy_stm32::adc::{self, AdcChannel, AdcConfig, SampleTime, adc4}; +use embassy_stm32::adc::{self, Adc, AdcChannel, AdcConfig, SampleTime, adc4}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -15,7 +15,7 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut config = AdcConfig::default(); config.averaging = Some(adc::Averaging::Samples1024); config.resolution = Some(adc::Resolution::BITS14); - let mut adc1 = adc::Adc::new_with_config(p.ADC1, config); + let mut adc1 = Adc::new_with_config(p.ADC1, config); let mut adc1_pin1 = p.PA3; // A0 on nucleo u5a5 let mut adc1_pin2 = p.PA2; // A1 let max1 = adc::resolution_to_max_count(adc::Resolution::BITS14); @@ -24,17 +24,17 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut config = AdcConfig::default(); config.averaging = Some(adc::Averaging::Samples1024); config.resolution = Some(adc::Resolution::BITS14); - let mut adc2 = adc::Adc::new_with_config(p.ADC2, config); + let mut adc2 = Adc::new_with_config(p.ADC2, config); let mut adc2_pin1 = p.PC3; // A2 let mut adc2_pin2 = p.PB0; // A3 let max2 = adc::resolution_to_max_count(adc::Resolution::BITS14); // **** ADC4 init **** - let mut adc4 = adc4::Adc4::new(p.ADC4); + let mut adc4 = Adc::new_adc4(p.ADC4); let mut adc4_pin1 = p.PC1; // A4 let mut adc4_pin2 = p.PC0; // A5 - adc4.set_resolution(adc4::Resolution::BITS12); - adc4.set_averaging(adc4::Averaging::Samples256); + adc4.set_resolution_adc4(adc4::Resolution::BITS12); + adc4.set_averaging_adc4(adc4::Averaging::Samples256); let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); // **** ADC1 blocking read **** @@ -95,11 +95,14 @@ async fn main(_spawner: embassy_executor::Spawner) { // The channels must be in ascending order and can't repeat for ADC4 adc4.read( p.GPDMA1_CH1.reborrow(), - [&mut degraded42, &mut degraded41].into_iter(), + [ + (&mut degraded42, adc4::SampleTime::CYCLES1_5), + (&mut degraded41, adc4::SampleTime::CYCLES1_5), + ] + .into_iter(), &mut measurements, ) - .await - .unwrap(); + .await; let volt2: f32 = 3.3 * measurements[0] as f32 / max4 as f32; let volt1: f32 = 3.3 * measurements[1] as f32 / max4 as f32; info!("Async read 4 pin 1 {}", volt1); diff --git a/examples/stm32wba/src/bin/adc.rs b/examples/stm32wba/src/bin/adc.rs index 177aab3f3..ade3f5d6a 100644 --- a/examples/stm32wba/src/bin/adc.rs +++ b/examples/stm32wba/src/bin/adc.rs @@ -2,7 +2,7 @@ #![no_main] use defmt::*; -use embassy_stm32::adc::{AdcChannel, adc4}; +use embassy_stm32::adc::{Adc, AdcChannel, SampleTime, adc4}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,11 +12,11 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut p = embassy_stm32::init(config); // **** ADC4 init **** - let mut adc4 = adc4::Adc4::new(p.ADC4); + let mut adc4 = Adc::new_adc4(p.ADC4); let mut adc4_pin1 = p.PA0; // A4 let mut adc4_pin2 = p.PA1; // A5 - adc4.set_resolution(adc4::Resolution::BITS12); - adc4.set_averaging(adc4::Averaging::Samples256); + adc4.set_resolution_adc4(adc4::Resolution::BITS12); + adc4.set_averaging_adc4(adc4::Averaging::Samples256); let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); @@ -37,11 +37,14 @@ async fn main(_spawner: embassy_executor::Spawner) { // The channels must be in ascending order and can't repeat for ADC4 adc4.read( p.GPDMA1_CH1.reborrow(), - [&mut degraded42, &mut degraded41].into_iter(), + [ + (&mut degraded42, SampleTime::CYCLES12_5), + (&mut degraded41, SampleTime::CYCLES12_5), + ] + .into_iter(), &mut measurements, ) - .await - .unwrap(); + .await; let volt2: f32 = 3.3 * measurements[0] as f32 / max4 as f32; let volt1: f32 = 3.0 * measurements[1] as f32 / max4 as f32; info!("Async read 4 pin 1 {}", volt1); diff --git a/examples/stm32wba6/src/bin/adc.rs b/examples/stm32wba6/src/bin/adc.rs index 0887e124c..9d1f39419 100644 --- a/examples/stm32wba6/src/bin/adc.rs +++ b/examples/stm32wba6/src/bin/adc.rs @@ -2,7 +2,7 @@ #![no_main] use defmt::*; -use embassy_stm32::adc::{AdcChannel, adc4}; +use embassy_stm32::adc::{Adc, AdcChannel, SampleTime, adc4}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,11 +12,11 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut p = embassy_stm32::init(config); // **** ADC4 init **** - let mut adc4 = adc4::Adc4::new(p.ADC4); + let mut adc4 = Adc::new_adc4(p.ADC4); let mut adc4_pin1 = p.PA0; // A4 let mut adc4_pin2 = p.PA1; // A5 - adc4.set_resolution(adc4::Resolution::BITS12); - adc4.set_averaging(adc4::Averaging::Samples256); + adc4.set_resolution_adc4(adc4::Resolution::BITS12); + adc4.set_averaging_adc4(adc4::Averaging::Samples256); let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); // **** ADC4 blocking read **** @@ -36,11 +36,14 @@ async fn main(_spawner: embassy_executor::Spawner) { // The channels must be in ascending order and can't repeat for ADC4 adc4.read( p.GPDMA1_CH1.reborrow(), - [&mut degraded42, &mut degraded41].into_iter(), + [ + (&mut degraded42, SampleTime::CYCLES12_5), + (&mut degraded41, SampleTime::CYCLES12_5), + ] + .into_iter(), &mut measurements, ) - .await - .unwrap(); + .await; let volt2: f32 = 3.3 * measurements[0] as f32 / max4 as f32; let volt1: f32 = 3.0 * measurements[1] as f32 / max4 as f32; info!("Async read 4 pin 1 {}", volt1); -- cgit From 03050a369befb7aeed88079626de21b4055ebccb Mon Sep 17 00:00:00 2001 From: HybridChild Date: Thu, 13 Nov 2025 09:14:03 +0100 Subject: stm32/i2c: Add comprehensive v2 Master API tests and fix async issues --- embassy-stm32/src/i2c/v2.rs | 28 +- tests/stm32/Cargo.toml | 4 +- tests/stm32/src/bin/i2c_v2.rs | 398 ---------------------- tests/stm32/src/bin/i2c_v2_master.rs | 618 +++++++++++++++++++++++++++++++++++ 4 files changed, 627 insertions(+), 421 deletions(-) delete mode 100644 tests/stm32/src/bin/i2c_v2.rs create mode 100644 tests/stm32/src/bin/i2c_v2_master.rs diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index c9656d2c2..9771d7c98 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -1003,9 +1003,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { return Poll::Ready(Ok(())); } } else if isr.tcr() { - // poll_fn was woken without an interrupt present - return Poll::Pending; - } else { + // Transfer Complete Reload - need to set up next chunk let last_piece = remaining_len <= 255; if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, Stop::Automatic, timeout) { @@ -1017,6 +1015,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { return Poll::Ready(Ok(())); } self.info.regs.cr1().modify(|w| w.set_tcie(true)); + } else { + // poll_fn was woken without TCR interrupt + return Poll::Pending; } remaining_len = remaining_len.saturating_sub(255); @@ -1052,25 +1053,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { #[cfg(all(feature = "low-power", stm32wlex))] let _device_busy = crate::low_power::DeviceBusy::new_stop1(); - let timeout = self.timeout(); - if write.is_empty() { - return Err(Error::ZeroLengthTransfer); - } - let mut iter = write.iter(); - - let mut first = true; - let mut current = iter.next(); - while let Some(c) = current { - let next = iter.next(); - let is_last = next.is_none(); - - let fut = self.write_dma_internal(address, c, first, is_last, is_last, false, timeout); - timeout.with(fut).await?; - first = false; - current = next; - } - Ok(()) + // For now, use blocking implementation for write_vectored + // This avoids complexity of handling multiple non-contiguous buffers with DMA + self.blocking_write_vectored((address.addr() & 0xFF) as u8, write) } /// Read. diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index fa757e276..1912a772c 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -161,8 +161,8 @@ path = "src/bin/hash.rs" required-features = [ "hash",] [[bin]] -name = "i2c_v2" -path = "src/bin/i2c_v2.rs" +name = "i2c_v2_master" +path = "src/bin/i2c_v2_master.rs" required-features = [ "stm32f072rb",] [[bin]] diff --git a/tests/stm32/src/bin/i2c_v2.rs b/tests/stm32/src/bin/i2c_v2.rs deleted file mode 100644 index 087b8bbd9..000000000 --- a/tests/stm32/src/bin/i2c_v2.rs +++ /dev/null @@ -1,398 +0,0 @@ -#![no_std] -#![no_main] -// required-features: stm32f072rb -// -// Hardware Setup for NUCLEO-F072RB: -// - I2C1 pins: PB8 (SCL), PB9 (SDA) on CN5 connector -// - Connect to I2C slave device (e.g., Digilent Analog Discovery I2C slave, or EEPROM) -// - Default slave address: 0x50 -// - Pull-up resistors: 4.7kΩ on both SCL and SDA -// - CN5 Pin 10 (PB8/SCL) and CN5 Pin 9 (PB9/SDA) -// -// Analog Discovery Setup: -// - Configure as I2C Slave at address 0x50 -// - DIO 0: SCL -// - DIO 1: SDA -// - Enable pull-ups or use external 4.7kΩ pull-up resistors - -#[path = "../common.rs"] -mod common; - -use common::*; -use embassy_executor::Spawner; -use embassy_stm32::i2c::{Config, I2c, Master}; -use embassy_stm32::mode::{Async, Blocking}; -use embassy_stm32::time::Hertz; -use embassy_time::Timer; -use embedded_hal_1::i2c::Operation; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = init(); - info!("I2C v2 Transaction Test Starting..."); - - let mut i2c_peri = peri!(p, I2C); - let mut scl = peri!(p, I2C_SCL); - let mut sda = peri!(p, I2C_SDA); - - let mut config = Config::default(); - config.frequency = Hertz(100_000); - - // I2C slave address for Analog Discovery or test EEPROM - let slave_addr = 0x50u8; - - // Wait for slave device to be ready - Timer::after_millis(100).await; - - // ========== BLOCKING TESTS ========== - info!("========== BLOCKING TRANSACTION TESTS =========="); - { - let mut i2c = I2c::new_blocking( - i2c_peri.reborrow(), - scl.reborrow(), - sda.reborrow(), - config, - ); - - info!("=== Test 1: Consecutive Writes (Should Merge) ==="); - test_consecutive_writes_blocking(&mut i2c, slave_addr); - - info!("=== Test 2: Consecutive Reads (Should Merge) ==="); - test_consecutive_reads_blocking(&mut i2c, slave_addr); - - info!("=== Test 3: Write then Read (RESTART) ==="); - test_write_then_read_blocking(&mut i2c, slave_addr); - - info!("=== Test 4: Read then Write (RESTART) ==="); - test_read_then_write_blocking(&mut i2c, slave_addr); - - info!("=== Test 5: Complex Mixed Sequence ==="); - test_mixed_sequence_blocking(&mut i2c, slave_addr); - - info!("=== Test 6: Single Operations ==="); - test_single_operations_blocking(&mut i2c, slave_addr); - - info!("Blocking tests OK"); - } - - Timer::after_millis(100).await; - - // ========== ASYNC TESTS ========== - info!("========== ASYNC TRANSACTION TESTS (DMA) =========="); - { - let tx_dma = peri!(p, I2C_TX_DMA); - let rx_dma = peri!(p, I2C_RX_DMA); - let irq = irqs!(I2C); - - let mut i2c = I2c::new(i2c_peri, scl, sda, irq, tx_dma, rx_dma, config); - - info!("=== Test 1: Consecutive Writes (Should Merge) ==="); - test_consecutive_writes_async(&mut i2c, slave_addr).await; - - info!("=== Test 2: Consecutive Reads (Should Merge) ==="); - test_consecutive_reads_async(&mut i2c, slave_addr).await; - - info!("=== Test 3: Write then Read (RESTART) ==="); - test_write_then_read_async(&mut i2c, slave_addr).await; - - info!("=== Test 4: Read then Write (RESTART) ==="); - test_read_then_write_async(&mut i2c, slave_addr).await; - - info!("=== Test 5: Complex Mixed Sequence ==="); - test_mixed_sequence_async(&mut i2c, slave_addr).await; - - info!("=== Test 6: Single Operations ==="); - test_single_operations_async(&mut i2c, slave_addr).await; - - info!("Async tests OK"); - } - - info!("All tests OK"); - cortex_m::asm::bkpt(); -} - -fn test_consecutive_writes_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Expected on bus: START, ADDR+W, data1, data2, data3, STOP - // NO intermediate RESTART/STOP between writes - they should be merged - let data1 = [0x10, 0x11, 0x12]; - let data2 = [0x20, 0x21]; - let data3 = [0x30, 0x31, 0x32, 0x33]; - - let mut ops = [ - Operation::Write(&data1), - Operation::Write(&data2), - Operation::Write(&data3), - ]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"), - Err(e) => { - error!("✗ Consecutive writes failed: {:?}", e); - defmt::panic!("Test failed: consecutive writes"); - } - } -} - -fn test_consecutive_reads_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP - // NO intermediate RESTART/STOP between reads - they should be merged - let mut buf1 = [0u8; 4]; - let mut buf2 = [0u8; 3]; - let mut buf3 = [0u8; 2]; - - let mut ops = [ - Operation::Read(&mut buf1), - Operation::Read(&mut buf2), - Operation::Read(&mut buf3), - ]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Consecutive reads succeeded (merged 9 bytes)"); - info!(" buf1: {:02x}", buf1); - info!(" buf2: {:02x}", buf2); - info!(" buf3: {:02x}", buf3); - } - Err(e) => { - error!("✗ Consecutive reads failed: {:?}", e); - defmt::panic!("Test failed: consecutive reads"); - } - } -} - -fn test_write_then_read_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Expected: START, ADDR+W, data, RESTART, ADDR+R, data, NACK, STOP - let write_data = [0xAA, 0xBB]; - let mut read_buf = [0u8; 4]; - - let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Write-then-read succeeded with RESTART"); - info!(" Written: {:02x}", write_data); - info!(" Read: {:02x}", read_buf); - } - Err(e) => { - error!("✗ Write-then-read failed: {:?}", e); - defmt::panic!("Test failed: write-then-read"); - } - } -} - -fn test_read_then_write_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Expected: START, ADDR+R, data, NACK, RESTART, ADDR+W, data, STOP - let mut read_buf = [0u8; 3]; - let write_data = [0xCC, 0xDD, 0xEE]; - - let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Read-then-write succeeded with RESTART"); - info!(" Read: {:02x}", read_buf); - info!(" Written: {:02x}", write_data); - } - Err(e) => { - error!("✗ Read-then-write failed: {:?}", e); - defmt::panic!("Test failed: read-then-write"); - } - } -} - -fn test_mixed_sequence_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Complex: W, W, R, R, W, R - // Groups: [W,W] RESTART [R,R] RESTART [W] RESTART [R] - let w1 = [0x01, 0x02]; - let w2 = [0x03, 0x04]; - let mut r1 = [0u8; 2]; - let mut r2 = [0u8; 2]; - let w3 = [0x05]; - let mut r3 = [0u8; 1]; - - let mut ops = [ - Operation::Write(&w1), - Operation::Write(&w2), - Operation::Read(&mut r1), - Operation::Read(&mut r2), - Operation::Write(&w3), - Operation::Read(&mut r3), - ]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Mixed sequence succeeded"); - info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]"); - } - Err(e) => { - error!("✗ Mixed sequence failed: {:?}", e); - defmt::panic!("Test failed: mixed sequence"); - } - } -} - -fn test_single_operations_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Test single write - let write_data = [0xFF]; - let mut ops = [Operation::Write(&write_data)]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => info!("✓ Single write succeeded"), - Err(e) => { - error!("✗ Single write failed: {:?}", e); - defmt::panic!("Test failed: single write"); - } - } - - // Test single read - let mut read_buf = [0u8; 1]; - let mut ops = [Operation::Read(&mut read_buf)]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), - Err(e) => { - error!("✗ Single read failed: {:?}", e); - defmt::panic!("Test failed: single read"); - } - } -} - -// ==================== ASYNC TEST FUNCTIONS ==================== - -async fn test_consecutive_writes_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let data1 = [0x10, 0x11, 0x12]; - let data2 = [0x20, 0x21]; - let data3 = [0x30, 0x31, 0x32, 0x33]; - - let mut ops = [ - Operation::Write(&data1), - Operation::Write(&data2), - Operation::Write(&data3), - ]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"), - Err(e) => { - error!("✗ Consecutive writes failed: {:?}", e); - defmt::panic!("Test failed: consecutive writes"); - } - } -} - -async fn test_consecutive_reads_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let mut buf1 = [0u8; 4]; - let mut buf2 = [0u8; 3]; - let mut buf3 = [0u8; 2]; - - let mut ops = [ - Operation::Read(&mut buf1), - Operation::Read(&mut buf2), - Operation::Read(&mut buf3), - ]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => { - info!("✓ Consecutive reads succeeded (merged 9 bytes)"); - info!(" buf1: {:02x}", buf1); - info!(" buf2: {:02x}", buf2); - info!(" buf3: {:02x}", buf3); - } - Err(e) => { - error!("✗ Consecutive reads failed: {:?}", e); - defmt::panic!("Test failed: consecutive reads"); - } - } -} - -async fn test_write_then_read_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let write_data = [0xAA, 0xBB]; - let mut read_buf = [0u8; 4]; - - let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => { - info!("✓ Write-then-read succeeded with RESTART"); - info!(" Written: {:02x}", write_data); - info!(" Read: {:02x}", read_buf); - } - Err(e) => { - error!("✗ Write-then-read failed: {:?}", e); - defmt::panic!("Test failed: write-then-read"); - } - } -} - -async fn test_read_then_write_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let mut read_buf = [0u8; 3]; - let write_data = [0xCC, 0xDD, 0xEE]; - - let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => { - info!("✓ Read-then-write succeeded with RESTART"); - info!(" Read: {:02x}", read_buf); - info!(" Written: {:02x}", write_data); - } - Err(e) => { - error!("✗ Read-then-write failed: {:?}", e); - defmt::panic!("Test failed: read-then-write"); - } - } -} - -async fn test_mixed_sequence_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let w1 = [0x01, 0x02]; - let w2 = [0x03, 0x04]; - let mut r1 = [0u8; 2]; - let mut r2 = [0u8; 2]; - let w3 = [0x05]; - let mut r3 = [0u8; 1]; - - let mut ops = [ - Operation::Write(&w1), - Operation::Write(&w2), - Operation::Read(&mut r1), - Operation::Read(&mut r2), - Operation::Write(&w3), - Operation::Read(&mut r3), - ]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => { - info!("✓ Mixed sequence succeeded"); - info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]"); - } - Err(e) => { - error!("✗ Mixed sequence failed: {:?}", e); - defmt::panic!("Test failed: mixed sequence"); - } - } -} - -async fn test_single_operations_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - // Test single write - let write_data = [0xFF]; - let mut ops = [Operation::Write(&write_data)]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => info!("✓ Single write succeeded"), - Err(e) => { - error!("✗ Single write failed: {:?}", e); - defmt::panic!("Test failed: single write"); - } - } - - // Test single read - let mut read_buf = [0u8; 1]; - let mut ops = [Operation::Read(&mut read_buf)]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), - Err(e) => { - error!("✗ Single read failed: {:?}", e); - defmt::panic!("Test failed: single read"); - } - } -} diff --git a/tests/stm32/src/bin/i2c_v2_master.rs b/tests/stm32/src/bin/i2c_v2_master.rs new file mode 100644 index 000000000..b841d556a --- /dev/null +++ b/tests/stm32/src/bin/i2c_v2_master.rs @@ -0,0 +1,618 @@ +#![no_std] +#![no_main] +// required-features: stm32f072rb +// +// Hardware Setup for NUCLEO-F072RB: +// - I2C1 pins: PB8 (SCL), PB9 (SDA) on CN5 connector +// - Connect to I2C slave device (e.g., Digilent Analog Discovery I2C slave, or EEPROM) +// - Default slave address: 0x50 +// - Pull-up resistors: 4.7kΩ on both SCL and SDA +// - CN5 Pin 10 (PB8/SCL) and CN5 Pin 9 (PB9/SDA) +// +// Analog Discovery - Waveforms Setup: +// - Increase buffer size: Settings -> Device Manager -> Option 4 +// - Run Protocol Analyzer +// - Configure as I2C Slave at address 0x50 +// - Connect and configure DIO pins for SCL and SDA +// - Frequency: 100kHz - [✓] Clock Stretching + +#[path = "../common.rs"] +mod common; + +use common::*; +use embassy_executor::Spawner; +use embassy_stm32::i2c::{Config, I2c, Master}; +use embassy_stm32::mode::{Async, Blocking}; +use embassy_stm32::time::Hertz; +use embassy_time::Timer; +use embedded_hal_1::i2c::Operation; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = init(); + info!("Run stm32 I2C v2 Master Tests..."); + + let mut i2c_peri = peri!(p, I2C); + let mut scl = peri!(p, I2C_SCL); + let mut sda = peri!(p, I2C_SDA); + + let mut config = Config::default(); + config.frequency = Hertz(100_000); + + // I2C slave address for Analog Discovery or test EEPROM + let slave_addr = 0x50u8; + + // Wait for slave device to be ready + Timer::after_millis(100).await; + + // ========== BLOCKING DIRECT API TESTS ========== + info!("========== BLOCKING DIRECT API TESTS =========="); + { + let mut i2c = I2c::new_blocking( + i2c_peri.reborrow(), + scl.reborrow(), + sda.reborrow(), + config, + ); + + info!("=== Test 1: Direct blocking_write ==="); + test_blocking_write(&mut i2c, slave_addr); + + info!("=== Test 2: Direct blocking_read ==="); + test_blocking_read(&mut i2c, slave_addr); + + info!("=== Test 3: Direct blocking_write_read ==="); + test_blocking_write_read(&mut i2c, slave_addr); + + info!("=== Test 4: Direct blocking_write_vectored ==="); + test_blocking_write_vectored(&mut i2c, slave_addr); + + info!("=== Test 5: Large buffer (>255 bytes) ==="); + test_blocking_large_buffer(&mut i2c, slave_addr); + + info!("Blocking direct API tests OK"); + } + + Timer::after_millis(100).await; + + // ========== BLOCKING TRANSACTION TESTS ========== + info!("========== BLOCKING TRANSACTION TESTS =========="); + { + let mut i2c = I2c::new_blocking( + i2c_peri.reborrow(), + scl.reborrow(), + sda.reborrow(), + config, + ); + + info!("=== Test 6: Consecutive Writes (Should Merge) ==="); + test_consecutive_writes_blocking(&mut i2c, slave_addr); + + info!("=== Test 7: Consecutive Reads (Should Merge) ==="); + test_consecutive_reads_blocking(&mut i2c, slave_addr); + + info!("=== Test 8: Write then Read (RESTART) ==="); + test_write_then_read_blocking(&mut i2c, slave_addr); + + info!("=== Test 9: Read then Write (RESTART) ==="); + test_read_then_write_blocking(&mut i2c, slave_addr); + + info!("=== Test 10: Complex Mixed Sequence ==="); + test_mixed_sequence_blocking(&mut i2c, slave_addr); + + info!("=== Test 11: Single Operations ==="); + test_single_operations_blocking(&mut i2c, slave_addr); + + info!("Blocking transaction tests OK"); + } + + Timer::after_millis(100).await; + + // ========== ASYNC TESTS (DMA) ========== + info!("========== ASYNC TESTS (DMA) =========="); + { + let tx_dma = peri!(p, I2C_TX_DMA); + let rx_dma = peri!(p, I2C_RX_DMA); + let irq = irqs!(I2C); + + let mut i2c = I2c::new(i2c_peri, scl, sda, irq, tx_dma, rx_dma, config); + + // Direct API tests (reusing same I2C instance) + info!("=== Direct API Test 1: write() ==="); + test_async_write(&mut i2c, slave_addr).await; + + info!("=== Direct API Test 2: read() ==="); + test_async_read(&mut i2c, slave_addr).await; + + info!("=== Direct API Test 3: write_read() ==="); + test_async_write_read(&mut i2c, slave_addr).await; + + info!("=== Direct API Test 4: write_vectored() ==="); + test_async_write_vectored(&mut i2c, slave_addr).await; + + info!("=== Direct API Test 5: Large buffer (>255 bytes) ==="); + test_async_large_buffer(&mut i2c, slave_addr).await; + + info!("Async Direct API tests OK"); + + // Transaction tests + info!("=== Transaction Test 6: Consecutive Writes (Should Merge) ==="); + test_consecutive_writes_async(&mut i2c, slave_addr).await; + + info!("=== Transaction Test 7: Consecutive Reads (Should Merge) ==="); + test_consecutive_reads_async(&mut i2c, slave_addr).await; + + info!("=== Transaction Test 8: Write then Read (RESTART) ==="); + test_write_then_read_async(&mut i2c, slave_addr).await; + + info!("=== Transaction Test 9: Read then Write (RESTART) ==="); + test_read_then_write_async(&mut i2c, slave_addr).await; + + info!("=== Transaction Test 10: Complex Mixed Sequence ==="); + test_mixed_sequence_async(&mut i2c, slave_addr).await; + + info!("=== Transaction Test 11: Single Operations ==="); + test_single_operations_async(&mut i2c, slave_addr).await; + + info!("Async transaction tests OK"); + } + + info!("All tests OK"); + cortex_m::asm::bkpt(); +} + +// ==================== BLOCKING DIRECT API TEST FUNCTIONS ==================== + +fn test_blocking_write(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + let write_data = [0x42, 0x43, 0x44, 0x45]; + + match i2c.blocking_write(addr, &write_data) { + Ok(_) => info!("✓ blocking_write succeeded: {:02x}", write_data), + Err(e) => { + error!("✗ blocking_write failed: {:?}", e); + defmt::panic!("Test failed: blocking_write"); + } + } +} + +fn test_blocking_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + let mut read_buf = [0u8; 8]; + + match i2c.blocking_read(addr, &mut read_buf) { + Ok(_) => info!("✓ blocking_read succeeded: {:02x}", read_buf), + Err(e) => { + error!("✗ blocking_read failed: {:?}", e); + defmt::panic!("Test failed: blocking_read"); + } + } +} + +fn test_blocking_write_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + let write_data = [0x50, 0x51]; + let mut read_buf = [0u8; 6]; + + match i2c.blocking_write_read(addr, &write_data, &mut read_buf) { + Ok(_) => { + info!("✓ blocking_write_read succeeded"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => { + error!("✗ blocking_write_read failed: {:?}", e); + defmt::panic!("Test failed: blocking_write_read"); + } + } +} + +fn test_blocking_write_vectored(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + let buf1 = [0x60, 0x61, 0x62]; + let buf2 = [0x70, 0x71]; + let buf3 = [0x80, 0x81, 0x82, 0x83]; + let bufs = [&buf1[..], &buf2[..], &buf3[..]]; + + match i2c.blocking_write_vectored(addr, &bufs) { + Ok(_) => info!("✓ blocking_write_vectored succeeded (9 bytes total)"), + Err(e) => { + error!("✗ blocking_write_vectored failed: {:?}", e); + defmt::panic!("Test failed: blocking_write_vectored"); + } + } +} + +fn test_blocking_large_buffer(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Test with 300 bytes to verify RELOAD mechanism works (needs chunking at 255 bytes) + let mut write_buf = [0u8; 300]; + for (i, byte) in write_buf.iter_mut().enumerate() { + *byte = (i & 0xFF) as u8; + } + + match i2c.blocking_write(addr, &write_buf) { + Ok(_) => info!("✓ Large buffer write succeeded (300 bytes, tests RELOAD)"), + Err(e) => { + error!("✗ Large buffer write failed: {:?}", e); + defmt::panic!("Test failed: large buffer write"); + } + } + + // Test large read + let mut read_buf = [0u8; 300]; + match i2c.blocking_read(addr, &mut read_buf) { + Ok(_) => info!("✓ Large buffer read succeeded (300 bytes, tests RELOAD)"), + Err(e) => { + error!("✗ Large buffer read failed: {:?}", e); + defmt::panic!("Test failed: large buffer read"); + } + } +} + +// ==================== BLOCKING TRANSACTION TEST FUNCTIONS ==================== + +fn test_consecutive_writes_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected on bus: START, ADDR+W, data1, data2, data3, STOP + // NO intermediate RESTART/STOP between writes - they should be merged + let data1 = [0x10, 0x11, 0x12]; + let data2 = [0x20, 0x21]; + let data3 = [0x30, 0x31, 0x32, 0x33]; + + let mut ops = [ + Operation::Write(&data1), + Operation::Write(&data2), + Operation::Write(&data3), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"), + Err(e) => { + error!("✗ Consecutive writes failed: {:?}", e); + defmt::panic!("Test failed: consecutive writes"); + } + } +} + +fn test_consecutive_reads_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP + // NO intermediate RESTART/STOP between reads - they should be merged + let mut buf1 = [0u8; 4]; + let mut buf2 = [0u8; 3]; + let mut buf3 = [0u8; 2]; + + let mut ops = [ + Operation::Read(&mut buf1), + Operation::Read(&mut buf2), + Operation::Read(&mut buf3), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Consecutive reads succeeded (merged 9 bytes)"); + info!(" buf1: {:02x}", buf1); + info!(" buf2: {:02x}", buf2); + info!(" buf3: {:02x}", buf3); + } + Err(e) => { + error!("✗ Consecutive reads failed: {:?}", e); + defmt::panic!("Test failed: consecutive reads"); + } + } +} + +fn test_write_then_read_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected: START, ADDR+W, data, RESTART, ADDR+R, data, NACK, STOP + let write_data = [0xAA, 0xBB]; + let mut read_buf = [0u8; 4]; + + let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Write-then-read succeeded with RESTART"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => { + error!("✗ Write-then-read failed: {:?}", e); + defmt::panic!("Test failed: write-then-read"); + } + } +} + +fn test_read_then_write_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected: START, ADDR+R, data, NACK, RESTART, ADDR+W, data, STOP + let mut read_buf = [0u8; 3]; + let write_data = [0xCC, 0xDD, 0xEE]; + + let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Read-then-write succeeded with RESTART"); + info!(" Read: {:02x}", read_buf); + info!(" Written: {:02x}", write_data); + } + Err(e) => { + error!("✗ Read-then-write failed: {:?}", e); + defmt::panic!("Test failed: read-then-write"); + } + } +} + +fn test_mixed_sequence_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Complex: W, W, R, R, W, R + // Groups: [W,W] RESTART [R,R] RESTART [W] RESTART [R] + let w1 = [0x01, 0x02]; + let w2 = [0x03, 0x04]; + let mut r1 = [0u8; 2]; + let mut r2 = [0u8; 2]; + let w3 = [0x05]; + let mut r3 = [0u8; 1]; + + let mut ops = [ + Operation::Write(&w1), + Operation::Write(&w2), + Operation::Read(&mut r1), + Operation::Read(&mut r2), + Operation::Write(&w3), + Operation::Read(&mut r3), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Mixed sequence succeeded"); + info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]"); + } + Err(e) => { + error!("✗ Mixed sequence failed: {:?}", e); + defmt::panic!("Test failed: mixed sequence"); + } + } +} + +fn test_single_operations_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Test single write + let write_data = [0xFF]; + let mut ops = [Operation::Write(&write_data)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => info!("✓ Single write succeeded"), + Err(e) => { + error!("✗ Single write failed: {:?}", e); + defmt::panic!("Test failed: single write"); + } + } + + // Test single read + let mut read_buf = [0u8; 1]; + let mut ops = [Operation::Read(&mut read_buf)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), + Err(e) => { + error!("✗ Single read failed: {:?}", e); + defmt::panic!("Test failed: single read"); + } + } +} + +// ==================== ASYNC DIRECT API TEST FUNCTIONS ==================== + +async fn test_async_write(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let write_data = [0x42, 0x43, 0x44, 0x45]; + + match i2c.write(addr, &write_data).await { + Ok(_) => info!("✓ async write succeeded: {:02x}", write_data), + Err(e) => { + error!("✗ async write failed: {:?}", e); + defmt::panic!("Test failed: async write"); + } + } +} + +async fn test_async_read(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let mut read_buf = [0u8; 8]; + + match i2c.read(addr, &mut read_buf).await { + Ok(_) => info!("✓ async read succeeded: {:02x}", read_buf), + Err(e) => { + error!("✗ async read failed: {:?}", e); + defmt::panic!("Test failed: async read"); + } + } +} + +async fn test_async_write_read(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let write_data = [0x50, 0x51]; + let mut read_buf = [0u8; 6]; + + match i2c.write_read(addr, &write_data, &mut read_buf).await { + Ok(_) => { + info!("✓ async write_read succeeded"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => { + error!("✗ async write_read failed: {:?}", e); + defmt::panic!("Test failed: async write_read"); + } + } +} + +async fn test_async_write_vectored(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let buf1 = [0x60, 0x61, 0x62]; + let buf2 = [0x70, 0x71]; + let buf3 = [0x80, 0x81, 0x82, 0x83]; + let bufs = [&buf1[..], &buf2[..], &buf3[..]]; + + match i2c.write_vectored(addr.into(), &bufs).await { + Ok(_) => info!("✓ async write_vectored succeeded (9 bytes total)"), + Err(e) => { + error!("✗ async write_vectored failed: {:?}", e); + defmt::panic!("Test failed: async write_vectored"); + } + } +} + +async fn test_async_large_buffer(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + // Test with 300 bytes to verify RELOAD mechanism works with DMA (needs chunking at 255 bytes) + let mut write_buf = [0u8; 300]; + for (i, byte) in write_buf.iter_mut().enumerate() { + *byte = (i & 0xFF) as u8; + } + + match i2c.write(addr, &write_buf).await { + Ok(_) => info!("✓ Large buffer async write succeeded (300 bytes, tests RELOAD with DMA)"), + Err(e) => { + error!("✗ Large buffer async write failed: {:?}", e); + defmt::panic!("Test failed: large buffer async write"); + } + } + + // Test large read + let mut read_buf = [0u8; 300]; + match i2c.read(addr, &mut read_buf).await { + Ok(_) => info!("✓ Large buffer async read succeeded (300 bytes, tests RELOAD with DMA)"), + Err(e) => { + error!("✗ Large buffer async read failed: {:?}", e); + defmt::panic!("Test failed: large buffer async read"); + } + } +} + +// ==================== ASYNC TRANSACTION TEST FUNCTIONS ==================== + +async fn test_consecutive_writes_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let data1 = [0x10, 0x11, 0x12]; + let data2 = [0x20, 0x21]; + let data3 = [0x30, 0x31, 0x32, 0x33]; + + let mut ops = [ + Operation::Write(&data1), + Operation::Write(&data2), + Operation::Write(&data3), + ]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"), + Err(e) => { + error!("✗ Consecutive writes failed: {:?}", e); + defmt::panic!("Test failed: consecutive writes"); + } + } +} + +async fn test_consecutive_reads_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let mut buf1 = [0u8; 4]; + let mut buf2 = [0u8; 3]; + let mut buf3 = [0u8; 2]; + + let mut ops = [ + Operation::Read(&mut buf1), + Operation::Read(&mut buf2), + Operation::Read(&mut buf3), + ]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Consecutive reads succeeded (merged 9 bytes)"); + info!(" buf1: {:02x}", buf1); + info!(" buf2: {:02x}", buf2); + info!(" buf3: {:02x}", buf3); + } + Err(e) => { + error!("✗ Consecutive reads failed: {:?}", e); + defmt::panic!("Test failed: consecutive reads"); + } + } +} + +async fn test_write_then_read_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let write_data = [0xAA, 0xBB]; + let mut read_buf = [0u8; 4]; + + let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Write-then-read succeeded with RESTART"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => { + error!("✗ Write-then-read failed: {:?}", e); + defmt::panic!("Test failed: write-then-read"); + } + } +} + +async fn test_read_then_write_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let mut read_buf = [0u8; 3]; + let write_data = [0xCC, 0xDD, 0xEE]; + + let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Read-then-write succeeded with RESTART"); + info!(" Read: {:02x}", read_buf); + info!(" Written: {:02x}", write_data); + } + Err(e) => { + error!("✗ Read-then-write failed: {:?}", e); + defmt::panic!("Test failed: read-then-write"); + } + } +} + +async fn test_mixed_sequence_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let w1 = [0x01, 0x02]; + let w2 = [0x03, 0x04]; + let mut r1 = [0u8; 2]; + let mut r2 = [0u8; 2]; + let w3 = [0x05]; + let mut r3 = [0u8; 1]; + + let mut ops = [ + Operation::Write(&w1), + Operation::Write(&w2), + Operation::Read(&mut r1), + Operation::Read(&mut r2), + Operation::Write(&w3), + Operation::Read(&mut r3), + ]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Mixed sequence succeeded"); + info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]"); + } + Err(e) => { + error!("✗ Mixed sequence failed: {:?}", e); + defmt::panic!("Test failed: mixed sequence"); + } + } +} + +async fn test_single_operations_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + // Test single write + let write_data = [0xFF]; + let mut ops = [Operation::Write(&write_data)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => info!("✓ Single write succeeded"), + Err(e) => { + error!("✗ Single write failed: {:?}", e); + defmt::panic!("Test failed: single write"); + } + } + + // Test single read + let mut read_buf = [0u8; 1]; + let mut ops = [Operation::Read(&mut read_buf)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), + Err(e) => { + error!("✗ Single read failed: {:?}", e); + defmt::panic!("Test failed: single read"); + } + } +} -- cgit From dbd4c384f94044505917295145c25777768a3081 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Thu, 13 Nov 2025 10:50:48 +0100 Subject: stm32/i2c: Run cargo fmt --- embassy-stm32/src/i2c/v2.rs | 91 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 22 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 9771d7c98..7bcfa00b0 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -222,7 +222,13 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { Ok(()) } - fn reload(info: &'static Info, length: usize, will_reload: bool, stop: Stop, timeout: Timeout) -> Result<(), Error> { + fn reload( + info: &'static Info, + length: usize, + will_reload: bool, + stop: Stop, + timeout: Timeout, + ) -> Result<(), Error> { assert!(length < 256 && length > 0); // Wait for either TCR (Transfer Complete Reload) or TC (Transfer Complete) @@ -417,7 +423,13 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { for (number, chunk) in read.chunks_mut(255).enumerate() { if number != 0 { - Self::reload(self.info, chunk.len(), number != last_chunk_idx, Stop::Automatic, timeout)?; + Self::reload( + self.info, + chunk.len(), + number != last_chunk_idx, + Stop::Automatic, + timeout, + )?; } for byte in chunk { @@ -466,7 +478,13 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { for (number, chunk) in write.chunks(255).enumerate() { if number != 0 { - Self::reload(self.info, chunk.len(), number != last_chunk_idx, Stop::Software, timeout)?; + Self::reload( + self.info, + chunk.len(), + number != last_chunk_idx, + Stop::Software, + timeout, + )?; } for byte in chunk { @@ -606,7 +624,15 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { if first_chunk { // First chunk: initiate transfer // If not first group, use RESTART instead of START - Self::master_write(self.info, address, chunk_len, Stop::Software, will_reload, !is_first_group, timeout)?; + Self::master_write( + self.info, + address, + chunk_len, + Stop::Software, + will_reload, + !is_first_group, + timeout, + )?; first_chunk = false; } else { // Subsequent chunks: use reload @@ -906,7 +932,13 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { } else if remaining_len == 0 { return Poll::Ready(Ok(())); } else { - if let Err(e) = Self::reload(self.info, remaining_len.min(255), remaining_len > 255, Stop::Software, timeout) { + if let Err(e) = Self::reload( + self.info, + remaining_len.min(255), + remaining_len > 255, + Stop::Software, + timeout, + ) { return Poll::Ready(Err(e)); } self.info.regs.cr1().modify(|w| w.set_tcie(true)); @@ -1225,14 +1257,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { }; // We need a custom DMA read that respects our stop mode - self.read_dma_group_internal( - address, - buffer, - restart, - stop_mode, - timeout, - ) - .await?; + self.read_dma_group_internal(address, buffer, restart, stop_mode, timeout) + .await?; is_first_in_group = false; } else { // Subsequent buffers: need to reload and continue @@ -1243,11 +1269,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { }; self.read_dma_group_internal( - address, - buffer, - false, // no restart for subsequent buffers in same group - stop_mode, - timeout, + address, buffer, false, // no restart for subsequent buffers in same group + stop_mode, timeout, ) .await?; } @@ -1499,7 +1522,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { if number == 0 { Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); } else { - Self::reload(self.info, chunk.len(), number != last_chunk_idx, Stop::Software, timeout)?; + Self::reload( + self.info, + chunk.len(), + number != last_chunk_idx, + Stop::Software, + timeout, + )?; } let mut index = 0; @@ -1548,7 +1577,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { if number == 0 { Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); } else { - Self::reload(self.info, chunk.len(), number != last_chunk_idx, Stop::Software, timeout)?; + Self::reload( + self.info, + chunk.len(), + number != last_chunk_idx, + Stop::Software, + timeout, + )?; } let mut index = 0; @@ -1684,7 +1719,13 @@ impl<'d> I2c<'d, Async, MultiMaster> { Poll::Pending } else if isr.tcr() { let is_last_slice = remaining_len <= 255; - if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, Stop::Software, timeout) { + if let Err(e) = Self::reload( + self.info, + remaining_len.min(255), + !is_last_slice, + Stop::Software, + timeout, + ) { return Poll::Ready(Err(e)); } remaining_len = remaining_len.saturating_sub(255); @@ -1748,7 +1789,13 @@ impl<'d> I2c<'d, Async, MultiMaster> { Poll::Pending } else if isr.tcr() { let is_last_slice = remaining_len <= 255; - if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, Stop::Software, timeout) { + if let Err(e) = Self::reload( + self.info, + remaining_len.min(255), + !is_last_slice, + Stop::Software, + timeout, + ) { return Poll::Ready(Err(e)); } remaining_len = remaining_len.saturating_sub(255); -- cgit From 260a3fdc530ef430956ed313811efea94e1dff5c Mon Sep 17 00:00:00 2001 From: HybridChild Date: Thu, 13 Nov 2025 10:57:41 +0100 Subject: stm32: Run cargo fmt for tests/ --- tests/stm32/src/bin/i2c_v2_master.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/tests/stm32/src/bin/i2c_v2_master.rs b/tests/stm32/src/bin/i2c_v2_master.rs index b841d556a..34f9b48d3 100644 --- a/tests/stm32/src/bin/i2c_v2_master.rs +++ b/tests/stm32/src/bin/i2c_v2_master.rs @@ -48,12 +48,7 @@ async fn main(_spawner: Spawner) { // ========== BLOCKING DIRECT API TESTS ========== info!("========== BLOCKING DIRECT API TESTS =========="); { - let mut i2c = I2c::new_blocking( - i2c_peri.reborrow(), - scl.reborrow(), - sda.reborrow(), - config, - ); + let mut i2c = I2c::new_blocking(i2c_peri.reborrow(), scl.reborrow(), sda.reborrow(), config); info!("=== Test 1: Direct blocking_write ==="); test_blocking_write(&mut i2c, slave_addr); @@ -78,12 +73,7 @@ async fn main(_spawner: Spawner) { // ========== BLOCKING TRANSACTION TESTS ========== info!("========== BLOCKING TRANSACTION TESTS =========="); { - let mut i2c = I2c::new_blocking( - i2c_peri.reborrow(), - scl.reborrow(), - sda.reborrow(), - config, - ); + let mut i2c = I2c::new_blocking(i2c_peri.reborrow(), scl.reborrow(), sda.reborrow(), config); info!("=== Test 6: Consecutive Writes (Should Merge) ==="); test_consecutive_writes_blocking(&mut i2c, slave_addr); -- cgit From dccf185e1489c0055fcacdea59ce7837cc4d076d Mon Sep 17 00:00:00 2001 From: "Andreas Lindahl Flåten (ALF)" Date: Wed, 5 Nov 2025 16:47:09 +0100 Subject: Add c.rs flash for the stm32c0 family This is basically a copy of the `g.rs` file, with multi bank support removed (c0 is single bank only). --- embassy-stm32/src/flash/c.rs | 122 ++++++++++++++++++++++++++++++++++++++ embassy-stm32/src/flash/common.rs | 2 +- embassy-stm32/src/flash/mod.rs | 3 +- 3 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 embassy-stm32/src/flash/c.rs diff --git a/embassy-stm32/src/flash/c.rs b/embassy-stm32/src/flash/c.rs new file mode 100644 index 000000000..af3d07ac6 --- /dev/null +++ b/embassy-stm32/src/flash/c.rs @@ -0,0 +1,122 @@ +use core::ptr::write_volatile; +use core::sync::atomic::{Ordering, fence}; + +use cortex_m::interrupt; + +use super::{FlashSector, WRITE_SIZE}; +use crate::flash::Error; +use crate::pac; + +pub(crate) unsafe fn lock() { + pac::FLASH.cr().modify(|w| w.set_lock(true)); +} +pub(crate) unsafe fn unlock() { + // Wait, while the memory interface is busy. + wait_busy(); + + // Unlock flash + if pac::FLASH.cr().read().lock() { + pac::FLASH.keyr().write_value(0x4567_0123); + pac::FLASH.keyr().write_value(0xCDEF_89AB); + } +} + +pub(crate) unsafe fn enable_blocking_write() { + assert_eq!(0, WRITE_SIZE % 4); + pac::FLASH.cr().write(|w| w.set_pg(true)); +} + +pub(crate) unsafe fn disable_blocking_write() { + pac::FLASH.cr().write(|w| w.set_pg(false)); +} + +pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + let mut address = start_address; + for val in buf.chunks(4) { + write_volatile(address as *mut u32, u32::from_le_bytes(unwrap!(val.try_into()))); + address += val.len() as u32; + + // prevents parallelism errors + fence(Ordering::SeqCst); + } + + wait_ready_blocking() +} + +pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { + let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; + + #[cfg(feature = "defmt")] + defmt::trace!("STM32C0 Erase: addr=0x{:08x}, idx={}, erase_size={}", sector.start, idx, super::BANK1_REGION.erase_size); + + + wait_busy(); + clear_all_err(); + + // Explicitly unlock before erase + unlock(); + + interrupt::free(|_| { + #[cfg(feature = "defmt")] + { + let cr_before = pac::FLASH.cr().read(); + defmt::trace!("FLASH_CR before: 0x{:08x}", cr_before.0); + } + + pac::FLASH.cr().modify(|w| { + w.set_per(true); + w.set_pnb(idx as u8); + w.set_strt(true); + }); + + #[cfg(feature = "defmt")] + { + let cr_after = pac::FLASH.cr().read(); + defmt::trace!("FLASH_CR after: 0x{:08x}, PER={}, PNB={}, STRT={}", + cr_after.0, cr_after.per(), cr_after.pnb(), cr_after.strt()); + } + }); + + let ret: Result<(), Error> = wait_ready_blocking(); + + // Clear erase bit + pac::FLASH.cr().modify(|w| w.set_per(false)); + + // Explicitly lock after erase + lock(); + + // Extra wait to ensure operation completes + wait_busy(); + + ret +} + +pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> { + while pac::FLASH.sr().read().bsy() {} + + let sr = pac::FLASH.sr().read(); + + if sr.progerr() { + return Err(Error::Prog); + } + + if sr.wrperr() { + return Err(Error::Protected); + } + + if sr.pgaerr() { + return Err(Error::Unaligned); + } + + Ok(()) +} + +pub(crate) unsafe fn clear_all_err() { + // read and write back the same value. + // This clears all "write 1 to clear" bits. + pac::FLASH.sr().modify(|_| {}); +} + +fn wait_busy() { + while pac::FLASH.sr().read().bsy() {} +} diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index b595938a6..508bb2548 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -102,7 +102,7 @@ pub(super) unsafe fn blocking_write( } let mut address = base + offset; - trace!("Writing {} bytes at 0x{:x}", bytes.len(), address); + trace!("Writing {} bytes at 0x{:x} (base=0x{:x}, offset=0x{:x})", bytes.len(), address, base, offset); for chunk in bytes.chunks(WRITE_SIZE) { write_chunk(address, chunk)?; diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 3e74d857a..39cd9b3a9 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -99,6 +99,7 @@ compile_error!("The 'eeprom' cfg is enabled for a non-L0/L1 chip family. This is #[cfg_attr(flash_f4, path = "f4.rs")] #[cfg_attr(flash_f7, path = "f7.rs")] #[cfg_attr(any(flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")] +#[cfg_attr(flash_c0, path = "c.rs")] #[cfg_attr(flash_h7, path = "h7.rs")] #[cfg_attr(flash_h7ab, path = "h7.rs")] #[cfg_attr(any(flash_u5, flash_wba), path = "u5.rs")] @@ -108,7 +109,7 @@ compile_error!("The 'eeprom' cfg is enabled for a non-L0/L1 chip family. This is #[cfg_attr( not(any( flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4, - flash_f7, flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, + flash_f7, flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4, flash_c0, flash_h7, flash_h7ab, flash_u5, flash_wba, flash_h50, flash_u0, flash_h5, )), path = "other.rs" -- cgit From f72349660eb30f6fc32104db60c33a732a99f6b5 Mon Sep 17 00:00:00 2001 From: "Andreas Lindahl Flåten (ALF)" Date: Thu, 13 Nov 2025 11:24:43 +0100 Subject: add changelog and fix rustfmt errors --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/src/flash/c.rs | 17 +++++++++++++---- embassy-stm32/src/flash/common.rs | 8 +++++++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 3431848d3..7586861ef 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -55,6 +55,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - chore: Updated stm32-metapac and stm32-data dependencies - adc: reogranize and cleanup somewhat. require sample_time to be passed on conversion - fix: stm32/i2c v2 slave: prevent misaligned reads, error false positives, and incorrect counts of bytes read/written +- feat: add flash support for c0 family ([#4874](https://github.com/embassy-rs/embassy/pull/4874)) ## 0.4.0 - 2025-08-26 diff --git a/embassy-stm32/src/flash/c.rs b/embassy-stm32/src/flash/c.rs index af3d07ac6..0ad1002b0 100644 --- a/embassy-stm32/src/flash/c.rs +++ b/embassy-stm32/src/flash/c.rs @@ -47,8 +47,12 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; #[cfg(feature = "defmt")] - defmt::trace!("STM32C0 Erase: addr=0x{:08x}, idx={}, erase_size={}", sector.start, idx, super::BANK1_REGION.erase_size); - + defmt::trace!( + "STM32C0 Erase: addr=0x{:08x}, idx={}, erase_size={}", + sector.start, + idx, + super::BANK1_REGION.erase_size + ); wait_busy(); clear_all_err(); @@ -72,8 +76,13 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E #[cfg(feature = "defmt")] { let cr_after = pac::FLASH.cr().read(); - defmt::trace!("FLASH_CR after: 0x{:08x}, PER={}, PNB={}, STRT={}", - cr_after.0, cr_after.per(), cr_after.pnb(), cr_after.strt()); + defmt::trace!( + "FLASH_CR after: 0x{:08x}, PER={}, PNB={}, STRT={}", + cr_after.0, + cr_after.per(), + cr_after.pnb(), + cr_after.strt() + ); } }); diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 508bb2548..60d00e766 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -102,7 +102,13 @@ pub(super) unsafe fn blocking_write( } let mut address = base + offset; - trace!("Writing {} bytes at 0x{:x} (base=0x{:x}, offset=0x{:x})", bytes.len(), address, base, offset); + trace!( + "Writing {} bytes at 0x{:x} (base=0x{:x}, offset=0x{:x})", + bytes.len(), + address, + base, + offset + ); for chunk in bytes.chunks(WRITE_SIZE) { write_chunk(address, chunk)?; -- cgit From c17d24d0cc8fedbe69b22032ea7323997ddfe4dc Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 13 Nov 2025 07:38:06 -0600 Subject: extract averaging enum --- embassy-stm32/src/adc/c0.rs | 19 ------------------- embassy-stm32/src/adc/mod.rs | 20 ++++++++++++++++++++ embassy-stm32/src/adc/v3.rs | 17 +---------------- embassy-stm32/src/adc/v4.rs | 19 +------------------ 4 files changed, 22 insertions(+), 53 deletions(-) diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index bc97a7c4b..8992d6e6e 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs @@ -119,25 +119,6 @@ impl<'a> defmt::Format for Prescaler { } } -/// Number of samples used for averaging. -/// TODO: Implement hardware averaging setting. -#[allow(unused)] -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Averaging { - Disabled, - Samples2, - Samples4, - Samples8, - Samples16, - Samples32, - Samples64, - Samples128, - Samples256, - Samples512, - Samples1024, -} - impl<'d, T: Instance> Adc<'d, T> { /// Create a new ADC driver. pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self { diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 856c2e61e..c91d68e87 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -148,6 +148,26 @@ pub(crate) fn blocking_delay_us(us: u32) { } } +#[cfg(any(adc_c0, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] +/// Number of samples used for averaging. +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Averaging { + Disabled, + Samples2, + Samples4, + Samples8, + Samples16, + Samples32, + Samples64, + Samples128, + Samples256, + #[cfg(any(adc_c0, adc_v4, adc_u5))] + Samples512, + #[cfg(any(adc_c0, adc_v4, adc_u5))] + Samples1024, +} + #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] #[allow(dead_code)] pub(crate) enum ConversionMode { diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 4cce1dac3..fa191c663 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -11,7 +11,7 @@ pub use pac::adc::vals::{Ovsr, Ovss, Presc}; #[allow(unused_imports)] use super::SealedAdcChannel; -use super::{Adc, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; +use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; use crate::adc::ConversionMode; use crate::{Peri, pac, rcc}; @@ -100,21 +100,6 @@ cfg_if! { } } -/// Number of samples used for averaging. -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Averaging { - Disabled, - Samples2, - Samples4, - Samples8, - Samples16, - Samples32, - Samples64, - Samples128, - Samples256, -} - cfg_if! { if #[cfg(adc_g0)] { /// Synchronous PCLK prescaler diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 43eb16fd5..1b17b744f 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -4,7 +4,7 @@ use pac::adc::vals::{Adcaldif, Boost}; use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; use pac::adccommon::vals::Presc; -use super::{Adc, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; +use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; use crate::adc::ConversionMode; use crate::time::Hertz; use crate::{Peri, pac, rcc}; @@ -127,23 +127,6 @@ impl Prescaler { } } -/// Number of samples used for averaging. -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Averaging { - Disabled, - Samples2, - Samples4, - Samples8, - Samples16, - Samples32, - Samples64, - Samples128, - Samples256, - Samples512, - Samples1024, -} - /// Adc configuration #[derive(Default)] pub struct AdcConfig { -- cgit From 2553ced205d49d2890e000069f5a170b75d267a9 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Thu, 13 Nov 2025 14:36:31 +0100 Subject: stm32: Move i2c_master test to examples --- examples/stm32f0/Cargo.toml | 1 + examples/stm32f0/src/bin/i2c_master.rs | 609 +++++++++++++++++++++++++++++++++ tests/stm32/Cargo.toml | 7 - tests/stm32/build.rs | 1 - tests/stm32/src/bin/i2c_v2_master.rs | 608 -------------------------------- tests/stm32/src/common.rs | 25 -- 6 files changed, 610 insertions(+), 641 deletions(-) create mode 100644 examples/stm32f0/src/bin/i2c_master.rs delete mode 100644 tests/stm32/src/bin/i2c_v2_master.rs diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index a78873d21..177dd0ac2 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -16,6 +16,7 @@ panic-probe = { version = "1.0.0", features = ["print-defmt"] } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } static_cell = "2" portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } diff --git a/examples/stm32f0/src/bin/i2c_master.rs b/examples/stm32f0/src/bin/i2c_master.rs new file mode 100644 index 000000000..2e61ecdf7 --- /dev/null +++ b/examples/stm32f0/src/bin/i2c_master.rs @@ -0,0 +1,609 @@ +#![no_std] +#![no_main] + +// Hardware Setup for NUCLEO-F072RB: +// - I2C1 pins: PB8 (SCL), PB9 (SDA) on CN5 connector +// - Connect to I2C slave device (e.g., Digilent Analog Discovery I2C slave, or EEPROM) +// - Default slave address: 0x50 +// - Pull-up resistors: 4.7kΩ on both SCL and SDA +// - CN5 Pin 10 (PB8/SCL) and CN5 Pin 9 (PB9/SDA) +// +// Analog Discovery - Waveforms Setup: +// - Increase buffer size: Settings -> Device Manager -> Option 4 +// - Run Protocol Analyzer +// - Configure as I2C Slave at address 0x50 +// - Connect and configure DIO pins for SCL and SDA +// - Frequency: 100kHz - [✓] Clock Stretching + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::i2c::{Config, I2c, Master}; +use embassy_stm32::mode::{Async, Blocking}; +use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, i2c, peripherals}; +use embassy_time::Timer; +use embedded_hal_1::i2c::Operation; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + I2C1 => i2c::EventInterruptHandler, i2c::ErrorInterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Run stm32 I2C v2 Master Tests..."); + + let mut i2c_peri = p.I2C1; + let mut scl = p.PB8; + let mut sda = p.PB9; + + let mut config = Config::default(); + config.frequency = Hertz(100_000); + + // I2C slave address for Analog Discovery or test EEPROM + let slave_addr = 0x50u8; + + // Wait for slave device to be ready + Timer::after_millis(100).await; + + // ========== BLOCKING DIRECT API TESTS ========== + info!("========== BLOCKING DIRECT API TESTS =========="); + { + let mut i2c = I2c::new_blocking(i2c_peri.reborrow(), scl.reborrow(), sda.reborrow(), config); + + info!("=== Test 1: Direct blocking_write ==="); + test_blocking_write(&mut i2c, slave_addr); + + info!("=== Test 2: Direct blocking_read ==="); + test_blocking_read(&mut i2c, slave_addr); + + info!("=== Test 3: Direct blocking_write_read ==="); + test_blocking_write_read(&mut i2c, slave_addr); + + info!("=== Test 4: Direct blocking_write_vectored ==="); + test_blocking_write_vectored(&mut i2c, slave_addr); + + info!("=== Test 5: Large buffer (>255 bytes) ==="); + test_blocking_large_buffer(&mut i2c, slave_addr); + + info!("Blocking direct API tests OK"); + } + + Timer::after_millis(100).await; + + // ========== BLOCKING TRANSACTION TESTS ========== + info!("========== BLOCKING TRANSACTION TESTS =========="); + { + let mut i2c = I2c::new_blocking(i2c_peri.reborrow(), scl.reborrow(), sda.reborrow(), config); + + info!("=== Test 6: Consecutive Writes (Should Merge) ==="); + test_consecutive_writes_blocking(&mut i2c, slave_addr); + + info!("=== Test 7: Consecutive Reads (Should Merge) ==="); + test_consecutive_reads_blocking(&mut i2c, slave_addr); + + info!("=== Test 8: Write then Read (RESTART) ==="); + test_write_then_read_blocking(&mut i2c, slave_addr); + + info!("=== Test 9: Read then Write (RESTART) ==="); + test_read_then_write_blocking(&mut i2c, slave_addr); + + info!("=== Test 10: Complex Mixed Sequence ==="); + test_mixed_sequence_blocking(&mut i2c, slave_addr); + + info!("=== Test 11: Single Operations ==="); + test_single_operations_blocking(&mut i2c, slave_addr); + + info!("Blocking transaction tests OK"); + } + + Timer::after_millis(100).await; + + // ========== ASYNC TESTS (DMA) ========== + info!("========== ASYNC TESTS (DMA) =========="); + { + let tx_dma = p.DMA1_CH2; + let rx_dma = p.DMA1_CH3; + + let mut i2c = I2c::new(i2c_peri, scl, sda, Irqs, tx_dma, rx_dma, config); + + // Direct API tests (reusing same I2C instance) + info!("=== Direct API Test 1: write() ==="); + test_async_write(&mut i2c, slave_addr).await; + + info!("=== Direct API Test 2: read() ==="); + test_async_read(&mut i2c, slave_addr).await; + + info!("=== Direct API Test 3: write_read() ==="); + test_async_write_read(&mut i2c, slave_addr).await; + + info!("=== Direct API Test 4: write_vectored() ==="); + test_async_write_vectored(&mut i2c, slave_addr).await; + + info!("=== Direct API Test 5: Large buffer (>255 bytes) ==="); + test_async_large_buffer(&mut i2c, slave_addr).await; + + info!("Async Direct API tests OK"); + + // Transaction tests + info!("=== Transaction Test 6: Consecutive Writes (Should Merge) ==="); + test_consecutive_writes_async(&mut i2c, slave_addr).await; + + info!("=== Transaction Test 7: Consecutive Reads (Should Merge) ==="); + test_consecutive_reads_async(&mut i2c, slave_addr).await; + + info!("=== Transaction Test 8: Write then Read (RESTART) ==="); + test_write_then_read_async(&mut i2c, slave_addr).await; + + info!("=== Transaction Test 9: Read then Write (RESTART) ==="); + test_read_then_write_async(&mut i2c, slave_addr).await; + + info!("=== Transaction Test 10: Complex Mixed Sequence ==="); + test_mixed_sequence_async(&mut i2c, slave_addr).await; + + info!("=== Transaction Test 11: Single Operations ==="); + test_single_operations_async(&mut i2c, slave_addr).await; + + info!("Async transaction tests OK"); + } + + info!("All tests OK"); + cortex_m::asm::bkpt(); +} + +// ==================== BLOCKING DIRECT API TEST FUNCTIONS ==================== + +fn test_blocking_write(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + let write_data = [0x42, 0x43, 0x44, 0x45]; + + match i2c.blocking_write(addr, &write_data) { + Ok(_) => info!("✓ blocking_write succeeded: {:02x}", write_data), + Err(e) => { + error!("✗ blocking_write failed: {:?}", e); + defmt::panic!("Test failed: blocking_write"); + } + } +} + +fn test_blocking_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + let mut read_buf = [0u8; 8]; + + match i2c.blocking_read(addr, &mut read_buf) { + Ok(_) => info!("✓ blocking_read succeeded: {:02x}", read_buf), + Err(e) => { + error!("✗ blocking_read failed: {:?}", e); + defmt::panic!("Test failed: blocking_read"); + } + } +} + +fn test_blocking_write_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + let write_data = [0x50, 0x51]; + let mut read_buf = [0u8; 6]; + + match i2c.blocking_write_read(addr, &write_data, &mut read_buf) { + Ok(_) => { + info!("✓ blocking_write_read succeeded"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => { + error!("✗ blocking_write_read failed: {:?}", e); + defmt::panic!("Test failed: blocking_write_read"); + } + } +} + +fn test_blocking_write_vectored(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + let buf1 = [0x60, 0x61, 0x62]; + let buf2 = [0x70, 0x71]; + let buf3 = [0x80, 0x81, 0x82, 0x83]; + let bufs = [&buf1[..], &buf2[..], &buf3[..]]; + + match i2c.blocking_write_vectored(addr, &bufs) { + Ok(_) => info!("✓ blocking_write_vectored succeeded (9 bytes total)"), + Err(e) => { + error!("✗ blocking_write_vectored failed: {:?}", e); + defmt::panic!("Test failed: blocking_write_vectored"); + } + } +} + +fn test_blocking_large_buffer(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Test with 300 bytes to verify RELOAD mechanism works (needs chunking at 255 bytes) + let mut write_buf = [0u8; 300]; + for (i, byte) in write_buf.iter_mut().enumerate() { + *byte = (i & 0xFF) as u8; + } + + match i2c.blocking_write(addr, &write_buf) { + Ok(_) => info!("✓ Large buffer write succeeded (300 bytes, tests RELOAD)"), + Err(e) => { + error!("✗ Large buffer write failed: {:?}", e); + defmt::panic!("Test failed: large buffer write"); + } + } + + // Test large read + let mut read_buf = [0u8; 300]; + match i2c.blocking_read(addr, &mut read_buf) { + Ok(_) => info!("✓ Large buffer read succeeded (300 bytes, tests RELOAD)"), + Err(e) => { + error!("✗ Large buffer read failed: {:?}", e); + defmt::panic!("Test failed: large buffer read"); + } + } +} + +// ==================== BLOCKING TRANSACTION TEST FUNCTIONS ==================== + +fn test_consecutive_writes_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected on bus: START, ADDR+W, data1, data2, data3, STOP + // NO intermediate RESTART/STOP between writes - they should be merged + let data1 = [0x10, 0x11, 0x12]; + let data2 = [0x20, 0x21]; + let data3 = [0x30, 0x31, 0x32, 0x33]; + + let mut ops = [ + Operation::Write(&data1), + Operation::Write(&data2), + Operation::Write(&data3), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"), + Err(e) => { + error!("✗ Consecutive writes failed: {:?}", e); + defmt::panic!("Test failed: consecutive writes"); + } + } +} + +fn test_consecutive_reads_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP + // NO intermediate RESTART/STOP between reads - they should be merged + let mut buf1 = [0u8; 4]; + let mut buf2 = [0u8; 3]; + let mut buf3 = [0u8; 2]; + + let mut ops = [ + Operation::Read(&mut buf1), + Operation::Read(&mut buf2), + Operation::Read(&mut buf3), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Consecutive reads succeeded (merged 9 bytes)"); + info!(" buf1: {:02x}", buf1); + info!(" buf2: {:02x}", buf2); + info!(" buf3: {:02x}", buf3); + } + Err(e) => { + error!("✗ Consecutive reads failed: {:?}", e); + defmt::panic!("Test failed: consecutive reads"); + } + } +} + +fn test_write_then_read_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected: START, ADDR+W, data, RESTART, ADDR+R, data, NACK, STOP + let write_data = [0xAA, 0xBB]; + let mut read_buf = [0u8; 4]; + + let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Write-then-read succeeded with RESTART"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => { + error!("✗ Write-then-read failed: {:?}", e); + defmt::panic!("Test failed: write-then-read"); + } + } +} + +fn test_read_then_write_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected: START, ADDR+R, data, NACK, RESTART, ADDR+W, data, STOP + let mut read_buf = [0u8; 3]; + let write_data = [0xCC, 0xDD, 0xEE]; + + let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Read-then-write succeeded with RESTART"); + info!(" Read: {:02x}", read_buf); + info!(" Written: {:02x}", write_data); + } + Err(e) => { + error!("✗ Read-then-write failed: {:?}", e); + defmt::panic!("Test failed: read-then-write"); + } + } +} + +fn test_mixed_sequence_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Complex: W, W, R, R, W, R + // Groups: [W,W] RESTART [R,R] RESTART [W] RESTART [R] + let w1 = [0x01, 0x02]; + let w2 = [0x03, 0x04]; + let mut r1 = [0u8; 2]; + let mut r2 = [0u8; 2]; + let w3 = [0x05]; + let mut r3 = [0u8; 1]; + + let mut ops = [ + Operation::Write(&w1), + Operation::Write(&w2), + Operation::Read(&mut r1), + Operation::Read(&mut r2), + Operation::Write(&w3), + Operation::Read(&mut r3), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Mixed sequence succeeded"); + info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]"); + } + Err(e) => { + error!("✗ Mixed sequence failed: {:?}", e); + defmt::panic!("Test failed: mixed sequence"); + } + } +} + +fn test_single_operations_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Test single write + let write_data = [0xFF]; + let mut ops = [Operation::Write(&write_data)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => info!("✓ Single write succeeded"), + Err(e) => { + error!("✗ Single write failed: {:?}", e); + defmt::panic!("Test failed: single write"); + } + } + + // Test single read + let mut read_buf = [0u8; 1]; + let mut ops = [Operation::Read(&mut read_buf)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), + Err(e) => { + error!("✗ Single read failed: {:?}", e); + defmt::panic!("Test failed: single read"); + } + } +} + +// ==================== ASYNC DIRECT API TEST FUNCTIONS ==================== + +async fn test_async_write(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let write_data = [0x42, 0x43, 0x44, 0x45]; + + match i2c.write(addr, &write_data).await { + Ok(_) => info!("✓ async write succeeded: {:02x}", write_data), + Err(e) => { + error!("✗ async write failed: {:?}", e); + defmt::panic!("Test failed: async write"); + } + } +} + +async fn test_async_read(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let mut read_buf = [0u8; 8]; + + match i2c.read(addr, &mut read_buf).await { + Ok(_) => info!("✓ async read succeeded: {:02x}", read_buf), + Err(e) => { + error!("✗ async read failed: {:?}", e); + defmt::panic!("Test failed: async read"); + } + } +} + +async fn test_async_write_read(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let write_data = [0x50, 0x51]; + let mut read_buf = [0u8; 6]; + + match i2c.write_read(addr, &write_data, &mut read_buf).await { + Ok(_) => { + info!("✓ async write_read succeeded"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => { + error!("✗ async write_read failed: {:?}", e); + defmt::panic!("Test failed: async write_read"); + } + } +} + +async fn test_async_write_vectored(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let buf1 = [0x60, 0x61, 0x62]; + let buf2 = [0x70, 0x71]; + let buf3 = [0x80, 0x81, 0x82, 0x83]; + let bufs = [&buf1[..], &buf2[..], &buf3[..]]; + + match i2c.write_vectored(addr.into(), &bufs).await { + Ok(_) => info!("✓ async write_vectored succeeded (9 bytes total)"), + Err(e) => { + error!("✗ async write_vectored failed: {:?}", e); + defmt::panic!("Test failed: async write_vectored"); + } + } +} + +async fn test_async_large_buffer(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + // Test with 300 bytes to verify RELOAD mechanism works with DMA (needs chunking at 255 bytes) + let mut write_buf = [0u8; 300]; + for (i, byte) in write_buf.iter_mut().enumerate() { + *byte = (i & 0xFF) as u8; + } + + match i2c.write(addr, &write_buf).await { + Ok(_) => info!("✓ Large buffer async write succeeded (300 bytes, tests RELOAD with DMA)"), + Err(e) => { + error!("✗ Large buffer async write failed: {:?}", e); + defmt::panic!("Test failed: large buffer async write"); + } + } + + // Test large read + let mut read_buf = [0u8; 300]; + match i2c.read(addr, &mut read_buf).await { + Ok(_) => info!("✓ Large buffer async read succeeded (300 bytes, tests RELOAD with DMA)"), + Err(e) => { + error!("✗ Large buffer async read failed: {:?}", e); + defmt::panic!("Test failed: large buffer async read"); + } + } +} + +// ==================== ASYNC TRANSACTION TEST FUNCTIONS ==================== + +async fn test_consecutive_writes_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let data1 = [0x10, 0x11, 0x12]; + let data2 = [0x20, 0x21]; + let data3 = [0x30, 0x31, 0x32, 0x33]; + + let mut ops = [ + Operation::Write(&data1), + Operation::Write(&data2), + Operation::Write(&data3), + ]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"), + Err(e) => { + error!("✗ Consecutive writes failed: {:?}", e); + defmt::panic!("Test failed: consecutive writes"); + } + } +} + +async fn test_consecutive_reads_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let mut buf1 = [0u8; 4]; + let mut buf2 = [0u8; 3]; + let mut buf3 = [0u8; 2]; + + let mut ops = [ + Operation::Read(&mut buf1), + Operation::Read(&mut buf2), + Operation::Read(&mut buf3), + ]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Consecutive reads succeeded (merged 9 bytes)"); + info!(" buf1: {:02x}", buf1); + info!(" buf2: {:02x}", buf2); + info!(" buf3: {:02x}", buf3); + } + Err(e) => { + error!("✗ Consecutive reads failed: {:?}", e); + defmt::panic!("Test failed: consecutive reads"); + } + } +} + +async fn test_write_then_read_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let write_data = [0xAA, 0xBB]; + let mut read_buf = [0u8; 4]; + + let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Write-then-read succeeded with RESTART"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => { + error!("✗ Write-then-read failed: {:?}", e); + defmt::panic!("Test failed: write-then-read"); + } + } +} + +async fn test_read_then_write_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let mut read_buf = [0u8; 3]; + let write_data = [0xCC, 0xDD, 0xEE]; + + let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Read-then-write succeeded with RESTART"); + info!(" Read: {:02x}", read_buf); + info!(" Written: {:02x}", write_data); + } + Err(e) => { + error!("✗ Read-then-write failed: {:?}", e); + defmt::panic!("Test failed: read-then-write"); + } + } +} + +async fn test_mixed_sequence_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let w1 = [0x01, 0x02]; + let w2 = [0x03, 0x04]; + let mut r1 = [0u8; 2]; + let mut r2 = [0u8; 2]; + let w3 = [0x05]; + let mut r3 = [0u8; 1]; + + let mut ops = [ + Operation::Write(&w1), + Operation::Write(&w2), + Operation::Read(&mut r1), + Operation::Read(&mut r2), + Operation::Write(&w3), + Operation::Read(&mut r3), + ]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Mixed sequence succeeded"); + info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]"); + } + Err(e) => { + error!("✗ Mixed sequence failed: {:?}", e); + defmt::panic!("Test failed: mixed sequence"); + } + } +} + +async fn test_single_operations_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + // Test single write + let write_data = [0xFF]; + let mut ops = [Operation::Write(&write_data)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => info!("✓ Single write succeeded"), + Err(e) => { + error!("✗ Single write failed: {:?}", e); + defmt::panic!("Test failed: single write"); + } + } + + // Test single read + let mut read_buf = [0u8; 1]; + let mut ops = [Operation::Read(&mut read_buf)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), + Err(e) => { + error!("✗ Single read failed: {:?}", e); + defmt::panic!("Test failed: single read"); + } + } +} diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 1912a772c..b92b47be2 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -35,7 +35,6 @@ stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" stm32wba52cg = ["embassy-stm32/stm32wba52cg", "spi-v345", "chrono", "rng", "hash"] stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"] -stm32f072rb = ["embassy-stm32/stm32f072rb", "cm0", "not-gpdma", "chrono"] stm32h503rb = ["embassy-stm32/stm32h503rb", "spi-v345", "rng", "stop"] stm32h7s3l8 = ["embassy-stm32/stm32h7s3l8", "spi-v345", "rng", "cordic", "hash-v34"] # TODO: fdcan crashes, cryp dma hangs. stm32u083rc = ["embassy-stm32/stm32u083rc", "cm0", "rng", "chrono"] @@ -160,11 +159,6 @@ name = "hash" path = "src/bin/hash.rs" required-features = [ "hash",] -[[bin]] -name = "i2c_v2_master" -path = "src/bin/i2c_v2_master.rs" -required-features = [ "stm32f072rb",] - [[bin]] name = "rng" path = "src/bin/rng.rs" @@ -291,7 +285,6 @@ build = [ { target = "thumbv7em-none-eabi", features = ["stm32wl55jc"], artifact-dir = "out/tests/stm32wl55jc" }, { target = "thumbv7em-none-eabi", features = ["stm32h7s3l8"], artifact-dir = "out/tests/stm32h7s3l8" }, { target = "thumbv6m-none-eabi", features = ["stm32f091rc"], artifact-dir = "out/tests/stm32f091rc" }, - { target = "thumbv6m-none-eabi", features = ["stm32f072rb"], artifact-dir = "out/tests/stm32f072rb" }, { target = "thumbv8m.main-none-eabihf", features = ["stm32h503rb"], artifact-dir = "out/tests/stm32h503rb" }, { target = "thumbv6m-none-eabi", features = ["stm32u083rc"], artifact-dir = "out/tests/stm32u083rc" } ] diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs index 34030c206..556d77a20 100644 --- a/tests/stm32/build.rs +++ b/tests/stm32/build.rs @@ -15,7 +15,6 @@ fn main() -> Result<(), Box> { feature = "stm32c071rb", // 24 kb feature = "stm32l073rz", // 20 kb feature = "stm32h503rb", // 32 kb - feature = "stm32f072rb", // 16 kb - I2C v2 test with async too large for RAM // no VTOR, so interrupts can't work when running from RAM feature = "stm32f091rc", )) { diff --git a/tests/stm32/src/bin/i2c_v2_master.rs b/tests/stm32/src/bin/i2c_v2_master.rs deleted file mode 100644 index 34f9b48d3..000000000 --- a/tests/stm32/src/bin/i2c_v2_master.rs +++ /dev/null @@ -1,608 +0,0 @@ -#![no_std] -#![no_main] -// required-features: stm32f072rb -// -// Hardware Setup for NUCLEO-F072RB: -// - I2C1 pins: PB8 (SCL), PB9 (SDA) on CN5 connector -// - Connect to I2C slave device (e.g., Digilent Analog Discovery I2C slave, or EEPROM) -// - Default slave address: 0x50 -// - Pull-up resistors: 4.7kΩ on both SCL and SDA -// - CN5 Pin 10 (PB8/SCL) and CN5 Pin 9 (PB9/SDA) -// -// Analog Discovery - Waveforms Setup: -// - Increase buffer size: Settings -> Device Manager -> Option 4 -// - Run Protocol Analyzer -// - Configure as I2C Slave at address 0x50 -// - Connect and configure DIO pins for SCL and SDA -// - Frequency: 100kHz - [✓] Clock Stretching - -#[path = "../common.rs"] -mod common; - -use common::*; -use embassy_executor::Spawner; -use embassy_stm32::i2c::{Config, I2c, Master}; -use embassy_stm32::mode::{Async, Blocking}; -use embassy_stm32::time::Hertz; -use embassy_time::Timer; -use embedded_hal_1::i2c::Operation; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = init(); - info!("Run stm32 I2C v2 Master Tests..."); - - let mut i2c_peri = peri!(p, I2C); - let mut scl = peri!(p, I2C_SCL); - let mut sda = peri!(p, I2C_SDA); - - let mut config = Config::default(); - config.frequency = Hertz(100_000); - - // I2C slave address for Analog Discovery or test EEPROM - let slave_addr = 0x50u8; - - // Wait for slave device to be ready - Timer::after_millis(100).await; - - // ========== BLOCKING DIRECT API TESTS ========== - info!("========== BLOCKING DIRECT API TESTS =========="); - { - let mut i2c = I2c::new_blocking(i2c_peri.reborrow(), scl.reborrow(), sda.reborrow(), config); - - info!("=== Test 1: Direct blocking_write ==="); - test_blocking_write(&mut i2c, slave_addr); - - info!("=== Test 2: Direct blocking_read ==="); - test_blocking_read(&mut i2c, slave_addr); - - info!("=== Test 3: Direct blocking_write_read ==="); - test_blocking_write_read(&mut i2c, slave_addr); - - info!("=== Test 4: Direct blocking_write_vectored ==="); - test_blocking_write_vectored(&mut i2c, slave_addr); - - info!("=== Test 5: Large buffer (>255 bytes) ==="); - test_blocking_large_buffer(&mut i2c, slave_addr); - - info!("Blocking direct API tests OK"); - } - - Timer::after_millis(100).await; - - // ========== BLOCKING TRANSACTION TESTS ========== - info!("========== BLOCKING TRANSACTION TESTS =========="); - { - let mut i2c = I2c::new_blocking(i2c_peri.reborrow(), scl.reborrow(), sda.reborrow(), config); - - info!("=== Test 6: Consecutive Writes (Should Merge) ==="); - test_consecutive_writes_blocking(&mut i2c, slave_addr); - - info!("=== Test 7: Consecutive Reads (Should Merge) ==="); - test_consecutive_reads_blocking(&mut i2c, slave_addr); - - info!("=== Test 8: Write then Read (RESTART) ==="); - test_write_then_read_blocking(&mut i2c, slave_addr); - - info!("=== Test 9: Read then Write (RESTART) ==="); - test_read_then_write_blocking(&mut i2c, slave_addr); - - info!("=== Test 10: Complex Mixed Sequence ==="); - test_mixed_sequence_blocking(&mut i2c, slave_addr); - - info!("=== Test 11: Single Operations ==="); - test_single_operations_blocking(&mut i2c, slave_addr); - - info!("Blocking transaction tests OK"); - } - - Timer::after_millis(100).await; - - // ========== ASYNC TESTS (DMA) ========== - info!("========== ASYNC TESTS (DMA) =========="); - { - let tx_dma = peri!(p, I2C_TX_DMA); - let rx_dma = peri!(p, I2C_RX_DMA); - let irq = irqs!(I2C); - - let mut i2c = I2c::new(i2c_peri, scl, sda, irq, tx_dma, rx_dma, config); - - // Direct API tests (reusing same I2C instance) - info!("=== Direct API Test 1: write() ==="); - test_async_write(&mut i2c, slave_addr).await; - - info!("=== Direct API Test 2: read() ==="); - test_async_read(&mut i2c, slave_addr).await; - - info!("=== Direct API Test 3: write_read() ==="); - test_async_write_read(&mut i2c, slave_addr).await; - - info!("=== Direct API Test 4: write_vectored() ==="); - test_async_write_vectored(&mut i2c, slave_addr).await; - - info!("=== Direct API Test 5: Large buffer (>255 bytes) ==="); - test_async_large_buffer(&mut i2c, slave_addr).await; - - info!("Async Direct API tests OK"); - - // Transaction tests - info!("=== Transaction Test 6: Consecutive Writes (Should Merge) ==="); - test_consecutive_writes_async(&mut i2c, slave_addr).await; - - info!("=== Transaction Test 7: Consecutive Reads (Should Merge) ==="); - test_consecutive_reads_async(&mut i2c, slave_addr).await; - - info!("=== Transaction Test 8: Write then Read (RESTART) ==="); - test_write_then_read_async(&mut i2c, slave_addr).await; - - info!("=== Transaction Test 9: Read then Write (RESTART) ==="); - test_read_then_write_async(&mut i2c, slave_addr).await; - - info!("=== Transaction Test 10: Complex Mixed Sequence ==="); - test_mixed_sequence_async(&mut i2c, slave_addr).await; - - info!("=== Transaction Test 11: Single Operations ==="); - test_single_operations_async(&mut i2c, slave_addr).await; - - info!("Async transaction tests OK"); - } - - info!("All tests OK"); - cortex_m::asm::bkpt(); -} - -// ==================== BLOCKING DIRECT API TEST FUNCTIONS ==================== - -fn test_blocking_write(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - let write_data = [0x42, 0x43, 0x44, 0x45]; - - match i2c.blocking_write(addr, &write_data) { - Ok(_) => info!("✓ blocking_write succeeded: {:02x}", write_data), - Err(e) => { - error!("✗ blocking_write failed: {:?}", e); - defmt::panic!("Test failed: blocking_write"); - } - } -} - -fn test_blocking_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - let mut read_buf = [0u8; 8]; - - match i2c.blocking_read(addr, &mut read_buf) { - Ok(_) => info!("✓ blocking_read succeeded: {:02x}", read_buf), - Err(e) => { - error!("✗ blocking_read failed: {:?}", e); - defmt::panic!("Test failed: blocking_read"); - } - } -} - -fn test_blocking_write_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - let write_data = [0x50, 0x51]; - let mut read_buf = [0u8; 6]; - - match i2c.blocking_write_read(addr, &write_data, &mut read_buf) { - Ok(_) => { - info!("✓ blocking_write_read succeeded"); - info!(" Written: {:02x}", write_data); - info!(" Read: {:02x}", read_buf); - } - Err(e) => { - error!("✗ blocking_write_read failed: {:?}", e); - defmt::panic!("Test failed: blocking_write_read"); - } - } -} - -fn test_blocking_write_vectored(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - let buf1 = [0x60, 0x61, 0x62]; - let buf2 = [0x70, 0x71]; - let buf3 = [0x80, 0x81, 0x82, 0x83]; - let bufs = [&buf1[..], &buf2[..], &buf3[..]]; - - match i2c.blocking_write_vectored(addr, &bufs) { - Ok(_) => info!("✓ blocking_write_vectored succeeded (9 bytes total)"), - Err(e) => { - error!("✗ blocking_write_vectored failed: {:?}", e); - defmt::panic!("Test failed: blocking_write_vectored"); - } - } -} - -fn test_blocking_large_buffer(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Test with 300 bytes to verify RELOAD mechanism works (needs chunking at 255 bytes) - let mut write_buf = [0u8; 300]; - for (i, byte) in write_buf.iter_mut().enumerate() { - *byte = (i & 0xFF) as u8; - } - - match i2c.blocking_write(addr, &write_buf) { - Ok(_) => info!("✓ Large buffer write succeeded (300 bytes, tests RELOAD)"), - Err(e) => { - error!("✗ Large buffer write failed: {:?}", e); - defmt::panic!("Test failed: large buffer write"); - } - } - - // Test large read - let mut read_buf = [0u8; 300]; - match i2c.blocking_read(addr, &mut read_buf) { - Ok(_) => info!("✓ Large buffer read succeeded (300 bytes, tests RELOAD)"), - Err(e) => { - error!("✗ Large buffer read failed: {:?}", e); - defmt::panic!("Test failed: large buffer read"); - } - } -} - -// ==================== BLOCKING TRANSACTION TEST FUNCTIONS ==================== - -fn test_consecutive_writes_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Expected on bus: START, ADDR+W, data1, data2, data3, STOP - // NO intermediate RESTART/STOP between writes - they should be merged - let data1 = [0x10, 0x11, 0x12]; - let data2 = [0x20, 0x21]; - let data3 = [0x30, 0x31, 0x32, 0x33]; - - let mut ops = [ - Operation::Write(&data1), - Operation::Write(&data2), - Operation::Write(&data3), - ]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"), - Err(e) => { - error!("✗ Consecutive writes failed: {:?}", e); - defmt::panic!("Test failed: consecutive writes"); - } - } -} - -fn test_consecutive_reads_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP - // NO intermediate RESTART/STOP between reads - they should be merged - let mut buf1 = [0u8; 4]; - let mut buf2 = [0u8; 3]; - let mut buf3 = [0u8; 2]; - - let mut ops = [ - Operation::Read(&mut buf1), - Operation::Read(&mut buf2), - Operation::Read(&mut buf3), - ]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Consecutive reads succeeded (merged 9 bytes)"); - info!(" buf1: {:02x}", buf1); - info!(" buf2: {:02x}", buf2); - info!(" buf3: {:02x}", buf3); - } - Err(e) => { - error!("✗ Consecutive reads failed: {:?}", e); - defmt::panic!("Test failed: consecutive reads"); - } - } -} - -fn test_write_then_read_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Expected: START, ADDR+W, data, RESTART, ADDR+R, data, NACK, STOP - let write_data = [0xAA, 0xBB]; - let mut read_buf = [0u8; 4]; - - let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Write-then-read succeeded with RESTART"); - info!(" Written: {:02x}", write_data); - info!(" Read: {:02x}", read_buf); - } - Err(e) => { - error!("✗ Write-then-read failed: {:?}", e); - defmt::panic!("Test failed: write-then-read"); - } - } -} - -fn test_read_then_write_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Expected: START, ADDR+R, data, NACK, RESTART, ADDR+W, data, STOP - let mut read_buf = [0u8; 3]; - let write_data = [0xCC, 0xDD, 0xEE]; - - let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Read-then-write succeeded with RESTART"); - info!(" Read: {:02x}", read_buf); - info!(" Written: {:02x}", write_data); - } - Err(e) => { - error!("✗ Read-then-write failed: {:?}", e); - defmt::panic!("Test failed: read-then-write"); - } - } -} - -fn test_mixed_sequence_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Complex: W, W, R, R, W, R - // Groups: [W,W] RESTART [R,R] RESTART [W] RESTART [R] - let w1 = [0x01, 0x02]; - let w2 = [0x03, 0x04]; - let mut r1 = [0u8; 2]; - let mut r2 = [0u8; 2]; - let w3 = [0x05]; - let mut r3 = [0u8; 1]; - - let mut ops = [ - Operation::Write(&w1), - Operation::Write(&w2), - Operation::Read(&mut r1), - Operation::Read(&mut r2), - Operation::Write(&w3), - Operation::Read(&mut r3), - ]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Mixed sequence succeeded"); - info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]"); - } - Err(e) => { - error!("✗ Mixed sequence failed: {:?}", e); - defmt::panic!("Test failed: mixed sequence"); - } - } -} - -fn test_single_operations_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Test single write - let write_data = [0xFF]; - let mut ops = [Operation::Write(&write_data)]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => info!("✓ Single write succeeded"), - Err(e) => { - error!("✗ Single write failed: {:?}", e); - defmt::panic!("Test failed: single write"); - } - } - - // Test single read - let mut read_buf = [0u8; 1]; - let mut ops = [Operation::Read(&mut read_buf)]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), - Err(e) => { - error!("✗ Single read failed: {:?}", e); - defmt::panic!("Test failed: single read"); - } - } -} - -// ==================== ASYNC DIRECT API TEST FUNCTIONS ==================== - -async fn test_async_write(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let write_data = [0x42, 0x43, 0x44, 0x45]; - - match i2c.write(addr, &write_data).await { - Ok(_) => info!("✓ async write succeeded: {:02x}", write_data), - Err(e) => { - error!("✗ async write failed: {:?}", e); - defmt::panic!("Test failed: async write"); - } - } -} - -async fn test_async_read(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let mut read_buf = [0u8; 8]; - - match i2c.read(addr, &mut read_buf).await { - Ok(_) => info!("✓ async read succeeded: {:02x}", read_buf), - Err(e) => { - error!("✗ async read failed: {:?}", e); - defmt::panic!("Test failed: async read"); - } - } -} - -async fn test_async_write_read(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let write_data = [0x50, 0x51]; - let mut read_buf = [0u8; 6]; - - match i2c.write_read(addr, &write_data, &mut read_buf).await { - Ok(_) => { - info!("✓ async write_read succeeded"); - info!(" Written: {:02x}", write_data); - info!(" Read: {:02x}", read_buf); - } - Err(e) => { - error!("✗ async write_read failed: {:?}", e); - defmt::panic!("Test failed: async write_read"); - } - } -} - -async fn test_async_write_vectored(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let buf1 = [0x60, 0x61, 0x62]; - let buf2 = [0x70, 0x71]; - let buf3 = [0x80, 0x81, 0x82, 0x83]; - let bufs = [&buf1[..], &buf2[..], &buf3[..]]; - - match i2c.write_vectored(addr.into(), &bufs).await { - Ok(_) => info!("✓ async write_vectored succeeded (9 bytes total)"), - Err(e) => { - error!("✗ async write_vectored failed: {:?}", e); - defmt::panic!("Test failed: async write_vectored"); - } - } -} - -async fn test_async_large_buffer(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - // Test with 300 bytes to verify RELOAD mechanism works with DMA (needs chunking at 255 bytes) - let mut write_buf = [0u8; 300]; - for (i, byte) in write_buf.iter_mut().enumerate() { - *byte = (i & 0xFF) as u8; - } - - match i2c.write(addr, &write_buf).await { - Ok(_) => info!("✓ Large buffer async write succeeded (300 bytes, tests RELOAD with DMA)"), - Err(e) => { - error!("✗ Large buffer async write failed: {:?}", e); - defmt::panic!("Test failed: large buffer async write"); - } - } - - // Test large read - let mut read_buf = [0u8; 300]; - match i2c.read(addr, &mut read_buf).await { - Ok(_) => info!("✓ Large buffer async read succeeded (300 bytes, tests RELOAD with DMA)"), - Err(e) => { - error!("✗ Large buffer async read failed: {:?}", e); - defmt::panic!("Test failed: large buffer async read"); - } - } -} - -// ==================== ASYNC TRANSACTION TEST FUNCTIONS ==================== - -async fn test_consecutive_writes_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let data1 = [0x10, 0x11, 0x12]; - let data2 = [0x20, 0x21]; - let data3 = [0x30, 0x31, 0x32, 0x33]; - - let mut ops = [ - Operation::Write(&data1), - Operation::Write(&data2), - Operation::Write(&data3), - ]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"), - Err(e) => { - error!("✗ Consecutive writes failed: {:?}", e); - defmt::panic!("Test failed: consecutive writes"); - } - } -} - -async fn test_consecutive_reads_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let mut buf1 = [0u8; 4]; - let mut buf2 = [0u8; 3]; - let mut buf3 = [0u8; 2]; - - let mut ops = [ - Operation::Read(&mut buf1), - Operation::Read(&mut buf2), - Operation::Read(&mut buf3), - ]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => { - info!("✓ Consecutive reads succeeded (merged 9 bytes)"); - info!(" buf1: {:02x}", buf1); - info!(" buf2: {:02x}", buf2); - info!(" buf3: {:02x}", buf3); - } - Err(e) => { - error!("✗ Consecutive reads failed: {:?}", e); - defmt::panic!("Test failed: consecutive reads"); - } - } -} - -async fn test_write_then_read_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let write_data = [0xAA, 0xBB]; - let mut read_buf = [0u8; 4]; - - let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => { - info!("✓ Write-then-read succeeded with RESTART"); - info!(" Written: {:02x}", write_data); - info!(" Read: {:02x}", read_buf); - } - Err(e) => { - error!("✗ Write-then-read failed: {:?}", e); - defmt::panic!("Test failed: write-then-read"); - } - } -} - -async fn test_read_then_write_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let mut read_buf = [0u8; 3]; - let write_data = [0xCC, 0xDD, 0xEE]; - - let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => { - info!("✓ Read-then-write succeeded with RESTART"); - info!(" Read: {:02x}", read_buf); - info!(" Written: {:02x}", write_data); - } - Err(e) => { - error!("✗ Read-then-write failed: {:?}", e); - defmt::panic!("Test failed: read-then-write"); - } - } -} - -async fn test_mixed_sequence_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let w1 = [0x01, 0x02]; - let w2 = [0x03, 0x04]; - let mut r1 = [0u8; 2]; - let mut r2 = [0u8; 2]; - let w3 = [0x05]; - let mut r3 = [0u8; 1]; - - let mut ops = [ - Operation::Write(&w1), - Operation::Write(&w2), - Operation::Read(&mut r1), - Operation::Read(&mut r2), - Operation::Write(&w3), - Operation::Read(&mut r3), - ]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => { - info!("✓ Mixed sequence succeeded"); - info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]"); - } - Err(e) => { - error!("✗ Mixed sequence failed: {:?}", e); - defmt::panic!("Test failed: mixed sequence"); - } - } -} - -async fn test_single_operations_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - // Test single write - let write_data = [0xFF]; - let mut ops = [Operation::Write(&write_data)]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => info!("✓ Single write succeeded"), - Err(e) => { - error!("✗ Single write failed: {:?}", e); - defmt::panic!("Test failed: single write"); - } - } - - // Test single read - let mut read_buf = [0u8; 1]; - let mut ops = [Operation::Read(&mut read_buf)]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), - Err(e) => { - error!("✗ Single read failed: {:?}", e); - defmt::panic!("Test failed: single read"); - } - } -} diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index de06cb267..096cce947 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -60,8 +60,6 @@ teleprobe_meta::target!(b"nucleo-stm32wl55jc"); teleprobe_meta::target!(b"nucleo-stm32wba52cg"); #[cfg(feature = "stm32f091rc")] teleprobe_meta::target!(b"nucleo-stm32f091rc"); -#[cfg(feature = "stm32f072rb")] -teleprobe_meta::target!(b"nucleo-stm32f072rb"); #[cfg(feature = "stm32h503rb")] teleprobe_meta::target!(b"nucleo-stm32h503rb"); #[cfg(feature = "stm32h7s3l8")] @@ -105,14 +103,6 @@ define_peris!( SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, ); -#[cfg(feature = "stm32f072rb")] -define_peris!( - UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5, - SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, - I2C = I2C1, I2C_SCL = PB8, I2C_SDA = PB9, I2C_TX_DMA = DMA1_CH6, I2C_RX_DMA = DMA1_CH7, - @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, - @irq I2C = {I2C1 => embassy_stm32::i2c::EventInterruptHandler, embassy_stm32::i2c::ErrorInterruptHandler;}, -); #[cfg(any(feature = "stm32f100rd", feature = "stm32f103c8", feature = "stm32f107vc"))] define_peris!( UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5, @@ -335,21 +325,6 @@ pub fn config() -> Config { config.rcc.ahb_pre = AHBPrescaler::DIV1; config.rcc.apb1_pre = APBPrescaler::DIV1; } - #[cfg(feature = "stm32f072rb")] - { - config.rcc.hse = Some(Hse { - freq: Hertz(8_000_000), - mode: HseMode::Bypass, - }); - config.rcc.pll = Some(Pll { - src: PllSource::HSE, - prediv: PllPreDiv::DIV1, - mul: PllMul::MUL6, - }); - config.rcc.sys = Sysclk::PLL1_P; - config.rcc.ahb_pre = AHBPrescaler::DIV1; - config.rcc.apb1_pre = APBPrescaler::DIV1; - } #[cfg(feature = "stm32f103c8")] { config.rcc.hse = Some(Hse { -- cgit From de582f7d5ed9d4903fb5f07d7816f67a907c1d47 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 13 Nov 2025 08:51:14 -0600 Subject: adc: extract prescalers --- embassy-stm32/build.rs | 124 ++++++++++++++++++++++++------------------ embassy-stm32/src/adc/adc4.rs | 82 +++++----------------------- embassy-stm32/src/adc/g4.rs | 82 +++++----------------------- embassy-stm32/src/adc/v4.rs | 82 +++++----------------------- 4 files changed, 113 insertions(+), 257 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index ad6743f96..67041a9e0 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1695,70 +1695,88 @@ fn main() { } // ======== - // Generate Div/Mul impls for RCC prescalers/dividers/multipliers. - for e in rcc_registers.ir.enums { - fn is_rcc_name(e: &str) -> bool { - match e { - "Pllp" | "Pllq" | "Pllr" | "Plldivst" | "Pllm" | "Plln" | "Prediv1" | "Prediv2" | "Hpre5" => true, - "Timpre" | "Pllrclkpre" => false, - e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true, - _ => false, + // Generate Div/Mul impls for RCC and ADC prescalers/dividers/multipliers. + for (kind, psc_enums) in ["rcc", "adc", "adccommon"].iter().filter_map(|kind| { + METADATA + .peripherals + .iter() + .filter_map(|p| p.registers.as_ref()) + .find(|r| r.kind == *kind) + .map(|r| (*kind, r.ir.enums)) + }) { + for e in psc_enums.iter() { + fn is_adc_name(e: &str) -> bool { + match e { + "Presc" | "Adc4Presc" => true, + _ => false, + } } - } - fn parse_num(n: &str) -> Result { - for prefix in ["DIV", "MUL"] { - if let Some(n) = n.strip_prefix(prefix) { - let exponent = n.find('_').map(|e| n.len() - 1 - e).unwrap_or(0) as u32; - let mantissa = n.replace('_', "").parse().map_err(|_| ())?; - let f = Frac { - num: mantissa, - denom: 10u32.pow(exponent), - }; - return Ok(f.simplify()); + fn is_rcc_name(e: &str) -> bool { + match e { + "Pllp" | "Pllq" | "Pllr" | "Plldivst" | "Pllm" | "Plln" | "Prediv1" | "Prediv2" | "Hpre5" => true, + "Timpre" | "Pllrclkpre" => false, + e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true, + _ => false, } } - Err(()) - } - if is_rcc_name(e.name) { - let enum_name = format_ident!("{}", e.name); - let mut muls = Vec::new(); - let mut divs = Vec::new(); - for v in e.variants { - let Ok(val) = parse_num(v.name) else { - panic!("could not parse mul/div. enum={} variant={}", e.name, v.name) - }; - let variant_name = format_ident!("{}", v.name); - let variant = quote!(crate::pac::rcc::vals::#enum_name::#variant_name); - let num = val.num; - let denom = val.denom; - muls.push(quote!(#variant => self * #num / #denom,)); - divs.push(quote!(#variant => self * #denom / #num,)); + fn parse_num(n: &str) -> Result { + for prefix in ["DIV", "MUL"] { + if let Some(n) = n.strip_prefix(prefix) { + let exponent = n.find('_').map(|e| n.len() - 1 - e).unwrap_or(0) as u32; + let mantissa = n.replace('_', "").parse().map_err(|_| ())?; + let f = Frac { + num: mantissa, + denom: 10u32.pow(exponent), + }; + return Ok(f.simplify()); + } + } + Err(()) } - g.extend(quote! { - impl core::ops::Div for crate::time::Hertz { - type Output = crate::time::Hertz; - fn div(self, rhs: crate::pac::rcc::vals::#enum_name) -> Self::Output { - match rhs { - #(#divs)* - #[allow(unreachable_patterns)] - _ => unreachable!(), + if (kind == "rcc" && is_rcc_name(e.name)) || ((kind == "adccommon" || kind == "adc") && is_adc_name(e.name)) + { + let kind = format_ident!("{}", kind); + let enum_name = format_ident!("{}", e.name); + let mut muls = Vec::new(); + let mut divs = Vec::new(); + for v in e.variants { + let Ok(val) = parse_num(v.name) else { + panic!("could not parse mul/div. enum={} variant={}", e.name, v.name) + }; + let variant_name = format_ident!("{}", v.name); + let variant = quote!(crate::pac::#kind::vals::#enum_name::#variant_name); + let num = val.num; + let denom = val.denom; + muls.push(quote!(#variant => self * #num / #denom,)); + divs.push(quote!(#variant => self * #denom / #num,)); + } + + g.extend(quote! { + impl core::ops::Div for crate::time::Hertz { + type Output = crate::time::Hertz; + fn div(self, rhs: crate::pac::#kind::vals::#enum_name) -> Self::Output { + match rhs { + #(#divs)* + #[allow(unreachable_patterns)] + _ => unreachable!(), + } } } - } - impl core::ops::Mul for crate::time::Hertz { - type Output = crate::time::Hertz; - fn mul(self, rhs: crate::pac::rcc::vals::#enum_name) -> Self::Output { - match rhs { - #(#muls)* - #[allow(unreachable_patterns)] - _ => unreachable!(), + impl core::ops::Mul for crate::time::Hertz { + type Output = crate::time::Hertz; + fn mul(self, rhs: crate::pac::#kind::vals::#enum_name) -> Self::Output { + match rhs { + #(#muls)* + #[allow(unreachable_patterns)] + _ => unreachable!(), + } } } - } - }); + }); + } } } diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs index 52678d1b6..d816eea57 100644 --- a/embassy-stm32/src/adc/adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs @@ -76,71 +76,17 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 { } } -// NOTE (unused): The prescaler enum closely copies the hardware capabilities, -// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. -#[allow(unused)] -enum Prescaler { - NotDivided, - DividedBy2, - DividedBy4, - DividedBy6, - DividedBy8, - DividedBy10, - DividedBy12, - DividedBy16, - DividedBy32, - DividedBy64, - DividedBy128, - DividedBy256, -} - -impl Prescaler { - fn from_ker_ck(frequency: Hertz) -> Self { - let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; - match raw_prescaler { - 0 => Self::NotDivided, - 1 => Self::DividedBy2, - 2..=3 => Self::DividedBy4, - 4..=5 => Self::DividedBy6, - 6..=7 => Self::DividedBy8, - 8..=9 => Self::DividedBy10, - 10..=11 => Self::DividedBy12, - _ => unimplemented!(), - } - } - - fn divisor(&self) -> u32 { - match self { - Prescaler::NotDivided => 1, - Prescaler::DividedBy2 => 2, - Prescaler::DividedBy4 => 4, - Prescaler::DividedBy6 => 6, - Prescaler::DividedBy8 => 8, - Prescaler::DividedBy10 => 10, - Prescaler::DividedBy12 => 12, - Prescaler::DividedBy16 => 16, - Prescaler::DividedBy32 => 32, - Prescaler::DividedBy64 => 64, - Prescaler::DividedBy128 => 128, - Prescaler::DividedBy256 => 256, - } - } - - fn presc(&self) -> Presc { - match self { - Prescaler::NotDivided => Presc::DIV1, - Prescaler::DividedBy2 => Presc::DIV2, - Prescaler::DividedBy4 => Presc::DIV4, - Prescaler::DividedBy6 => Presc::DIV6, - Prescaler::DividedBy8 => Presc::DIV8, - Prescaler::DividedBy10 => Presc::DIV10, - Prescaler::DividedBy12 => Presc::DIV12, - Prescaler::DividedBy16 => Presc::DIV16, - Prescaler::DividedBy32 => Presc::DIV32, - Prescaler::DividedBy64 => Presc::DIV64, - Prescaler::DividedBy128 => Presc::DIV128, - Prescaler::DividedBy256 => Presc::DIV256, - } +fn from_ker_ck(frequency: Hertz) -> Presc { + let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; + match raw_prescaler { + 0 => Presc::DIV1, + 1 => Presc::DIV2, + 2..=3 => Presc::DIV4, + 4..=5 => Presc::DIV6, + 6..=7 => Presc::DIV8, + 8..=9 => Presc::DIV10, + 10..=11 => Presc::DIV12, + _ => unimplemented!(), } } @@ -283,11 +229,11 @@ impl<'d, T: Instance + super::AnyInstance> super::Adc<'d, T> { /// Create a new ADC driver. pub fn new_adc4(adc: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); - let prescaler = Prescaler::from_ker_ck(T::frequency()); + let prescaler = from_ker_ck(T::frequency()); - T::regs().ccr().modify(|w| w.set_presc(prescaler.presc())); + T::regs().ccr().modify(|w| w.set_presc(prescaler)); - let frequency = Hertz(T::frequency().0 / prescaler.divisor()); + let frequency = T::frequency() / prescaler; info!("ADC4 frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 71dc8acc0..514734017 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -32,71 +32,17 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); #[cfg(stm32h7)] const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); -// NOTE (unused): The prescaler enum closely copies the hardware capabilities, -// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. -#[allow(unused)] -enum Prescaler { - NotDivided, - DividedBy2, - DividedBy4, - DividedBy6, - DividedBy8, - DividedBy10, - DividedBy12, - DividedBy16, - DividedBy32, - DividedBy64, - DividedBy128, - DividedBy256, -} - -impl Prescaler { - fn from_ker_ck(frequency: Hertz) -> Self { - let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; - match raw_prescaler { - 0 => Self::NotDivided, - 1 => Self::DividedBy2, - 2..=3 => Self::DividedBy4, - 4..=5 => Self::DividedBy6, - 6..=7 => Self::DividedBy8, - 8..=9 => Self::DividedBy10, - 10..=11 => Self::DividedBy12, - _ => unimplemented!(), - } - } - - fn divisor(&self) -> u32 { - match self { - Prescaler::NotDivided => 1, - Prescaler::DividedBy2 => 2, - Prescaler::DividedBy4 => 4, - Prescaler::DividedBy6 => 6, - Prescaler::DividedBy8 => 8, - Prescaler::DividedBy10 => 10, - Prescaler::DividedBy12 => 12, - Prescaler::DividedBy16 => 16, - Prescaler::DividedBy32 => 32, - Prescaler::DividedBy64 => 64, - Prescaler::DividedBy128 => 128, - Prescaler::DividedBy256 => 256, - } - } - - fn presc(&self) -> Presc { - match self { - Prescaler::NotDivided => Presc::DIV1, - Prescaler::DividedBy2 => Presc::DIV2, - Prescaler::DividedBy4 => Presc::DIV4, - Prescaler::DividedBy6 => Presc::DIV6, - Prescaler::DividedBy8 => Presc::DIV8, - Prescaler::DividedBy10 => Presc::DIV10, - Prescaler::DividedBy12 => Presc::DIV12, - Prescaler::DividedBy16 => Presc::DIV16, - Prescaler::DividedBy32 => Presc::DIV32, - Prescaler::DividedBy64 => Presc::DIV64, - Prescaler::DividedBy128 => Presc::DIV128, - Prescaler::DividedBy256 => Presc::DIV256, - } +fn from_ker_ck(frequency: Hertz) -> Presc { + let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; + match raw_prescaler { + 0 => Presc::DIV1, + 1 => Presc::DIV2, + 2..=3 => Presc::DIV4, + 4..=5 => Presc::DIV6, + 6..=7 => Presc::DIV8, + 8..=9 => Presc::DIV10, + 10..=11 => Presc::DIV12, + _ => unimplemented!(), } } @@ -292,11 +238,11 @@ impl<'d, T: Instance + AnyInstance> Adc<'d, T> { pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self { rcc::enable_and_reset::(); - let prescaler = Prescaler::from_ker_ck(T::frequency()); + let prescaler = from_ker_ck(T::frequency()); - T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); + T::common_regs().ccr().modify(|w| w.set_presc(prescaler)); - let frequency = Hertz(T::frequency().0 / prescaler.divisor()); + let frequency = T::frequency() / prescaler; trace!("ADC frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 1b17b744f..5c4a1975f 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -59,71 +59,17 @@ impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 18; } -// NOTE (unused): The prescaler enum closely copies the hardware capabilities, -// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. -#[allow(unused)] -enum Prescaler { - NotDivided, - DividedBy2, - DividedBy4, - DividedBy6, - DividedBy8, - DividedBy10, - DividedBy12, - DividedBy16, - DividedBy32, - DividedBy64, - DividedBy128, - DividedBy256, -} - -impl Prescaler { - fn from_ker_ck(frequency: Hertz) -> Self { - let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; - match raw_prescaler { - 0 => Self::NotDivided, - 1 => Self::DividedBy2, - 2..=3 => Self::DividedBy4, - 4..=5 => Self::DividedBy6, - 6..=7 => Self::DividedBy8, - 8..=9 => Self::DividedBy10, - 10..=11 => Self::DividedBy12, - _ => unimplemented!(), - } - } - - fn divisor(&self) -> u32 { - match self { - Prescaler::NotDivided => 1, - Prescaler::DividedBy2 => 2, - Prescaler::DividedBy4 => 4, - Prescaler::DividedBy6 => 6, - Prescaler::DividedBy8 => 8, - Prescaler::DividedBy10 => 10, - Prescaler::DividedBy12 => 12, - Prescaler::DividedBy16 => 16, - Prescaler::DividedBy32 => 32, - Prescaler::DividedBy64 => 64, - Prescaler::DividedBy128 => 128, - Prescaler::DividedBy256 => 256, - } - } - - fn presc(&self) -> Presc { - match self { - Prescaler::NotDivided => Presc::DIV1, - Prescaler::DividedBy2 => Presc::DIV2, - Prescaler::DividedBy4 => Presc::DIV4, - Prescaler::DividedBy6 => Presc::DIV6, - Prescaler::DividedBy8 => Presc::DIV8, - Prescaler::DividedBy10 => Presc::DIV10, - Prescaler::DividedBy12 => Presc::DIV12, - Prescaler::DividedBy16 => Presc::DIV16, - Prescaler::DividedBy32 => Presc::DIV32, - Prescaler::DividedBy64 => Presc::DIV64, - Prescaler::DividedBy128 => Presc::DIV128, - Prescaler::DividedBy256 => Presc::DIV256, - } +fn from_ker_ck(frequency: Hertz) -> Presc { + let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; + match raw_prescaler { + 0 => Presc::DIV1, + 1 => Presc::DIV2, + 2..=3 => Presc::DIV4, + 4..=5 => Presc::DIV6, + 6..=7 => Presc::DIV8, + 8..=9 => Presc::DIV10, + 10..=11 => Presc::DIV12, + _ => unimplemented!(), } } @@ -292,11 +238,11 @@ impl<'d, T: Instance + super::AnyInstance> Adc<'d, T> { pub fn new(adc: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); - let prescaler = Prescaler::from_ker_ck(T::frequency()); + let prescaler = from_ker_ck(T::frequency()); - T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); + T::common_regs().ccr().modify(|w| w.set_presc(prescaler)); - let frequency = Hertz(T::frequency().0 / prescaler.divisor()); + let frequency = T::frequency() / prescaler; info!("ADC frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { -- cgit From 1a3da1c582b4a9fec1af561e2f4a7ed0352aff33 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 13 Nov 2025 09:33:27 -0600 Subject: adc: extract v2 psc. --- embassy-stm32/build.rs | 2 +- embassy-stm32/src/adc/v2.rs | 51 +++++++++++++++------------------------------ 2 files changed, 18 insertions(+), 35 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 67041a9e0..1e11eb8dc 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1707,7 +1707,7 @@ fn main() { for e in psc_enums.iter() { fn is_adc_name(e: &str) -> bool { match e { - "Presc" | "Adc4Presc" => true, + "Presc" | "Adc4Presc" | "Adcpre" => true, _ => false, } } diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 4065f89a7..07eaebf7c 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -3,6 +3,7 @@ use core::sync::atomic::{Ordering, compiler_fence}; use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us}; use crate::adc::{Adc, Instance, Resolution, SampleTime}; use crate::pac::adc::vals; +pub use crate::pac::adccommon::vals::Adcpre; use crate::time::Hertz; use crate::{Peri, rcc}; @@ -50,38 +51,20 @@ impl Temperature { } } -enum Prescaler { - Div2, - Div4, - Div6, - Div8, -} - -impl Prescaler { - fn from_pclk2(freq: Hertz) -> Self { - // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V). - #[cfg(stm32f2)] - const MAX_FREQUENCY: Hertz = Hertz(30_000_000); - // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. - #[cfg(not(stm32f2))] - const MAX_FREQUENCY: Hertz = Hertz(36_000_000); - let raw_div = freq.0 / MAX_FREQUENCY.0; - match raw_div { - 0..=1 => Self::Div2, - 2..=3 => Self::Div4, - 4..=5 => Self::Div6, - 6..=7 => Self::Div8, - _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."), - } - } - - fn adcpre(&self) -> crate::pac::adccommon::vals::Adcpre { - match self { - Prescaler::Div2 => crate::pac::adccommon::vals::Adcpre::DIV2, - Prescaler::Div4 => crate::pac::adccommon::vals::Adcpre::DIV4, - Prescaler::Div6 => crate::pac::adccommon::vals::Adcpre::DIV6, - Prescaler::Div8 => crate::pac::adccommon::vals::Adcpre::DIV8, - } +fn from_pclk2(freq: Hertz) -> Adcpre { + // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V). + #[cfg(stm32f2)] + const MAX_FREQUENCY: Hertz = Hertz(30_000_000); + // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. + #[cfg(not(stm32f2))] + const MAX_FREQUENCY: Hertz = Hertz(36_000_000); + let raw_div = freq.0 / MAX_FREQUENCY.0; + match raw_div { + 0..=1 => Adcpre::DIV2, + 2..=3 => Adcpre::DIV4, + 4..=5 => Adcpre::DIV6, + 6..=7 => Adcpre::DIV8, + _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."), } } @@ -224,8 +207,8 @@ where pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { rcc::enable_and_reset::(); - let presc = Prescaler::from_pclk2(T::frequency()); - T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); + let presc = from_pclk2(T::frequency()); + T::common_regs().ccr().modify(|w| w.set_adcpre(presc)); T::regs().cr2().modify(|reg| { reg.set_adon(true); }); -- cgit From a8de2ccb8c0721284281715ce6eda28271db3950 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 13 Nov 2025 10:26:56 -0600 Subject: remove allow dead_code --- embassy-stm32/src/adc/adc4.rs | 1 + embassy-stm32/src/adc/mod.rs | 14 +++++++------- embassy-stm32/src/adc/v3.rs | 1 + embassy-stm32/src/adc/v4.rs | 1 + 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs index d816eea57..babdebfdb 100644 --- a/embassy-stm32/src/adc/adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs @@ -158,6 +158,7 @@ foreach_adc!( reg.set_chselrmod(Chselrmod::ENABLE_INPUT) }); } + #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] _ => unreachable!(), } } diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index c91d68e87..fd5b94224 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -88,19 +88,17 @@ pub(crate) trait SealedAdcChannel { } // Temporary patch for ADCs that have not implemented the standard iface yet -#[cfg(not(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4)))] +#[cfg(any(adc_v1, adc_l0, adc_f1, adc_f3v1, adc_f3v2, adc_f3v3, adc_v1, adc_c0))] trait_set::trait_set! { pub trait AnyInstance = Instance; } #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] -#[allow(dead_code)] pub trait BasicAnyInstance { type SampleTime; } #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] -#[allow(dead_code)] pub(self) trait SealedAnyInstance: BasicAnyInstance { fn enable(); fn start(); @@ -108,6 +106,7 @@ pub(self) trait SealedAnyInstance: BasicAnyInstance { fn convert() -> u16; fn configure_dma(conversion_mode: ConversionMode); fn configure_sequence(sequence: impl ExactSizeIterator); + #[allow(dead_code)] fn dr() -> *mut u16; } @@ -169,17 +168,18 @@ pub enum Averaging { } #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] -#[allow(dead_code)] pub(crate) enum ConversionMode { + // Should match the cfg on "read" below #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] Singular, - #[allow(dead_code)] + // Should match the cfg on "into_ring_buffered" below + #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] Repeated(RegularConversionMode), } -#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] +// Should match the cfg on "into_ring_buffered" below +#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] // Conversion mode for regular ADC channels -#[allow(dead_code)] #[derive(Copy, Clone)] pub enum RegularConversionMode { // Samples as fast as possible diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index fa191c663..78b497727 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -259,6 +259,7 @@ impl super::SealedAnyInstance for T { reg.set_cont(true); reg.set_dmacfg(match conversion_mode { ConversionMode::Singular => Dmacfg::ONE_SHOT, + #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] ConversionMode::Repeated(_) => Dmacfg::CIRCULAR, }); reg.set_dmaen(true); diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 5c4a1975f..804e63db6 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -143,6 +143,7 @@ impl super::SealedAnyInstance for T { reg.set_dmngt(Dmngt::DMA_ONE_SHOT); }); } + #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] _ => unreachable!(), } } -- cgit From 32408f4a031dff11c1c3c8c4aeb2044f1a7e8f42 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 13 Nov 2025 12:02:38 -0600 Subject: adc: extract c0 --- embassy-stm32/src/adc/c0.rs | 488 ++++++++++++++-------------------------- embassy-stm32/src/adc/mod.rs | 53 ++++- examples/stm32c0/src/bin/adc.rs | 18 +- 3 files changed, 214 insertions(+), 345 deletions(-) diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index 8992d6e6e..983e7c10d 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs @@ -1,12 +1,10 @@ -use pac::adc::vals::Scandir; #[allow(unused)] use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; use pac::adccommon::vals::Presc; +use stm32_metapac::adc::vals::Scandir; -use super::{ - Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, -}; -use crate::dma::Transfer; +use super::{Adc, Instance, Resolution, blocking_delay_us}; +use crate::adc::{AnyInstance, ConversionMode}; use crate::time::Hertz; use crate::{Peri, pac, rcc}; @@ -32,104 +30,184 @@ impl super::SealedSpecialConverter for T { const CHANNEL: u8 = 9; } -#[derive(Copy, Clone, Debug)] -pub enum Prescaler { - NotDivided, - DividedBy2, - DividedBy4, - DividedBy6, - DividedBy8, - DividedBy10, - DividedBy12, - DividedBy16, - DividedBy32, - DividedBy64, - DividedBy128, - DividedBy256, +fn from_ker_ck(frequency: Hertz) -> Presc { + let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; + match raw_prescaler { + 0 => Presc::DIV1, + 1 => Presc::DIV2, + 2..=3 => Presc::DIV4, + 4..=5 => Presc::DIV6, + 6..=7 => Presc::DIV8, + 8..=9 => Presc::DIV10, + 10..=11 => Presc::DIV12, + _ => unimplemented!(), + } } -impl Prescaler { - fn from_ker_ck(frequency: Hertz) -> Self { - let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; - match raw_prescaler { - 0 => Self::NotDivided, - 1 => Self::DividedBy2, - 2..=3 => Self::DividedBy4, - 4..=5 => Self::DividedBy6, - 6..=7 => Self::DividedBy8, - 8..=9 => Self::DividedBy10, - 10..=11 => Self::DividedBy12, - _ => unimplemented!(), - } +impl super::SealedAnyInstance for T { + fn dr() -> *mut u16 { + T::regs().dr().as_ptr() as *mut u16 } - #[allow(unused)] - fn divisor(&self) -> u32 { - match self { - Prescaler::NotDivided => 1, - Prescaler::DividedBy2 => 2, - Prescaler::DividedBy4 => 4, - Prescaler::DividedBy6 => 6, - Prescaler::DividedBy8 => 8, - Prescaler::DividedBy10 => 10, - Prescaler::DividedBy12 => 12, - Prescaler::DividedBy16 => 16, - Prescaler::DividedBy32 => 32, - Prescaler::DividedBy64 => 64, - Prescaler::DividedBy128 => 128, - Prescaler::DividedBy256 => 256, + fn enable() { + T::regs().isr().modify(|w| w.set_adrdy(true)); + T::regs().cr().modify(|w| w.set_aden(true)); + // ADRDY is "ADC ready". Wait until it will be True. + while !T::regs().isr().read().adrdy() {} + } + + fn start() { + // Start conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + } + + fn stop() { + if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { + T::regs().cr().modify(|reg| { + reg.set_adstp(Adstp::STOP); + }); + while T::regs().cr().read().adstart() {} } + + // Reset configuration. + T::regs().cfgr1().modify(|reg| { + reg.set_cont(false); + reg.set_dmacfg(Dmacfg::from_bits(0)); + reg.set_dmaen(false); + }); } - fn presc(&self) -> Presc { - match self { - Prescaler::NotDivided => Presc::DIV1, - Prescaler::DividedBy2 => Presc::DIV2, - Prescaler::DividedBy4 => Presc::DIV4, - Prescaler::DividedBy6 => Presc::DIV6, - Prescaler::DividedBy8 => Presc::DIV8, - Prescaler::DividedBy10 => Presc::DIV10, - Prescaler::DividedBy12 => Presc::DIV12, - Prescaler::DividedBy16 => Presc::DIV16, - Prescaler::DividedBy32 => Presc::DIV32, - Prescaler::DividedBy64 => Presc::DIV64, - Prescaler::DividedBy128 => Presc::DIV128, - Prescaler::DividedBy256 => Presc::DIV256, + fn configure_dma(conversion_mode: super::ConversionMode) { + match conversion_mode { + ConversionMode::Singular => { + // Enable overrun control, so no new DMA requests will be generated until + // previous DR values is read. + T::regs().isr().modify(|reg| { + reg.set_ovr(true); + }); + + // Set continuous mode with oneshot dma. + T::regs().cfgr1().modify(|reg| { + reg.set_discen(false); + reg.set_cont(true); + reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT); + reg.set_dmaen(true); + reg.set_ovrmod(Ovrmod::PRESERVE); + }); + } } } -} -#[cfg(feature = "defmt")] -impl<'a> defmt::Format for Prescaler { - fn format(&self, fmt: defmt::Formatter) { - match self { - Prescaler::NotDivided => defmt::write!(fmt, "Prescaler::NotDivided"), - Prescaler::DividedBy2 => defmt::write!(fmt, "Prescaler::DividedBy2"), - Prescaler::DividedBy4 => defmt::write!(fmt, "Prescaler::DividedBy4"), - Prescaler::DividedBy6 => defmt::write!(fmt, "Prescaler::DividedBy6"), - Prescaler::DividedBy8 => defmt::write!(fmt, "Prescaler::DividedBy8"), - Prescaler::DividedBy10 => defmt::write!(fmt, "Prescaler::DividedBy10"), - Prescaler::DividedBy12 => defmt::write!(fmt, "Prescaler::DividedBy12"), - Prescaler::DividedBy16 => defmt::write!(fmt, "Prescaler::DividedBy16"), - Prescaler::DividedBy32 => defmt::write!(fmt, "Prescaler::DividedBy32"), - Prescaler::DividedBy64 => defmt::write!(fmt, "Prescaler::DividedBy64"), - Prescaler::DividedBy128 => defmt::write!(fmt, "Prescaler::DividedBy128"), - Prescaler::DividedBy256 => defmt::write!(fmt, "Prescaler::DividedBy256"), + fn configure_sequence(mut sequence: impl ExactSizeIterator, blocking: bool) { + T::regs().cfgr1().modify(|reg| { + reg.set_chselrmod(!blocking); + reg.set_align(Align::RIGHT); + }); + + assert!(!blocking || sequence.len() == 1, "Sequence len must be 1 for blocking."); + if blocking { + let ((ch, _), sample_time) = sequence.next().unwrap(); + // Set all channels to use SMP1 field as source. + T::regs().smpr().modify(|w| { + w.smpsel(0); + w.set_smp1(sample_time); + }); + + // write() because we want all other bits to be set to 0. + T::regs().chselr().write(|w| w.set_chsel(ch.into(), true)); + } else { + let mut hw_channel_selection: u32 = 0; + let mut is_ordered_up = true; + let mut is_ordered_down = true; + let mut needs_hw = false; + + assert!( + sequence.len() <= CHSELR_SQ_SIZE, + "Sequence read set cannot be more than {} in size.", + CHSELR_SQ_SIZE + ); + let mut last_sq_set: usize = 0; + let mut last_channel: u8 = 0; + T::regs().chselr_sq().write(|w| { + for (i, ((channel, _), _sample_time)) in sequence.enumerate() { + needs_hw = needs_hw || channel > CHSELR_SQ_MAX_CHANNEL; + last_sq_set = i; + is_ordered_up = is_ordered_up && channel > last_channel; + is_ordered_down = is_ordered_down && channel < last_channel; + hw_channel_selection += 1 << channel; + last_channel = channel; + + if !needs_hw { + w.set_sq(i, channel); + } + } + + assert!( + !needs_hw || is_ordered_up || is_ordered_down, + "Sequencer is required because of unordered channels, but only support HW channels smaller than {}.", + CHSELR_SQ_MAX_CHANNEL + ); + + if needs_hw { + assert!( + hw_channel_selection != 0, + "Some bits in `hw_channel_selection` shall be set." + ); + assert!( + (hw_channel_selection >> NUM_HW_CHANNELS) == 0, + "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.", + NUM_HW_CHANNELS + ); + + T::regs().cfgr1().modify(|reg| { + reg.set_chselrmod(false); + reg.set_scandir(if is_ordered_up { Scandir::UP} else { Scandir::BACK }); + }); + + // Set required channels for multi-convert. + unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) } + } else { + for i in (last_sq_set + 1)..CHSELR_SQ_SIZE { + w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER); + } + } + }); } + + // Trigger and wait for the channel selection procedure to complete. + T::regs().isr().modify(|w| w.set_ccrdy(false)); + while !T::regs().isr().read().ccrdy() {} + } + + fn convert() -> u16 { + // Set single conversion mode. + T::regs().cfgr1().modify(|w| w.set_cont(false)); + + // Start conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + + // Waiting for End Of Conversion (EOC). + while !T::regs().isr().read().eoc() {} + + T::regs().dr().read().data() as u16 } } -impl<'d, T: Instance> Adc<'d, T> { +impl<'d, T: AnyInstance> Adc<'d, T> { /// Create a new ADC driver. pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self { rcc::enable_and_reset::(); T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK)); - let prescaler = Prescaler::from_ker_ck(T::frequency()); - T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); + let prescaler = from_ker_ck(T::frequency()); + T::common_regs().ccr().modify(|w| w.set_presc(prescaler)); - let frequency = Hertz(T::frequency().0 / prescaler.divisor()); + let frequency = T::frequency() / prescaler; debug!("ADC frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { @@ -139,22 +217,6 @@ impl<'d, T: Instance> Adc<'d, T> { ); } - let mut s = Self { adc }; - - s.power_up(); - - s.set_resolution(resolution); - - s.calibrate(); - - s.enable(); - - s.configure_default(); - - s - } - - fn power_up(&mut self) { T::regs().cr().modify(|reg| { reg.set_advregen(true); }); @@ -162,9 +224,9 @@ impl<'d, T: Instance> Adc<'d, T> { // "The software must wait for the ADC voltage regulator startup time." // See datasheet for the value. blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US + 1); - } - fn calibrate(&mut self) { + T::regs().cfgr1().modify(|reg| reg.set_res(resolution)); + // We have to make sure AUTOFF is OFF, but keep its value after calibration. let autoff_value = T::regs().cfgr1().read().autoff(); T::regs().cfgr1().modify(|w| w.set_autoff(false)); @@ -178,22 +240,17 @@ impl<'d, T: Instance> Adc<'d, T> { debug!("ADC calibration value: {}.", T::regs().dr().read().data()); T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value)); - } - fn enable(&mut self) { - T::regs().isr().modify(|w| w.set_adrdy(true)); - T::regs().cr().modify(|w| w.set_aden(true)); - // ADRDY is "ADC ready". Wait until it will be True. - while !T::regs().isr().read().adrdy() {} - } + T::enable(); - fn configure_default(&mut self) { // single conversion mode, software trigger T::regs().cfgr1().modify(|w| { w.set_cont(false); w.set_exten(Exten::DISABLED); w.set_align(Align::RIGHT); }); + + Self { adc } } /// Enable reading the voltage reference internal channel. @@ -214,219 +271,4 @@ impl<'d, T: Instance> Adc<'d, T> { super::Temperature {} } - - /// Set the ADC sample time. - /// Shall only be called when ADC is not converting. - pub fn set_sample_time_all_channels(&mut self, sample_time: SampleTime) { - // Set all channels to use SMP1 field as source. - T::regs().smpr().modify(|w| { - w.smpsel(0); - w.set_smp1(sample_time); - }); - } - - /// Set the ADC resolution. - pub fn set_resolution(&mut self, resolution: Resolution) { - T::regs().cfgr1().modify(|reg| reg.set_res(resolution)); - } - - /// Perform a single conversion. - fn convert(&mut self) -> u16 { - // Set single conversion mode. - T::regs().cfgr1().modify(|w| w.set_cont(false)); - - // Start conversion - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); - - // Waiting for End Of Conversion (EOC). - while !T::regs().isr().read().eoc() {} - - T::regs().dr().read().data() as u16 - } - - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { - self.set_sample_time_all_channels(sample_time); - - Self::configure_channel(channel); - T::regs().cfgr1().write(|reg| { - reg.set_chselrmod(false); - reg.set_align(Align::RIGHT); - }); - self.convert() - } - - fn setup_channel_sequencer<'a>(channel_sequence: impl ExactSizeIterator>) { - assert!( - channel_sequence.len() <= CHSELR_SQ_SIZE, - "Seqenced read set cannot be more than {} in size.", - CHSELR_SQ_SIZE - ); - let mut last_sq_set: usize = 0; - T::regs().chselr_sq().write(|w| { - for (i, channel) in channel_sequence.enumerate() { - assert!( - channel.channel() <= CHSELR_SQ_MAX_CHANNEL, - "Sequencer only support HW channels smaller than {}.", - CHSELR_SQ_MAX_CHANNEL - ); - w.set_sq(i, channel.channel()); - last_sq_set = i; - } - - for i in (last_sq_set + 1)..CHSELR_SQ_SIZE { - w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER); - } - }); - - Self::apply_channel_conf() - } - - async fn dma_convert(&mut self, rx_dma: Peri<'_, impl RxDma>, readings: &mut [u16]) { - // Enable overrun control, so no new DMA requests will be generated until - // previous DR values is read. - T::regs().isr().modify(|reg| { - reg.set_ovr(true); - }); - - // Set continuous mode with oneshot dma. - T::regs().cfgr1().modify(|reg| { - reg.set_discen(false); - reg.set_cont(true); - reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT); - reg.set_dmaen(true); - reg.set_ovrmod(Ovrmod::PRESERVE); - }); - - let request = rx_dma.request(); - let transfer = unsafe { - Transfer::new_read( - rx_dma, - request, - T::regs().dr().as_ptr() as *mut u16, - readings, - Default::default(), - ) - }; - - // Start conversion. - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); - - // Wait for conversion sequence to finish. - transfer.await; - - // Ensure conversions are finished. - Self::cancel_conversions(); - - // Reset configuration. - T::regs().cfgr1().modify(|reg| { - reg.set_cont(false); - reg.set_dmacfg(Dmacfg::from_bits(0)); - reg.set_dmaen(false); - }); - } - - /// Read one or multiple ADC channels using DMA in hardware order. - /// Readings will be ordered based on **hardware** ADC channel number and `scandir` setting. - /// Readings won't be in the same order as in the `set`! - /// - /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use - /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0). - /// TODO(chudsaviet): externalize generic code and merge with read(). - pub async fn read_in_hw_order( - &mut self, - rx_dma: Peri<'_, impl RxDma>, - hw_channel_selection: u32, - scandir: Scandir, - readings: &mut [u16], - ) { - assert!( - hw_channel_selection != 0, - "Some bits in `hw_channel_selection` shall be set." - ); - assert!( - (hw_channel_selection >> NUM_HW_CHANNELS) == 0, - "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.", - NUM_HW_CHANNELS - ); - // To check for correct readings slice size, we shall solve Hamming weight problem, - // which is either slow or memory consuming. - // Since we have limited resources, we don't do it here. - // Not doing this have a great potential for a bug through. - - // Ensure no conversions are ongoing. - Self::cancel_conversions(); - - T::regs().cfgr1().modify(|reg| { - reg.set_chselrmod(false); - reg.set_scandir(scandir); - reg.set_align(Align::RIGHT); - }); - - // Set required channels for multi-convert. - unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) } - - Self::apply_channel_conf(); - - self.dma_convert(rx_dma, readings).await - } - - // Read ADC channels in specified order using DMA (CHSELRMOD = 1). - // In STM32C0, only lower 14 ADC channels can be read this way. - // For other channels, use `read_in_hw_order()` or blocking read. - pub async fn read( - &mut self, - rx_dma: Peri<'_, impl RxDma>, - channel_sequence: impl ExactSizeIterator>, - readings: &mut [u16], - ) { - assert!( - channel_sequence.len() != 0, - "Asynchronous read channel sequence cannot be empty." - ); - assert!( - channel_sequence.len() == readings.len(), - "Channel sequence length must be equal to readings length." - ); - - // Ensure no conversions are ongoing. - Self::cancel_conversions(); - - T::regs().cfgr1().modify(|reg| { - reg.set_chselrmod(true); - reg.set_align(Align::RIGHT); - }); - - Self::setup_channel_sequencer(channel_sequence); - - self.dma_convert(rx_dma, readings).await - } - - fn configure_channel(channel: &mut impl AdcChannel) { - channel.setup(); - // write() because we want all other bits to be set to 0. - T::regs() - .chselr() - .write(|w| w.set_chsel(channel.channel().into(), true)); - - Self::apply_channel_conf(); - } - - fn apply_channel_conf() { - // Trigger and wait for the channel selection procedure to complete. - T::regs().isr().modify(|w| w.set_ccrdy(false)); - while !T::regs().isr().read().ccrdy() {} - } - - fn cancel_conversions() { - if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { - T::regs().cr().modify(|reg| { - reg.set_adstp(Adstp::STOP); - }); - while T::regs().cr().read().adstart() {} - } - } } diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index fd5b94224..549f2f5a5 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -88,30 +88,37 @@ pub(crate) trait SealedAdcChannel { } // Temporary patch for ADCs that have not implemented the standard iface yet -#[cfg(any(adc_v1, adc_l0, adc_f1, adc_f3v1, adc_f3v2, adc_f3v3, adc_v1, adc_c0))] +#[cfg(any(adc_v1, adc_l0, adc_f1, adc_f3v1, adc_f3v2, adc_f3v3, adc_v1))] trait_set::trait_set! { pub trait AnyInstance = Instance; } -#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] +#[cfg(any( + adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 +))] pub trait BasicAnyInstance { type SampleTime; } -#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] +#[cfg(any( + adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 +))] pub(self) trait SealedAnyInstance: BasicAnyInstance { fn enable(); fn start(); fn stop(); fn convert() -> u16; fn configure_dma(conversion_mode: ConversionMode); + #[cfg(not(adc_c0))] fn configure_sequence(sequence: impl ExactSizeIterator); + #[cfg(adc_c0)] + fn configure_sequence(sequence: impl ExactSizeIterator, blocking: bool); #[allow(dead_code)] fn dr() -> *mut u16; } // On chips without ADC4, AnyInstance is an Instance -#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4))] +#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4, adc_c0))] #[allow(private_bounds)] pub trait AnyInstance: SealedAnyInstance + Instance {} @@ -121,12 +128,16 @@ pub trait AnyInstance: SealedAnyInstance + Instance {} pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {} // Implement AnyInstance automatically for SealedAnyInstance -#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] +#[cfg(any( + adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 +))] impl BasicAnyInstance for T { type SampleTime = SampleTime; } -#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] +#[cfg(any( + adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 +))] impl AnyInstance for T {} /// Performs a busy-wait delay for a specified number of microseconds. @@ -167,10 +178,12 @@ pub enum Averaging { Samples1024, } -#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] +#[cfg(any( + adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0 +))] pub(crate) enum ConversionMode { // Should match the cfg on "read" below - #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] + #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] Singular, // Should match the cfg on "into_ring_buffered" below #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] @@ -190,7 +203,9 @@ pub enum RegularConversionMode { } impl<'d, T: AnyInstance> Adc<'d, T> { - #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba))] + #[cfg(any( + adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba, adc_c0 + ))] /// Read an ADC pin. pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: T::SampleTime) -> u16 { #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] @@ -198,12 +213,18 @@ impl<'d, T: AnyInstance> Adc<'d, T> { #[cfg(not(adc_v4))] T::enable(); + #[cfg(not(adc_c0))] T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); + #[cfg(adc_c0)] + T::configure_sequence( + [((channel.channel(), channel.is_differential()), sample_time)].into_iter(), + true, + ); T::convert() } - #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] + #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] /// Read one or multiple ADC regular channels using DMA. /// /// `sequence` iterator and `readings` must have the same length. @@ -232,6 +253,11 @@ impl<'d, T: AnyInstance> Adc<'d, T> { /// /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use /// `into_ring_buffered`, `into_ring_buffered_and_injected` + /// + /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use + /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0). + /// + /// In addtion, on STM320, this method will panic if the channels are not passed in order pub async fn read( &mut self, rx_dma: embassy_hal_internal::Peri<'_, impl RxDma>, @@ -252,8 +278,15 @@ impl<'d, T: AnyInstance> Adc<'d, T> { T::stop(); T::enable(); + #[cfg(not(adc_c0))] + T::configure_sequence( + sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), + ); + + #[cfg(adc_c0)] T::configure_sequence( sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), + false, ); T::configure_dma(ConversionMode::Singular); diff --git a/examples/stm32c0/src/bin/adc.rs b/examples/stm32c0/src/bin/adc.rs index b52c9e7f8..ad597b63c 100644 --- a/examples/stm32c0/src/bin/adc.rs +++ b/examples/stm32c0/src/bin/adc.rs @@ -3,7 +3,6 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::vals::Scandir; use embassy_stm32::adc::{Adc, AdcChannel, AnyAdcChannel, Resolution, SampleTime}; use embassy_stm32::peripherals::ADC1; use embassy_time::Timer; @@ -35,8 +34,12 @@ async fn main(_spawner: Spawner) { blocking_vref, blocking_temp, blocing_pin0 ); - let channels_seqence: [&mut AnyAdcChannel; 3] = [&mut vref, &mut temp, &mut pin0]; - adc.read(dma.reborrow(), channels_seqence.into_iter(), &mut read_buffer) + let channels_sequence: [(&mut AnyAdcChannel, SampleTime); 3] = [ + (&mut vref, SampleTime::CYCLES12_5), + (&mut temp, SampleTime::CYCLES12_5), + (&mut pin0, SampleTime::CYCLES12_5), + ]; + adc.read(dma.reborrow(), channels_sequence.into_iter(), &mut read_buffer) .await; // Values are ordered according to hardware ADC channel number! info!( @@ -44,15 +47,6 @@ async fn main(_spawner: Spawner) { read_buffer[0], read_buffer[1], read_buffer[2] ); - let hw_channel_selection: u32 = - (1 << temp.get_hw_channel()) + (1 << vref.get_hw_channel()) + (1 << pin0.get_hw_channel()); - adc.read_in_hw_order(dma.reborrow(), hw_channel_selection, Scandir::UP, &mut read_buffer) - .await; - info!( - "DMA ADC read in hardware order: vref = {}, temp = {}, pin0 = {}.", - read_buffer[2], read_buffer[1], read_buffer[0] - ); - Timer::after_millis(2000).await; } } -- cgit From de16754a2d340eca49885238e265f50bfc3ec2e5 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Thu, 13 Nov 2025 21:18:12 +0100 Subject: stm32/i2c: Fix async write_vectored and restore DMA implementation --- embassy-stm32/src/i2c/v2.rs | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 7bcfa00b0..c35f3694c 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -389,7 +389,9 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { loop { let isr = self.info.regs.isr().read(); self.error_occurred(&isr, timeout)?; - if isr.tc() { + // Wait for either TC or TCR - both indicate transfer completion + // TCR occurs when RELOAD=1, TC occurs when RELOAD=0 + if isr.tc() || isr.tcr() { return Ok(()); } timeout.check()?; @@ -918,12 +920,12 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { address, total_len.min(255), Stop::Software, - total_len > 255, + (total_len > 255) || !last_slice, restart, timeout, )?; } else { - Self::reload(self.info, total_len.min(255), total_len > 255, Stop::Software, timeout)?; + Self::reload(self.info, total_len.min(255), (total_len > 255) || !last_slice, Stop::Software, timeout)?; self.info.regs.cr1().modify(|w| w.set_tcie(true)); } } else if !(isr.tcr() || isr.tc()) { @@ -935,7 +937,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { if let Err(e) = Self::reload( self.info, remaining_len.min(255), - remaining_len > 255, + (remaining_len > 255) || !last_slice, Stop::Software, timeout, ) { @@ -1085,10 +1087,35 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { #[cfg(all(feature = "low-power", stm32wlex))] let _device_busy = crate::low_power::DeviceBusy::new_stop1(); + let timeout = self.timeout(); - // For now, use blocking implementation for write_vectored - // This avoids complexity of handling multiple non-contiguous buffers with DMA - self.blocking_write_vectored((address.addr() & 0xFF) as u8, write) + if write.is_empty() { + return Err(Error::ZeroLengthTransfer); + } + + let mut iter = write.iter(); + let mut first = true; + let mut current = iter.next(); + + while let Some(c) = current { + let next = iter.next(); + let is_last = next.is_none(); + + let fut = self.write_dma_internal( + address, + c, + first, // first_slice + is_last, // last_slice + is_last, // send_stop (only on last buffer) + false, // restart (false for all - they're one continuous write) + timeout, + ); + timeout.with(fut).await?; + + first = false; + current = next; + } + Ok(()) } /// Read. -- cgit From 42f38d5b3209134baa8bf424cdb754e1901ac0da Mon Sep 17 00:00:00 2001 From: HybridChild Date: Thu, 13 Nov 2025 21:23:13 +0100 Subject: stm32/i2c: Implement async DMA for transaction write groups --- embassy-stm32/src/i2c/v2.rs | 50 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index c35f3694c..8f51627ff 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -1222,9 +1222,53 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { is_last_group: bool, timeout: Timeout, ) -> Result<(), Error> { - // For now, use blocking implementation for write groups - // This avoids complexity of handling multiple non-contiguous buffers with DMA - self.execute_write_group(address, operations, is_first_group, is_last_group, timeout) + // Calculate total bytes across all operations in this group + let total_bytes = Self::total_operation_bytes(operations); + + if total_bytes == 0 { + // Handle empty write group using blocking call + if is_first_group { + Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?; + } + if is_last_group { + self.master_stop(); + } + return Ok(()); + } + + // Collect all write buffers + let mut write_buffers: heapless::Vec<&[u8], 16> = heapless::Vec::new(); + for operation in operations { + if let Operation::Write(buffer) = operation { + if !buffer.is_empty() { + let _ = write_buffers.push(buffer); + } + } + } + + if write_buffers.is_empty() { + return Ok(()); + } + + // Send each buffer using DMA + let num_buffers = write_buffers.len(); + for (idx, buffer) in write_buffers.iter().enumerate() { + let is_first_buffer = idx == 0; + let is_last_buffer = idx == num_buffers - 1; + + let fut = self.write_dma_internal( + address, + buffer, + is_first_buffer, // first_slice + is_last_buffer, // last_slice + is_last_buffer && is_last_group, // send_stop + is_first_buffer && !is_first_group, // restart (only for first buffer if not first group) + timeout, + ); + timeout.with(fut).await?; + } + + Ok(()) } async fn execute_read_group_async( -- cgit From 82dcaf118100c883a95397e3f9867a4043a4de7b Mon Sep 17 00:00:00 2001 From: HybridChild Date: Thu, 13 Nov 2025 21:24:09 +0100 Subject: stm32: Run cargo fmt --- embassy-stm32/src/i2c/v2.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 8f51627ff..61e550ad4 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -925,7 +925,13 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { timeout, )?; } else { - Self::reload(self.info, total_len.min(255), (total_len > 255) || !last_slice, Stop::Software, timeout)?; + Self::reload( + self.info, + total_len.min(255), + (total_len > 255) || !last_slice, + Stop::Software, + timeout, + )?; self.info.regs.cr1().modify(|w| w.set_tcie(true)); } } else if !(isr.tcr() || isr.tc()) { @@ -1102,12 +1108,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { let is_last = next.is_none(); let fut = self.write_dma_internal( - address, - c, - first, // first_slice - is_last, // last_slice - is_last, // send_stop (only on last buffer) - false, // restart (false for all - they're one continuous write) + address, c, first, // first_slice + is_last, // last_slice + is_last, // send_stop (only on last buffer) + false, // restart (false for all - they're one continuous write) timeout, ); timeout.with(fut).await?; -- cgit From 64b9c28eca4822a3ba1bd07d20964c2291c01cf5 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 13 Nov 2025 14:42:14 -0600 Subject: stm32: extract block_for_us remove from pub api --- embassy-stm32/src/adc/c0.rs | 2 +- embassy-stm32/src/adc/f1.rs | 4 ++-- embassy-stm32/src/adc/f3.rs | 2 +- embassy-stm32/src/adc/mod.rs | 20 ++------------------ embassy-stm32/src/dsihost.rs | 17 +++++------------ embassy-stm32/src/eth/generic_phy.rs | 14 +------------- embassy-stm32/src/lib.rs | 14 ++++++++++++++ embassy-stm32/src/opamp.rs | 13 +++---------- examples/stm32f469/src/bin/dsi_bsp.rs | 14 +++++++------- 9 files changed, 36 insertions(+), 64 deletions(-) diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index 983e7c10d..3bdca7edb 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs @@ -223,7 +223,7 @@ impl<'d, T: AnyInstance> Adc<'d, T> { // "The software must wait for the ADC voltage regulator startup time." // See datasheet for the value. - blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US + 1); + blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US as u64 + 1); T::regs().cfgr1().modify(|reg| reg.set_res(resolution)); diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index f6220de78..d6c6f480b 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -43,7 +43,7 @@ impl<'d, T: Instance> Adc<'d, T> { // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) // for at least two ADC clock cycles. - blocking_delay_us((1_000_000 * 2) / Self::freq().0 + 1); + blocking_delay_us((1_000_000 * 2) / Self::freq().0 as u64 + 1); // Reset calibration T::regs().cr2().modify(|reg| reg.set_rstcal(true)); @@ -58,7 +58,7 @@ impl<'d, T: Instance> Adc<'d, T> { } // One cycle after calibration - blocking_delay_us((1_000_000 * 1) / Self::freq().0 + 1); + blocking_delay_us((1_000_000 * 1) / Self::freq().0 as u64 + 1); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 4a77f3c5b..29bfdac97 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -62,7 +62,7 @@ impl<'d, T: Instance> Adc<'d, T> { while T::regs().cr().read().adcal() {} // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223). - blocking_delay_us((1_000_000 * 4) / Self::freq().0 + 1); + blocking_delay_us((1_000_000 * 4) / Self::freq().0 as u64 + 1); // Enable the adc T::regs().cr().modify(|w| w.set_aden(true)); diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 549f2f5a5..5ec08a22d 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -35,6 +35,8 @@ pub use ringbuffered::RingBufferedAdc; #[path = "adc4.rs"] pub mod adc4; +#[allow(unused)] +pub(self) use crate::block_for_us as blocking_delay_us; pub use crate::pac::adc::vals; #[cfg(not(any(adc_f1, adc_f3v3)))] pub use crate::pac::adc::vals::Res as Resolution; @@ -140,24 +142,6 @@ impl BasicAnyInstance for T { ))] impl AnyInstance for T {} -/// Performs a busy-wait delay for a specified number of microseconds. -#[allow(unused)] -pub(crate) fn blocking_delay_us(us: u32) { - cfg_if::cfg_if! { - // this does strange things on stm32wlx in low power mode depending on exactly when it's called - // as in sometimes 15 us (1 tick) would take > 20 seconds. - if #[cfg(all(feature = "time", all(not(feature = "low-power"), not(stm32wlex))))] { - let duration = embassy_time::Duration::from_micros(us as u64); - embassy_time::block_for(duration); - } else { - let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64; - let us = us as u64; - let cycles = freq * us / 1_000_000; - cortex_m::asm::delay(cycles as u32); - } - } -} - #[cfg(any(adc_c0, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] /// Number of samples used for averaging. #[derive(Copy, Clone, Debug)] diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs index 59a2cbcdb..b8945820c 100644 --- a/embassy-stm32/src/dsihost.rs +++ b/embassy-stm32/src/dsihost.rs @@ -5,18 +5,11 @@ use core::marker::PhantomData; use embassy_hal_internal::PeripheralType; //use crate::gpio::{AnyPin, SealedPin}; +use crate::block_for_us; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::rcc::{self, RccPeripheral}; use crate::{Peri, peripherals}; -/// Performs a busy-wait delay for a specified number of microseconds. -pub fn blocking_delay_ms(ms: u32) { - #[cfg(feature = "time")] - embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64)); - #[cfg(not(feature = "time"))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000 * ms); -} - /// PacketTypes extracted from CubeMX #[repr(u8)] #[allow(dead_code)] @@ -334,7 +327,7 @@ impl<'d, T: Instance> DsiHost<'d, T> { if T::regs().gpsr().read().cmdfe() { return Ok(()); } - blocking_delay_ms(1); + block_for_us(1_000); } Err(Error::FifoTimeout) } @@ -345,7 +338,7 @@ impl<'d, T: Instance> DsiHost<'d, T> { if !T::regs().gpsr().read().cmdff() { return Ok(()); } - blocking_delay_ms(1); + block_for_us(1_000); } Err(Error::FifoTimeout) } @@ -356,7 +349,7 @@ impl<'d, T: Instance> DsiHost<'d, T> { if !self.read_busy() { return Ok(()); } - blocking_delay_ms(1); + block_for_us(1_000); } Err(Error::ReadTimeout) } @@ -367,7 +360,7 @@ impl<'d, T: Instance> DsiHost<'d, T> { if !T::regs().gpsr().read().prdfe() { return Ok(()); } - blocking_delay_ms(1); + block_for_us(1_000); } Err(Error::FifoTimeout) } diff --git a/embassy-stm32/src/eth/generic_phy.rs b/embassy-stm32/src/eth/generic_phy.rs index 774beef80..947874d7f 100644 --- a/embassy-stm32/src/eth/generic_phy.rs +++ b/embassy-stm32/src/eth/generic_phy.rs @@ -8,6 +8,7 @@ use embassy_time::{Duration, Timer}; use futures_util::FutureExt; use super::{Phy, StationManagement}; +use crate::block_for_us as blocking_delay_us; #[allow(dead_code)] mod phy_consts { @@ -76,19 +77,6 @@ impl GenericPhy { } } -// TODO: Factor out to shared functionality -fn blocking_delay_us(us: u32) { - #[cfg(feature = "time")] - embassy_time::block_for(Duration::from_micros(us as u64)); - #[cfg(not(feature = "time"))] - { - let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64; - let us = us as u64; - let cycles = freq * us / 1_000_000; - cortex_m::asm::delay(cycles as u32); - } -} - impl Phy for GenericPhy { fn phy_reset(&mut self, sm: &mut S) { // Detect SMI address diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 680edf433..6e492946a 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -658,3 +658,17 @@ fn init_hw(config: Config) -> Peripherals { p }) } + +/// Performs a busy-wait delay for a specified number of microseconds. +#[allow(unused)] +pub(crate) fn block_for_us(us: u64) { + cfg_if::cfg_if! { + // this does strange things on stm32wlx in low power mode depending on exactly when it's called + // as in sometimes 15 us (1 tick) would take > 20 seconds. + if #[cfg(all(feature = "time", all(not(feature = "low-power"), not(stm32wlex))))] { + embassy_time::block_for(embassy_time::Duration::from_micros(us)); + } else { + cortex_m::asm::delay(unsafe { rcc::get_freqs().sys.to_hertz().unwrap().0 as u64 * us / 1_000_000 } as u32); + } + } +} diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index ac8d5de21..4a55f5bd3 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -4,19 +4,12 @@ use embassy_hal_internal::PeripheralType; use crate::Peri; +#[cfg(opamp_v5)] +use crate::block_for_us; use crate::pac::opamp::vals::*; #[cfg(not(any(stm32g4, stm32f3)))] use crate::rcc::RccInfo; -/// Performs a busy-wait delay for a specified number of microseconds. -#[cfg(opamp_v5)] -fn blocking_delay_ms(ms: u32) { - #[cfg(feature = "time")] - embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64)); - #[cfg(not(feature = "time"))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000 * ms); -} - /// Gain #[allow(missing_docs)] #[derive(Clone, Copy)] @@ -439,7 +432,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { // The closer the trimming value is to the optimum trimming value, the longer it takes to stabilize // (with a maximum stabilization time remaining below 2 ms in any case) -- RM0440 25.3.7 - blocking_delay_ms(2); + block_for_us(2_000); if !T::regs().csr().read().calout() { if mid == 0 { diff --git a/examples/stm32f469/src/bin/dsi_bsp.rs b/examples/stm32f469/src/bin/dsi_bsp.rs index d659291ff..7ba4da72b 100644 --- a/examples/stm32f469/src/bin/dsi_bsp.rs +++ b/examples/stm32f469/src/bin/dsi_bsp.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dsihost::{DsiHost, PacketType, blocking_delay_ms}; +use embassy_stm32::dsihost::{DsiHost, PacketType}; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::ltdc::Ltdc; use embassy_stm32::pac::dsihost::regs::{Ier0, Ier1}; @@ -13,7 +13,7 @@ use embassy_stm32::rcc::{ AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllMul, PllPDiv, PllPreDiv, PllQDiv, PllRDiv, PllSource, Sysclk, }; use embassy_stm32::time::mhz; -use embassy_time::Timer; +use embassy_time::{Duration, Timer, block_for}; use {defmt_rtt as _, panic_probe as _}; enum _Orientation { @@ -444,7 +444,7 @@ async fn main(_spawner: Spawner) { dsi.enable_wrapper_dsi(); // First, delay 120 ms (reason unknown, STM32 Cube Example does it) - blocking_delay_ms(120); + block_for(Duration::from_millis(120)); // 1 to 26 dsi.write_cmd(0, NT35510_WRITES_0[0], &NT35510_WRITES_0[1..]).unwrap(); @@ -480,7 +480,7 @@ async fn main(_spawner: Spawner) { dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap(); // Add a delay, otherwise MADCTL not taken - blocking_delay_ms(200); + block_for(Duration::from_millis(200)); // Configure orientation as landscape dsi.write_cmd(0, NT35510_MADCTL_LANDSCAPE[0], &NT35510_MADCTL_LANDSCAPE[1..]) @@ -494,7 +494,7 @@ async fn main(_spawner: Spawner) { dsi.write_cmd(0, NT35510_WRITES_27[0], &NT35510_WRITES_27[1..]).unwrap(); // Wait for sleep out exit - blocking_delay_ms(120); + block_for(Duration::from_millis(120)); // Configure COLOR_CODING dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap(); @@ -590,7 +590,7 @@ async fn main(_spawner: Spawner) { //LTDC->SRCR = LTDC_SRCR_IMR; LTDC.srcr().modify(|w| w.set_imr(Imr::RELOAD)); - blocking_delay_ms(5000); + block_for(Duration::from_millis(5000)); const READ_SIZE: u16 = 1; let mut data = [1u8; READ_SIZE as usize]; @@ -606,7 +606,7 @@ async fn main(_spawner: Spawner) { .unwrap(); info!("Display ID3: {:#04x}", data); - blocking_delay_ms(500); + block_for(Duration::from_millis(500)); info!("Config done, start blinking LED"); loop { -- cgit From 4fb60b5991c4c98427ef23e6c011210341ba09e1 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 13 Nov 2025 17:41:20 -0600 Subject: fix async adc for h5 and others closes #4882. --- embassy-stm32/src/adc/v3.rs | 47 ++++++++++++++++--------------------- examples/stm32h5/src/bin/adc_dma.rs | 9 +++++-- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 4cce1dac3..ba1afbe05 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -189,38 +189,31 @@ impl super::SealedAnyInstance for T { } fn start() { - #[cfg(any(adc_v3, adc_g0, adc_u0))] - { - // Start adc conversion - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); - } + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); } fn stop() { - #[cfg(any(adc_v3, adc_g0, adc_u0))] - { - // Ensure conversions are finished. - if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { - T::regs().cr().modify(|reg| { - reg.set_adstp(true); - }); - while T::regs().cr().read().adstart() {} - } - - // Reset configuration. - #[cfg(not(any(adc_g0, adc_u0)))] - T::regs().cfgr().modify(|reg| { - reg.set_cont(false); - reg.set_dmaen(false); - }); - #[cfg(any(adc_g0, adc_u0))] - T::regs().cfgr1().modify(|reg| { - reg.set_cont(false); - reg.set_dmaen(false); + // Ensure conversions are finished. + if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { + T::regs().cr().modify(|reg| { + reg.set_adstp(true); }); + while T::regs().cr().read().adstart() {} } + + // Reset configuration. + #[cfg(not(any(adc_g0, adc_u0)))] + T::regs().cfgr().modify(|reg| { + reg.set_cont(false); + reg.set_dmaen(false); + }); + #[cfg(any(adc_g0, adc_u0))] + T::regs().cfgr1().modify(|reg| { + reg.set_cont(false); + reg.set_dmaen(false); + }); } /// Perform a single conversion. diff --git a/examples/stm32h5/src/bin/adc_dma.rs b/examples/stm32h5/src/bin/adc_dma.rs index fb9fcbc5c..2138257f7 100644 --- a/examples/stm32h5/src/bin/adc_dma.rs +++ b/examples/stm32h5/src/bin/adc_dma.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::adc::{self, Adc, AdcChannel, RxDma, SampleTime}; use embassy_stm32::peripherals::{ADC1, ADC2, GPDMA1_CH0, GPDMA1_CH1, PA0, PA1, PA2, PA3}; use embassy_stm32::{Config, Peri}; -use embassy_time::Instant; +use embassy_time::{Duration, Instant, Ticker}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -76,6 +76,9 @@ async fn adc_task<'a, T: adc::Instance>( let mut pin1 = pin1.degrade_adc(); let mut pin2 = pin2.degrade_adc(); + info!("adc init"); + + let mut ticker = Ticker::every(Duration::from_millis(500)); let mut tic = Instant::now(); let mut buffer = [0u16; 512]; loop { @@ -84,11 +87,13 @@ async fn adc_task<'a, T: adc::Instance>( adc.read( dma.reborrow(), [(&mut pin1, SampleTime::CYCLES2_5), (&mut pin2, SampleTime::CYCLES2_5)].into_iter(), - &mut buffer, + &mut buffer[0..2], ) .await; let toc = Instant::now(); info!("\n adc1: {} dt = {}", buffer[0..16], (toc - tic).as_micros()); tic = toc; + + ticker.next().await; } } -- cgit From 945ed1200957d9a4265cc5ac811ee39dce132317 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 13 Nov 2025 19:47:29 -0600 Subject: adc: fix c0 algorithm --- embassy-stm32/src/adc/c0.rs | 122 +++++++++++++++++++------------------------ embassy-stm32/src/adc/mod.rs | 16 ------ 2 files changed, 53 insertions(+), 85 deletions(-) diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index 3bdca7edb..d87bd1ed4 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs @@ -1,7 +1,7 @@ #[allow(unused)] use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; use pac::adccommon::vals::Presc; -use stm32_metapac::adc::vals::Scandir; +use stm32_metapac::adc::vals::{SampleTime, Scandir}; use super::{Adc, Instance, Resolution, blocking_delay_us}; use crate::adc::{AnyInstance, ConversionMode}; @@ -17,7 +17,6 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(25); const TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US: u32 = 20; -const NUM_HW_CHANNELS: u8 = 22; const CHSELR_SQ_SIZE: usize = 8; const CHSELR_SQ_MAX_CHANNEL: u8 = 14; const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111; @@ -100,82 +99,67 @@ impl super::SealedAnyInstance for T { } } - fn configure_sequence(mut sequence: impl ExactSizeIterator, blocking: bool) { - T::regs().cfgr1().modify(|reg| { - reg.set_chselrmod(!blocking); - reg.set_align(Align::RIGHT); - }); + fn configure_sequence(sequence: impl ExactSizeIterator) { + let mut needs_hw = sequence.len() == 1 || sequence.len() > CHSELR_SQ_SIZE; + let mut is_ordered_up = true; + let mut is_ordered_down = true; - assert!(!blocking || sequence.len() == 1, "Sequence len must be 1 for blocking."); - if blocking { - let ((ch, _), sample_time) = sequence.next().unwrap(); - // Set all channels to use SMP1 field as source. - T::regs().smpr().modify(|w| { - w.smpsel(0); - w.set_smp1(sample_time); - }); + let sequence_len = sequence.len(); + let mut hw_channel_selection: u32 = 0; + let mut last_channel: u8 = 0; + let mut sample_time: Self::SampleTime = SampleTime::CYCLES2_5; + + T::regs().chselr_sq().write(|w| { + for (i, ((channel, _), _sample_time)) in sequence.enumerate() { + assert!( + sample_time == _sample_time || i == 0, + "C0 only supports one sample time for the sequence." + ); - // write() because we want all other bits to be set to 0. - T::regs().chselr().write(|w| w.set_chsel(ch.into(), true)); - } else { - let mut hw_channel_selection: u32 = 0; - let mut is_ordered_up = true; - let mut is_ordered_down = true; - let mut needs_hw = false; + sample_time = _sample_time; + needs_hw = needs_hw || channel > CHSELR_SQ_MAX_CHANNEL; + is_ordered_up = is_ordered_up && (channel > last_channel || i == 0); + is_ordered_down = is_ordered_down && (channel < last_channel || i == 0); + hw_channel_selection += 1 << channel; + last_channel = channel; + if !needs_hw { + w.set_sq(i, channel); + } + } + + for i in sequence_len..CHSELR_SQ_SIZE { + w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER); + } + }); + + if needs_hw { assert!( - sequence.len() <= CHSELR_SQ_SIZE, - "Sequence read set cannot be more than {} in size.", + sequence_len <= CHSELR_SQ_SIZE || is_ordered_up || is_ordered_down, + "Sequencer is required because of unordered channels, but read set cannot be more than {} in size.", CHSELR_SQ_SIZE ); - let mut last_sq_set: usize = 0; - let mut last_channel: u8 = 0; - T::regs().chselr_sq().write(|w| { - for (i, ((channel, _), _sample_time)) in sequence.enumerate() { - needs_hw = needs_hw || channel > CHSELR_SQ_MAX_CHANNEL; - last_sq_set = i; - is_ordered_up = is_ordered_up && channel > last_channel; - is_ordered_down = is_ordered_down && channel < last_channel; - hw_channel_selection += 1 << channel; - last_channel = channel; - - if !needs_hw { - w.set_sq(i, channel); - } - } - - assert!( - !needs_hw || is_ordered_up || is_ordered_down, - "Sequencer is required because of unordered channels, but only support HW channels smaller than {}.", - CHSELR_SQ_MAX_CHANNEL - ); + assert!( + sequence_len > CHSELR_SQ_SIZE || is_ordered_up || is_ordered_down, + "Sequencer is required because of unordered channels, but only support HW channels smaller than {}.", + CHSELR_SQ_MAX_CHANNEL + ); - if needs_hw { - assert!( - hw_channel_selection != 0, - "Some bits in `hw_channel_selection` shall be set." - ); - assert!( - (hw_channel_selection >> NUM_HW_CHANNELS) == 0, - "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.", - NUM_HW_CHANNELS - ); - - T::regs().cfgr1().modify(|reg| { - reg.set_chselrmod(false); - reg.set_scandir(if is_ordered_up { Scandir::UP} else { Scandir::BACK }); - }); - - // Set required channels for multi-convert. - unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) } - } else { - for i in (last_sq_set + 1)..CHSELR_SQ_SIZE { - w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER); - } - } - }); + // Set required channels for multi-convert. + unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) } } + T::regs().smpr().modify(|w| { + w.smpsel(0); + w.set_smp1(sample_time); + }); + + T::regs().cfgr1().modify(|reg| { + reg.set_chselrmod(!needs_hw); + reg.set_align(Align::RIGHT); + reg.set_scandir(if is_ordered_up { Scandir::UP } else { Scandir::BACK }); + }); + // Trigger and wait for the channel selection procedure to complete. T::regs().isr().modify(|w| w.set_ccrdy(false)); while !T::regs().isr().read().ccrdy() {} diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 5ec08a22d..13f8a1544 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -111,10 +111,7 @@ pub(self) trait SealedAnyInstance: BasicAnyInstance { fn stop(); fn convert() -> u16; fn configure_dma(conversion_mode: ConversionMode); - #[cfg(not(adc_c0))] fn configure_sequence(sequence: impl ExactSizeIterator); - #[cfg(adc_c0)] - fn configure_sequence(sequence: impl ExactSizeIterator, blocking: bool); #[allow(dead_code)] fn dr() -> *mut u16; } @@ -197,13 +194,7 @@ impl<'d, T: AnyInstance> Adc<'d, T> { #[cfg(not(adc_v4))] T::enable(); - #[cfg(not(adc_c0))] T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); - #[cfg(adc_c0)] - T::configure_sequence( - [((channel.channel(), channel.is_differential()), sample_time)].into_iter(), - true, - ); T::convert() } @@ -262,15 +253,8 @@ impl<'d, T: AnyInstance> Adc<'d, T> { T::stop(); T::enable(); - #[cfg(not(adc_c0))] - T::configure_sequence( - sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), - ); - - #[cfg(adc_c0)] T::configure_sequence( sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), - false, ); T::configure_dma(ConversionMode::Singular); -- cgit From 7e5cd16ca79cf36d2c28c7e2fe35642a27f18b72 Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Thu, 13 Nov 2025 14:51:00 +0100 Subject: correcting channel on interval Vbat, adding Vbat resistor disable to preserve current when not sampling. --- embassy-stm32/src/adc/v3.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 78b497727..c65357aff 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -65,7 +65,7 @@ impl super::SealedSpecialConverter for T { } #[cfg(any(adc_h5, adc_h7rs))] impl super::SealedSpecialConverter for T { - const CHANNEL: u8 = 2; + const CHANNEL: u8 = 16; } #[cfg(adc_u0)] impl super::SealedSpecialConverter for T { @@ -82,7 +82,7 @@ cfg_if! { impl super::AdcChannel for VddCore {} impl super::SealedAdcChannel for VddCore { fn channel(&self) -> u8 { - 6 + 17 } } } @@ -582,6 +582,24 @@ impl<'d, T: Instance> Adc<'d, T> { Vbat {} } + pub fn disable_vbat(&self) { + cfg_if! { + if #[cfg(any(adc_g0, adc_u0))] { + T::regs().ccr().modify(|reg| { + reg.set_vbaten(false); + }); + } else if #[cfg(any(adc_h5, adc_h7rs))] { + T::common_regs().ccr().modify(|reg| { + reg.set_vbaten(false); + }); + } else { + T::common_regs().ccr().modify(|reg| { + reg.set_ch18sel(false); + }); + } + } + } + /* /// Convert a raw sample from the `Temperature` to deg C pub fn to_degrees_centigrade(sample: u16) -> f32 { -- cgit From 80eed58c30087d6d61474e8a1ac21da1ea679763 Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Fri, 14 Nov 2025 07:58:17 +0100 Subject: splitting up ADC1/2 implementations on Adc to ensure relevant methods are only visible on the ADC block where they are supported --- embassy-stm32/src/adc/v3.rs | 128 +++++++++++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 50 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index c65357aff..3bda0ae54 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -13,7 +13,7 @@ pub use pac::adc::vals::{Ovsr, Ovss, Presc}; use super::SealedAdcChannel; use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; use crate::adc::ConversionMode; -use crate::{Peri, pac, rcc}; +use crate::{Peri, pac, rcc, peripherals}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -489,6 +489,22 @@ impl<'d, T: Instance> Adc<'d, T> { s } + #[cfg(any(adc_g0, adc_u0))] + pub fn enable_vbat(&self) -> Vbat { + T::regs().ccr().modify(|reg| { + reg.set_vbaten(true); + }); + + Vbat { } + } + + #[cfg(any(adc_g0, adc_u0))] + pub fn disable_vbat(&self) { + T::regs().ccr().modify(|reg| { + reg.set_vbaten(false); + }); + } + #[cfg(adc_g0)] /// Initialize ADC with explicit clock for the analog ADC pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self { @@ -525,87 +541,99 @@ impl<'d, T: Instance> Adc<'d, T> { Self { adc } } - pub fn enable_vrefint(&self) -> VrefInt { - #[cfg(not(any(adc_g0, adc_u0)))] - T::common_regs().ccr().modify(|reg| { - reg.set_vrefen(true); - }); - #[cfg(any(adc_g0, adc_u0))] - T::regs().ccr().modify(|reg| { - reg.set_vrefen(true); - }); - - // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us - // to stabilize the internal voltage reference. - blocking_delay_us(15); - - VrefInt {} + /* + /// Convert a raw sample from the `Temperature` to deg C + pub fn to_degrees_centigrade(sample: u16) -> f32 { + (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32) + * (sample as f32 - VtempCal30::get().read() as f32) + + 30.0 } + */ +} - pub fn enable_temperature(&self) -> Temperature { + +#[cfg(not(any(adc_g0, adc_u0)))] +impl<'d> Adc<'d, peripherals::ADC2> { + pub fn enable_vbat(&self) -> Vbat { cfg_if! { - if #[cfg(any(adc_g0, adc_u0))] { - T::regs().ccr().modify(|reg| { - reg.set_tsen(true); - }); - } else if #[cfg(any(adc_h5, adc_h7rs))] { - T::common_regs().ccr().modify(|reg| { - reg.set_tsen(true); + if #[cfg(any(adc_h5, adc_h7rs))] { + pac::ADC12_COMMON.ccr().modify(|reg| { + reg.set_vbaten(true); }); } else { - T::common_regs().ccr().modify(|reg| { - reg.set_ch17sel(true); + pac::ADC12_COMMON.ccr().modify(|reg| { + reg.set_ch18sel(true); }); } } - Temperature {} + Vbat { } } - pub fn enable_vbat(&self) -> Vbat { + pub fn disable_vbat(&self) { cfg_if! { if #[cfg(any(adc_g0, adc_u0))] { - T::regs().ccr().modify(|reg| { - reg.set_vbaten(true); + pac::ADC2.ccr().modify(|reg| { + reg.set_vbaten(false); }); } else if #[cfg(any(adc_h5, adc_h7rs))] { - T::common_regs().ccr().modify(|reg| { - reg.set_vbaten(true); + pac::ADC12_COMMON.ccr().modify(|reg| { + reg.set_vbaten(false); }); } else { - T::common_regs().ccr().modify(|reg| { - reg.set_ch18sel(true); + pac::ADC12_COMMON.ccr().modify(|reg| { + reg.set_ch18sel(false); }); } } + } - Vbat {} + #[cfg(any(adc_h5, adc_h7rs))] + pub fn enable_vddcore(&self) -> VddCore { + pac::ADC2.or().modify(|reg| { + reg.set_op0(true); + }); + + VddCore { } } +} - pub fn disable_vbat(&self) { + +impl<'d> Adc<'d, peripherals::ADC1> { + pub fn enable_vrefint(&self) -> VrefInt { + #[cfg(not(any(adc_g0, adc_u0)))] + pac::ADC12_COMMON.ccr().modify(|reg| { + reg.set_vrefen(true); + }); + #[cfg(any(adc_g0, adc_u0))] + pac::ADC1.ccr().modify(|reg| { + reg.set_vrefen(true); + }); + + // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us + // to stabilize the internal voltage reference. + blocking_delay_us(15); + + VrefInt { } + } + + pub fn enable_temperature(&self) -> Temperature { cfg_if! { if #[cfg(any(adc_g0, adc_u0))] { - T::regs().ccr().modify(|reg| { - reg.set_vbaten(false); + pac::ADC1.ccr().modify(|reg| { + reg.set_tsen(true); }); } else if #[cfg(any(adc_h5, adc_h7rs))] { - T::common_regs().ccr().modify(|reg| { - reg.set_vbaten(false); + pac::ADC12_COMMON.ccr().modify(|reg| { + reg.set_tsen(true); }); } else { - T::common_regs().ccr().modify(|reg| { - reg.set_ch18sel(false); + pac::ADC12_COMMON.ccr().modify(|reg| { + reg.set_ch17sel(true); }); } } - } - /* - /// Convert a raw sample from the `Temperature` to deg C - pub fn to_degrees_centigrade(sample: u16) -> f32 { - (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32) - * (sample as f32 - VtempCal30::get().read() as f32) - + 30.0 + Temperature { } } - */ } -- cgit From 2c75390b8cbb9dd815b53130d03fe0803112a6c6 Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Fri, 14 Nov 2025 08:03:17 +0100 Subject: updating changelog --- embassy-stm32/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 8bd930e79..259eaf9c0 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -58,6 +58,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - adc: reogranize and cleanup somewhat. require sample_time to be passed on conversion - fix: stm32/i2c v2 slave: prevent misaligned reads, error false positives, and incorrect counts of bytes read/written - feat: add flash support for c0 family ([#4874](https://github.com/embassy-rs/embassy/pull/4874)) +- fix: fixing channel numbers on vbat and vddcore for adc on adc +- adc: splitting up implementations to distinguish ADC1 & 2 hosted internal special channels are only accessible on the relevant block ## 0.4.0 - 2025-08-26 -- cgit From 9fd57c165997bf575517aea0fde98b930b1c893a Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Fri, 14 Nov 2025 08:04:58 +0100 Subject: fixing failed rust fmt ci --- embassy-stm32/src/adc/v3.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 3bda0ae54..55fe70f72 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -594,7 +594,7 @@ impl<'d> Adc<'d, peripherals::ADC2> { reg.set_op0(true); }); - VddCore { } + VddCore {} } } @@ -614,7 +614,7 @@ impl<'d> Adc<'d, peripherals::ADC1> { // to stabilize the internal voltage reference. blocking_delay_us(15); - VrefInt { } + VrefInt {} } pub fn enable_temperature(&self) -> Temperature { @@ -634,6 +634,6 @@ impl<'d> Adc<'d, peripherals::ADC1> { } } - Temperature { } + Temperature {} } } -- cgit From f7c1aba09f7ef0b99396dc626d5d8c575f5b18e4 Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Fri, 14 Nov 2025 08:06:18 +0100 Subject: fixing one more failed rust fmt ci --- embassy-stm32/src/adc/v3.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 55fe70f72..51e1e654b 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -495,7 +495,7 @@ impl<'d, T: Instance> Adc<'d, T> { reg.set_vbaten(true); }); - Vbat { } + Vbat {} } #[cfg(any(adc_g0, adc_u0))] @@ -567,7 +567,7 @@ impl<'d> Adc<'d, peripherals::ADC2> { } } - Vbat { } + Vbat {} } pub fn disable_vbat(&self) { -- cgit From 3bbc2515062046638cc19edb0f02f1490de21087 Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Fri, 14 Nov 2025 08:12:14 +0100 Subject: indention fix --- embassy-stm32/src/adc/v3.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 51e1e654b..54824c253 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -13,7 +13,7 @@ pub use pac::adc::vals::{Ovsr, Ovss, Presc}; use super::SealedAdcChannel; use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; use crate::adc::ConversionMode; -use crate::{Peri, pac, rcc, peripherals}; +use crate::{Peri, pac, peripherals, rcc}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -554,7 +554,7 @@ impl<'d, T: Instance> Adc<'d, T> { #[cfg(not(any(adc_g0, adc_u0)))] impl<'d> Adc<'d, peripherals::ADC2> { - pub fn enable_vbat(&self) -> Vbat { + pub fn enable_vbat(&self) -> Vbat { cfg_if! { if #[cfg(any(adc_h5, adc_h7rs))] { pac::ADC12_COMMON.ccr().modify(|reg| { -- cgit From 31a6bb84bc27c79640edb490d2a96117a413375e Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Fri, 14 Nov 2025 08:14:42 +0100 Subject: ci fix: whitespace removal --- embassy-stm32/src/adc/v3.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 54824c253..8559d0697 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -551,7 +551,6 @@ impl<'d, T: Instance> Adc<'d, T> { */ } - #[cfg(not(any(adc_g0, adc_u0)))] impl<'d> Adc<'d, peripherals::ADC2> { pub fn enable_vbat(&self) -> Vbat { @@ -598,7 +597,6 @@ impl<'d> Adc<'d, peripherals::ADC2> { } } - impl<'d> Adc<'d, peripherals::ADC1> { pub fn enable_vrefint(&self) -> VrefInt { #[cfg(not(any(adc_g0, adc_u0)))] -- cgit From d866a7f73775e0694f9c9a280df9d3603cb52541 Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Fri, 14 Nov 2025 08:42:46 +0100 Subject: walking around stm32wb differences --- embassy-stm32/src/adc/v3.rs | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 8559d0697..b833247a9 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -551,7 +551,7 @@ impl<'d, T: Instance> Adc<'d, T> { */ } -#[cfg(not(any(adc_g0, adc_u0)))] +#[cfg(not(any(adc_g0, adc_u0, stm32wb)))] impl<'d> Adc<'d, peripherals::ADC2> { pub fn enable_vbat(&self) -> Vbat { cfg_if! { @@ -599,14 +599,21 @@ impl<'d> Adc<'d, peripherals::ADC2> { impl<'d> Adc<'d, peripherals::ADC1> { pub fn enable_vrefint(&self) -> VrefInt { - #[cfg(not(any(adc_g0, adc_u0)))] - pac::ADC12_COMMON.ccr().modify(|reg| { - reg.set_vrefen(true); - }); - #[cfg(any(adc_g0, adc_u0))] - pac::ADC1.ccr().modify(|reg| { - reg.set_vrefen(true); - }); + cfg_if! { + if #[cfg(not(any(adc_g0, adc_u0, stm32wb)))] { + pac::ADC12_COMMON.ccr().modify(|reg| { + reg.set_vrefen(true); + }); + } else if #[cfg(any(adc_g0, adc_u0))] { + pac::ADC1.ccr().modify(|reg| { + reg.set_vrefen(true); + }); + } else { + pac::ADC1_COMMON.ccr().modify(|reg| { + reg.set_vrefen(true); + }); + } + } // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us // to stabilize the internal voltage reference. @@ -625,10 +632,12 @@ impl<'d> Adc<'d, peripherals::ADC1> { pac::ADC12_COMMON.ccr().modify(|reg| { reg.set_tsen(true); }); + } else if #[cfg(any(stm32wb))] { + todo!(); } else { pac::ADC12_COMMON.ccr().modify(|reg| { reg.set_ch17sel(true); - }); + }); } } -- cgit From 536b4e8fe3a62fae25bd3b1d2ae0f196bfb734f9 Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Fri, 14 Nov 2025 08:52:08 +0100 Subject: walking around ci unreachable code warning --- embassy-stm32/src/adc/v3.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index b833247a9..e4ccaba53 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -11,7 +11,8 @@ pub use pac::adc::vals::{Ovsr, Ovss, Presc}; #[allow(unused_imports)] use super::SealedAdcChannel; -use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; +#[allow(unused_imports)] +use super::{Adc, Avergaing, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; use crate::adc::ConversionMode; use crate::{Peri, pac, peripherals, rcc}; @@ -628,19 +629,24 @@ impl<'d> Adc<'d, peripherals::ADC1> { pac::ADC1.ccr().modify(|reg| { reg.set_tsen(true); }); + + Temperature {} } else if #[cfg(any(adc_h5, adc_h7rs))] { pac::ADC12_COMMON.ccr().modify(|reg| { reg.set_tsen(true); }); + + Temperature {} } else if #[cfg(any(stm32wb))] { todo!(); } else { pac::ADC12_COMMON.ccr().modify(|reg| { reg.set_ch17sel(true); }); + + Temperature {} } } - Temperature {} } } -- cgit From 00f80b56c3f72db31117427d6294df19b7401f2e Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Fri, 14 Nov 2025 08:53:33 +0100 Subject: whitespace fix.. --- embassy-stm32/src/adc/v3.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index e4ccaba53..e6ead5dcf 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -642,11 +642,10 @@ impl<'d> Adc<'d, peripherals::ADC1> { } else { pac::ADC12_COMMON.ccr().modify(|reg| { reg.set_ch17sel(true); - }); + }); Temperature {} } } - } } -- cgit From 31908a26e0ef597511af25b7ffb50f7c64e85560 Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Fri, 14 Nov 2025 09:32:26 +0100 Subject: import spelling error fix --- embassy-stm32/src/adc/v3.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index e6ead5dcf..ce02168ba 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -12,7 +12,7 @@ pub use pac::adc::vals::{Ovsr, Ovss, Presc}; #[allow(unused_imports)] use super::SealedAdcChannel; #[allow(unused_imports)] -use super::{Adc, Avergaing, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; +use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; use crate::adc::ConversionMode; use crate::{Peri, pac, peripherals, rcc}; -- cgit From 20c75352c388546e8d105d03837c06f32d28ffbc Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Fri, 14 Nov 2025 10:10:42 +0100 Subject: adding support for stm32l4 --- embassy-stm32/src/adc/v3.rs | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index ce02168ba..93219168d 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -560,6 +560,10 @@ impl<'d> Adc<'d, peripherals::ADC2> { pac::ADC12_COMMON.ccr().modify(|reg| { reg.set_vbaten(true); }); + } else if #[cfg(stm32l4)] { + pac::ADC123_COMMON.ccr().modify(|reg| { + reg.set_ch18sel(true); + }); } else { pac::ADC12_COMMON.ccr().modify(|reg| { reg.set_ch18sel(true); @@ -572,18 +576,18 @@ impl<'d> Adc<'d, peripherals::ADC2> { pub fn disable_vbat(&self) { cfg_if! { - if #[cfg(any(adc_g0, adc_u0))] { - pac::ADC2.ccr().modify(|reg| { - reg.set_vbaten(false); - }); - } else if #[cfg(any(adc_h5, adc_h7rs))] { + if #[cfg(any(adc_h5, adc_h7rs))] { pac::ADC12_COMMON.ccr().modify(|reg| { reg.set_vbaten(false); }); + } else if #[cfg(stm32l4)] { + pac::ADC123_COMMON.ccr().modify(|reg| { + reg.set_ch18sel(false); + }); } else { pac::ADC12_COMMON.ccr().modify(|reg| { reg.set_ch18sel(false); - }); + }); } } } @@ -601,7 +605,7 @@ impl<'d> Adc<'d, peripherals::ADC2> { impl<'d> Adc<'d, peripherals::ADC1> { pub fn enable_vrefint(&self) -> VrefInt { cfg_if! { - if #[cfg(not(any(adc_g0, adc_u0, stm32wb)))] { + if #[cfg(any(adc_h5, adc_h7rs))] { pac::ADC12_COMMON.ccr().modify(|reg| { reg.set_vrefen(true); }); @@ -609,6 +613,10 @@ impl<'d> Adc<'d, peripherals::ADC1> { pac::ADC1.ccr().modify(|reg| { reg.set_vrefen(true); }); + } else if #[cfg(stm32l4)] { + pac::ADC123_COMMON.ccr().modify(|reg| { + reg.set_vrefen(true); + }); } else { pac::ADC1_COMMON.ccr().modify(|reg| { reg.set_vrefen(true); @@ -637,8 +645,14 @@ impl<'d> Adc<'d, peripherals::ADC1> { }); Temperature {} - } else if #[cfg(any(stm32wb))] { - todo!(); + } else if #[cfg(stm32wb)] { + todo(); + } else if #[cfg(stm32l4)] { + pac::ADC123_COMMON.ccr().modify(|reg| { + reg.set_ch17sel(true); + }); + + Temperature {} } else { pac::ADC12_COMMON.ccr().modify(|reg| { reg.set_ch17sel(true); -- cgit From 2cdefb7d09a6c77e325c8fc074017873fb0296ac Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Fri, 14 Nov 2025 10:17:33 +0100 Subject: fix whitespace issues --- embassy-stm32/src/adc/v3.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 93219168d..072d6e592 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -587,7 +587,7 @@ impl<'d> Adc<'d, peripherals::ADC2> { } else { pac::ADC12_COMMON.ccr().modify(|reg| { reg.set_ch18sel(false); - }); + }); } } } -- cgit From 7ddee557405bbd11a2915818044b508158aa149f Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Fri, 14 Nov 2025 10:37:04 +0100 Subject: misspelled todo macro --- embassy-stm32/src/adc/v3.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 072d6e592..c77a1d4f5 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -646,7 +646,7 @@ impl<'d> Adc<'d, peripherals::ADC1> { Temperature {} } else if #[cfg(stm32wb)] { - todo(); + todo!(); } else if #[cfg(stm32l4)] { pac::ADC123_COMMON.ccr().modify(|reg| { reg.set_ch17sel(true); -- cgit From 842ee9bef98975d2a874a425983cfad59610a963 Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Fri, 14 Nov 2025 11:15:42 +0100 Subject: undoing channel split --- embassy-stm32/src/adc/v3.rs | 154 ++++++++++++++------------------------------ 1 file changed, 50 insertions(+), 104 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index c77a1d4f5..c65357aff 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -11,10 +11,9 @@ pub use pac::adc::vals::{Ovsr, Ovss, Presc}; #[allow(unused_imports)] use super::SealedAdcChannel; -#[allow(unused_imports)] use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; use crate::adc::ConversionMode; -use crate::{Peri, pac, peripherals, rcc}; +use crate::{Peri, pac, rcc}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -490,22 +489,6 @@ impl<'d, T: Instance> Adc<'d, T> { s } - #[cfg(any(adc_g0, adc_u0))] - pub fn enable_vbat(&self) -> Vbat { - T::regs().ccr().modify(|reg| { - reg.set_vbaten(true); - }); - - Vbat {} - } - - #[cfg(any(adc_g0, adc_u0))] - pub fn disable_vbat(&self) { - T::regs().ccr().modify(|reg| { - reg.set_vbaten(false); - }); - } - #[cfg(adc_g0)] /// Initialize ADC with explicit clock for the analog ADC pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self { @@ -542,124 +525,87 @@ impl<'d, T: Instance> Adc<'d, T> { Self { adc } } - /* - /// Convert a raw sample from the `Temperature` to deg C - pub fn to_degrees_centigrade(sample: u16) -> f32 { - (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32) - * (sample as f32 - VtempCal30::get().read() as f32) - + 30.0 - } - */ -} + pub fn enable_vrefint(&self) -> VrefInt { + #[cfg(not(any(adc_g0, adc_u0)))] + T::common_regs().ccr().modify(|reg| { + reg.set_vrefen(true); + }); + #[cfg(any(adc_g0, adc_u0))] + T::regs().ccr().modify(|reg| { + reg.set_vrefen(true); + }); -#[cfg(not(any(adc_g0, adc_u0, stm32wb)))] -impl<'d> Adc<'d, peripherals::ADC2> { - pub fn enable_vbat(&self) -> Vbat { - cfg_if! { - if #[cfg(any(adc_h5, adc_h7rs))] { - pac::ADC12_COMMON.ccr().modify(|reg| { - reg.set_vbaten(true); - }); - } else if #[cfg(stm32l4)] { - pac::ADC123_COMMON.ccr().modify(|reg| { - reg.set_ch18sel(true); - }); - } else { - pac::ADC12_COMMON.ccr().modify(|reg| { - reg.set_ch18sel(true); - }); - } - } + // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us + // to stabilize the internal voltage reference. + blocking_delay_us(15); - Vbat {} + VrefInt {} } - pub fn disable_vbat(&self) { + pub fn enable_temperature(&self) -> Temperature { cfg_if! { - if #[cfg(any(adc_h5, adc_h7rs))] { - pac::ADC12_COMMON.ccr().modify(|reg| { - reg.set_vbaten(false); + if #[cfg(any(adc_g0, adc_u0))] { + T::regs().ccr().modify(|reg| { + reg.set_tsen(true); }); - } else if #[cfg(stm32l4)] { - pac::ADC123_COMMON.ccr().modify(|reg| { - reg.set_ch18sel(false); + } else if #[cfg(any(adc_h5, adc_h7rs))] { + T::common_regs().ccr().modify(|reg| { + reg.set_tsen(true); }); } else { - pac::ADC12_COMMON.ccr().modify(|reg| { - reg.set_ch18sel(false); + T::common_regs().ccr().modify(|reg| { + reg.set_ch17sel(true); }); } } - } - - #[cfg(any(adc_h5, adc_h7rs))] - pub fn enable_vddcore(&self) -> VddCore { - pac::ADC2.or().modify(|reg| { - reg.set_op0(true); - }); - VddCore {} + Temperature {} } -} -impl<'d> Adc<'d, peripherals::ADC1> { - pub fn enable_vrefint(&self) -> VrefInt { + pub fn enable_vbat(&self) -> Vbat { cfg_if! { - if #[cfg(any(adc_h5, adc_h7rs))] { - pac::ADC12_COMMON.ccr().modify(|reg| { - reg.set_vrefen(true); - }); - } else if #[cfg(any(adc_g0, adc_u0))] { - pac::ADC1.ccr().modify(|reg| { - reg.set_vrefen(true); + if #[cfg(any(adc_g0, adc_u0))] { + T::regs().ccr().modify(|reg| { + reg.set_vbaten(true); }); - } else if #[cfg(stm32l4)] { - pac::ADC123_COMMON.ccr().modify(|reg| { - reg.set_vrefen(true); + } else if #[cfg(any(adc_h5, adc_h7rs))] { + T::common_regs().ccr().modify(|reg| { + reg.set_vbaten(true); }); } else { - pac::ADC1_COMMON.ccr().modify(|reg| { - reg.set_vrefen(true); + T::common_regs().ccr().modify(|reg| { + reg.set_ch18sel(true); }); } } - // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us - // to stabilize the internal voltage reference. - blocking_delay_us(15); - - VrefInt {} + Vbat {} } - pub fn enable_temperature(&self) -> Temperature { + pub fn disable_vbat(&self) { cfg_if! { if #[cfg(any(adc_g0, adc_u0))] { - pac::ADC1.ccr().modify(|reg| { - reg.set_tsen(true); + T::regs().ccr().modify(|reg| { + reg.set_vbaten(false); }); - - Temperature {} } else if #[cfg(any(adc_h5, adc_h7rs))] { - pac::ADC12_COMMON.ccr().modify(|reg| { - reg.set_tsen(true); - }); - - Temperature {} - } else if #[cfg(stm32wb)] { - todo!(); - } else if #[cfg(stm32l4)] { - pac::ADC123_COMMON.ccr().modify(|reg| { - reg.set_ch17sel(true); + T::common_regs().ccr().modify(|reg| { + reg.set_vbaten(false); }); - - Temperature {} } else { - pac::ADC12_COMMON.ccr().modify(|reg| { - reg.set_ch17sel(true); + T::common_regs().ccr().modify(|reg| { + reg.set_ch18sel(false); }); - - Temperature {} } } } + + /* + /// Convert a raw sample from the `Temperature` to deg C + pub fn to_degrees_centigrade(sample: u16) -> f32 { + (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32) + * (sample as f32 - VtempCal30::get().read() as f32) + + 30.0 + } + */ } -- cgit From 34b5b4eb92de4c135156c52ce3d5b59c14a5c841 Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Fri, 14 Nov 2025 11:17:02 +0100 Subject: adjusting changelog --- embassy-stm32/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 259eaf9c0..9153e15b9 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -59,7 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - fix: stm32/i2c v2 slave: prevent misaligned reads, error false positives, and incorrect counts of bytes read/written - feat: add flash support for c0 family ([#4874](https://github.com/embassy-rs/embassy/pull/4874)) - fix: fixing channel numbers on vbat and vddcore for adc on adc -- adc: splitting up implementations to distinguish ADC1 & 2 hosted internal special channels are only accessible on the relevant block +- adc: adding disable to vbat ## 0.4.0 - 2025-08-26 -- cgit From 9b5fc685a11bc4d5254dffde37beeaba721d1f2a Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 14 Nov 2025 12:53:10 +0100 Subject: fix: use correct nrf54l15 flash size Both SVD and documentation agrees on 1524kB --- embassy-nrf/src/chips/nrf54l15_app.rs | 2 +- examples/nrf54l15/memory.x | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/chips/nrf54l15_app.rs b/embassy-nrf/src/chips/nrf54l15_app.rs index 0724f2ff6..8846717db 100644 --- a/embassy-nrf/src/chips/nrf54l15_app.rs +++ b/embassy-nrf/src/chips/nrf54l15_app.rs @@ -204,7 +204,7 @@ pub const FORCE_COPY_BUFFER_SIZE: usize = 1024; // 1.5 MB NVM #[allow(unused)] -pub const FLASH_SIZE: usize = 1536 * 1024; +pub const FLASH_SIZE: usize = 1524 * 1024; embassy_hal_internal::peripherals! { // PPI diff --git a/examples/nrf54l15/memory.x b/examples/nrf54l15/memory.x index 1064c8a5c..332200828 100644 --- a/examples/nrf54l15/memory.x +++ b/examples/nrf54l15/memory.x @@ -1,5 +1,5 @@ MEMORY { - FLASH : ORIGIN = 0x00000000, LENGTH = 1536K + FLASH : ORIGIN = 0x00000000, LENGTH = 1524K RAM : ORIGIN = 0x20000000, LENGTH = 256K } -- cgit From a5a4e9f82e1843261ae98418f8646be73fcb1f5e Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 14 Nov 2025 12:59:00 +0100 Subject: docs: add changelog --- embassy-nrf/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 52a8a7a05..f6fe1e14f 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - added: add `gpiote::InputChannel::wait_for_high()` and `wait_for_low()` to wait for specific signal level - changed: `gpiote::InputChannel::wait()` now takes a mutable reference to `self` to avoid interference from concurrent calls - changed: `gpiote::InputChannel::wait()` now ensures events are seen as soon as the function is called, even if the future is not polled +- bugfix: use correct flash size for nRF54l ## 0.8.0 - 2025-09-30 -- cgit From a2c5a0d9480b99cdb09940637354bc61405ed7bd Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 14 Nov 2025 10:17:45 -0600 Subject: adc: fix g4 injected sequence --- embassy-stm32/src/adc/g4.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 514734017..bd8ccbf17 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -1,3 +1,5 @@ +#[cfg(stm32g4)] +use pac::adc::regs::Difsel as DifselReg; #[allow(unused)] #[cfg(stm32h7)] use pac::adc::vals::{Adcaldif, Difsel, Exten}; @@ -179,6 +181,9 @@ impl super::SealedAnyInstance for T { w.set_l(sequence.len() as u8 - 1); }); + #[cfg(stm32g4)] + let mut difsel = DifselReg::default(); + // Configure channels and ranks for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() { let sample_time = sample_time.into(); @@ -214,10 +219,8 @@ impl super::SealedAnyInstance for T { #[cfg(stm32g4)] { - T::regs().cr().modify(|w| w.set_aden(false)); // disable adc - - T::regs().difsel().modify(|w| { - w.set_difsel( + if ch < 18 { + difsel.set_difsel( ch.into(), if is_differential { Difsel::DIFFERENTIAL @@ -225,11 +228,16 @@ impl super::SealedAnyInstance for T { Difsel::SINGLE_ENDED }, ); - }); - - T::regs().cr().modify(|w| w.set_aden(true)); // enable adc + } } } + + #[cfg(stm32g4)] + { + T::regs().cr().modify(|w| w.set_aden(false)); + T::regs().difsel().write_value(difsel); + T::enable(); + } } } @@ -412,7 +420,6 @@ impl<'d, T: Instance + AnyInstance> Adc<'d, T> { NR_INJECTED_RANKS ); - T::stop(); T::enable(); T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); -- cgit