aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-11 16:12:02 +0000
committerGitHub <[email protected]>2025-11-11 16:12:02 +0000
commitf078c85454f09f28a85aa834a9496b37058695e0 (patch)
treed42ce0ef8fcca3d654566e6d83eee8978435e664
parent3d1f09597335d3681699ba09a77da4b39ed984fd (diff)
parent94c4cd8500b131bbfb0ed22176c35dc4df5ff009 (diff)
Merge pull request #4714 from everdrone/n6
STM32N6 RCC implementation
-rw-r--r--.helix/languages.toml11
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/Cargo.toml3
-rw-r--r--embassy-stm32/build.rs226
-rw-r--r--embassy-stm32/src/dma/gpdma/mod.rs1
-rw-r--r--embassy-stm32/src/dma/mod.rs4
-rw-r--r--embassy-stm32/src/dts/tsel.rs17
-rw-r--r--embassy-stm32/src/exti.rs32
-rw-r--r--embassy-stm32/src/gpio.rs44
-rw-r--r--embassy-stm32/src/lib.rs18
-rw-r--r--embassy-stm32/src/rcc/bd.rs110
-rw-r--r--embassy-stm32/src/rcc/mco.rs10
-rw-r--r--embassy-stm32/src/rcc/mod.rs1
-rw-r--r--embassy-stm32/src/rcc/n6.rs1046
-rw-r--r--embassy-stm32/src/ucpd.rs3
-rw-r--r--examples/stm32n6/.cargo/config.toml8
-rw-r--r--examples/stm32n6/Cargo.toml78
-rw-r--r--examples/stm32n6/build.rs5
-rw-r--r--examples/stm32n6/memory.x5
-rw-r--r--examples/stm32n6/src/bin/blinky.rs36
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]
2allTargets = false
3noDefaultFeatures = true
4target = "thumbv8m.main-none-eabihf"
5features = ["stm32n657x0", "time-driver-any", "unstable-pac", "exti"]
6
7[language-server.rust-analyzer.config.check]
8allTargets = false
9noDefaultFeatures = true
10target = "thumbv8m.main-none-eabihf"
11features = ["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"
213proptest-state-machine = "0.3.0" 214proptest-state-machine = "0.3.0"
214 215
215 216
216
217[features] 217[features]
218default = ["rt"] 218default = ["rt"]
219 219
@@ -1642,6 +1642,7 @@ stm32l562qe = [ "stm32-metapac/stm32l562qe" ]
1642stm32l562re = [ "stm32-metapac/stm32l562re" ] 1642stm32l562re = [ "stm32-metapac/stm32l562re" ]
1643stm32l562ve = [ "stm32-metapac/stm32l562ve" ] 1643stm32l562ve = [ "stm32-metapac/stm32l562ve" ]
1644stm32l562ze = [ "stm32-metapac/stm32l562ze" ] 1644stm32l562ze = [ "stm32-metapac/stm32l562ze" ]
1645stm32n657x0 = [ "stm32-metapac/stm32n657x0" ]
1645stm32u031c6 = [ "stm32-metapac/stm32u031c6" ] 1646stm32u031c6 = [ "stm32-metapac/stm32u031c6" ]
1646stm32u031c8 = [ "stm32-metapac/stm32u031c8" ] 1647stm32u031c8 = [ "stm32-metapac/stm32u031c8" ]
1647stm32u031f4 = [ "stm32-metapac/stm32u031f4" ] 1648stm32u031f4 = [ "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
137impl AnyChannel { 137impl 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;
46pub type Request = (); 46pub type Request = ();
47 47
48pub(crate) trait SealedChannel { 48pub(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))]
52pub(crate) trait ChannelInterrupt { 54pub(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)]
59pub trait Channel: SealedChannel + PeripheralType + Into<AnyChannel> + 'static {} 61pub trait Channel: SealedChannel + PeripheralType + Into<AnyChannel> + 'static {}
60 62
63#[cfg(not(stm32n6))]
61macro_rules! dma_channel_impl { 64macro_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
98impl SealedChannel for AnyChannel { 101impl 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))]
57pub 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};
8use embassy_hal_internal::{PeripheralType, impl_peripheral}; 8use embassy_hal_internal::{PeripheralType, impl_peripheral};
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10 10
11use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, Pull}; 11use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, PinNumber, Pull};
12use crate::pac::EXTI; 12use crate::pac::EXTI;
13use crate::pac::exti::regs::Lines; 13use crate::pac::exti::regs::Lines;
14use crate::{Peri, interrupt, pac, peripherals}; 14use 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)))]
35fn exticr_regs() -> pac::syscfg::Syscfg { 35fn 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))]
39fn exticr_regs() -> pac::exti::Exti { 39fn 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
47unsafe fn on_irq() { 47unsafe 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"]
228struct ExtiInputFuture<'a> { 228struct ExtiInputFuture<'a> {
229 pin: u8, 229 pin: PinNumber,
230 phantom: PhantomData<&'a mut AnyPin>, 230 phantom: PhantomData<&'a mut AnyPin>,
231} 231}
232 232
233impl<'a> ExtiInputFuture<'a> { 233impl<'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)]
335pub trait Channel: PeripheralType + SealedChannel + Sized { 335pub 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.
343pub struct AnyChannel { 343pub struct AnyChannel {
344 number: u8, 344 number: PinNumber,
345} 345}
346 346
347impl_peripheral!(AnyChannel); 347impl_peripheral!(AnyChannel);
348impl SealedChannel for AnyChannel {} 348impl SealedChannel for AnyChannel {}
349impl Channel for AnyChannel { 349impl 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)]
595fn set_as_af(pin_port: u8, af_type: AfType) { 595fn 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)]
652fn set_as_af(pin_port: u8, af_num: u8, af_type: AfType) { 652fn 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)]
666fn set_speed(pin_port: u8, speed: Speed) { 666fn 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)]
675fn set_as_analog(pin_port: u8) { 675fn 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)]
691fn get_pull(pin_port: u8) -> Pull { 691fn 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>;
727pub struct AfioRemapNotApplicable; 727pub struct AfioRemapNotApplicable;
728 728
729pub(crate) trait SealedPin { 729pub(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))]
806pub 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)]
813pub type PinNumber = u16;
814
801/// GPIO pin trait. 815/// GPIO pin trait.
802#[allow(private_bounds)] 816#[allow(private_bounds)]
803pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static { 817pub 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
824pub struct AnyPin { 838pub struct AnyPin {
825 pin_port: u8, 839 pin_port: PinNumber,
826} 840}
827 841
828impl AnyPin { 842impl 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}
855impl SealedPin for AnyPin { 869impl 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;
77pub mod eth; 77pub mod eth;
78#[cfg(feature = "exti")] 78#[cfg(feature = "exti")]
79pub mod exti; 79pub mod exti;
80#[cfg(flash)]
80pub mod flash; 81pub mod flash;
81#[cfg(fmc)] 82#[cfg(fmc)]
82pub mod fmc; 83pub 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]
183macro_rules! bind_interrupts { 183macro_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))]
1use core::sync::atomic::{Ordering, compiler_fence}; 2use core::sync::atomic::{Ordering, compiler_fence};
2 3
4#[cfg(not(stm32n6))]
3use crate::pac::common::{RW, Reg}; 5use crate::pac::common::{RW, Reg};
4#[cfg(backup_sram)] 6#[cfg(backup_sram)]
5use crate::pac::pwr::vals::Retention; 7use 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)))]
58type Bdcr = crate::pac::rcc::regs::Bdcr; 60type Bdcr = crate::pac::rcc::regs::Bdcr;
59#[cfg(any(rtc_v2_l0, rtc_v2_l1))] 61#[cfg(any(rtc_v2_l0, rtc_v2_l1))]
60type Bdcr = crate::pac::rcc::regs::Csr; 62type 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))]
65fn unlock() {} 67fn unlock() {}
66 68
67#[cfg(not(any(stm32c0)))] 69#[cfg(not(any(stm32c0, stm32n6)))]
68fn unlock() { 70fn 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))]
80fn bdcr() -> Reg<Bdcr, RW> { 85fn 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
152impl LsConfig { 157impl 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)))]
21pub use crate::pac::rcc::vals::Mcosel as McoSource; 22pub 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))]
34pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; 36pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source};
35use crate::{Peri, peripherals}; 37use 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")]
31mod _version; 32mod _version;
32 33
33pub use _version::*; 34pub 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 @@
1use stm32_metapac::rcc::vals::{
2 Cpusw, Cpusws, Hseext, Hsitrim, Icint, Icsel, Msifreqsel, Plldivm, Pllmodssdis, Pllpdiv, Pllsel, Syssw, Syssws,
3 Timpre,
4};
5pub use stm32_metapac::rcc::vals::{
6 Hpre as AhbPrescaler, Hsidiv as HsiPrescaler, Hsitrim as HsiCalibration, Ppre as ApbPrescaler,
7};
8
9use crate::pac::{PWR, RCC, SYSCFG};
10use crate::time::Hertz;
11
12pub const HSI_FREQ: Hertz = Hertz(64_000_000);
13pub const LSE_FREQ: Hertz = Hertz(32_768);
14
15#[derive(Clone, Copy, Eq, PartialEq)]
16pub 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)]
26pub 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)]
34pub struct Hsi {
35 pub pre: HsiPrescaler,
36 pub trim: Hsitrim,
37}
38
39#[derive(Clone, Copy, PartialEq)]
40pub enum SupplyConfig {
41 Smps,
42 External,
43}
44
45#[derive(Clone, Copy, PartialEq)]
46pub enum CpuClk {
47 Hse,
48 Ic1 { source: Icsel, divider: Icint },
49 Msi,
50 Hsi,
51}
52
53impl 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)]
65pub struct IcConfig {
66 source: Icsel,
67 divider: Icint,
68}
69
70#[derive(Clone, Copy, PartialEq)]
71pub enum SysClk {
72 Hse,
73 Ic2 {
74 ic2: IcConfig,
75 ic6: IcConfig,
76 ic11: IcConfig,
77 },
78 Msi,
79 Hsi,
80}
81
82impl 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)]
94pub struct Msi {
95 pub freq: Msifreqsel,
96 pub trim: u8,
97}
98
99#[derive(Clone, Copy, PartialEq)]
100pub 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)]
117pub 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
141impl 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)]
171struct 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
182struct ClocksInput {
183 hsi: Option<Hertz>,
184 msi: Option<Hertz>,
185 hse: Option<Hertz>,
186}
187
188fn 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
353fn 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
530const 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
543fn 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
553fn pll_sources_ready(source1: u8, source2: u8) -> bool {
554 pll_source_ready(source1) && pll_source_ready(source2)
555}
556
557impl Default for Config {
558 fn default() -> Self {
559 Self::new()
560 }
561}
562
563fn 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
576struct 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)]
585struct PllOutput {
586 divm: Option<Hertz>,
587 divn: Option<Hertz>,
588 divp1: Option<Hertz>,
589 divp2: Option<Hertz>,
590 output: Option<Hertz>,
591}
592
593fn 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)]
713struct 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
729fn 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
934fn 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
974pub(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
33pub(crate) fn init( 33pub(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]
2runner = 'probe-rs run --chip STM32N657'
3
4[build]
5target = "thumbv8m.main-none-eabihf"
6
7[env]
8DEFMT_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]
2edition = "2021"
3name = "embassy-stm32n6-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6publish = false
7
8[dependencies]
9# Change stm32h563zi to your chip name, if necessary.
10embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = ["defmt", "stm32n657x0", "time-driver-any", "exti", "unstable-pac"] }
11embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
12embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
13embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] }
15embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] }
16embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
17
18defmt = "1.0.1"
19defmt-rtt = "1.0.0"
20
21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
22cortex-m-rt = "0.7.0"
23embedded-hal = "0.2.6"
24embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
25embedded-hal-async = { version = "1.0" }
26embedded-io-async = { version = "0.6.1" }
27embedded-nal-async = "0.8.0"
28panic-probe = { version = "1.0.0", features = ["print-defmt"] }
29heapless = { version = "0.8", default-features = false }
30critical-section = "1.1"
31micromath = "2.0.0"
32stm32-fmc = "0.3.0"
33embedded-storage = "0.3.1"
34static_cell = "2"
35
36
37# cargo build/run
38[profile.dev]
39codegen-units = 1
40debug = 2
41debug-assertions = true # <-
42incremental = false
43opt-level = 3 # <-
44overflow-checks = true # <-
45
46# cargo test
47[profile.test]
48codegen-units = 1
49debug = 2
50debug-assertions = true # <-
51incremental = false
52opt-level = 3 # <-
53overflow-checks = true # <-
54
55# cargo build/run --release
56[profile.release]
57codegen-units = 1
58debug = 2
59debug-assertions = false # <-
60incremental = false
61lto = 'fat'
62opt-level = 3 # <-
63overflow-checks = false # <-
64
65# cargo test --release
66[profile.bench]
67codegen-units = 1
68debug = 2
69debug-assertions = false # <-
70incremental = false
71lto = 'fat'
72opt-level = 3 # <-
73overflow-checks = false # <-
74
75[package.metadata.embassy]
76build = [
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 @@
1fn 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 @@
1MEMORY
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
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Level, Output, Pull, Speed};
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::task]
12async 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]
20async 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}