diff options
| author | xoviat <[email protected]> | 2025-11-11 16:12:02 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-11 16:12:02 +0000 |
| commit | f078c85454f09f28a85aa834a9496b37058695e0 (patch) | |
| tree | d42ce0ef8fcca3d654566e6d83eee8978435e664 | |
| parent | 3d1f09597335d3681699ba09a77da4b39ed984fd (diff) | |
| parent | 94c4cd8500b131bbfb0ed22176c35dc4df5ff009 (diff) | |
Merge pull request #4714 from everdrone/n6
STM32N6 RCC implementation
| -rw-r--r-- | .helix/languages.toml | 11 | ||||
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | embassy-stm32/Cargo.toml | 3 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 226 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/gpdma/mod.rs | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/mod.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/dts/tsel.rs | 17 | ||||
| -rw-r--r-- | embassy-stm32/src/exti.rs | 32 | ||||
| -rw-r--r-- | embassy-stm32/src/gpio.rs | 44 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 18 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/bd.rs | 110 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mco.rs | 10 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/n6.rs | 1046 | ||||
| -rw-r--r-- | embassy-stm32/src/ucpd.rs | 3 | ||||
| -rw-r--r-- | examples/stm32n6/.cargo/config.toml | 8 | ||||
| -rw-r--r-- | examples/stm32n6/Cargo.toml | 78 | ||||
| -rw-r--r-- | examples/stm32n6/build.rs | 5 | ||||
| -rw-r--r-- | examples/stm32n6/memory.x | 5 | ||||
| -rw-r--r-- | examples/stm32n6/src/bin/blinky.rs | 36 |
20 files changed, 1491 insertions, 168 deletions
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 @@ | |||
| 1 | [language-server.rust-analyzer.config.cargo] | ||
| 2 | allTargets = false | ||
| 3 | noDefaultFeatures = true | ||
| 4 | target = "thumbv8m.main-none-eabihf" | ||
| 5 | features = ["stm32n657x0", "time-driver-any", "unstable-pac", "exti"] | ||
| 6 | |||
| 7 | [language-server.rust-analyzer.config.check] | ||
| 8 | allTargets = false | ||
| 9 | noDefaultFeatures = true | ||
| 10 | target = "thumbv8m.main-none-eabihf" | ||
| 11 | features = ["stm32n657x0", "time-driver-any", "unstable-pac", "exti"] | ||
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 | |||
| 7 | 7 | ||
| 8 | ## Unreleased - ReleaseDate | 8 | ## Unreleased - ReleaseDate |
| 9 | 9 | ||
| 10 | - feat: Add support for STM32N657X0 | ||
| 10 | - feat: timer: Add 32-bit timer support to SimplePwm waveform_up method following waveform pattern ([#4717](https://github.com/embassy-rs/embassy/pull/4717)) | 11 | - feat: timer: Add 32-bit timer support to SimplePwm waveform_up method following waveform pattern ([#4717](https://github.com/embassy-rs/embassy/pull/4717)) |
| 11 | - feat: Add support for injected ADC measurements for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840)) | 12 | - feat: Add support for injected ADC measurements for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840)) |
| 12 | - feat: Implement into_ring_buffered for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840)) | 13 | - feat: Implement into_ring_buffered for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840)) |
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 108321d0a..0a1854dab 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -99,6 +99,7 @@ build = [ | |||
| 99 | {target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "low-power", "stm32wba65ri", "time", "time-driver-any"]}, | 99 | {target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "low-power", "stm32wba65ri", "time", "time-driver-any"]}, |
| 100 | {target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "stm32u5f9zj", "time", "time-driver-any"]}, | 100 | {target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "stm32u5f9zj", "time", "time-driver-any"]}, |
| 101 | {target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "stm32u5g9nj", "time", "time-driver-any"]}, | 101 | {target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "stm32u5g9nj", "time", "time-driver-any"]}, |
| 102 | {target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "stm32n657x0", "time", "time-driver-any"]}, | ||
| 102 | {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32wb35ce", "time", "time-driver-any"]}, | 103 | {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32wb35ce", "time", "time-driver-any"]}, |
| 103 | {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "low-power", "stm32wb55rg", "time", "time-driver-any"]}, | 104 | {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "low-power", "stm32wb55rg", "time", "time-driver-any"]}, |
| 104 | {target = "thumbv6m-none-eabi", features = ["defmt", "exti", "stm32u031r8", "time", "time-driver-any"]}, | 105 | {target = "thumbv6m-none-eabi", features = ["defmt", "exti", "stm32u031r8", "time", "time-driver-any"]}, |
| @@ -213,7 +214,6 @@ proptest = "1.5.0" | |||
| 213 | proptest-state-machine = "0.3.0" | 214 | proptest-state-machine = "0.3.0" |
| 214 | 215 | ||
| 215 | 216 | ||
| 216 | |||
| 217 | [features] | 217 | [features] |
| 218 | default = ["rt"] | 218 | default = ["rt"] |
| 219 | 219 | ||
| @@ -1642,6 +1642,7 @@ stm32l562qe = [ "stm32-metapac/stm32l562qe" ] | |||
| 1642 | stm32l562re = [ "stm32-metapac/stm32l562re" ] | 1642 | stm32l562re = [ "stm32-metapac/stm32l562re" ] |
| 1643 | stm32l562ve = [ "stm32-metapac/stm32l562ve" ] | 1643 | stm32l562ve = [ "stm32-metapac/stm32l562ve" ] |
| 1644 | stm32l562ze = [ "stm32-metapac/stm32l562ze" ] | 1644 | stm32l562ze = [ "stm32-metapac/stm32l562ze" ] |
| 1645 | stm32n657x0 = [ "stm32-metapac/stm32n657x0" ] | ||
| 1645 | stm32u031c6 = [ "stm32-metapac/stm32u031c6" ] | 1646 | stm32u031c6 = [ "stm32-metapac/stm32u031c6" ] |
| 1646 | stm32u031c8 = [ "stm32-metapac/stm32u031c8" ] | 1647 | stm32u031c8 = [ "stm32-metapac/stm32u031c8" ] |
| 1647 | stm32u031f4 = [ "stm32-metapac/stm32u031f4" ] | 1648 | stm32u031f4 = [ "stm32-metapac/stm32u031f4" ] |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 940e29417..09a05ce68 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -363,101 +363,108 @@ fn main() { | |||
| 363 | 363 | ||
| 364 | // ======== | 364 | // ======== |
| 365 | // Generate FLASH regions | 365 | // Generate FLASH regions |
| 366 | let mut flash_regions = TokenStream::new(); | 366 | cfgs.declare("flash"); |
| 367 | let flash_memory_regions: Vec<_> = memory | 367 | let mut has_flash = false; |
| 368 | .iter() | 368 | if !chip_name.starts_with("stm32n6") { |
| 369 | .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some()) | 369 | cfgs.enable("flash"); |
| 370 | .collect(); | 370 | has_flash = true; |
| 371 | for region in flash_memory_regions.iter() { | 371 | |
| 372 | let region_name = format_ident!("{}", get_flash_region_name(region.name)); | 372 | let mut flash_regions = TokenStream::new(); |
| 373 | let bank_variant = format_ident!( | 373 | let flash_memory_regions: Vec<_> = memory |
| 374 | "{}", | 374 | .iter() |
| 375 | if region.name.starts_with("BANK_1") { | 375 | .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some()) |
| 376 | "Bank1" | 376 | .collect(); |
| 377 | } else if region.name.starts_with("BANK_2") { | 377 | for region in flash_memory_regions.iter() { |
| 378 | "Bank2" | 378 | let region_name = format_ident!("{}", get_flash_region_name(region.name)); |
| 379 | } else if region.name == "OTP" { | 379 | let bank_variant = format_ident!( |
| 380 | "Otp" | 380 | "{}", |
| 381 | } else { | 381 | if region.name.starts_with("BANK_1") { |
| 382 | continue; | 382 | "Bank1" |
| 383 | } | 383 | } else if region.name.starts_with("BANK_2") { |
| 384 | ); | 384 | "Bank2" |
| 385 | let base = region.address; | 385 | } else if region.name == "OTP" { |
| 386 | let size = region.size; | 386 | "Otp" |
| 387 | let settings = region.settings.as_ref().unwrap(); | 387 | } else { |
| 388 | let erase_size = settings.erase_size; | 388 | continue; |
| 389 | let write_size = settings.write_size; | 389 | } |
| 390 | let erase_value = settings.erase_value; | 390 | ); |
| 391 | 391 | let base = region.address; | |
| 392 | flash_regions.extend(quote! { | 392 | let size = region.size; |
| 393 | pub const #region_name: crate::flash::FlashRegion = crate::flash::FlashRegion { | 393 | let settings = region.settings.as_ref().unwrap(); |
| 394 | bank: crate::flash::FlashBank::#bank_variant, | 394 | let erase_size = settings.erase_size; |
| 395 | base: #base, | 395 | let write_size = settings.write_size; |
| 396 | size: #size, | 396 | let erase_value = settings.erase_value; |
| 397 | erase_size: #erase_size, | 397 | |
| 398 | write_size: #write_size, | 398 | flash_regions.extend(quote! { |
| 399 | erase_value: #erase_value, | 399 | pub const #region_name: crate::flash::FlashRegion = crate::flash::FlashRegion { |
| 400 | _ensure_internal: (), | 400 | bank: crate::flash::FlashBank::#bank_variant, |
| 401 | }; | 401 | base: #base, |
| 402 | }); | 402 | size: #size, |
| 403 | erase_size: #erase_size, | ||
| 404 | write_size: #write_size, | ||
| 405 | erase_value: #erase_value, | ||
| 406 | _ensure_internal: (), | ||
| 407 | }; | ||
| 408 | }); | ||
| 403 | 409 | ||
| 404 | let region_type = format_ident!("{}", get_flash_region_type_name(region.name)); | 410 | let region_type = format_ident!("{}", get_flash_region_type_name(region.name)); |
| 405 | flash_regions.extend(quote! { | 411 | flash_regions.extend(quote! { |
| 406 | #[cfg(flash)] | 412 | #[cfg(flash)] |
| 407 | 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<MODE>); | 413 | 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<MODE>); |
| 408 | }); | 414 | }); |
| 409 | } | 415 | } |
| 410 | 416 | ||
| 411 | let (fields, (inits, region_names)): (Vec<TokenStream>, (Vec<TokenStream>, Vec<Ident>)) = flash_memory_regions | 417 | let (fields, (inits, region_names)): (Vec<TokenStream>, (Vec<TokenStream>, Vec<Ident>)) = flash_memory_regions |
| 412 | .iter() | 418 | .iter() |
| 413 | .map(|f| { | 419 | .map(|f| { |
| 414 | let region_name = get_flash_region_name(f.name); | 420 | let region_name = get_flash_region_name(f.name); |
| 415 | let field_name = format_ident!("{}", region_name.to_lowercase()); | 421 | let field_name = format_ident!("{}", region_name.to_lowercase()); |
| 416 | let field_type = format_ident!("{}", get_flash_region_type_name(f.name)); | 422 | let field_type = format_ident!("{}", get_flash_region_type_name(f.name)); |
| 417 | let field = quote! { | 423 | let field = quote! { |
| 418 | pub #field_name: #field_type<'d, MODE> | 424 | pub #field_name: #field_type<'d, MODE> |
| 419 | }; | 425 | }; |
| 420 | let region_name = format_ident!("{}", region_name); | 426 | let region_name = format_ident!("{}", region_name); |
| 421 | let init = quote! { | 427 | let init = quote! { |
| 422 | #field_name: #field_type(&#region_name, unsafe { p.clone_unchecked()}, core::marker::PhantomData) | 428 | #field_name: #field_type(&#region_name, unsafe { p.clone_unchecked()}, core::marker::PhantomData) |
| 423 | }; | 429 | }; |
| 424 | 430 | ||
| 425 | (field, (init, region_name)) | 431 | (field, (init, region_name)) |
| 426 | }) | 432 | }) |
| 427 | .unzip(); | 433 | .unzip(); |
| 428 | |||
| 429 | let regions_len = flash_memory_regions.len(); | ||
| 430 | flash_regions.extend(quote! { | ||
| 431 | #[cfg(flash)] | ||
| 432 | pub struct FlashLayout<'d, MODE = crate::flash::Async> { | ||
| 433 | #(#fields),*, | ||
| 434 | _mode: core::marker::PhantomData<MODE>, | ||
| 435 | } | ||
| 436 | 434 | ||
| 437 | #[cfg(flash)] | 435 | let regions_len = flash_memory_regions.len(); |
| 438 | impl<'d, MODE> FlashLayout<'d, MODE> { | 436 | flash_regions.extend(quote! { |
| 439 | pub(crate) fn new(p: embassy_hal_internal::Peri<'d, crate::peripherals::FLASH>) -> Self { | 437 | #[cfg(flash)] |
| 440 | Self { | 438 | pub struct FlashLayout<'d, MODE = crate::flash::Async> { |
| 441 | #(#inits),*, | 439 | #(#fields),*, |
| 442 | _mode: core::marker::PhantomData, | 440 | _mode: core::marker::PhantomData<MODE>, |
| 441 | } | ||
| 442 | |||
| 443 | #[cfg(flash)] | ||
| 444 | impl<'d, MODE> FlashLayout<'d, MODE> { | ||
| 445 | pub(crate) fn new(p: embassy_hal_internal::Peri<'d, crate::peripherals::FLASH>) -> Self { | ||
| 446 | Self { | ||
| 447 | #(#inits),*, | ||
| 448 | _mode: core::marker::PhantomData, | ||
| 449 | } | ||
| 443 | } | 450 | } |
| 444 | } | 451 | } |
| 445 | } | ||
| 446 | 452 | ||
| 447 | pub const FLASH_REGIONS: [&crate::flash::FlashRegion; #regions_len] = [ | 453 | pub const FLASH_REGIONS: [&crate::flash::FlashRegion; #regions_len] = [ |
| 448 | #(&#region_names),* | 454 | #(&#region_names),* |
| 449 | ]; | 455 | ]; |
| 450 | }); | 456 | }); |
| 451 | 457 | ||
| 452 | let max_erase_size = flash_memory_regions | 458 | let max_erase_size = flash_memory_regions |
| 453 | .iter() | 459 | .iter() |
| 454 | .map(|region| region.settings.as_ref().unwrap().erase_size) | 460 | .map(|region| region.settings.as_ref().unwrap().erase_size) |
| 455 | .max() | 461 | .max() |
| 456 | .unwrap(); | 462 | .unwrap(); |
| 457 | 463 | ||
| 458 | g.extend(quote! { pub const MAX_ERASE_SIZE: usize = #max_erase_size as usize; }); | 464 | g.extend(quote! { pub const MAX_ERASE_SIZE: usize = #max_erase_size as usize; }); |
| 459 | 465 | ||
| 460 | g.extend(quote! { pub mod flash_regions { #flash_regions } }); | 466 | g.extend(quote! { pub mod flash_regions { #flash_regions } }); |
| 467 | } | ||
| 461 | 468 | ||
| 462 | // ======== | 469 | // ======== |
| 463 | // Extract the rcc registers | 470 | // Extract the rcc registers |
| @@ -1855,7 +1862,12 @@ fn main() { | |||
| 1855 | if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" || r.kind == "lpdma" { | 1862 | if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" || r.kind == "lpdma" { |
| 1856 | for irq in p.interrupts { | 1863 | for irq in p.interrupts { |
| 1857 | let ch_name = format!("{}_{}", p.name, irq.signal); | 1864 | let ch_name = format!("{}_{}", p.name, irq.signal); |
| 1858 | let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name).unwrap(); | 1865 | let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name); |
| 1866 | |||
| 1867 | if ch.is_none() { | ||
| 1868 | continue; | ||
| 1869 | } | ||
| 1870 | let ch = ch.unwrap(); | ||
| 1859 | 1871 | ||
| 1860 | // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it. | 1872 | // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it. |
| 1861 | if has_dmamux && ch.dmamux.is_none() { | 1873 | if has_dmamux && ch.dmamux.is_none() { |
| @@ -2008,31 +2020,33 @@ fn main() { | |||
| 2008 | // ======== | 2020 | // ======== |
| 2009 | // Generate flash constants | 2021 | // Generate flash constants |
| 2010 | 2022 | ||
| 2011 | let flash_regions: Vec<&MemoryRegion> = memory | 2023 | if has_flash { |
| 2012 | .iter() | 2024 | let flash_regions: Vec<&MemoryRegion> = memory |
| 2013 | .filter(|x| x.kind == MemoryRegionKind::Flash && x.name.starts_with("BANK_")) | 2025 | .iter() |
| 2014 | .collect(); | 2026 | .filter(|x| x.kind == MemoryRegionKind::Flash && x.name.starts_with("BANK_")) |
| 2015 | let first_flash = flash_regions.first().unwrap(); | 2027 | .collect(); |
| 2016 | let total_flash_size = flash_regions | 2028 | let first_flash = flash_regions.first().unwrap(); |
| 2017 | .iter() | 2029 | let total_flash_size = flash_regions |
| 2018 | .map(|x| x.size) | 2030 | .iter() |
| 2019 | .reduce(|acc, item| acc + item) | 2031 | .map(|x| x.size) |
| 2020 | .unwrap(); | 2032 | .reduce(|acc, item| acc + item) |
| 2021 | let write_sizes: HashSet<_> = flash_regions | 2033 | .unwrap(); |
| 2022 | .iter() | 2034 | let write_sizes: HashSet<_> = flash_regions |
| 2023 | .map(|r| r.settings.as_ref().unwrap().write_size) | 2035 | .iter() |
| 2024 | .collect(); | 2036 | .map(|r| r.settings.as_ref().unwrap().write_size) |
| 2025 | assert_eq!(1, write_sizes.len()); | 2037 | .collect(); |
| 2038 | assert_eq!(1, write_sizes.len()); | ||
| 2026 | 2039 | ||
| 2027 | let flash_base = first_flash.address as usize; | 2040 | let flash_base = first_flash.address as usize; |
| 2028 | let total_flash_size = total_flash_size as usize; | 2041 | let total_flash_size = total_flash_size as usize; |
| 2029 | let write_size = (*write_sizes.iter().next().unwrap()) as usize; | 2042 | let write_size = (*write_sizes.iter().next().unwrap()) as usize; |
| 2030 | 2043 | ||
| 2031 | g.extend(quote!( | 2044 | g.extend(quote!( |
| 2032 | pub const FLASH_BASE: usize = #flash_base; | 2045 | pub const FLASH_BASE: usize = #flash_base; |
| 2033 | pub const FLASH_SIZE: usize = #total_flash_size; | 2046 | pub const FLASH_SIZE: usize = #total_flash_size; |
| 2034 | pub const WRITE_SIZE: usize = #write_size; | 2047 | pub const WRITE_SIZE: usize = #write_size; |
| 2035 | )); | 2048 | )); |
| 2049 | } | ||
| 2036 | 2050 | ||
| 2037 | // ======== | 2051 | // ======== |
| 2038 | // Generate EEPROM constants | 2052 | // Generate EEPROM constants |
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 | |||
| 136 | 136 | ||
| 137 | impl AnyChannel { | 137 | impl AnyChannel { |
| 138 | /// Safety: Must be called with a matching set of parameters for a valid dma channel | 138 | /// Safety: Must be called with a matching set of parameters for a valid dma channel |
| 139 | #[cfg(not(stm32n6))] | ||
| 139 | pub(crate) unsafe fn on_irq(&self) { | 140 | pub(crate) unsafe fn on_irq(&self) { |
| 140 | let info = self.info(); | 141 | let info = self.info(); |
| 141 | #[cfg(feature = "_dual-core")] | 142 | #[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; | |||
| 46 | pub type Request = (); | 46 | pub type Request = (); |
| 47 | 47 | ||
| 48 | pub(crate) trait SealedChannel { | 48 | pub(crate) trait SealedChannel { |
| 49 | #[cfg(not(stm32n6))] | ||
| 49 | fn id(&self) -> u8; | 50 | fn id(&self) -> u8; |
| 50 | } | 51 | } |
| 51 | 52 | ||
| 53 | #[cfg(not(stm32n6))] | ||
| 52 | pub(crate) trait ChannelInterrupt { | 54 | pub(crate) trait ChannelInterrupt { |
| 53 | #[cfg_attr(not(feature = "rt"), allow(unused))] | 55 | #[cfg_attr(not(feature = "rt"), allow(unused))] |
| 54 | unsafe fn on_irq(); | 56 | unsafe fn on_irq(); |
| @@ -58,6 +60,7 @@ pub(crate) trait ChannelInterrupt { | |||
| 58 | #[allow(private_bounds)] | 60 | #[allow(private_bounds)] |
| 59 | pub trait Channel: SealedChannel + PeripheralType + Into<AnyChannel> + 'static {} | 61 | pub trait Channel: SealedChannel + PeripheralType + Into<AnyChannel> + 'static {} |
| 60 | 62 | ||
| 63 | #[cfg(not(stm32n6))] | ||
| 61 | macro_rules! dma_channel_impl { | 64 | macro_rules! dma_channel_impl { |
| 62 | ($channel_peri:ident, $index:expr) => { | 65 | ($channel_peri:ident, $index:expr) => { |
| 63 | impl crate::dma::SealedChannel for crate::peripherals::$channel_peri { | 66 | impl crate::dma::SealedChannel for crate::peripherals::$channel_peri { |
| @@ -96,6 +99,7 @@ impl AnyChannel { | |||
| 96 | } | 99 | } |
| 97 | 100 | ||
| 98 | impl SealedChannel for AnyChannel { | 101 | impl SealedChannel for AnyChannel { |
| 102 | #[cfg(not(stm32n6))] | ||
| 99 | fn id(&self) -> u8 { | 103 | fn id(&self) -> u8 { |
| 100 | self.id | 104 | self.id |
| 101 | } | 105 | } |
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 { | |||
| 49 | /// EXTI13 | 49 | /// EXTI13 |
| 50 | Exti13 = 4, | 50 | Exti13 = 4, |
| 51 | } | 51 | } |
| 52 | |||
| 53 | /// Trigger selection for N6 | ||
| 54 | #[cfg(stm32n6)] | ||
| 55 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 56 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 57 | pub enum TriggerSel { | ||
| 58 | /// Software triggering. Performs continuous measurements. | ||
| 59 | Software = 0, | ||
| 60 | /// LPTIM4 OUT | ||
| 61 | Lptim4 = 1, | ||
| 62 | /// LPTIM2 CH1 | ||
| 63 | Lptim2 = 2, | ||
| 64 | /// LPTIM3 CH1 | ||
| 65 | Lptim3 = 3, | ||
| 66 | /// EXTI13 | ||
| 67 | Exti13 = 4, | ||
| 68 | } | ||
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 2f5c3406a..cb46d362c 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs | |||
| @@ -8,7 +8,7 @@ use core::task::{Context, Poll}; | |||
| 8 | use embassy_hal_internal::{PeripheralType, impl_peripheral}; | 8 | use embassy_hal_internal::{PeripheralType, impl_peripheral}; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 10 | 10 | ||
| 11 | use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, Pull}; | 11 | use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, PinNumber, Pull}; |
| 12 | use crate::pac::EXTI; | 12 | use crate::pac::EXTI; |
| 13 | use crate::pac::exti::regs::Lines; | 13 | use crate::pac::exti::regs::Lines; |
| 14 | use crate::{Peri, interrupt, pac, peripherals}; | 14 | use crate::{Peri, interrupt, pac, peripherals}; |
| @@ -31,11 +31,11 @@ fn cpu_regs() -> pac::exti::Exti { | |||
| 31 | EXTI | 31 | EXTI |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))] | 34 | #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50, exti_n6)))] |
| 35 | fn exticr_regs() -> pac::syscfg::Syscfg { | 35 | fn exticr_regs() -> pac::syscfg::Syscfg { |
| 36 | pac::SYSCFG | 36 | pac::SYSCFG |
| 37 | } | 37 | } |
| 38 | #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] | 38 | #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))] |
| 39 | fn exticr_regs() -> pac::exti::Exti { | 39 | fn exticr_regs() -> pac::exti::Exti { |
| 40 | EXTI | 40 | EXTI |
| 41 | } | 41 | } |
| @@ -45,9 +45,9 @@ fn exticr_regs() -> pac::afio::Afio { | |||
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | unsafe fn on_irq() { | 47 | unsafe fn on_irq() { |
| 48 | #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] | 48 | #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))] |
| 49 | let bits = EXTI.pr(0).read().0; | 49 | let bits = EXTI.pr(0).read().0; |
| 50 | #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] | 50 | #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))] |
| 51 | let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0; | 51 | let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0; |
| 52 | 52 | ||
| 53 | // We don't handle or change any EXTI lines above 16. | 53 | // We don't handle or change any EXTI lines above 16. |
| @@ -62,9 +62,9 @@ unsafe fn on_irq() { | |||
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | // Clear pending | 64 | // Clear pending |
| 65 | #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] | 65 | #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))] |
| 66 | EXTI.pr(0).write_value(Lines(bits)); | 66 | EXTI.pr(0).write_value(Lines(bits)); |
| 67 | #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] | 67 | #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))] |
| 68 | { | 68 | { |
| 69 | EXTI.rpr(0).write_value(Lines(bits)); | 69 | EXTI.rpr(0).write_value(Lines(bits)); |
| 70 | EXTI.fpr(0).write_value(Lines(bits)); | 70 | EXTI.fpr(0).write_value(Lines(bits)); |
| @@ -226,12 +226,12 @@ impl<'d> embedded_hal_async::digital::Wait for ExtiInput<'d> { | |||
| 226 | 226 | ||
| 227 | #[must_use = "futures do nothing unless you `.await` or poll them"] | 227 | #[must_use = "futures do nothing unless you `.await` or poll them"] |
| 228 | struct ExtiInputFuture<'a> { | 228 | struct ExtiInputFuture<'a> { |
| 229 | pin: u8, | 229 | pin: PinNumber, |
| 230 | phantom: PhantomData<&'a mut AnyPin>, | 230 | phantom: PhantomData<&'a mut AnyPin>, |
| 231 | } | 231 | } |
| 232 | 232 | ||
| 233 | impl<'a> ExtiInputFuture<'a> { | 233 | impl<'a> ExtiInputFuture<'a> { |
| 234 | fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self { | 234 | fn new(pin: PinNumber, port: PinNumber, rising: bool, falling: bool) -> Self { |
| 235 | critical_section::with(|_| { | 235 | critical_section::with(|_| { |
| 236 | let pin = pin as usize; | 236 | let pin = pin as usize; |
| 237 | exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port)); | 237 | exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port)); |
| @@ -239,9 +239,9 @@ impl<'a> ExtiInputFuture<'a> { | |||
| 239 | EXTI.ftsr(0).modify(|w| w.set_line(pin, falling)); | 239 | EXTI.ftsr(0).modify(|w| w.set_line(pin, falling)); |
| 240 | 240 | ||
| 241 | // clear pending bit | 241 | // clear pending bit |
| 242 | #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] | 242 | #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))] |
| 243 | EXTI.pr(0).write(|w| w.set_line(pin, true)); | 243 | EXTI.pr(0).write(|w| w.set_line(pin, true)); |
| 244 | #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] | 244 | #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))] |
| 245 | { | 245 | { |
| 246 | EXTI.rpr(0).write(|w| w.set_line(pin, true)); | 246 | EXTI.rpr(0).write(|w| w.set_line(pin, true)); |
| 247 | EXTI.fpr(0).write(|w| w.set_line(pin, true)); | 247 | EXTI.fpr(0).write(|w| w.set_line(pin, true)); |
| @@ -334,20 +334,20 @@ trait SealedChannel {} | |||
| 334 | #[allow(private_bounds)] | 334 | #[allow(private_bounds)] |
| 335 | pub trait Channel: PeripheralType + SealedChannel + Sized { | 335 | pub trait Channel: PeripheralType + SealedChannel + Sized { |
| 336 | /// Get the EXTI channel number. | 336 | /// Get the EXTI channel number. |
| 337 | fn number(&self) -> u8; | 337 | fn number(&self) -> PinNumber; |
| 338 | } | 338 | } |
| 339 | 339 | ||
| 340 | /// Type-erased EXTI channel. | 340 | /// Type-erased EXTI channel. |
| 341 | /// | 341 | /// |
| 342 | /// This represents ownership over any EXTI channel, known at runtime. | 342 | /// This represents ownership over any EXTI channel, known at runtime. |
| 343 | pub struct AnyChannel { | 343 | pub struct AnyChannel { |
| 344 | number: u8, | 344 | number: PinNumber, |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | impl_peripheral!(AnyChannel); | 347 | impl_peripheral!(AnyChannel); |
| 348 | impl SealedChannel for AnyChannel {} | 348 | impl SealedChannel for AnyChannel {} |
| 349 | impl Channel for AnyChannel { | 349 | impl Channel for AnyChannel { |
| 350 | fn number(&self) -> u8 { | 350 | fn number(&self) -> PinNumber { |
| 351 | self.number | 351 | self.number |
| 352 | } | 352 | } |
| 353 | } | 353 | } |
| @@ -356,7 +356,7 @@ macro_rules! impl_exti { | |||
| 356 | ($type:ident, $number:expr) => { | 356 | ($type:ident, $number:expr) => { |
| 357 | impl SealedChannel for peripherals::$type {} | 357 | impl SealedChannel for peripherals::$type {} |
| 358 | impl Channel for peripherals::$type { | 358 | impl Channel for peripherals::$type { |
| 359 | fn number(&self) -> u8 { | 359 | fn number(&self) -> PinNumber { |
| 360 | $number | 360 | $number |
| 361 | } | 361 | } |
| 362 | } | 362 | } |
| @@ -364,7 +364,7 @@ macro_rules! impl_exti { | |||
| 364 | impl From<peripherals::$type> for AnyChannel { | 364 | impl From<peripherals::$type> for AnyChannel { |
| 365 | fn from(val: peripherals::$type) -> Self { | 365 | fn from(val: peripherals::$type) -> Self { |
| 366 | Self { | 366 | Self { |
| 367 | number: val.number() as u8, | 367 | number: val.number() as PinNumber, |
| 368 | } | 368 | } |
| 369 | } | 369 | } |
| 370 | } | 370 | } |
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index b55baffdc..17c5a9962 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs | |||
| @@ -592,7 +592,7 @@ impl AfType { | |||
| 592 | 592 | ||
| 593 | #[inline(never)] | 593 | #[inline(never)] |
| 594 | #[cfg(gpio_v1)] | 594 | #[cfg(gpio_v1)] |
| 595 | fn set_as_af(pin_port: u8, af_type: AfType) { | 595 | fn set_as_af(pin_port: PinNumber, af_type: AfType) { |
| 596 | let pin = unsafe { AnyPin::steal(pin_port) }; | 596 | let pin = unsafe { AnyPin::steal(pin_port) }; |
| 597 | let r = pin.block(); | 597 | let r = pin.block(); |
| 598 | let n = pin._pin() as usize; | 598 | let n = pin._pin() as usize; |
| @@ -649,7 +649,7 @@ impl AfType { | |||
| 649 | 649 | ||
| 650 | #[inline(never)] | 650 | #[inline(never)] |
| 651 | #[cfg(gpio_v2)] | 651 | #[cfg(gpio_v2)] |
| 652 | fn set_as_af(pin_port: u8, af_num: u8, af_type: AfType) { | 652 | fn set_as_af(pin_port: PinNumber, af_num: u8, af_type: AfType) { |
| 653 | let pin = unsafe { AnyPin::steal(pin_port) }; | 653 | let pin = unsafe { AnyPin::steal(pin_port) }; |
| 654 | let r = pin.block(); | 654 | let r = pin.block(); |
| 655 | let n = pin._pin() as usize; | 655 | let n = pin._pin() as usize; |
| @@ -663,7 +663,7 @@ fn set_as_af(pin_port: u8, af_num: u8, af_type: AfType) { | |||
| 663 | 663 | ||
| 664 | #[inline(never)] | 664 | #[inline(never)] |
| 665 | #[cfg(gpio_v2)] | 665 | #[cfg(gpio_v2)] |
| 666 | fn set_speed(pin_port: u8, speed: Speed) { | 666 | fn set_speed(pin_port: PinNumber, speed: Speed) { |
| 667 | let pin = unsafe { AnyPin::steal(pin_port) }; | 667 | let pin = unsafe { AnyPin::steal(pin_port) }; |
| 668 | let r = pin.block(); | 668 | let r = pin.block(); |
| 669 | let n = pin._pin() as usize; | 669 | let n = pin._pin() as usize; |
| @@ -672,7 +672,7 @@ fn set_speed(pin_port: u8, speed: Speed) { | |||
| 672 | } | 672 | } |
| 673 | 673 | ||
| 674 | #[inline(never)] | 674 | #[inline(never)] |
| 675 | fn set_as_analog(pin_port: u8) { | 675 | fn set_as_analog(pin_port: PinNumber) { |
| 676 | let pin = unsafe { AnyPin::steal(pin_port) }; | 676 | let pin = unsafe { AnyPin::steal(pin_port) }; |
| 677 | let r = pin.block(); | 677 | let r = pin.block(); |
| 678 | let n = pin._pin() as usize; | 678 | let n = pin._pin() as usize; |
| @@ -688,7 +688,7 @@ fn set_as_analog(pin_port: u8) { | |||
| 688 | } | 688 | } |
| 689 | 689 | ||
| 690 | #[inline(never)] | 690 | #[inline(never)] |
| 691 | fn get_pull(pin_port: u8) -> Pull { | 691 | fn get_pull(pin_port: PinNumber) -> Pull { |
| 692 | let pin = unsafe { AnyPin::steal(pin_port) }; | 692 | let pin = unsafe { AnyPin::steal(pin_port) }; |
| 693 | let r = pin.block(); | 693 | let r = pin.block(); |
| 694 | let n = pin._pin() as usize; | 694 | let n = pin._pin() as usize; |
| @@ -727,15 +727,15 @@ pub struct AfioRemapBool<const V: bool>; | |||
| 727 | pub struct AfioRemapNotApplicable; | 727 | pub struct AfioRemapNotApplicable; |
| 728 | 728 | ||
| 729 | pub(crate) trait SealedPin { | 729 | pub(crate) trait SealedPin { |
| 730 | fn pin_port(&self) -> u8; | 730 | fn pin_port(&self) -> PinNumber; |
| 731 | 731 | ||
| 732 | #[inline] | 732 | #[inline] |
| 733 | fn _pin(&self) -> u8 { | 733 | fn _pin(&self) -> PinNumber { |
| 734 | self.pin_port() % 16 | 734 | self.pin_port() % 16 |
| 735 | } | 735 | } |
| 736 | 736 | ||
| 737 | #[inline] | 737 | #[inline] |
| 738 | fn _port(&self) -> u8 { | 738 | fn _port(&self) -> PinNumber { |
| 739 | self.pin_port() / 16 | 739 | self.pin_port() / 16 |
| 740 | } | 740 | } |
| 741 | 741 | ||
| @@ -798,6 +798,20 @@ pub(crate) trait SealedPin { | |||
| 798 | } | 798 | } |
| 799 | } | 799 | } |
| 800 | 800 | ||
| 801 | /// GPIO pin number type. | ||
| 802 | /// | ||
| 803 | /// Some chips have a total number of ports that exceeds 8, a larger integer | ||
| 804 | /// is needed to hold the total pin number `(ports * number)`. | ||
| 805 | #[cfg(not(stm32n6))] | ||
| 806 | pub type PinNumber = u8; | ||
| 807 | |||
| 808 | /// GPIO pin number type. | ||
| 809 | /// | ||
| 810 | /// Some chips have a total number of ports that exceeds 8, a larger integer | ||
| 811 | /// is needed to hold the total pin number `(ports * number)`. | ||
| 812 | #[cfg(stm32n6)] | ||
| 813 | pub type PinNumber = u16; | ||
| 814 | |||
| 801 | /// GPIO pin trait. | 815 | /// GPIO pin trait. |
| 802 | #[allow(private_bounds)] | 816 | #[allow(private_bounds)] |
| 803 | pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static { | 817 | pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static { |
| @@ -809,20 +823,20 @@ pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static { | |||
| 809 | 823 | ||
| 810 | /// Number of the pin within the port (0..31) | 824 | /// Number of the pin within the port (0..31) |
| 811 | #[inline] | 825 | #[inline] |
| 812 | fn pin(&self) -> u8 { | 826 | fn pin(&self) -> PinNumber { |
| 813 | self._pin() | 827 | self._pin() |
| 814 | } | 828 | } |
| 815 | 829 | ||
| 816 | /// Port of the pin | 830 | /// Port of the pin |
| 817 | #[inline] | 831 | #[inline] |
| 818 | fn port(&self) -> u8 { | 832 | fn port(&self) -> PinNumber { |
| 819 | self._port() | 833 | self._port() |
| 820 | } | 834 | } |
| 821 | } | 835 | } |
| 822 | 836 | ||
| 823 | /// Type-erased GPIO pin | 837 | /// Type-erased GPIO pin |
| 824 | pub struct AnyPin { | 838 | pub struct AnyPin { |
| 825 | pin_port: u8, | 839 | pin_port: PinNumber, |
| 826 | } | 840 | } |
| 827 | 841 | ||
| 828 | impl AnyPin { | 842 | impl AnyPin { |
| @@ -830,12 +844,12 @@ impl AnyPin { | |||
| 830 | /// | 844 | /// |
| 831 | /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc... | 845 | /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc... |
| 832 | #[inline] | 846 | #[inline] |
| 833 | pub unsafe fn steal(pin_port: u8) -> Peri<'static, Self> { | 847 | pub unsafe fn steal(pin_port: PinNumber) -> Peri<'static, Self> { |
| 834 | Peri::new_unchecked(Self { pin_port }) | 848 | Peri::new_unchecked(Self { pin_port }) |
| 835 | } | 849 | } |
| 836 | 850 | ||
| 837 | #[inline] | 851 | #[inline] |
| 838 | fn _port(&self) -> u8 { | 852 | fn _port(&self) -> PinNumber { |
| 839 | self.pin_port / 16 | 853 | self.pin_port / 16 |
| 840 | } | 854 | } |
| 841 | 855 | ||
| @@ -854,7 +868,7 @@ impl Pin for AnyPin { | |||
| 854 | } | 868 | } |
| 855 | impl SealedPin for AnyPin { | 869 | impl SealedPin for AnyPin { |
| 856 | #[inline] | 870 | #[inline] |
| 857 | fn pin_port(&self) -> u8 { | 871 | fn pin_port(&self) -> PinNumber { |
| 858 | self.pin_port | 872 | self.pin_port |
| 859 | } | 873 | } |
| 860 | } | 874 | } |
| @@ -869,7 +883,7 @@ foreach_pin!( | |||
| 869 | } | 883 | } |
| 870 | impl SealedPin for peripherals::$pin_name { | 884 | impl SealedPin for peripherals::$pin_name { |
| 871 | #[inline] | 885 | #[inline] |
| 872 | fn pin_port(&self) -> u8 { | 886 | fn pin_port(&self) -> PinNumber { |
| 873 | $port_num * 16 + $pin_num | 887 | $port_num * 16 + $pin_num |
| 874 | } | 888 | } |
| 875 | } | 889 | } |
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index e08ab30e6..680edf433 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -77,6 +77,7 @@ pub mod dts; | |||
| 77 | pub mod eth; | 77 | pub mod eth; |
| 78 | #[cfg(feature = "exti")] | 78 | #[cfg(feature = "exti")] |
| 79 | pub mod exti; | 79 | pub mod exti; |
| 80 | #[cfg(flash)] | ||
| 80 | pub mod flash; | 81 | pub mod flash; |
| 81 | #[cfg(fmc)] | 82 | #[cfg(fmc)] |
| 82 | pub mod fmc; | 83 | pub mod fmc; |
| @@ -177,7 +178,6 @@ pub use crate::_generated::interrupt; | |||
| 177 | /// } | 178 | /// } |
| 178 | /// ); | 179 | /// ); |
| 179 | /// ``` | 180 | /// ``` |
| 180 | |||
| 181 | // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. | 181 | // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. |
| 182 | #[macro_export] | 182 | #[macro_export] |
| 183 | macro_rules! bind_interrupts { | 183 | macro_rules! bind_interrupts { |
| @@ -510,6 +510,16 @@ fn init_hw(config: Config) -> Peripherals { | |||
| 510 | critical_section::with(|cs| { | 510 | critical_section::with(|cs| { |
| 511 | let p = Peripherals::take_with_cs(cs); | 511 | let p = Peripherals::take_with_cs(cs); |
| 512 | 512 | ||
| 513 | #[cfg(dbgmcu_n6)] | ||
| 514 | { | ||
| 515 | crate::pac::RCC.miscensr().write(|w| w.set_dbgens(true)); | ||
| 516 | crate::pac::RCC.miscenr().read(); // volatile read | ||
| 517 | crate::pac::DBGMCU | ||
| 518 | .cr() | ||
| 519 | .modify(|w| w.set_dbgclken(stm32_metapac::dbgmcu::vals::Dbgclken::B_0X1)); | ||
| 520 | crate::pac::DBGMCU.cr().read(); | ||
| 521 | } | ||
| 522 | |||
| 513 | #[cfg(dbgmcu)] | 523 | #[cfg(dbgmcu)] |
| 514 | crate::pac::DBGMCU.cr().modify(|cr| { | 524 | crate::pac::DBGMCU.cr().modify(|cr| { |
| 515 | #[cfg(dbgmcu_h5)] | 525 | #[cfg(dbgmcu_h5)] |
| @@ -524,7 +534,7 @@ fn init_hw(config: Config) -> Peripherals { | |||
| 524 | } | 534 | } |
| 525 | #[cfg(any( | 535 | #[cfg(any( |
| 526 | dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, | 536 | dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, |
| 527 | dbgmcu_l4, dbgmcu_wb, dbgmcu_wl | 537 | dbgmcu_l4, dbgmcu_wb, dbgmcu_wl, dbgmcu_n6 |
| 528 | ))] | 538 | ))] |
| 529 | { | 539 | { |
| 530 | cr.set_dbg_sleep(config.enable_debug_during_sleep); | 540 | cr.set_dbg_sleep(config.enable_debug_during_sleep); |
| @@ -545,7 +555,7 @@ fn init_hw(config: Config) -> Peripherals { | |||
| 545 | rcc::enable_and_reset_with_cs::<peripherals::SYSCFG>(cs); | 555 | rcc::enable_and_reset_with_cs::<peripherals::SYSCFG>(cs); |
| 546 | #[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))] | 556 | #[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))] |
| 547 | rcc::enable_and_reset_with_cs::<peripherals::PWR>(cs); | 557 | rcc::enable_and_reset_with_cs::<peripherals::PWR>(cs); |
| 548 | #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs)))] | 558 | #[cfg(all(flash, not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs))))] |
| 549 | rcc::enable_and_reset_with_cs::<peripherals::FLASH>(cs); | 559 | rcc::enable_and_reset_with_cs::<peripherals::FLASH>(cs); |
| 550 | 560 | ||
| 551 | // Enable the VDDIO2 power supply on chips that have it. | 561 | // Enable the VDDIO2 power supply on chips that have it. |
| @@ -605,7 +615,7 @@ fn init_hw(config: Config) -> Peripherals { | |||
| 605 | #[cfg(ucpd)] | 615 | #[cfg(ucpd)] |
| 606 | ucpd::init( | 616 | ucpd::init( |
| 607 | cs, | 617 | cs, |
| 608 | #[cfg(peri_ucpd1)] | 618 | #[cfg(all(peri_ucpd1, not(stm32n6)))] |
| 609 | config.enable_ucpd1_dead_battery, | 619 | config.enable_ucpd1_dead_battery, |
| 610 | #[cfg(peri_ucpd2)] | 620 | #[cfg(peri_ucpd2)] |
| 611 | config.enable_ucpd2_dead_battery, | 621 | config.enable_ucpd2_dead_battery, |
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 5b367c043..219be208f 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | #[cfg(not(stm32n6))] | ||
| 1 | use core::sync::atomic::{Ordering, compiler_fence}; | 2 | use core::sync::atomic::{Ordering, compiler_fence}; |
| 2 | 3 | ||
| 4 | #[cfg(not(stm32n6))] | ||
| 3 | use crate::pac::common::{RW, Reg}; | 5 | use crate::pac::common::{RW, Reg}; |
| 4 | #[cfg(backup_sram)] | 6 | #[cfg(backup_sram)] |
| 5 | use crate::pac::pwr::vals::Retention; | 7 | use crate::pac::pwr::vals::Retention; |
| @@ -54,7 +56,7 @@ impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv { | |||
| 54 | } | 56 | } |
| 55 | } | 57 | } |
| 56 | 58 | ||
| 57 | #[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0)))] | 59 | #[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0, stm32n6)))] |
| 58 | type Bdcr = crate::pac::rcc::regs::Bdcr; | 60 | type Bdcr = crate::pac::rcc::regs::Bdcr; |
| 59 | #[cfg(any(rtc_v2_l0, rtc_v2_l1))] | 61 | #[cfg(any(rtc_v2_l0, rtc_v2_l1))] |
| 60 | type Bdcr = crate::pac::rcc::regs::Csr; | 62 | type Bdcr = crate::pac::rcc::regs::Csr; |
| @@ -64,19 +66,22 @@ type Bdcr = crate::pac::rcc::regs::Csr1; | |||
| 64 | #[cfg(any(stm32c0))] | 66 | #[cfg(any(stm32c0))] |
| 65 | fn unlock() {} | 67 | fn unlock() {} |
| 66 | 68 | ||
| 67 | #[cfg(not(any(stm32c0)))] | 69 | #[cfg(not(any(stm32c0, stm32n6)))] |
| 68 | fn unlock() { | 70 | fn unlock() { |
| 69 | #[cfg(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1))] | 71 | #[cfg(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1))] |
| 70 | let cr = crate::pac::PWR.cr(); | 72 | let cr = crate::pac::PWR.cr(); |
| 71 | #[cfg(not(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba)))] | 73 | #[cfg(not(any( |
| 74 | stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba, stm32n6 | ||
| 75 | )))] | ||
| 72 | let cr = crate::pac::PWR.cr1(); | 76 | let cr = crate::pac::PWR.cr1(); |
| 73 | #[cfg(any(stm32u5, stm32h5, stm32wba))] | 77 | #[cfg(any(stm32u5, stm32h5, stm32wba, stm32n6))] |
| 74 | let cr = crate::pac::PWR.dbpcr(); | 78 | let cr = crate::pac::PWR.dbpcr(); |
| 75 | 79 | ||
| 76 | cr.modify(|w| w.set_dbp(true)); | 80 | cr.modify(|w| w.set_dbp(true)); |
| 77 | while !cr.read().dbp() {} | 81 | while !cr.read().dbp() {} |
| 78 | } | 82 | } |
| 79 | 83 | ||
| 84 | #[cfg(not(stm32n6))] | ||
| 80 | fn bdcr() -> Reg<Bdcr, RW> { | 85 | fn bdcr() -> Reg<Bdcr, RW> { |
| 81 | #[cfg(any(rtc_v2_l0, rtc_v2_l1))] | 86 | #[cfg(any(rtc_v2_l0, rtc_v2_l1))] |
| 82 | return crate::pac::RCC.csr(); | 87 | return crate::pac::RCC.csr(); |
| @@ -150,6 +155,7 @@ impl Default for LsConfig { | |||
| 150 | } | 155 | } |
| 151 | 156 | ||
| 152 | impl LsConfig { | 157 | impl LsConfig { |
| 158 | #[cfg(not(stm32n6))] | ||
| 153 | pub(crate) fn init(&self) -> Option<Hertz> { | 159 | pub(crate) fn init(&self) -> Option<Hertz> { |
| 154 | let rtc_clk = match self.rtc { | 160 | let rtc_clk = match self.rtc { |
| 155 | RtcClockSource::LSI => { | 161 | RtcClockSource::LSI => { |
| @@ -185,14 +191,19 @@ impl LsConfig { | |||
| 185 | if self.lsi { | 191 | if self.lsi { |
| 186 | #[cfg(any(stm32u5, stm32h5, stm32wba))] | 192 | #[cfg(any(stm32u5, stm32h5, stm32wba))] |
| 187 | let csr = crate::pac::RCC.bdcr(); | 193 | let csr = crate::pac::RCC.bdcr(); |
| 188 | #[cfg(not(any(stm32u5, stm32h5, stm32wba, stm32c0)))] | 194 | #[cfg(stm32n6)] |
| 195 | let csr = crate::pac::RCC.sr(); | ||
| 196 | #[cfg(not(any(stm32u5, stm32h5, stm32wba, stm32c0, stm32n6)))] | ||
| 189 | let csr = crate::pac::RCC.csr(); | 197 | let csr = crate::pac::RCC.csr(); |
| 190 | #[cfg(any(stm32c0))] | 198 | #[cfg(stm32c0)] |
| 191 | let csr = crate::pac::RCC.csr2(); | 199 | let csr = crate::pac::RCC.csr2(); |
| 192 | 200 | ||
| 193 | #[cfg(not(any(rcc_wb, rcc_wba)))] | 201 | #[cfg(not(any(rcc_wb, rcc_wba, rcc_n6)))] |
| 194 | csr.modify(|w| w.set_lsion(true)); | 202 | csr.modify(|w| w.set_lsion(true)); |
| 195 | 203 | ||
| 204 | #[cfg(rcc_n6)] | ||
| 205 | crate::pac::RCC.cr().modify(|w| w.set_lsion(true)); | ||
| 206 | |||
| 196 | #[cfg(any(rcc_wb, rcc_wba))] | 207 | #[cfg(any(rcc_wb, rcc_wba))] |
| 197 | csr.modify(|w| w.set_lsi1on(true)); | 208 | csr.modify(|w| w.set_lsi1on(true)); |
| 198 | 209 | ||
| @@ -222,25 +233,58 @@ impl LsConfig { | |||
| 222 | // backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets. | 233 | // backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets. |
| 223 | // once set, changing it requires a backup domain reset. | 234 | // once set, changing it requires a backup domain reset. |
| 224 | // first check if the configuration matches what we want. | 235 | // first check if the configuration matches what we want. |
| 236 | // N6 has all the fields spread across multiple registers under RCC. | ||
| 225 | 237 | ||
| 226 | // check if it's already enabled and in the source we want. | 238 | // check if it's already enabled and in the source we want. |
| 239 | #[cfg(not(rcc_n6))] | ||
| 227 | let reg = bdcr().read(); | 240 | let reg = bdcr().read(); |
| 241 | #[cfg(rcc_n6)] | ||
| 242 | let reg = crate::pac::RCC.cr().read(); | ||
| 243 | #[cfg(rcc_n6)] | ||
| 244 | let apb4lenr = crate::pac::RCC.apb4lenr().read(); | ||
| 245 | #[cfg(rcc_n6)] | ||
| 246 | let ccipr7 = crate::pac::RCC.ccipr7().read(); | ||
| 247 | #[cfg(rcc_n6)] | ||
| 248 | let lsecfgr = crate::pac::RCC.lsecfgr().read(); | ||
| 249 | |||
| 228 | let mut ok = true; | 250 | let mut ok = true; |
| 229 | ok &= reg.rtcsel() == self.rtc; | 251 | #[cfg(not(rcc_n6))] |
| 230 | #[cfg(not(rcc_wba))] | 252 | { |
| 253 | ok &= reg.rtcsel() == self.rtc; | ||
| 254 | } | ||
| 255 | #[cfg(rcc_n6)] | ||
| 256 | { | ||
| 257 | ok &= ccipr7.rtcsel() == self.rtc; | ||
| 258 | } | ||
| 259 | #[cfg(not(any(rcc_wba, rcc_n6)))] | ||
| 231 | { | 260 | { |
| 232 | ok &= reg.rtcen() == (self.rtc != RtcClockSource::DISABLE); | 261 | ok &= reg.rtcen() == (self.rtc != RtcClockSource::DISABLE); |
| 233 | } | 262 | } |
| 263 | #[cfg(rcc_n6)] | ||
| 264 | { | ||
| 265 | ok &= apb4lenr.rtcen() == (self.rtc != RtcClockSource::DISABLE); | ||
| 266 | } | ||
| 234 | ok &= reg.lseon() == lse_en; | 267 | ok &= reg.lseon() == lse_en; |
| 235 | ok &= reg.lsebyp() == lse_byp; | 268 | #[cfg(not(rcc_n6))] |
| 269 | { | ||
| 270 | ok &= reg.lsebyp() == lse_byp; | ||
| 271 | } | ||
| 272 | #[cfg(rcc_n6)] | ||
| 273 | { | ||
| 274 | ok &= lsecfgr.lsebyp() == lse_byp; | ||
| 275 | } | ||
| 236 | #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))] | 276 | #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))] |
| 237 | if let Some(lse_sysen) = lse_sysen { | 277 | if let Some(lse_sysen) = lse_sysen { |
| 238 | ok &= reg.lsesysen() == lse_sysen; | 278 | ok &= reg.lsesysen() == lse_sysen; |
| 239 | } | 279 | } |
| 240 | #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))] | 280 | #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1, rcc_n6)))] |
| 241 | if let Some(lse_drv) = lse_drv { | 281 | if let Some(lse_drv) = lse_drv { |
| 242 | ok &= reg.lsedrv() == lse_drv.into(); | 282 | ok &= reg.lsedrv() == lse_drv.into(); |
| 243 | } | 283 | } |
| 284 | #[cfg(rcc_n6)] | ||
| 285 | if let Some(lse_drv) = lse_drv { | ||
| 286 | ok &= lsecfgr.lsedrv() == lse_drv.into(); | ||
| 287 | } | ||
| 244 | 288 | ||
| 245 | // if configuration is OK, we're done. | 289 | // if configuration is OK, we're done. |
| 246 | if ok { | 290 | if ok { |
| @@ -249,7 +293,7 @@ impl LsConfig { | |||
| 249 | } | 293 | } |
| 250 | 294 | ||
| 251 | // If not OK, reset backup domain and configure it. | 295 | // If not OK, reset backup domain and configure it. |
| 252 | #[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32h7rs, stm32c0)))] | 296 | #[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32h7rs, stm32c0, stm32n6)))] |
| 253 | { | 297 | { |
| 254 | bdcr().modify(|w| w.set_bdrst(true)); | 298 | bdcr().modify(|w| w.set_bdrst(true)); |
| 255 | bdcr().modify(|w| w.set_bdrst(false)); | 299 | bdcr().modify(|w| w.set_bdrst(false)); |
| @@ -262,7 +306,7 @@ impl LsConfig { | |||
| 262 | // STM32H503CB/EB/KB/RB device errata - 2.2.8 SRAM2 unduly erased upon a backup domain reset | 306 | // STM32H503CB/EB/KB/RB device errata - 2.2.8 SRAM2 unduly erased upon a backup domain reset |
| 263 | // STM32H562xx/563xx/573xx device errata - 2.2.14 SRAM2 is erased when the backup domain is reset | 307 | // STM32H562xx/563xx/573xx device errata - 2.2.14 SRAM2 is erased when the backup domain is reset |
| 264 | //#[cfg(any(stm32h5, stm32h7rs))] | 308 | //#[cfg(any(stm32h5, stm32h7rs))] |
| 265 | #[cfg(any(stm32h7rs))] | 309 | #[cfg(any(stm32h7rs, stm32n6))] |
| 266 | { | 310 | { |
| 267 | bdcr().modify(|w| w.set_vswrst(true)); | 311 | bdcr().modify(|w| w.set_vswrst(true)); |
| 268 | bdcr().modify(|w| w.set_vswrst(false)); | 312 | bdcr().modify(|w| w.set_vswrst(false)); |
| @@ -274,16 +318,31 @@ impl LsConfig { | |||
| 274 | } | 318 | } |
| 275 | 319 | ||
| 276 | if lse_en { | 320 | if lse_en { |
| 277 | bdcr().modify(|w| { | 321 | #[cfg(not(rcc_n6))] |
| 278 | #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))] | 322 | { |
| 279 | if let Some(lse_drv) = lse_drv { | 323 | bdcr().modify(|w| { |
| 280 | w.set_lsedrv(lse_drv.into()); | 324 | #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))] |
| 281 | } | 325 | if let Some(lse_drv) = lse_drv { |
| 282 | w.set_lsebyp(lse_byp); | 326 | w.set_lsedrv(lse_drv.into()); |
| 283 | w.set_lseon(true); | 327 | } |
| 284 | }); | 328 | w.set_lsebyp(lse_byp); |
| 329 | w.set_lseon(true); | ||
| 330 | }); | ||
| 285 | 331 | ||
| 286 | while !bdcr().read().lserdy() {} | 332 | while !bdcr().read().lserdy() {} |
| 333 | } | ||
| 334 | #[cfg(rcc_n6)] | ||
| 335 | { | ||
| 336 | crate::pac::RCC.lsecfgr().modify(|w| { | ||
| 337 | if let Some(lse_drv) = lse_drv { | ||
| 338 | w.set_lsedrv(lse_drv.into()); | ||
| 339 | } | ||
| 340 | w.set_lsebyp(lse_byp); | ||
| 341 | }); | ||
| 342 | crate::pac::RCC.cr().modify(|w| w.set_lseon(true)); | ||
| 343 | |||
| 344 | while !crate::pac::RCC.sr().read().lserdy() {} | ||
| 345 | } | ||
| 287 | 346 | ||
| 288 | #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))] | 347 | #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))] |
| 289 | if let Some(lse_sysen) = lse_sysen { | 348 | if let Some(lse_sysen) = lse_sysen { |
| @@ -298,6 +357,7 @@ impl LsConfig { | |||
| 298 | } | 357 | } |
| 299 | 358 | ||
| 300 | if self.rtc != RtcClockSource::DISABLE { | 359 | if self.rtc != RtcClockSource::DISABLE { |
| 360 | #[cfg(not(rcc_n6))] | ||
| 301 | bdcr().modify(|w| { | 361 | bdcr().modify(|w| { |
| 302 | #[cfg(any(rtc_v2_h7, rtc_v2_l4, rtc_v2_wb, rtc_v3_base, rtc_v3_u5))] | 362 | #[cfg(any(rtc_v2_h7, rtc_v2_l4, rtc_v2_wb, rtc_v3_base, rtc_v3_u5))] |
| 303 | assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet."); | 363 | assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet."); |
| @@ -306,6 +366,12 @@ impl LsConfig { | |||
| 306 | w.set_rtcen(true); | 366 | w.set_rtcen(true); |
| 307 | w.set_rtcsel(self.rtc); | 367 | w.set_rtcsel(self.rtc); |
| 308 | }); | 368 | }); |
| 369 | |||
| 370 | #[cfg(rcc_n6)] | ||
| 371 | { | ||
| 372 | crate::pac::RCC.ccipr7().modify(|w| w.set_rtcsel(self.rtc)); | ||
| 373 | crate::pac::RCC.apb4lenr().modify(|w| w.set_rtcen(true)) | ||
| 374 | } | ||
| 309 | } | 375 | } |
| 310 | 376 | ||
| 311 | trace!("BDCR configured: {:08x}", bdcr().read().0); | 377 | trace!("BDCR configured: {:08x}", bdcr().read().0); |
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index 3d961df03..0624fdf26 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs | |||
| @@ -16,7 +16,8 @@ pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; | |||
| 16 | rcc_h7ab, | 16 | rcc_h7ab, |
| 17 | rcc_h7rm0433, | 17 | rcc_h7rm0433, |
| 18 | rcc_h7, | 18 | rcc_h7, |
| 19 | rcc_h7rs | 19 | rcc_h7rs, |
| 20 | rcc_n6 | ||
| 20 | )))] | 21 | )))] |
| 21 | pub use crate::pac::rcc::vals::Mcosel as McoSource; | 22 | pub use crate::pac::rcc::vals::Mcosel as McoSource; |
| 22 | #[cfg(any( | 23 | #[cfg(any( |
| @@ -29,7 +30,8 @@ pub use crate::pac::rcc::vals::Mcosel as McoSource; | |||
| 29 | rcc_h7ab, | 30 | rcc_h7ab, |
| 30 | rcc_h7rm0433, | 31 | rcc_h7rm0433, |
| 31 | rcc_h7, | 32 | rcc_h7, |
| 32 | rcc_h7rs | 33 | rcc_h7rs, |
| 34 | rcc_n6 | ||
| 33 | ))] | 35 | ))] |
| 34 | pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; | 36 | pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; |
| 35 | use crate::{Peri, peripherals}; | 37 | use crate::{Peri, peripherals}; |
| @@ -59,10 +61,12 @@ macro_rules! impl_peri { | |||
| 59 | type Source = $source; | 61 | type Source = $source; |
| 60 | 62 | ||
| 61 | unsafe fn _apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) { | 63 | unsafe fn _apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) { |
| 62 | #[cfg(not(any(stm32u5, stm32wba)))] | 64 | #[cfg(not(any(stm32u5, stm32wba, stm32n6)))] |
| 63 | let r = RCC.cfgr(); | 65 | let r = RCC.cfgr(); |
| 64 | #[cfg(any(stm32u5, stm32wba))] | 66 | #[cfg(any(stm32u5, stm32wba))] |
| 65 | let r = RCC.cfgr1(); | 67 | let r = RCC.cfgr1(); |
| 68 | #[cfg(any(stm32n6))] | ||
| 69 | let r = RCC.ccipr5(); | ||
| 66 | 70 | ||
| 67 | r.modify(|w| { | 71 | r.modify(|w| { |
| 68 | w.$set_source(source); | 72 | w.$set_source(source); |
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 01fa3a475..592890777 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -28,6 +28,7 @@ pub use hsi48::*; | |||
| 28 | #[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl, stm32u0), path = "l.rs")] | 28 | #[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl, stm32u0), path = "l.rs")] |
| 29 | #[cfg_attr(stm32u5, path = "u5.rs")] | 29 | #[cfg_attr(stm32u5, path = "u5.rs")] |
| 30 | #[cfg_attr(stm32wba, path = "wba.rs")] | 30 | #[cfg_attr(stm32wba, path = "wba.rs")] |
| 31 | #[cfg_attr(stm32n6, path = "n6.rs")] | ||
| 31 | mod _version; | 32 | mod _version; |
| 32 | 33 | ||
| 33 | pub use _version::*; | 34 | 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..866851bbd --- /dev/null +++ b/embassy-stm32/src/rcc/n6.rs | |||
| @@ -0,0 +1,1046 @@ | |||
| 1 | use stm32_metapac::rcc::vals::{ | ||
| 2 | Cpusw, Cpusws, Hseext, Hsitrim, Icint, Icsel, Msifreqsel, Plldivm, Pllmodssdis, Pllpdiv, Pllsel, Syssw, Syssws, | ||
| 3 | Timpre, | ||
| 4 | }; | ||
| 5 | pub use stm32_metapac::rcc::vals::{ | ||
| 6 | Hpre as AhbPrescaler, Hsidiv as HsiPrescaler, Hsitrim as HsiCalibration, Ppre as ApbPrescaler, | ||
| 7 | }; | ||
| 8 | |||
| 9 | use crate::pac::{PWR, RCC, SYSCFG}; | ||
| 10 | use crate::time::Hertz; | ||
| 11 | |||
| 12 | pub const HSI_FREQ: Hertz = Hertz(64_000_000); | ||
| 13 | pub const LSE_FREQ: Hertz = Hertz(32_768); | ||
| 14 | |||
| 15 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 16 | pub enum HseMode { | ||
| 17 | /// crystal/ceramic oscillator | ||
| 18 | Oscillator, | ||
| 19 | /// oscillator bypassed with external clock (analog) | ||
| 20 | Bypass, | ||
| 21 | /// oscillator bypassed with external digital clock | ||
| 22 | BypassDigital, | ||
| 23 | } | ||
| 24 | |||
| 25 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 26 | pub struct Hse { | ||
| 27 | /// HSE frequency. | ||
| 28 | pub freq: Hertz, | ||
| 29 | /// HSE oscillator mode. | ||
| 30 | pub mode: HseMode, | ||
| 31 | } | ||
| 32 | |||
| 33 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 34 | pub struct Hsi { | ||
| 35 | pub pre: HsiPrescaler, | ||
| 36 | pub trim: Hsitrim, | ||
| 37 | } | ||
| 38 | |||
| 39 | #[derive(Clone, Copy, PartialEq)] | ||
| 40 | pub enum SupplyConfig { | ||
| 41 | Smps, | ||
| 42 | External, | ||
| 43 | } | ||
| 44 | |||
| 45 | #[derive(Clone, Copy, PartialEq)] | ||
| 46 | pub enum CpuClk { | ||
| 47 | Hse, | ||
| 48 | Ic1 { source: Icsel, divider: Icint }, | ||
| 49 | Msi, | ||
| 50 | Hsi, | ||
| 51 | } | ||
| 52 | |||
| 53 | impl CpuClk { | ||
| 54 | const fn to_bits(self) -> u8 { | ||
| 55 | match self { | ||
| 56 | Self::Hsi => 0x0, | ||
| 57 | Self::Msi => 0x1, | ||
| 58 | Self::Hse => 0x2, | ||
| 59 | Self::Ic1 { .. } => 0x3, | ||
| 60 | } | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | #[derive(Clone, Copy, PartialEq)] | ||
| 65 | pub struct IcConfig { | ||
| 66 | source: Icsel, | ||
| 67 | divider: Icint, | ||
| 68 | } | ||
| 69 | |||
| 70 | #[derive(Clone, Copy, PartialEq)] | ||
| 71 | pub enum SysClk { | ||
| 72 | Hse, | ||
| 73 | Ic2 { | ||
| 74 | ic2: IcConfig, | ||
| 75 | ic6: IcConfig, | ||
| 76 | ic11: IcConfig, | ||
| 77 | }, | ||
| 78 | Msi, | ||
| 79 | Hsi, | ||
| 80 | } | ||
| 81 | |||
| 82 | impl SysClk { | ||
| 83 | const fn to_bits(self) -> u8 { | ||
| 84 | match self { | ||
| 85 | Self::Hsi => 0x0, | ||
| 86 | Self::Msi => 0x1, | ||
| 87 | Self::Hse => 0x2, | ||
| 88 | Self::Ic2 { .. } => 0x3, | ||
| 89 | } | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | #[derive(Clone, Copy, PartialEq)] | ||
| 94 | pub struct Msi { | ||
| 95 | pub freq: Msifreqsel, | ||
| 96 | pub trim: u8, | ||
| 97 | } | ||
| 98 | |||
| 99 | #[derive(Clone, Copy, PartialEq)] | ||
| 100 | pub enum Pll { | ||
| 101 | Oscillator { | ||
| 102 | source: Pllsel, | ||
| 103 | divm: Plldivm, | ||
| 104 | fractional: u32, | ||
| 105 | divn: u16, | ||
| 106 | divp1: Pllpdiv, | ||
| 107 | divp2: Pllpdiv, | ||
| 108 | }, | ||
| 109 | Bypass { | ||
| 110 | source: Pllsel, | ||
| 111 | }, | ||
| 112 | } | ||
| 113 | |||
| 114 | /// Configuration of the core clocks | ||
| 115 | #[non_exhaustive] | ||
| 116 | #[derive(Clone, Copy)] | ||
| 117 | pub struct Config { | ||
| 118 | pub hsi: Option<Hsi>, | ||
| 119 | pub hse: Option<Hse>, | ||
| 120 | pub msi: Option<Msi>, | ||
| 121 | pub lsi: bool, | ||
| 122 | pub lse: bool, | ||
| 123 | |||
| 124 | pub sys: SysClk, | ||
| 125 | pub cpu: CpuClk, | ||
| 126 | |||
| 127 | pub pll1: Option<Pll>, | ||
| 128 | pub pll2: Option<Pll>, | ||
| 129 | pub pll3: Option<Pll>, | ||
| 130 | pub pll4: Option<Pll>, | ||
| 131 | |||
| 132 | pub ahb: AhbPrescaler, | ||
| 133 | pub apb1: ApbPrescaler, | ||
| 134 | pub apb2: ApbPrescaler, | ||
| 135 | pub apb4: ApbPrescaler, | ||
| 136 | pub apb5: ApbPrescaler, | ||
| 137 | |||
| 138 | pub supply_config: SupplyConfig, | ||
| 139 | } | ||
| 140 | |||
| 141 | impl Config { | ||
| 142 | pub const fn new() -> Self { | ||
| 143 | Self { | ||
| 144 | hsi: Some(Hsi { | ||
| 145 | pre: HsiPrescaler::DIV1, | ||
| 146 | trim: HsiCalibration::from_bits(32), | ||
| 147 | }), | ||
| 148 | hse: None, | ||
| 149 | msi: None, | ||
| 150 | lsi: true, | ||
| 151 | lse: false, | ||
| 152 | sys: SysClk::Hsi, | ||
| 153 | cpu: CpuClk::Hsi, | ||
| 154 | pll1: Some(Pll::Bypass { source: Pllsel::HSI }), | ||
| 155 | pll2: Some(Pll::Bypass { source: Pllsel::HSI }), | ||
| 156 | pll3: Some(Pll::Bypass { source: Pllsel::HSI }), | ||
| 157 | pll4: Some(Pll::Bypass { source: Pllsel::HSI }), | ||
| 158 | |||
| 159 | ahb: AhbPrescaler::DIV2, | ||
| 160 | apb1: ApbPrescaler::DIV1, | ||
| 161 | apb2: ApbPrescaler::DIV1, | ||
| 162 | apb4: ApbPrescaler::DIV1, | ||
| 163 | apb5: ApbPrescaler::DIV1, | ||
| 164 | |||
| 165 | supply_config: SupplyConfig::Smps, | ||
| 166 | } | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | #[allow(dead_code)] | ||
| 171 | struct ClocksOutput { | ||
| 172 | cpuclk: Hertz, | ||
| 173 | sysclk: Hertz, | ||
| 174 | pclk_tim: Hertz, | ||
| 175 | ahb: Hertz, | ||
| 176 | apb1: Hertz, | ||
| 177 | apb2: Hertz, | ||
| 178 | apb4: Hertz, | ||
| 179 | apb5: Hertz, | ||
| 180 | } | ||
| 181 | |||
| 182 | struct ClocksInput { | ||
| 183 | hsi: Option<Hertz>, | ||
| 184 | msi: Option<Hertz>, | ||
| 185 | hse: Option<Hertz>, | ||
| 186 | } | ||
| 187 | |||
| 188 | fn init_clocks(config: Config, input: &ClocksInput) -> ClocksOutput { | ||
| 189 | // handle increasing dividers | ||
| 190 | debug!("configuring increasing pclk dividers"); | ||
| 191 | RCC.cfgr2().modify(|w| { | ||
| 192 | if config.apb1 > w.ppre1() { | ||
| 193 | debug!(" - APB1"); | ||
| 194 | w.set_ppre1(config.apb1); | ||
| 195 | } | ||
| 196 | if config.apb2 > w.ppre2() { | ||
| 197 | debug!(" - APB2"); | ||
| 198 | w.set_ppre2(config.apb2); | ||
| 199 | } | ||
| 200 | if config.apb4 > w.ppre4() { | ||
| 201 | debug!(" - APB4"); | ||
| 202 | w.set_ppre4(config.apb4); | ||
| 203 | } | ||
| 204 | if config.apb5 > w.ppre5() { | ||
| 205 | debug!(" - APB5"); | ||
| 206 | w.set_ppre5(config.apb5); | ||
| 207 | } | ||
| 208 | if config.ahb > w.hpre() { | ||
| 209 | debug!(" - AHB"); | ||
| 210 | w.set_hpre(config.ahb); | ||
| 211 | } | ||
| 212 | }); | ||
| 213 | // cpuclk | ||
| 214 | debug!("configuring cpuclk"); | ||
| 215 | match config.cpu { | ||
| 216 | CpuClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"), | ||
| 217 | CpuClk::Ic1 { source, divider } => { | ||
| 218 | if !pll_sources_ready(RCC.iccfgr(0).read().icsel().to_bits(), source.to_bits()) { | ||
| 219 | panic!("ICx clock switch requires both origin and destination clock source to be active") | ||
| 220 | } | ||
| 221 | |||
| 222 | RCC.iccfgr(0).write(|w| { | ||
| 223 | w.set_icsel(source); | ||
| 224 | w.set_icint(divider); | ||
| 225 | }); | ||
| 226 | RCC.divensr().modify(|w| w.set_ic1ens(true)); | ||
| 227 | } | ||
| 228 | CpuClk::Msi if !RCC.sr().read().msirdy() => panic!("MSI is not ready to be selected as CPU clock source"), | ||
| 229 | CpuClk::Hsi if !RCC.sr().read().hsirdy() => panic!("HSI is not ready to be selected as CPU clock source"), | ||
| 230 | _ => {} | ||
| 231 | } | ||
| 232 | // set source | ||
| 233 | let cpusw = Cpusw::from_bits(config.cpu.to_bits()); | ||
| 234 | RCC.cfgr().modify(|w| w.set_cpusw(cpusw)); | ||
| 235 | // wait for changes to take effect | ||
| 236 | while RCC.cfgr().read().cpusws() != Cpusws::from_bits(config.cpu.to_bits()) {} | ||
| 237 | |||
| 238 | // sysclk | ||
| 239 | debug!("configuring sysclk"); | ||
| 240 | match config.sys { | ||
| 241 | SysClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"), | ||
| 242 | SysClk::Ic2 { ic2, ic6, ic11 } => { | ||
| 243 | if !pll_sources_ready(RCC.iccfgr(1).read().icsel().to_bits(), ic2.source.to_bits()) { | ||
| 244 | panic!("IC2 clock switch requires both origin and destination clock source to be active") | ||
| 245 | } | ||
| 246 | if !pll_sources_ready(RCC.iccfgr(5).read().icsel().to_bits(), ic6.source.to_bits()) { | ||
| 247 | panic!("IC6 clock switch requires both origin and destination clock source to be active") | ||
| 248 | } | ||
| 249 | if !pll_sources_ready(RCC.iccfgr(10).read().icsel().to_bits(), ic11.source.to_bits()) { | ||
| 250 | panic!("IC11 clock switch requires both origin and destination clock source to be active") | ||
| 251 | } | ||
| 252 | |||
| 253 | RCC.iccfgr(1).write(|w| { | ||
| 254 | w.set_icsel(ic2.source); | ||
| 255 | w.set_icint(ic2.divider); | ||
| 256 | }); | ||
| 257 | RCC.iccfgr(5).write(|w| { | ||
| 258 | w.set_icsel(ic6.source); | ||
| 259 | w.set_icint(ic6.divider); | ||
| 260 | }); | ||
| 261 | RCC.iccfgr(10).write(|w| { | ||
| 262 | w.set_icsel(ic11.source); | ||
| 263 | w.set_icint(ic11.divider); | ||
| 264 | }); | ||
| 265 | RCC.divensr().modify(|w| { | ||
| 266 | w.set_ic2ens(true); | ||
| 267 | w.set_ic6ens(true); | ||
| 268 | w.set_ic11ens(true); | ||
| 269 | }); | ||
| 270 | } | ||
| 271 | SysClk::Msi if !RCC.sr().read().msirdy() => panic!("MSI is not ready to be selected as CPU clock source"), | ||
| 272 | SysClk::Hsi if !RCC.sr().read().hsirdy() => panic!("HSI is not ready to be selected as CPU clock source"), | ||
| 273 | _ => {} | ||
| 274 | } | ||
| 275 | // switch the system bus clock | ||
| 276 | let syssw = Syssw::from_bits(config.sys.to_bits()); | ||
| 277 | RCC.cfgr().modify(|w| w.set_syssw(syssw)); | ||
| 278 | // wait for changes to be applied | ||
| 279 | while RCC.cfgr().read().syssws() != Syssws::from_bits(config.sys.to_bits()) {} | ||
| 280 | |||
| 281 | // decreasing dividers | ||
| 282 | debug!("configuring decreasing pclk dividers"); | ||
| 283 | RCC.cfgr2().modify(|w| { | ||
| 284 | if config.ahb < w.hpre() { | ||
| 285 | debug!(" - AHB"); | ||
| 286 | w.set_hpre(config.ahb); | ||
| 287 | } | ||
| 288 | if config.apb1 < w.ppre1() { | ||
| 289 | debug!(" - APB1"); | ||
| 290 | w.set_ppre1(config.apb1); | ||
| 291 | } | ||
| 292 | if config.apb2 < w.ppre2() { | ||
| 293 | debug!(" - APB2"); | ||
| 294 | w.set_ppre2(config.apb2); | ||
| 295 | } | ||
| 296 | if config.apb4 < w.ppre4() { | ||
| 297 | debug!(" - APB4"); | ||
| 298 | w.set_ppre4(config.apb4); | ||
| 299 | } | ||
| 300 | if config.apb5 < w.ppre5() { | ||
| 301 | debug!(" - APB5"); | ||
| 302 | w.set_ppre5(config.apb5); | ||
| 303 | } | ||
| 304 | }); | ||
| 305 | |||
| 306 | let cpuclk = match config.cpu { | ||
| 307 | CpuClk::Hsi => unwrap!(input.hsi), | ||
| 308 | CpuClk::Msi => unwrap!(input.msi), | ||
| 309 | CpuClk::Hse => unwrap!(input.hse), | ||
| 310 | CpuClk::Ic1 { .. } => todo!(), | ||
| 311 | }; | ||
| 312 | |||
| 313 | let sysclk = match config.sys { | ||
| 314 | SysClk::Hsi => unwrap!(input.hsi), | ||
| 315 | SysClk::Msi => unwrap!(input.msi), | ||
| 316 | SysClk::Hse => unwrap!(input.hse), | ||
| 317 | SysClk::Ic2 { .. } => todo!(), | ||
| 318 | }; | ||
| 319 | |||
| 320 | let timpre: u32 = match RCC.cfgr2().read().timpre() { | ||
| 321 | Timpre::DIV1 => 1, | ||
| 322 | Timpre::DIV2 => 2, | ||
| 323 | Timpre::DIV4 => 4, | ||
| 324 | Timpre::_RESERVED_3 => 8, | ||
| 325 | }; | ||
| 326 | |||
| 327 | let hpre = periph_prescaler_to_value(config.ahb.to_bits()); | ||
| 328 | let ppre1 = periph_prescaler_to_value(config.apb1.to_bits()); | ||
| 329 | let ppre2 = periph_prescaler_to_value(config.apb2.to_bits()); | ||
| 330 | let ppre4 = periph_prescaler_to_value(config.apb4.to_bits()); | ||
| 331 | let ppre5 = periph_prescaler_to_value(config.apb5.to_bits()); | ||
| 332 | |||
| 333 | // enable all peripherals in sleep mode | ||
| 334 | enable_low_power_peripherals(); | ||
| 335 | |||
| 336 | // enable interrupts | ||
| 337 | unsafe { | ||
| 338 | core::arch::asm!("cpsie i"); | ||
| 339 | } | ||
| 340 | |||
| 341 | ClocksOutput { | ||
| 342 | sysclk, | ||
| 343 | cpuclk, | ||
| 344 | pclk_tim: sysclk / timpre, | ||
| 345 | ahb: Hertz(sysclk.0 / hpre as u32), | ||
| 346 | apb1: sysclk / hpre / ppre1, | ||
| 347 | apb2: sysclk / hpre / ppre2, | ||
| 348 | apb4: sysclk / hpre / ppre4, | ||
| 349 | apb5: sysclk / hpre / ppre5, | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | fn enable_low_power_peripherals() { | ||
| 354 | // AHB1-5 | ||
| 355 | RCC.ahb1lpenr().modify(|w| { | ||
| 356 | w.set_adc12lpen(true); | ||
| 357 | w.set_gpdma1lpen(true); | ||
| 358 | }); | ||
| 359 | RCC.ahb2lpenr().modify(|w| { | ||
| 360 | w.set_adf1lpen(true); | ||
| 361 | w.set_mdf1lpen(true); | ||
| 362 | w.set_ramcfglpen(true); | ||
| 363 | }); | ||
| 364 | RCC.ahb3lpenr().modify(|w| { | ||
| 365 | w.set_risaflpen(true); | ||
| 366 | w.set_iaclpen(true); | ||
| 367 | w.set_rifsclpen(true); | ||
| 368 | w.set_pkalpen(true); | ||
| 369 | w.set_saeslpen(true); | ||
| 370 | w.set_cryplpen(true); | ||
| 371 | w.set_hashlpen(true); | ||
| 372 | w.set_rnglpen(true); | ||
| 373 | }); | ||
| 374 | RCC.ahb4lpenr().modify(|w| { | ||
| 375 | w.set_crclpen(true); | ||
| 376 | w.set_pwrlpen(true); | ||
| 377 | w.set_gpioqlpen(true); | ||
| 378 | w.set_gpioplpen(true); | ||
| 379 | w.set_gpioolpen(true); | ||
| 380 | w.set_gpionlpen(true); | ||
| 381 | w.set_gpiohlpen(true); | ||
| 382 | w.set_gpioglpen(true); | ||
| 383 | w.set_gpioflpen(true); | ||
| 384 | w.set_gpioelpen(true); | ||
| 385 | w.set_gpiodlpen(true); | ||
| 386 | w.set_gpioclpen(true); | ||
| 387 | w.set_gpioblpen(true); | ||
| 388 | w.set_gpioalpen(true); | ||
| 389 | }); | ||
| 390 | RCC.ahb5lpenr().modify(|w| { | ||
| 391 | w.set_npulpen(true); | ||
| 392 | w.set_npucachelpen(true); | ||
| 393 | w.set_otg2lpen(true); | ||
| 394 | w.set_otgphy2lpen(true); | ||
| 395 | w.set_otgphy1lpen(true); | ||
| 396 | w.set_otg1lpen(true); | ||
| 397 | w.set_eth1lpen(true); | ||
| 398 | w.set_eth1rxlpen(true); | ||
| 399 | w.set_eth1txlpen(true); | ||
| 400 | w.set_eth1maclpen(true); | ||
| 401 | w.set_gpulpen(true); | ||
| 402 | w.set_gfxmmulpen(true); | ||
| 403 | w.set_mce4lpen(true); | ||
| 404 | w.set_xspi3lpen(true); | ||
| 405 | w.set_mce3lpen(true); | ||
| 406 | w.set_mce2lpen(true); | ||
| 407 | w.set_mce1lpen(true); | ||
| 408 | w.set_xspimlpen(true); | ||
| 409 | w.set_xspi2lpen(true); | ||
| 410 | w.set_sdmmc1lpen(true); | ||
| 411 | w.set_sdmmc2lpen(true); | ||
| 412 | w.set_pssilpen(true); | ||
| 413 | w.set_xspi1lpen(true); | ||
| 414 | w.set_fmclpen(true); | ||
| 415 | w.set_jpeglpen(true); | ||
| 416 | w.set_dma2dlpen(true); | ||
| 417 | w.set_hpdma1lpen(true); | ||
| 418 | }); | ||
| 419 | |||
| 420 | // APB1-5 | ||
| 421 | RCC.apb1llpenr().modify(|w| { | ||
| 422 | w.set_uart8lpen(true); | ||
| 423 | w.set_uart7lpen(true); | ||
| 424 | w.set_i3c2lpen(true); | ||
| 425 | w.set_i3c1lpen(true); | ||
| 426 | w.set_i2c3lpen(true); | ||
| 427 | w.set_i2c2lpen(true); | ||
| 428 | w.set_i2c1lpen(true); | ||
| 429 | w.set_uart5lpen(true); | ||
| 430 | w.set_uart4lpen(true); | ||
| 431 | w.set_usart3lpen(true); | ||
| 432 | w.set_usart2lpen(true); | ||
| 433 | w.set_spdifrx1lpen(true); | ||
| 434 | w.set_spi3lpen(true); | ||
| 435 | w.set_spi2lpen(true); | ||
| 436 | w.set_tim11lpen(true); | ||
| 437 | w.set_tim10lpen(true); | ||
| 438 | w.set_wwdglpen(true); | ||
| 439 | w.set_lptim1lpen(true); | ||
| 440 | w.set_tim14lpen(true); | ||
| 441 | w.set_tim13lpen(true); | ||
| 442 | w.set_tim12lpen(true); | ||
| 443 | w.set_tim7lpen(true); | ||
| 444 | w.set_tim6lpen(true); | ||
| 445 | w.set_tim5lpen(true); | ||
| 446 | w.set_tim4lpen(true); | ||
| 447 | w.set_tim3lpen(true); | ||
| 448 | w.set_tim2lpen(true); | ||
| 449 | }); | ||
| 450 | RCC.apb1hlpenr().modify(|w| { | ||
| 451 | w.set_ucpd1lpen(true); | ||
| 452 | w.set_fdcanlpen(true); | ||
| 453 | w.set_mdioslpen(true); | ||
| 454 | }); | ||
| 455 | RCC.apb2lpenr().modify(|w| { | ||
| 456 | w.set_sai2lpen(true); | ||
| 457 | w.set_sai1lpen(true); | ||
| 458 | w.set_spi5lpen(true); | ||
| 459 | w.set_tim9lpen(true); | ||
| 460 | w.set_tim17lpen(true); | ||
| 461 | w.set_tim16lpen(true); | ||
| 462 | w.set_tim15lpen(true); | ||
| 463 | w.set_tim18lpen(true); | ||
| 464 | w.set_spi4lpen(true); | ||
| 465 | w.set_spi1lpen(true); | ||
| 466 | w.set_usart10lpen(true); | ||
| 467 | w.set_uart9lpen(true); | ||
| 468 | w.set_usart6lpen(true); | ||
| 469 | w.set_usart1lpen(true); | ||
| 470 | w.set_tim8lpen(true); | ||
| 471 | w.set_tim1lpen(true); | ||
| 472 | }); | ||
| 473 | RCC.apb3lpenr().modify(|w| { | ||
| 474 | w.set_dftlpen(true); | ||
| 475 | }); | ||
| 476 | RCC.apb4llpenr().modify(|w| { | ||
| 477 | w.set_rtcapblpen(true); | ||
| 478 | w.set_rtclpen(true); | ||
| 479 | w.set_vrefbuflpen(true); | ||
| 480 | w.set_lptim5lpen(true); | ||
| 481 | w.set_lptim4lpen(true); | ||
| 482 | w.set_lptim3lpen(true); | ||
| 483 | w.set_lptim2lpen(true); | ||
| 484 | w.set_i2c4lpen(true); | ||
| 485 | w.set_spi6lpen(true); | ||
| 486 | w.set_lpuart1lpen(true); | ||
| 487 | w.set_hdplpen(true); | ||
| 488 | }); | ||
| 489 | RCC.apb4hlpenr().modify(|w| { | ||
| 490 | w.set_dtslpen(true); | ||
| 491 | w.set_bseclpen(true); | ||
| 492 | w.set_syscfglpen(true); | ||
| 493 | }); | ||
| 494 | RCC.apb5lpenr().modify(|w| { | ||
| 495 | w.set_csilpen(true); | ||
| 496 | w.set_venclpen(true); | ||
| 497 | w.set_gfxtimlpen(true); | ||
| 498 | w.set_dcmilpen(true); | ||
| 499 | w.set_ltdclpen(true); | ||
| 500 | }); | ||
| 501 | |||
| 502 | RCC.buslpenr().modify(|w| { | ||
| 503 | w.set_aclknclpen(true); | ||
| 504 | w.set_aclknlpen(true); | ||
| 505 | }); | ||
| 506 | |||
| 507 | RCC.memlpenr().modify(|w| { | ||
| 508 | w.set_bootromlpen(true); | ||
| 509 | w.set_vencramlpen(true); | ||
| 510 | w.set_npucacheramlpen(true); | ||
| 511 | w.set_flexramlpen(true); | ||
| 512 | w.set_axisram2lpen(true); | ||
| 513 | w.set_axisram1lpen(true); | ||
| 514 | w.set_bkpsramlpen(true); | ||
| 515 | w.set_ahbsram2lpen(true); | ||
| 516 | w.set_ahbsram1lpen(true); | ||
| 517 | w.set_axisram6lpen(true); | ||
| 518 | w.set_axisram5lpen(true); | ||
| 519 | w.set_axisram4lpen(true); | ||
| 520 | w.set_axisram3lpen(true); | ||
| 521 | }); | ||
| 522 | |||
| 523 | RCC.misclpenr().modify(|w| { | ||
| 524 | w.set_perlpen(true); | ||
| 525 | w.set_xspiphycomplpen(true); | ||
| 526 | w.set_dbglpen(true); | ||
| 527 | }); | ||
| 528 | } | ||
| 529 | |||
| 530 | const fn periph_prescaler_to_value(bits: u8) -> u8 { | ||
| 531 | match bits { | ||
| 532 | 0 => 1, | ||
| 533 | 1 => 2, | ||
| 534 | 2 => 4, | ||
| 535 | 3 => 8, | ||
| 536 | 4 => 16, | ||
| 537 | 5 => 32, | ||
| 538 | 6 => 64, | ||
| 539 | 7.. => 128, | ||
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 543 | fn pll_source_ready(source: u8) -> bool { | ||
| 544 | match source { | ||
| 545 | 0x0 if !RCC.sr().read().pllrdy(0) && !RCC.pllcfgr1(0).read().pllbyp() => false, | ||
| 546 | 0x1 if !RCC.sr().read().pllrdy(1) && !RCC.pllcfgr1(1).read().pllbyp() => false, | ||
| 547 | 0x2 if !RCC.sr().read().pllrdy(2) && !RCC.pllcfgr1(2).read().pllbyp() => false, | ||
| 548 | 0x3 if !RCC.sr().read().pllrdy(3) && !RCC.pllcfgr1(3).read().pllbyp() => false, | ||
| 549 | _ => true, | ||
| 550 | } | ||
| 551 | } | ||
| 552 | |||
| 553 | fn pll_sources_ready(source1: u8, source2: u8) -> bool { | ||
| 554 | pll_source_ready(source1) && pll_source_ready(source2) | ||
| 555 | } | ||
| 556 | |||
| 557 | impl Default for Config { | ||
| 558 | fn default() -> Self { | ||
| 559 | Self::new() | ||
| 560 | } | ||
| 561 | } | ||
| 562 | |||
| 563 | fn power_supply_config(supply_config: SupplyConfig) { | ||
| 564 | // power supply config | ||
| 565 | PWR.cr1().modify(|w| { | ||
| 566 | w.set_sden(match supply_config { | ||
| 567 | SupplyConfig::External => false, | ||
| 568 | SupplyConfig::Smps => true, | ||
| 569 | }); | ||
| 570 | }); | ||
| 571 | |||
| 572 | // Validate supply configuration | ||
| 573 | while !PWR.voscr().read().actvosrdy() {} | ||
| 574 | } | ||
| 575 | |||
| 576 | struct PllInput { | ||
| 577 | hsi: Option<Hertz>, | ||
| 578 | msi: Option<Hertz>, | ||
| 579 | hse: Option<Hertz>, | ||
| 580 | i2s_ckin: Option<Hertz>, | ||
| 581 | } | ||
| 582 | |||
| 583 | #[derive(Clone, Copy, Default)] | ||
| 584 | #[allow(dead_code)] | ||
| 585 | struct PllOutput { | ||
| 586 | divm: Option<Hertz>, | ||
| 587 | divn: Option<Hertz>, | ||
| 588 | divp1: Option<Hertz>, | ||
| 589 | divp2: Option<Hertz>, | ||
| 590 | output: Option<Hertz>, | ||
| 591 | } | ||
| 592 | |||
| 593 | fn init_pll(pll_config: Option<Pll>, pll_index: usize, input: &PllInput) -> PllOutput { | ||
| 594 | let cfgr1 = RCC.pllcfgr1(pll_index); | ||
| 595 | let cfgr2 = RCC.pllcfgr2(pll_index); | ||
| 596 | let cfgr3 = RCC.pllcfgr3(pll_index); | ||
| 597 | |||
| 598 | match pll_config { | ||
| 599 | Some(Pll::Oscillator { | ||
| 600 | source, | ||
| 601 | divm, | ||
| 602 | fractional, | ||
| 603 | divn, | ||
| 604 | divp1, | ||
| 605 | divp2, | ||
| 606 | }) => { | ||
| 607 | // ensure pll is disabled | ||
| 608 | RCC.ccr().write(|w| w.set_pllonc(pll_index, true)); | ||
| 609 | while RCC.sr().read().pllrdy(pll_index) {} | ||
| 610 | |||
| 611 | // ensure PLLxMODSSDIS=1 to work in fractional mode | ||
| 612 | cfgr3.modify(|w| w.set_pllmodssdis(Pllmodssdis::FRACTIONAL_DIVIDE)); | ||
| 613 | // clear bypass mode | ||
| 614 | cfgr1.modify(|w| w.set_pllbyp(false)); | ||
| 615 | // configure the pll clock source, mul and div factors | ||
| 616 | cfgr1.modify(|w| { | ||
| 617 | w.set_pllsel(source); | ||
| 618 | w.set_plldivm(divm); | ||
| 619 | w.set_plldivn(divn); | ||
| 620 | }); | ||
| 621 | |||
| 622 | let in_clk = match source { | ||
| 623 | Pllsel::HSI => unwrap!(input.hsi), | ||
| 624 | Pllsel::MSI => unwrap!(input.msi), | ||
| 625 | Pllsel::HSE => unwrap!(input.hse), | ||
| 626 | Pllsel::I2S_CKIN => unwrap!(input.i2s_ckin), | ||
| 627 | _ => panic!("reserved PLL source not allowed"), | ||
| 628 | }; | ||
| 629 | |||
| 630 | let m = divm.to_bits() as u32; | ||
| 631 | let n = divn as u32; | ||
| 632 | |||
| 633 | cfgr3.modify(|w| { | ||
| 634 | w.set_pllpdiv1(divp1); | ||
| 635 | w.set_pllpdiv2(divp2); | ||
| 636 | }); | ||
| 637 | |||
| 638 | let p1 = divp1.to_bits() as u32; | ||
| 639 | let p2 = divp2.to_bits() as u32; | ||
| 640 | |||
| 641 | // configure pll divnfrac | ||
| 642 | cfgr2.modify(|w| w.set_plldivnfrac(fractional)); | ||
| 643 | // clear pllxmoddsen | ||
| 644 | cfgr3.modify(|w| w.set_pllmoddsen(false)); | ||
| 645 | // fractional mode | ||
| 646 | if fractional != 0 { | ||
| 647 | cfgr3.modify(|w| { | ||
| 648 | w.set_pllmoddsen(true); | ||
| 649 | w.set_plldacen(true); | ||
| 650 | }) | ||
| 651 | } | ||
| 652 | // enable pll post divider output | ||
| 653 | cfgr3.modify(|w| { | ||
| 654 | w.set_pllmodssrst(true); | ||
| 655 | w.set_pllpdiven(true); | ||
| 656 | }); | ||
| 657 | // enable the pll | ||
| 658 | RCC.csr().write(|w| w.pllons(pll_index)); | ||
| 659 | // wait until ready | ||
| 660 | while RCC.sr().read().pllrdy(pll_index) {} | ||
| 661 | |||
| 662 | PllOutput { | ||
| 663 | divm: Some(Hertz(m)), | ||
| 664 | divn: Some(Hertz(n)), | ||
| 665 | divp1: Some(Hertz(p1)), | ||
| 666 | divp2: Some(Hertz(p2)), | ||
| 667 | output: Some(Hertz(in_clk.0 / m / n / p1 / p2)), | ||
| 668 | } | ||
| 669 | } | ||
| 670 | Some(Pll::Bypass { source }) => { | ||
| 671 | // check if source is ready | ||
| 672 | if !pll_source_ready(source.to_bits()) { | ||
| 673 | panic!("PLL source is not ready") | ||
| 674 | } | ||
| 675 | |||
| 676 | // ensure pll is disabled | ||
| 677 | RCC.ccr().write(|w| w.set_pllonc(pll_index, true)); | ||
| 678 | while RCC.sr().read().pllrdy(pll_index) {} | ||
| 679 | |||
| 680 | cfgr1.modify(|w| { | ||
| 681 | w.set_pllbyp(true); | ||
| 682 | w.set_pllsel(source); | ||
| 683 | }); | ||
| 684 | |||
| 685 | let in_clk = match source { | ||
| 686 | Pllsel::HSI => unwrap!(input.hsi), | ||
| 687 | Pllsel::MSI => unwrap!(input.msi), | ||
| 688 | Pllsel::HSE => unwrap!(input.hse), | ||
| 689 | Pllsel::I2S_CKIN => unwrap!(input.i2s_ckin), | ||
| 690 | _ => panic!("reserved PLL source not allowed"), | ||
| 691 | }; | ||
| 692 | |||
| 693 | PllOutput { | ||
| 694 | output: Some(in_clk), | ||
| 695 | ..Default::default() | ||
| 696 | } | ||
| 697 | } | ||
| 698 | None => { | ||
| 699 | cfgr3.modify(|w| w.set_pllpdiven(false)); | ||
| 700 | RCC.ccr().write(|w| w.set_pllonc(pll_index, true)); | ||
| 701 | // wait till disabled | ||
| 702 | while RCC.sr().read().pllrdy(pll_index) {} | ||
| 703 | |||
| 704 | // clear bypass mode | ||
| 705 | cfgr1.modify(|w| w.set_pllbyp(false)); | ||
| 706 | |||
| 707 | PllOutput::default() | ||
| 708 | } | ||
| 709 | } | ||
| 710 | } | ||
| 711 | |||
| 712 | #[allow(dead_code)] | ||
| 713 | struct OscOutput { | ||
| 714 | hsi: Option<Hertz>, | ||
| 715 | hse: Option<Hertz>, | ||
| 716 | msi: Option<Hertz>, | ||
| 717 | lsi: Option<Hertz>, | ||
| 718 | lse: Option<Hertz>, | ||
| 719 | pll1: Option<Hertz>, | ||
| 720 | pll2: Option<Hertz>, | ||
| 721 | pll3: Option<Hertz>, | ||
| 722 | pll4: Option<Hertz>, | ||
| 723 | ic1sel: Icsel, | ||
| 724 | ic2sel: Icsel, | ||
| 725 | ic6sel: Icsel, | ||
| 726 | ic11sel: Icsel, | ||
| 727 | } | ||
| 728 | |||
| 729 | fn init_osc(config: Config) -> OscOutput { | ||
| 730 | let (cpu_src, sys_src) = { | ||
| 731 | let reg = RCC.cfgr().read(); | ||
| 732 | (reg.cpusws(), reg.syssws()) | ||
| 733 | }; | ||
| 734 | let pll1_src = RCC.pllcfgr1(0).read().pllsel(); | ||
| 735 | let pll2_src = RCC.pllcfgr1(1).read().pllsel(); | ||
| 736 | let pll3_src = RCC.pllcfgr1(2).read().pllsel(); | ||
| 737 | let pll4_src = RCC.pllcfgr1(3).read().pllsel(); | ||
| 738 | let rcc_sr = RCC.sr().read(); | ||
| 739 | |||
| 740 | debug!("configuring HSE"); | ||
| 741 | |||
| 742 | // hse configuration | ||
| 743 | let hse = if let Some(hse) = config.hse { | ||
| 744 | match hse.mode { | ||
| 745 | HseMode::Oscillator => { | ||
| 746 | debug!("HSE in oscillator mode"); | ||
| 747 | } | ||
| 748 | HseMode::Bypass => { | ||
| 749 | debug!("HSE in bypass mode"); | ||
| 750 | RCC.hsecfgr().modify(|w| { | ||
| 751 | w.set_hsebyp(true); | ||
| 752 | w.set_hseext(Hseext::ANALOG); | ||
| 753 | }); | ||
| 754 | } | ||
| 755 | HseMode::BypassDigital => { | ||
| 756 | debug!("HSE in bypass digital mode"); | ||
| 757 | RCC.hsecfgr().modify(|w| { | ||
| 758 | w.set_hsebyp(true); | ||
| 759 | w.set_hseext(Hseext::DIGITAL); | ||
| 760 | }); | ||
| 761 | } | ||
| 762 | } | ||
| 763 | RCC.csr().write(|w| w.set_hseons(true)); | ||
| 764 | |||
| 765 | // wait until the hse is ready | ||
| 766 | while !RCC.sr().read().hserdy() {} | ||
| 767 | |||
| 768 | Some(hse.freq) | ||
| 769 | } else if cpu_src == Cpusws::HSE | ||
| 770 | || sys_src == Syssws::HSE | ||
| 771 | || (pll1_src == Pllsel::HSE && rcc_sr.pllrdy(0)) | ||
| 772 | || (pll2_src == Pllsel::HSE && rcc_sr.pllrdy(1)) | ||
| 773 | || (pll3_src == Pllsel::HSE && rcc_sr.pllrdy(2)) | ||
| 774 | || (pll4_src == Pllsel::HSE && rcc_sr.pllrdy(3)) | ||
| 775 | { | ||
| 776 | panic!( | ||
| 777 | "When the HSE is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled" | ||
| 778 | ); | ||
| 779 | } else { | ||
| 780 | debug!("HSE off"); | ||
| 781 | |||
| 782 | RCC.ccr().write(|w| w.set_hseonc(true)); | ||
| 783 | RCC.hsecfgr().modify(|w| { | ||
| 784 | w.set_hseext(Hseext::ANALOG); | ||
| 785 | w.set_hsebyp(false); | ||
| 786 | }); | ||
| 787 | |||
| 788 | // wait until the hse is disabled | ||
| 789 | while RCC.sr().read().hserdy() {} | ||
| 790 | |||
| 791 | None | ||
| 792 | }; | ||
| 793 | |||
| 794 | // hsi configuration | ||
| 795 | debug!("configuring HSI"); | ||
| 796 | let hsi = if let Some(hsi) = config.hsi { | ||
| 797 | RCC.csr().write(|w| w.set_hsions(true)); | ||
| 798 | while !RCC.sr().read().hsirdy() {} | ||
| 799 | |||
| 800 | // set divider and calibration | ||
| 801 | RCC.hsicfgr().modify(|w| { | ||
| 802 | w.set_hsidiv(hsi.pre); | ||
| 803 | w.set_hsitrim(hsi.trim); | ||
| 804 | }); | ||
| 805 | |||
| 806 | Some(HSI_FREQ / hsi.pre) | ||
| 807 | } else if cpu_src == Cpusws::HSI | ||
| 808 | || sys_src == Syssws::HSI | ||
| 809 | || (pll1_src == Pllsel::HSI && rcc_sr.pllrdy(0)) | ||
| 810 | || (pll2_src == Pllsel::HSI && rcc_sr.pllrdy(1)) | ||
| 811 | || (pll3_src == Pllsel::HSI && rcc_sr.pllrdy(2)) | ||
| 812 | || (pll4_src == Pllsel::HSI && rcc_sr.pllrdy(3)) | ||
| 813 | { | ||
| 814 | panic!( | ||
| 815 | "When the HSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled" | ||
| 816 | ); | ||
| 817 | } else { | ||
| 818 | debug!("HSI off"); | ||
| 819 | |||
| 820 | RCC.ccr().write(|w| w.set_hsionc(true)); | ||
| 821 | while RCC.sr().read().hsirdy() {} | ||
| 822 | |||
| 823 | None | ||
| 824 | }; | ||
| 825 | |||
| 826 | // msi configuration | ||
| 827 | debug!("configuring MSI"); | ||
| 828 | let msi = if let Some(msi) = config.msi { | ||
| 829 | RCC.msicfgr().modify(|w| w.set_msifreqsel(msi.freq)); | ||
| 830 | RCC.csr().write(|w| w.set_msions(true)); | ||
| 831 | while !RCC.sr().read().msirdy() {} | ||
| 832 | RCC.msicfgr().modify(|w| w.set_msitrim(msi.trim)); | ||
| 833 | |||
| 834 | Some(match msi.freq { | ||
| 835 | Msifreqsel::_4MHZ => Hertz::mhz(4), | ||
| 836 | Msifreqsel::_16MHZ => Hertz::mhz(16), | ||
| 837 | }) | ||
| 838 | } else if cpu_src == Cpusws::MSI | ||
| 839 | || sys_src == Syssws::MSI | ||
| 840 | || (pll1_src == Pllsel::MSI && rcc_sr.pllrdy(0)) | ||
| 841 | || (pll2_src == Pllsel::MSI && rcc_sr.pllrdy(1)) | ||
| 842 | || (pll3_src == Pllsel::MSI && rcc_sr.pllrdy(2)) | ||
| 843 | || (pll4_src == Pllsel::MSI && rcc_sr.pllrdy(3)) | ||
| 844 | { | ||
| 845 | panic!( | ||
| 846 | "When the MSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled" | ||
| 847 | ); | ||
| 848 | } else { | ||
| 849 | RCC.ccr().write(|w| w.set_msionc(true)); | ||
| 850 | while RCC.sr().read().msirdy() {} | ||
| 851 | |||
| 852 | None | ||
| 853 | }; | ||
| 854 | |||
| 855 | // lsi configuration | ||
| 856 | debug!("configuring LSI"); | ||
| 857 | let lsi = if config.lsi { | ||
| 858 | RCC.csr().write(|w| w.set_lsions(true)); | ||
| 859 | while !RCC.sr().read().lsirdy() {} | ||
| 860 | Some(super::LSI_FREQ) | ||
| 861 | } else { | ||
| 862 | RCC.ccr().write(|w| w.set_lsionc(true)); | ||
| 863 | while RCC.sr().read().lsirdy() {} | ||
| 864 | None | ||
| 865 | }; | ||
| 866 | |||
| 867 | // lse configuration | ||
| 868 | debug!("configuring LSE"); | ||
| 869 | let lse = if config.lse { | ||
| 870 | RCC.csr().write(|w| w.set_lseons(true)); | ||
| 871 | while !RCC.sr().read().lserdy() {} | ||
| 872 | Some(LSE_FREQ) | ||
| 873 | } else { | ||
| 874 | RCC.ccr().write(|w| w.set_lseonc(true)); | ||
| 875 | while RCC.sr().read().lserdy() {} | ||
| 876 | None | ||
| 877 | }; | ||
| 878 | |||
| 879 | let pll_input = PllInput { | ||
| 880 | hse, | ||
| 881 | msi, | ||
| 882 | hsi, | ||
| 883 | i2s_ckin: None, | ||
| 884 | }; | ||
| 885 | |||
| 886 | // pll1,2,3,4 config | ||
| 887 | let pll_configs = [config.pll1, config.pll2, config.pll3, config.pll4]; | ||
| 888 | let mut pll_outputs: [PllOutput; 4] = [PllOutput::default(); 4]; | ||
| 889 | |||
| 890 | let ic1_src = RCC.iccfgr(0).read().icsel(); | ||
| 891 | let ic2_src = RCC.iccfgr(1).read().icsel(); | ||
| 892 | let ic6_src = RCC.iccfgr(5).read().icsel(); | ||
| 893 | let ic11_src = RCC.iccfgr(10).read().icsel(); | ||
| 894 | |||
| 895 | for (n, (&pll, out)) in pll_configs.iter().zip(pll_outputs.iter_mut()).enumerate() { | ||
| 896 | debug!("configuring PLL{}", n + 1); | ||
| 897 | let pll_ready = RCC.sr().read().pllrdy(n); | ||
| 898 | |||
| 899 | if is_new_pll_config(pll, 0) { | ||
| 900 | let this_pll = Icsel::from_bits(n as u8); | ||
| 901 | |||
| 902 | if cpu_src == Cpusws::IC1 && ic1_src == this_pll { | ||
| 903 | panic!("PLL should not be disabled / reconfigured if used for IC1 (cpuclksrc)") | ||
| 904 | } | ||
| 905 | |||
| 906 | if sys_src == Syssws::IC2 && (ic2_src == this_pll || ic6_src == this_pll || ic11_src == this_pll) { | ||
| 907 | panic!("PLL should not be disabled / reconfigured if used for IC2, IC6 or IC11 (sysclksrc)") | ||
| 908 | } | ||
| 909 | |||
| 910 | *out = init_pll(pll, 0, &pll_input); | ||
| 911 | } else if pll.is_some() && !pll_ready { | ||
| 912 | RCC.csr().write(|w| w.pllons(n)); | ||
| 913 | while !RCC.sr().read().pllrdy(n) {} | ||
| 914 | } | ||
| 915 | } | ||
| 916 | |||
| 917 | OscOutput { | ||
| 918 | hsi, | ||
| 919 | hse, | ||
| 920 | msi, | ||
| 921 | lsi, | ||
| 922 | lse, | ||
| 923 | pll1: pll_outputs[0].output, | ||
| 924 | pll2: pll_outputs[1].output, | ||
| 925 | pll3: pll_outputs[2].output, | ||
| 926 | pll4: pll_outputs[3].output, | ||
| 927 | ic1sel: ic1_src, | ||
| 928 | ic2sel: ic2_src, | ||
| 929 | ic6sel: ic6_src, | ||
| 930 | ic11sel: ic11_src, | ||
| 931 | } | ||
| 932 | } | ||
| 933 | |||
| 934 | fn is_new_pll_config(pll: Option<Pll>, pll_index: usize) -> bool { | ||
| 935 | let cfgr1 = RCC.pllcfgr1(pll_index).read(); | ||
| 936 | let cfgr2 = RCC.pllcfgr2(pll_index).read(); | ||
| 937 | let cfgr3 = RCC.pllcfgr3(pll_index).read(); | ||
| 938 | |||
| 939 | let ready = RCC.sr().read().pllrdy(pll_index); | ||
| 940 | let bypass = cfgr1.pllbyp(); | ||
| 941 | |||
| 942 | match (pll, ready, bypass) { | ||
| 943 | (None, true, _) => return true, | ||
| 944 | (Some(_), false, _) => return true, | ||
| 945 | (Some(conf), true, bypass) => match (conf, bypass) { | ||
| 946 | (Pll::Bypass { .. }, false) => return true, | ||
| 947 | (Pll::Oscillator { .. }, true) => return true, | ||
| 948 | _ => {} | ||
| 949 | }, | ||
| 950 | _ => {} | ||
| 951 | } | ||
| 952 | |||
| 953 | match pll { | ||
| 954 | Some(Pll::Bypass { source }) => cfgr1.pllsel() != source, | ||
| 955 | Some(Pll::Oscillator { | ||
| 956 | source, | ||
| 957 | divm: m, | ||
| 958 | fractional, | ||
| 959 | divn: n, | ||
| 960 | divp1: p1, | ||
| 961 | divp2: p2, | ||
| 962 | }) => { | ||
| 963 | cfgr1.pllsel() != source | ||
| 964 | || cfgr1.plldivm() != m | ||
| 965 | || cfgr1.plldivn() != n | ||
| 966 | || cfgr2.plldivnfrac() != fractional | ||
| 967 | || cfgr3.pllpdiv1() != p1 | ||
| 968 | || cfgr3.pllpdiv2() != p2 | ||
| 969 | } | ||
| 970 | None => false, | ||
| 971 | } | ||
| 972 | } | ||
| 973 | |||
| 974 | pub(crate) unsafe fn init(config: Config) { | ||
| 975 | debug!("enabling SYSCFG"); | ||
| 976 | // system configuration setup | ||
| 977 | RCC.apb4hensr().write(|w| w.set_syscfgens(true)); | ||
| 978 | // delay after RCC peripheral clock enabling | ||
| 979 | RCC.apb4hensr().read(); | ||
| 980 | |||
| 981 | debug!("setting VTOR"); | ||
| 982 | |||
| 983 | let vtor = unsafe { | ||
| 984 | let p = cortex_m::Peripherals::steal(); | ||
| 985 | p.SCB.vtor.read() | ||
| 986 | }; | ||
| 987 | |||
| 988 | // set default vector table location after reset or standby | ||
| 989 | SYSCFG.initsvtorcr().write(|w| w.set_svtor_addr(vtor)); | ||
| 990 | // read back the value to ensure it is written before deactivating SYSCFG | ||
| 991 | SYSCFG.initsvtorcr().read(); | ||
| 992 | |||
| 993 | debug!("deactivating SYSCFG"); | ||
| 994 | |||
| 995 | // deactivate SYSCFG | ||
| 996 | RCC.apb4hensr().write(|w| w.set_syscfgens(false)); | ||
| 997 | |||
| 998 | debug!("enabling FPU"); | ||
| 999 | |||
| 1000 | // enable fpu | ||
| 1001 | unsafe { | ||
| 1002 | let p = cortex_m::Peripherals::steal(); | ||
| 1003 | p.SCB.cpacr.modify(|w| w | (3 << 20) | (3 << 22)); | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | debug!("setting power supply config"); | ||
| 1007 | |||
| 1008 | power_supply_config(config.supply_config); | ||
| 1009 | |||
| 1010 | let osc = init_osc(config); | ||
| 1011 | let clock_inputs = ClocksInput { | ||
| 1012 | hsi: osc.hsi, | ||
| 1013 | msi: osc.msi, | ||
| 1014 | hse: osc.hse, | ||
| 1015 | }; | ||
| 1016 | let clocks = init_clocks(config, &clock_inputs); | ||
| 1017 | |||
| 1018 | // TODO: sysb, sysc, sysd must have the same clock source | ||
| 1019 | |||
| 1020 | set_clocks!( | ||
| 1021 | sys: Some(clocks.sysclk), | ||
| 1022 | hsi: osc.hsi, | ||
| 1023 | hsi_div: None, | ||
| 1024 | hse: osc.hse, | ||
| 1025 | msi: osc.msi, | ||
| 1026 | hclk1: Some(clocks.ahb), | ||
| 1027 | hclk2: Some(clocks.ahb), | ||
| 1028 | hclk3: Some(clocks.ahb), | ||
| 1029 | hclk4: Some(clocks.ahb), | ||
| 1030 | hclk5: Some(clocks.ahb), | ||
| 1031 | pclk1: Some(clocks.apb1), | ||
| 1032 | pclk2: Some(clocks.apb2), | ||
| 1033 | pclk1_tim: Some(clocks.pclk_tim), | ||
| 1034 | pclk2_tim: Some(clocks.pclk_tim), | ||
| 1035 | pclk4: Some(clocks.apb4), | ||
| 1036 | pclk5: Some(clocks.apb5), | ||
| 1037 | per: None, | ||
| 1038 | rtc: None, | ||
| 1039 | i2s_ckin: None, | ||
| 1040 | ic8: None, | ||
| 1041 | ic9: None, | ||
| 1042 | ic14: None, | ||
| 1043 | ic17: None, | ||
| 1044 | ic20: None, | ||
| 1045 | ); | ||
| 1046 | } | ||
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}; | |||
| 32 | 32 | ||
| 33 | pub(crate) fn init( | 33 | pub(crate) fn init( |
| 34 | _cs: critical_section::CriticalSection, | 34 | _cs: critical_section::CriticalSection, |
| 35 | #[cfg(peri_ucpd1)] ucpd1_db_enable: bool, | 35 | #[cfg(all(peri_ucpd1, not(stm32n6)))] ucpd1_db_enable: bool, |
| 36 | #[cfg(peri_ucpd2)] ucpd2_db_enable: bool, | 36 | #[cfg(peri_ucpd2)] ucpd2_db_enable: bool, |
| 37 | ) { | 37 | ) { |
| 38 | #[cfg(stm32g0x1)] | 38 | #[cfg(stm32g0x1)] |
| @@ -349,6 +349,7 @@ impl<'d, T: Instance> CcPhy<'d, T> { | |||
| 349 | critical_section::with(|cs| { | 349 | critical_section::with(|cs| { |
| 350 | init( | 350 | init( |
| 351 | cs, | 351 | cs, |
| 352 | #[cfg(not(stm32n6))] | ||
| 352 | false, | 353 | false, |
| 353 | #[cfg(peri_ucpd2)] | 354 | #[cfg(peri_ucpd2)] |
| 354 | false, | 355 | false, |
diff --git a/examples/stm32n6/.cargo/config.toml b/examples/stm32n6/.cargo/config.toml new file mode 100644 index 000000000..2fdd70649 --- /dev/null +++ b/examples/stm32n6/.cargo/config.toml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | [target.thumbv8m.main-none-eabihf] | ||
| 2 | runner = 'probe-rs run --chip STM32N657' | ||
| 3 | |||
| 4 | [build] | ||
| 5 | target = "thumbv8m.main-none-eabihf" | ||
| 6 | |||
| 7 | [env] | ||
| 8 | DEFMT_LOG = "trace" | ||
diff --git a/examples/stm32n6/Cargo.toml b/examples/stm32n6/Cargo.toml new file mode 100644 index 000000000..5ed28eed1 --- /dev/null +++ b/examples/stm32n6/Cargo.toml | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-stm32n6-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | publish = false | ||
| 7 | |||
| 8 | [dependencies] | ||
| 9 | # Change stm32h563zi to your chip name, if necessary. | ||
| 10 | embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = ["defmt", "stm32n657x0", "time-driver-any", "exti", "unstable-pac"] } | ||
| 11 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | ||
| 12 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } | ||
| 13 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | ||
| 14 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } | ||
| 15 | embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } | ||
| 16 | embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } | ||
| 17 | |||
| 18 | defmt = "1.0.1" | ||
| 19 | defmt-rtt = "1.0.0" | ||
| 20 | |||
| 21 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 22 | cortex-m-rt = "0.7.0" | ||
| 23 | embedded-hal = "0.2.6" | ||
| 24 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | ||
| 25 | embedded-hal-async = { version = "1.0" } | ||
| 26 | embedded-io-async = { version = "0.6.1" } | ||
| 27 | embedded-nal-async = "0.8.0" | ||
| 28 | panic-probe = { version = "1.0.0", features = ["print-defmt"] } | ||
| 29 | heapless = { version = "0.8", default-features = false } | ||
| 30 | critical-section = "1.1" | ||
| 31 | micromath = "2.0.0" | ||
| 32 | stm32-fmc = "0.3.0" | ||
| 33 | embedded-storage = "0.3.1" | ||
| 34 | static_cell = "2" | ||
| 35 | |||
| 36 | |||
| 37 | # cargo build/run | ||
| 38 | [profile.dev] | ||
| 39 | codegen-units = 1 | ||
| 40 | debug = 2 | ||
| 41 | debug-assertions = true # <- | ||
| 42 | incremental = false | ||
| 43 | opt-level = 3 # <- | ||
| 44 | overflow-checks = true # <- | ||
| 45 | |||
| 46 | # cargo test | ||
| 47 | [profile.test] | ||
| 48 | codegen-units = 1 | ||
| 49 | debug = 2 | ||
| 50 | debug-assertions = true # <- | ||
| 51 | incremental = false | ||
| 52 | opt-level = 3 # <- | ||
| 53 | overflow-checks = true # <- | ||
| 54 | |||
| 55 | # cargo build/run --release | ||
| 56 | [profile.release] | ||
| 57 | codegen-units = 1 | ||
| 58 | debug = 2 | ||
| 59 | debug-assertions = false # <- | ||
| 60 | incremental = false | ||
| 61 | lto = 'fat' | ||
| 62 | opt-level = 3 # <- | ||
| 63 | overflow-checks = false # <- | ||
| 64 | |||
| 65 | # cargo test --release | ||
| 66 | [profile.bench] | ||
| 67 | codegen-units = 1 | ||
| 68 | debug = 2 | ||
| 69 | debug-assertions = false # <- | ||
| 70 | incremental = false | ||
| 71 | lto = 'fat' | ||
| 72 | opt-level = 3 # <- | ||
| 73 | overflow-checks = false # <- | ||
| 74 | |||
| 75 | [package.metadata.embassy] | ||
| 76 | build = [ | ||
| 77 | { target = "thumbv8m.main-none-eabihf", artifact-dir = "out/examples/stm32n6" } | ||
| 78 | ] | ||
diff --git a/examples/stm32n6/build.rs b/examples/stm32n6/build.rs new file mode 100644 index 000000000..8cd32d7ed --- /dev/null +++ b/examples/stm32n6/build.rs | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | fn main() { | ||
| 2 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 3 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 4 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 5 | } | ||
diff --git a/examples/stm32n6/memory.x b/examples/stm32n6/memory.x new file mode 100644 index 000000000..59f127adc --- /dev/null +++ b/examples/stm32n6/memory.x | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | FLASH : ORIGIN = 0x34180400, LENGTH = 255K | ||
| 4 | RAM : ORIGIN = 0x341C0000, LENGTH = 256K | ||
| 5 | } | ||
diff --git a/examples/stm32n6/src/bin/blinky.rs b/examples/stm32n6/src/bin/blinky.rs new file mode 100644 index 000000000..018967f08 --- /dev/null +++ b/examples/stm32n6/src/bin/blinky.rs | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::exti::ExtiInput; | ||
| 7 | use embassy_stm32::gpio::{Level, Output, Pull, Speed}; | ||
| 8 | use embassy_time::Timer; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::task] | ||
| 12 | async fn button_task(mut p: ExtiInput<'static>) { | ||
| 13 | loop { | ||
| 14 | p.wait_for_any_edge().await; | ||
| 15 | info!("button pressed!"); | ||
| 16 | } | ||
| 17 | } | ||
| 18 | |||
| 19 | #[embassy_executor::main] | ||
| 20 | async fn main(spawner: Spawner) { | ||
| 21 | let p = embassy_stm32::init(Default::default()); | ||
| 22 | info!("Hello World!"); | ||
| 23 | |||
| 24 | let mut led = Output::new(p.PG10, Level::High, Speed::Low); | ||
| 25 | let button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); | ||
| 26 | |||
| 27 | spawner.spawn(button_task(button).unwrap()); | ||
| 28 | |||
| 29 | loop { | ||
| 30 | led.set_high(); | ||
| 31 | Timer::after_millis(500).await; | ||
| 32 | |||
| 33 | led.set_low(); | ||
| 34 | Timer::after_millis(500).await; | ||
| 35 | } | ||
| 36 | } | ||
