diff options
| author | Tyler <[email protected]> | 2023-09-29 20:02:24 -0600 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-09-29 20:02:24 -0600 |
| commit | 2f9b59c5cf21f1e2761a9ccefdfd86f0edea829c (patch) | |
| tree | 8964744b4fb753cf98f6f413464106c4d2a72976 /embassy-stm32 | |
| parent | ce91fb2bfc846570ef543a09396c428d70675245 (diff) | |
| parent | 95b3d9eb3b3657de3d7bc9c04f8fb83eae901640 (diff) | |
Merge branch 'main' into issue-1974-add-sai-driver
Diffstat (limited to 'embassy-stm32')
61 files changed, 3658 insertions, 2916 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 612a54f25..b3b3cd81c 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -8,31 +8,32 @@ license = "MIT OR Apache-2.0" | |||
| 8 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-v$VERSION/embassy-stm32/src/" | 8 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-v$VERSION/embassy-stm32/src/" |
| 9 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32/src/" | 9 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32/src/" |
| 10 | 10 | ||
| 11 | features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "time", "low-power"] | 11 | features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "time"] |
| 12 | flavors = [ | 12 | flavors = [ |
| 13 | { regex_feature = "stm32f0.*", target = "thumbv6m-none-eabi" }, | 13 | { regex_feature = "stm32f0.*", target = "thumbv6m-none-eabi" }, |
| 14 | { regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" }, | 14 | { regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" }, |
| 15 | { regex_feature = "stm32f2.*", target = "thumbv7m-none-eabi" }, | 15 | { regex_feature = "stm32f2.*", target = "thumbv7m-none-eabi" }, |
| 16 | { regex_feature = "stm32f3.*", target = "thumbv7em-none-eabi" }, | 16 | { regex_feature = "stm32f3.*", target = "thumbv7em-none-eabi" }, |
| 17 | { regex_feature = "stm32f4.*", target = "thumbv7em-none-eabi" }, | 17 | { regex_feature = "stm32f4.*", target = "thumbv7em-none-eabi", features = ["low-power"] }, |
| 18 | { regex_feature = "stm32f7.*", target = "thumbv7em-none-eabi" }, | 18 | { regex_feature = "stm32f7.*", target = "thumbv7em-none-eabi" }, |
| 19 | { regex_feature = "stm32c0.*", target = "thumbv6m-none-eabi" }, | 19 | { regex_feature = "stm32c0.*", target = "thumbv6m-none-eabi" }, |
| 20 | { regex_feature = "stm32g0.*", target = "thumbv6m-none-eabi" }, | 20 | { regex_feature = "stm32g0.*", target = "thumbv6m-none-eabi" }, |
| 21 | { regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi" }, | 21 | { regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi" }, |
| 22 | { regex_feature = "stm32h5.*", target = "thumbv8m.main-none-eabihf" }, | 22 | { regex_feature = "stm32h5.*", target = "thumbv8m.main-none-eabihf" }, |
| 23 | { regex_feature = "stm32h7.*", target = "thumbv7em-none-eabi" }, | 23 | { regex_feature = "stm32h7.*", target = "thumbv7em-none-eabi" }, |
| 24 | { regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi" }, | 24 | { regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi", features = ["low-power"] }, |
| 25 | { regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" }, | 25 | { regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" }, |
| 26 | { regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" }, | 26 | { regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" }, |
| 27 | { regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf" }, | 27 | { regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf" }, |
| 28 | { regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" }, | 28 | { regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" }, |
| 29 | { regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" }, | 29 | { regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" }, |
| 30 | { regex_feature = "stm32wba.*", target = "thumbv8m.main-none-eabihf" }, | ||
| 30 | { regex_feature = "stm32wl.*", target = "thumbv7em-none-eabi" }, | 31 | { regex_feature = "stm32wl.*", target = "thumbv7em-none-eabi" }, |
| 31 | ] | 32 | ] |
| 32 | 33 | ||
| 33 | [dependencies] | 34 | [dependencies] |
| 34 | embassy-sync = { version = "0.2.0", path = "../embassy-sync" } | 35 | embassy-sync = { version = "0.3.0", path = "../embassy-sync" } |
| 35 | embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } | 36 | embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } |
| 36 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } | 37 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } |
| 37 | embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } | 38 | embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } |
| 38 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } | 39 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } |
| @@ -62,7 +63,7 @@ stm32-metapac = "12" | |||
| 62 | vcell = "0.1.3" | 63 | vcell = "0.1.3" |
| 63 | bxcan = "0.7.0" | 64 | bxcan = "0.7.0" |
| 64 | nb = "1.0.0" | 65 | nb = "1.0.0" |
| 65 | stm32-fmc = "0.2.4" | 66 | stm32-fmc = "0.3.0" |
| 66 | seq-macro = "0.3.0" | 67 | seq-macro = "0.3.0" |
| 67 | cfg-if = "1.0.0" | 68 | cfg-if = "1.0.0" |
| 68 | embedded-io = { version = "0.5.0" } | 69 | embedded-io = { version = "0.5.0" } |
| @@ -77,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 77 | [build-dependencies] | 78 | [build-dependencies] |
| 78 | proc-macro2 = "1.0.36" | 79 | proc-macro2 = "1.0.36" |
| 79 | quote = "1.0.15" | 80 | quote = "1.0.15" |
| 80 | stm32-metapac = { path = "../../stm32-data-generated/stm32-metapac", default-features = false, features = ["metadata"]} | 81 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-735cab337aad6161f3d6bcf3e49cd1f034bc3130", default-features = false, features = ["metadata"]} |
| 81 | 82 | ||
| 82 | [features] | 83 | [features] |
| 83 | default = ["rt"] | 84 | default = ["rt"] |
| @@ -1454,6 +1455,10 @@ stm32wb55vc = [ "stm32-metapac/stm32wb55vc" ] | |||
| 1454 | stm32wb55ve = [ "stm32-metapac/stm32wb55ve" ] | 1455 | stm32wb55ve = [ "stm32-metapac/stm32wb55ve" ] |
| 1455 | stm32wb55vg = [ "stm32-metapac/stm32wb55vg" ] | 1456 | stm32wb55vg = [ "stm32-metapac/stm32wb55vg" ] |
| 1456 | stm32wb55vy = [ "stm32-metapac/stm32wb55vy" ] | 1457 | stm32wb55vy = [ "stm32-metapac/stm32wb55vy" ] |
| 1458 | stm32wba52ce = [ "stm32-metapac/stm32wba52ce" ] | ||
| 1459 | stm32wba52cg = [ "stm32-metapac/stm32wba52cg" ] | ||
| 1460 | stm32wba52ke = [ "stm32-metapac/stm32wba52ke" ] | ||
| 1461 | stm32wba52kg = [ "stm32-metapac/stm32wba52kg" ] | ||
| 1457 | stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4" ] | 1462 | stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4" ] |
| 1458 | stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p" ] | 1463 | stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p" ] |
| 1459 | stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4" ] | 1464 | stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4" ] |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 1b86dad7a..ccc9210df 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -308,13 +308,11 @@ fn main() { | |||
| 308 | // ======== | 308 | // ======== |
| 309 | // Generate RccPeripheral impls | 309 | // Generate RccPeripheral impls |
| 310 | 310 | ||
| 311 | let refcounted_peripherals = HashSet::from(["usart", "adc"]); | ||
| 312 | let mut refcount_statics = HashSet::new(); | ||
| 313 | |||
| 311 | for p in METADATA.peripherals { | 314 | for p in METADATA.peripherals { |
| 312 | // generating RccPeripheral impl for H7 ADC3 would result in bad frequency | 315 | if !singletons.contains(&p.name.to_string()) { |
| 313 | if !singletons.contains(&p.name.to_string()) | ||
| 314 | || (p.name == "ADC3" && METADATA.line.starts_with("STM32H7")) | ||
| 315 | || (p.name.starts_with("ADC") && p.registers.as_ref().map_or(false, |r| r.version == "f3")) | ||
| 316 | || (p.name.starts_with("ADC") && p.registers.as_ref().map_or(false, |r| r.version == "v4")) | ||
| 317 | { | ||
| 318 | continue; | 316 | continue; |
| 319 | } | 317 | } |
| 320 | 318 | ||
| @@ -344,11 +342,36 @@ fn main() { | |||
| 344 | TokenStream::new() | 342 | TokenStream::new() |
| 345 | }; | 343 | }; |
| 346 | 344 | ||
| 345 | let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" }; | ||
| 347 | let pname = format_ident!("{}", p.name); | 346 | let pname = format_ident!("{}", p.name); |
| 348 | let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase()); | 347 | let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase()); |
| 349 | let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); | 348 | let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); |
| 350 | let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); | 349 | let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); |
| 351 | 350 | ||
| 351 | let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype) { | ||
| 352 | let refcount_static = | ||
| 353 | format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); | ||
| 354 | |||
| 355 | refcount_statics.insert(refcount_static.clone()); | ||
| 356 | |||
| 357 | ( | ||
| 358 | quote! { | ||
| 359 | unsafe { refcount_statics::#refcount_static += 1 }; | ||
| 360 | if unsafe { refcount_statics::#refcount_static } > 1 { | ||
| 361 | return; | ||
| 362 | } | ||
| 363 | }, | ||
| 364 | quote! { | ||
| 365 | unsafe { refcount_statics::#refcount_static -= 1 }; | ||
| 366 | if unsafe { refcount_statics::#refcount_static } > 0 { | ||
| 367 | return; | ||
| 368 | } | ||
| 369 | }, | ||
| 370 | ) | ||
| 371 | } else { | ||
| 372 | (TokenStream::new(), TokenStream::new()) | ||
| 373 | }; | ||
| 374 | |||
| 352 | g.extend(quote! { | 375 | g.extend(quote! { |
| 353 | impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { | 376 | impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { |
| 354 | fn frequency() -> crate::time::Hertz { | 377 | fn frequency() -> crate::time::Hertz { |
| @@ -356,6 +379,7 @@ fn main() { | |||
| 356 | } | 379 | } |
| 357 | fn enable() { | 380 | fn enable() { |
| 358 | critical_section::with(|_| { | 381 | critical_section::with(|_| { |
| 382 | #before_enable | ||
| 359 | #[cfg(feature = "low-power")] | 383 | #[cfg(feature = "low-power")] |
| 360 | crate::rcc::clock_refcount_add(); | 384 | crate::rcc::clock_refcount_add(); |
| 361 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); | 385 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); |
| @@ -364,6 +388,7 @@ fn main() { | |||
| 364 | } | 388 | } |
| 365 | fn disable() { | 389 | fn disable() { |
| 366 | critical_section::with(|_| { | 390 | critical_section::with(|_| { |
| 391 | #before_disable | ||
| 367 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); | 392 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); |
| 368 | #[cfg(feature = "low-power")] | 393 | #[cfg(feature = "low-power")] |
| 369 | crate::rcc::clock_refcount_sub(); | 394 | crate::rcc::clock_refcount_sub(); |
| @@ -379,6 +404,19 @@ fn main() { | |||
| 379 | } | 404 | } |
| 380 | } | 405 | } |
| 381 | 406 | ||
| 407 | let mut refcount_mod = TokenStream::new(); | ||
| 408 | for refcount_static in refcount_statics { | ||
| 409 | refcount_mod.extend(quote! { | ||
| 410 | pub(crate) static mut #refcount_static: u8 = 0; | ||
| 411 | }); | ||
| 412 | } | ||
| 413 | |||
| 414 | g.extend(quote! { | ||
| 415 | mod refcount_statics { | ||
| 416 | #refcount_mod | ||
| 417 | } | ||
| 418 | }); | ||
| 419 | |||
| 382 | // ======== | 420 | // ======== |
| 383 | // Generate fns to enable GPIO, DMA in RCC | 421 | // Generate fns to enable GPIO, DMA in RCC |
| 384 | 422 | ||
| @@ -673,6 +711,10 @@ fn main() { | |||
| 673 | 711 | ||
| 674 | // ADC is special | 712 | // ADC is special |
| 675 | if regs.kind == "adc" { | 713 | if regs.kind == "adc" { |
| 714 | if p.rcc.is_none() { | ||
| 715 | continue; | ||
| 716 | } | ||
| 717 | |||
| 676 | let peri = format_ident!("{}", p.name); | 718 | let peri = format_ident!("{}", p.name); |
| 677 | let pin_name = format_ident!("{}", pin.pin); | 719 | let pin_name = format_ident!("{}", pin.pin); |
| 678 | 720 | ||
| @@ -786,6 +828,17 @@ fn main() { | |||
| 786 | let mut peripherals_table: Vec<Vec<String>> = Vec::new(); | 828 | let mut peripherals_table: Vec<Vec<String>> = Vec::new(); |
| 787 | let mut pins_table: Vec<Vec<String>> = Vec::new(); | 829 | let mut pins_table: Vec<Vec<String>> = Vec::new(); |
| 788 | let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); | 830 | let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); |
| 831 | let mut adc_common_table: Vec<Vec<String>> = Vec::new(); | ||
| 832 | |||
| 833 | /* | ||
| 834 | If ADC3_COMMON exists, ADC3 and higher are assigned to it | ||
| 835 | All other ADCs are assigned to ADC_COMMON | ||
| 836 | |||
| 837 | ADC3 and higher are assigned to the adc34 clock in the table | ||
| 838 | The adc3_common cfg directive is added if ADC3_COMMON exists | ||
| 839 | */ | ||
| 840 | let has_adc3 = METADATA.peripherals.iter().find(|p| p.name == "ADC3_COMMON").is_some(); | ||
| 841 | let set_adc345 = HashSet::from(["ADC3", "ADC4", "ADC5"]); | ||
| 789 | 842 | ||
| 790 | for m in METADATA | 843 | for m in METADATA |
| 791 | .memory | 844 | .memory |
| @@ -823,6 +876,17 @@ fn main() { | |||
| 823 | } | 876 | } |
| 824 | } | 877 | } |
| 825 | 878 | ||
| 879 | if regs.kind == "adc" { | ||
| 880 | let (adc_common, adc_clock) = if set_adc345.contains(p.name) && has_adc3 { | ||
| 881 | ("ADC3_COMMON", "adc34") | ||
| 882 | } else { | ||
| 883 | ("ADC_COMMON", "adc") | ||
| 884 | }; | ||
| 885 | |||
| 886 | let row = vec![p.name.to_string(), adc_common.to_string(), adc_clock.to_string()]; | ||
| 887 | adc_common_table.push(row); | ||
| 888 | } | ||
| 889 | |||
| 826 | for irq in p.interrupts { | 890 | for irq in p.interrupts { |
| 827 | let row = vec![ | 891 | let row = vec![ |
| 828 | p.name.to_string(), | 892 | p.name.to_string(), |
| @@ -901,6 +965,7 @@ fn main() { | |||
| 901 | make_table(&mut m, "foreach_peripheral", &peripherals_table); | 965 | make_table(&mut m, "foreach_peripheral", &peripherals_table); |
| 902 | make_table(&mut m, "foreach_pin", &pins_table); | 966 | make_table(&mut m, "foreach_pin", &pins_table); |
| 903 | make_table(&mut m, "foreach_dma_channel", &dma_channels_table); | 967 | make_table(&mut m, "foreach_dma_channel", &dma_channels_table); |
| 968 | make_table(&mut m, "foreach_adc", &adc_common_table); | ||
| 904 | 969 | ||
| 905 | let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | 970 | let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); |
| 906 | let out_file = out_dir.join("_macros.rs").to_string_lossy().to_string(); | 971 | let out_file = out_dir.join("_macros.rs").to_string_lossy().to_string(); |
| @@ -943,12 +1008,23 @@ fn main() { | |||
| 943 | } | 1008 | } |
| 944 | 1009 | ||
| 945 | // ======= | 1010 | // ======= |
| 1011 | // ADC3_COMMON is present | ||
| 1012 | if has_adc3 { | ||
| 1013 | println!("cargo:rustc-cfg={}", "adc3_common"); | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | // ======= | ||
| 946 | // Features for targeting groups of chips | 1017 | // Features for targeting groups of chips |
| 947 | 1018 | ||
| 948 | println!("cargo:rustc-cfg={}", &chip_name[..7]); // stm32f4 | 1019 | if &chip_name[..8] == "stm32wba" { |
| 949 | println!("cargo:rustc-cfg={}", &chip_name[..9]); // stm32f429 | 1020 | println!("cargo:rustc-cfg={}", &chip_name[..8]); // stm32wba |
| 950 | println!("cargo:rustc-cfg={}x", &chip_name[..8]); // stm32f42x | 1021 | println!("cargo:rustc-cfg={}", &chip_name[..10]); // stm32wba52 |
| 951 | println!("cargo:rustc-cfg={}x{}", &chip_name[..7], &chip_name[8..9]); // stm32f4x9 | 1022 | } else { |
| 1023 | println!("cargo:rustc-cfg={}", &chip_name[..7]); // stm32f4 | ||
| 1024 | println!("cargo:rustc-cfg={}", &chip_name[..9]); // stm32f429 | ||
| 1025 | println!("cargo:rustc-cfg={}x", &chip_name[..8]); // stm32f42x | ||
| 1026 | println!("cargo:rustc-cfg={}x{}", &chip_name[..7], &chip_name[8..9]); // stm32f4x9 | ||
| 1027 | } | ||
| 952 | 1028 | ||
| 953 | // Handle time-driver-XXXX features. | 1029 | // Handle time-driver-XXXX features. |
| 954 | if env::var("CARGO_FEATURE_TIME_DRIVER_ANY").is_ok() {} | 1030 | if env::var("CARGO_FEATURE_TIME_DRIVER_ANY").is_ok() {} |
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index e577ec289..c13264819 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs | |||
| @@ -1,16 +1,37 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 2 | use core::marker::PhantomData; | ||
| 3 | use core::task::Poll; | ||
| 4 | |||
| 1 | use embassy_hal_internal::into_ref; | 5 | use embassy_hal_internal::into_ref; |
| 2 | use embedded_hal_02::blocking::delay::DelayUs; | 6 | use embedded_hal_02::blocking::delay::DelayUs; |
| 3 | 7 | ||
| 4 | use crate::adc::{Adc, AdcPin, Instance, SampleTime}; | 8 | use crate::adc::{Adc, AdcPin, Instance, SampleTime}; |
| 5 | use crate::rcc::get_freqs; | 9 | use crate::rcc::get_freqs; |
| 6 | use crate::time::Hertz; | 10 | use crate::time::Hertz; |
| 7 | use crate::Peripheral; | 11 | use crate::{interrupt, Peripheral}; |
| 8 | 12 | ||
| 9 | pub const VDDA_CALIB_MV: u32 = 3300; | 13 | pub const VDDA_CALIB_MV: u32 = 3300; |
| 10 | pub const ADC_MAX: u32 = (1 << 12) - 1; | 14 | pub const ADC_MAX: u32 = (1 << 12) - 1; |
| 11 | // No calibration data for F103, voltage should be 1.2v | 15 | // No calibration data for F103, voltage should be 1.2v |
| 12 | pub const VREF_INT: u32 = 1200; | 16 | pub const VREF_INT: u32 = 1200; |
| 13 | 17 | ||
| 18 | /// Interrupt handler. | ||
| 19 | pub struct InterruptHandler<T: Instance> { | ||
| 20 | _phantom: PhantomData<T>, | ||
| 21 | } | ||
| 22 | |||
| 23 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 24 | unsafe fn on_interrupt() { | ||
| 25 | if T::regs().sr().read().eoc() { | ||
| 26 | T::regs().cr1().modify(|w| w.set_eocie(false)); | ||
| 27 | } else { | ||
| 28 | return; | ||
| 29 | } | ||
| 30 | |||
| 31 | T::state().waker.wake(); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 14 | pub struct Vref; | 35 | pub struct Vref; |
| 15 | impl<T: Instance> AdcPin<T> for Vref {} | 36 | impl<T: Instance> AdcPin<T> for Vref {} |
| 16 | impl<T: Instance> super::sealed::AdcPin<T> for Vref { | 37 | impl<T: Instance> super::sealed::AdcPin<T> for Vref { |
| @@ -60,7 +81,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 60 | } | 81 | } |
| 61 | 82 | ||
| 62 | fn freq() -> Hertz { | 83 | fn freq() -> Hertz { |
| 63 | unsafe { get_freqs() }.adc | 84 | unsafe { get_freqs() }.adc.unwrap() |
| 64 | } | 85 | } |
| 65 | 86 | ||
| 66 | pub fn sample_time_for_us(&self, us: u32) -> SampleTime { | 87 | pub fn sample_time_for_us(&self, us: u32) -> SampleTime { |
| @@ -95,18 +116,28 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 95 | } | 116 | } |
| 96 | 117 | ||
| 97 | /// Perform a single conversion. | 118 | /// Perform a single conversion. |
| 98 | fn convert(&mut self) -> u16 { | 119 | async fn convert(&mut self) -> u16 { |
| 99 | T::regs().cr2().modify(|reg| { | 120 | T::regs().cr2().modify(|reg| { |
| 100 | reg.set_adon(true); | 121 | reg.set_adon(true); |
| 101 | reg.set_swstart(true); | 122 | reg.set_swstart(true); |
| 102 | }); | 123 | }); |
| 103 | while T::regs().cr2().read().swstart() {} | 124 | T::regs().cr1().modify(|w| w.set_eocie(true)); |
| 104 | while !T::regs().sr().read().eoc() {} | 125 | |
| 126 | poll_fn(|cx| { | ||
| 127 | T::state().waker.register(cx.waker()); | ||
| 128 | |||
| 129 | if !T::regs().cr2().read().swstart() && T::regs().sr().read().eoc() { | ||
| 130 | Poll::Ready(()) | ||
| 131 | } else { | ||
| 132 | Poll::Pending | ||
| 133 | } | ||
| 134 | }) | ||
| 135 | .await; | ||
| 105 | 136 | ||
| 106 | T::regs().dr().read().0 as u16 | 137 | T::regs().dr().read().0 as u16 |
| 107 | } | 138 | } |
| 108 | 139 | ||
| 109 | pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { | 140 | pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { |
| 110 | Self::set_channel_sample_time(pin.channel(), self.sample_time); | 141 | Self::set_channel_sample_time(pin.channel(), self.sample_time); |
| 111 | T::regs().cr1().modify(|reg| { | 142 | T::regs().cr1().modify(|reg| { |
| 112 | reg.set_scan(false); | 143 | reg.set_scan(false); |
| @@ -123,7 +154,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 123 | 154 | ||
| 124 | // Configure the channel to sample | 155 | // Configure the channel to sample |
| 125 | T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())); | 156 | T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())); |
| 126 | self.convert() | 157 | self.convert().await |
| 127 | } | 158 | } |
| 128 | 159 | ||
| 129 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | 160 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { |
| @@ -135,3 +166,11 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 135 | } | 166 | } |
| 136 | } | 167 | } |
| 137 | } | 168 | } |
| 169 | |||
| 170 | impl<'d, T: Instance> Drop for Adc<'d, T> { | ||
| 171 | fn drop(&mut self) { | ||
| 172 | T::regs().cr2().modify(|reg| reg.set_adon(false)); | ||
| 173 | |||
| 174 | T::disable(); | ||
| 175 | } | ||
| 176 | } | ||
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs new file mode 100644 index 000000000..7c13f8106 --- /dev/null +++ b/embassy-stm32/src/adc/f3.rs | |||
| @@ -0,0 +1,195 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 2 | use core::marker::PhantomData; | ||
| 3 | use core::task::Poll; | ||
| 4 | |||
| 5 | use embassy_hal_internal::into_ref; | ||
| 6 | use embedded_hal_02::blocking::delay::DelayUs; | ||
| 7 | |||
| 8 | use crate::adc::{Adc, AdcPin, Instance, SampleTime}; | ||
| 9 | use crate::interrupt::typelevel::Interrupt; | ||
| 10 | use crate::time::Hertz; | ||
| 11 | use crate::{interrupt, Peripheral}; | ||
| 12 | |||
| 13 | pub const VDDA_CALIB_MV: u32 = 3300; | ||
| 14 | pub const ADC_MAX: u32 = (1 << 12) - 1; | ||
| 15 | pub const VREF_INT: u32 = 1230; | ||
| 16 | |||
| 17 | /// Interrupt handler. | ||
| 18 | pub struct InterruptHandler<T: Instance> { | ||
| 19 | _phantom: PhantomData<T>, | ||
| 20 | } | ||
| 21 | |||
| 22 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 23 | unsafe fn on_interrupt() { | ||
| 24 | if T::regs().isr().read().eoc() { | ||
| 25 | T::regs().ier().modify(|w| w.set_eocie(false)); | ||
| 26 | } else { | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | |||
| 30 | T::state().waker.wake(); | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | pub struct Vref; | ||
| 35 | impl<T: Instance> AdcPin<T> for Vref {} | ||
| 36 | impl<T: Instance> super::sealed::AdcPin<T> for Vref { | ||
| 37 | fn channel(&self) -> u8 { | ||
| 38 | 18 | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | impl Vref { | ||
| 43 | /// The value that vref would be if vdda was at 3300mv | ||
| 44 | pub fn value(&self) -> u16 { | ||
| 45 | crate::pac::VREFINTCAL.data().read().value() | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | pub struct Temperature; | ||
| 50 | impl<T: Instance> AdcPin<T> for Temperature {} | ||
| 51 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature { | ||
| 52 | fn channel(&self) -> u8 { | ||
| 53 | 16 | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | impl<'d, T: Instance> Adc<'d, T> { | ||
| 58 | pub fn new( | ||
| 59 | adc: impl Peripheral<P = T> + 'd, | ||
| 60 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 61 | delay: &mut impl DelayUs<u32>, | ||
| 62 | ) -> Self { | ||
| 63 | use crate::pac::adc::vals; | ||
| 64 | |||
| 65 | into_ref!(adc); | ||
| 66 | |||
| 67 | T::enable(); | ||
| 68 | T::reset(); | ||
| 69 | |||
| 70 | // Enable the adc regulator | ||
| 71 | T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE)); | ||
| 72 | T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::ENABLED)); | ||
| 73 | |||
| 74 | // Wait for the regulator to stabilize | ||
| 75 | delay.delay_us(10); | ||
| 76 | |||
| 77 | assert!(!T::regs().cr().read().aden()); | ||
| 78 | |||
| 79 | // Begin calibration | ||
| 80 | T::regs().cr().modify(|w| w.set_adcaldif(false)); | ||
| 81 | T::regs().cr().modify(|w| w.set_adcal(true)); | ||
| 82 | |||
| 83 | while T::regs().cr().read().adcal() {} | ||
| 84 | |||
| 85 | // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223) | ||
| 86 | delay.delay_us(1 + (6 * 1_000_000 / Self::freq().0)); | ||
| 87 | |||
| 88 | // Enable the adc | ||
| 89 | T::regs().cr().modify(|w| w.set_aden(true)); | ||
| 90 | |||
| 91 | // Wait until the adc is ready | ||
| 92 | while !T::regs().isr().read().adrdy() {} | ||
| 93 | |||
| 94 | T::Interrupt::unpend(); | ||
| 95 | unsafe { | ||
| 96 | T::Interrupt::enable(); | ||
| 97 | } | ||
| 98 | |||
| 99 | Self { | ||
| 100 | adc, | ||
| 101 | sample_time: Default::default(), | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | fn freq() -> Hertz { | ||
| 106 | <T as crate::adc::sealed::Instance>::frequency() | ||
| 107 | } | ||
| 108 | |||
| 109 | pub fn sample_time_for_us(&self, us: u32) -> SampleTime { | ||
| 110 | match us * Self::freq().0 / 1_000_000 { | ||
| 111 | 0..=1 => SampleTime::Cycles1_5, | ||
| 112 | 2..=4 => SampleTime::Cycles4_5, | ||
| 113 | 5..=7 => SampleTime::Cycles7_5, | ||
| 114 | 8..=19 => SampleTime::Cycles19_5, | ||
| 115 | 20..=61 => SampleTime::Cycles61_5, | ||
| 116 | 62..=181 => SampleTime::Cycles181_5, | ||
| 117 | _ => SampleTime::Cycles601_5, | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref { | ||
| 122 | T::common_regs().ccr().modify(|w| w.set_vrefen(true)); | ||
| 123 | |||
| 124 | Vref {} | ||
| 125 | } | ||
| 126 | |||
| 127 | pub fn enable_temperature(&self) -> Temperature { | ||
| 128 | T::common_regs().ccr().modify(|w| w.set_tsen(true)); | ||
| 129 | |||
| 130 | Temperature {} | ||
| 131 | } | ||
| 132 | |||
| 133 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { | ||
| 134 | self.sample_time = sample_time; | ||
| 135 | } | ||
| 136 | |||
| 137 | /// Perform a single conversion. | ||
| 138 | async fn convert(&mut self) -> u16 { | ||
| 139 | T::regs().isr().write(|_| {}); | ||
| 140 | T::regs().ier().modify(|w| w.set_eocie(true)); | ||
| 141 | T::regs().cr().modify(|w| w.set_adstart(true)); | ||
| 142 | |||
| 143 | poll_fn(|cx| { | ||
| 144 | T::state().waker.register(cx.waker()); | ||
| 145 | |||
| 146 | if T::regs().isr().read().eoc() { | ||
| 147 | Poll::Ready(()) | ||
| 148 | } else { | ||
| 149 | Poll::Pending | ||
| 150 | } | ||
| 151 | }) | ||
| 152 | .await; | ||
| 153 | |||
| 154 | T::regs().isr().write(|_| {}); | ||
| 155 | |||
| 156 | T::regs().dr().read().rdata() | ||
| 157 | } | ||
| 158 | |||
| 159 | pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { | ||
| 160 | Self::set_channel_sample_time(pin.channel(), self.sample_time); | ||
| 161 | |||
| 162 | // Configure the channel to sample | ||
| 163 | T::regs().sqr1().write(|w| w.set_sq(0, pin.channel())); | ||
| 164 | self.convert().await | ||
| 165 | } | ||
| 166 | |||
| 167 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | ||
| 168 | let sample_time = sample_time.into(); | ||
| 169 | if ch <= 9 { | ||
| 170 | T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time)); | ||
| 171 | } else { | ||
| 172 | T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); | ||
| 173 | } | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | impl<'d, T: Instance> Drop for Adc<'d, T> { | ||
| 178 | fn drop(&mut self) { | ||
| 179 | use crate::pac::adc::vals; | ||
| 180 | |||
| 181 | T::regs().cr().modify(|w| w.set_adstp(true)); | ||
| 182 | |||
| 183 | while T::regs().cr().read().adstp() {} | ||
| 184 | |||
| 185 | T::regs().cr().modify(|w| w.set_addis(true)); | ||
| 186 | |||
| 187 | while T::regs().cr().read().aden() {} | ||
| 188 | |||
| 189 | // Disable the adc regulator | ||
| 190 | T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE)); | ||
| 191 | T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::DISABLED)); | ||
| 192 | |||
| 193 | T::disable(); | ||
| 194 | } | ||
| 195 | } | ||
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index e57889aa6..365738a31 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -1,23 +1,24 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | #[cfg(not(any(adc_f3, adc_f3_v2)))] | 3 | #[cfg(not(adc_f3_v2))] |
| 4 | #[cfg_attr(adc_f1, path = "f1.rs")] | 4 | #[cfg_attr(adc_f1, path = "f1.rs")] |
| 5 | #[cfg_attr(adc_f3, path = "f3.rs")] | ||
| 5 | #[cfg_attr(adc_v1, path = "v1.rs")] | 6 | #[cfg_attr(adc_v1, path = "v1.rs")] |
| 6 | #[cfg_attr(adc_v2, path = "v2.rs")] | 7 | #[cfg_attr(adc_v2, path = "v2.rs")] |
| 7 | #[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] | 8 | #[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] |
| 8 | #[cfg_attr(adc_v4, path = "v4.rs")] | 9 | #[cfg_attr(adc_v4, path = "v4.rs")] |
| 9 | mod _version; | 10 | mod _version; |
| 10 | 11 | ||
| 11 | #[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))] | 12 | #[cfg(not(any(adc_f1, adc_f3_v2)))] |
| 12 | mod resolution; | 13 | mod resolution; |
| 13 | mod sample_time; | 14 | mod sample_time; |
| 14 | 15 | ||
| 15 | #[cfg(not(any(adc_f3, adc_f3_v2)))] | ||
| 16 | #[allow(unused)] | 16 | #[allow(unused)] |
| 17 | #[cfg(not(adc_f3_v2))] | ||
| 17 | pub use _version::*; | 18 | pub use _version::*; |
| 18 | #[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))] | 19 | #[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))] |
| 19 | pub use resolution::Resolution; | 20 | pub use resolution::Resolution; |
| 20 | #[cfg(not(any(adc_f3, adc_f3_v2)))] | 21 | #[cfg(not(adc_f3_v2))] |
| 21 | pub use sample_time::SampleTime; | 22 | pub use sample_time::SampleTime; |
| 22 | 23 | ||
| 23 | use crate::peripherals; | 24 | use crate::peripherals; |
| @@ -25,18 +26,46 @@ use crate::peripherals; | |||
| 25 | pub struct Adc<'d, T: Instance> { | 26 | pub struct Adc<'d, T: Instance> { |
| 26 | #[allow(unused)] | 27 | #[allow(unused)] |
| 27 | adc: crate::PeripheralRef<'d, T>, | 28 | adc: crate::PeripheralRef<'d, T>, |
| 28 | #[cfg(not(any(adc_f3, adc_f3_v2)))] | 29 | #[cfg(not(adc_f3_v2))] |
| 29 | sample_time: SampleTime, | 30 | sample_time: SampleTime, |
| 30 | } | 31 | } |
| 31 | 32 | ||
| 32 | pub(crate) mod sealed { | 33 | pub(crate) mod sealed { |
| 33 | pub trait Instance { | 34 | #[cfg(any(adc_f1, adc_f3, adc_v1))] |
| 35 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 36 | |||
| 37 | #[cfg(any(adc_f1, adc_f3, adc_v1))] | ||
| 38 | pub struct State { | ||
| 39 | pub waker: AtomicWaker, | ||
| 40 | } | ||
| 41 | |||
| 42 | #[cfg(any(adc_f1, adc_f3, adc_v1))] | ||
| 43 | impl State { | ||
| 44 | pub const fn new() -> Self { | ||
| 45 | Self { | ||
| 46 | waker: AtomicWaker::new(), | ||
| 47 | } | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | pub trait InterruptableInstance { | ||
| 52 | type Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 53 | } | ||
| 54 | |||
| 55 | pub trait Instance: InterruptableInstance { | ||
| 34 | fn regs() -> crate::pac::adc::Adc; | 56 | fn regs() -> crate::pac::adc::Adc; |
| 35 | #[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))] | 57 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] |
| 36 | fn common_regs() -> crate::pac::adccommon::AdcCommon; | 58 | fn common_regs() -> crate::pac::adccommon::AdcCommon; |
| 59 | #[cfg(adc_f3)] | ||
| 60 | fn frequency() -> crate::time::Hertz; | ||
| 61 | #[cfg(any(adc_f1, adc_f3, adc_v1))] | ||
| 62 | fn state() -> &'static State; | ||
| 37 | } | 63 | } |
| 38 | 64 | ||
| 39 | pub trait AdcPin<T: Instance> { | 65 | pub trait AdcPin<T: Instance> { |
| 66 | #[cfg(any(adc_v1, adc_v2))] | ||
| 67 | fn set_as_analog(&mut self) {} | ||
| 68 | |||
| 40 | fn channel(&self) -> u8; | 69 | fn channel(&self) -> u8; |
| 41 | } | 70 | } |
| 42 | 71 | ||
| @@ -45,68 +74,45 @@ pub(crate) mod sealed { | |||
| 45 | } | 74 | } |
| 46 | } | 75 | } |
| 47 | 76 | ||
| 48 | #[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4)))] | 77 | #[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3)))] |
| 49 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} | 78 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} |
| 50 | #[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4))] | 79 | #[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3))] |
| 51 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} | 80 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} |
| 52 | 81 | ||
| 53 | pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} | 82 | pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} |
| 54 | pub trait InternalChannel<T>: sealed::InternalChannel<T> {} | 83 | pub trait InternalChannel<T>: sealed::InternalChannel<T> {} |
| 55 | 84 | ||
| 56 | #[cfg(not(stm32h7))] | 85 | foreach_adc!( |
| 57 | foreach_peripheral!( | 86 | ($inst:ident, $common_inst:ident, $clock:ident) => { |
| 58 | (adc, $inst:ident) => { | ||
| 59 | impl crate::adc::sealed::Instance for peripherals::$inst { | 87 | impl crate::adc::sealed::Instance for peripherals::$inst { |
| 60 | fn regs() -> crate::pac::adc::Adc { | 88 | fn regs() -> crate::pac::adc::Adc { |
| 61 | crate::pac::$inst | 89 | crate::pac::$inst |
| 62 | } | 90 | } |
| 63 | #[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))] | 91 | |
| 92 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] | ||
| 64 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | 93 | fn common_regs() -> crate::pac::adccommon::AdcCommon { |
| 65 | foreach_peripheral!{ | 94 | return crate::pac::$common_inst |
| 66 | (adccommon, $common_inst:ident) => { | ||
| 67 | return crate::pac::$common_inst | ||
| 68 | }; | ||
| 69 | } | ||
| 70 | } | 95 | } |
| 71 | } | ||
| 72 | |||
| 73 | impl crate::adc::Instance for peripherals::$inst {} | ||
| 74 | }; | ||
| 75 | ); | ||
| 76 | 96 | ||
| 77 | #[cfg(stm32h7)] | 97 | #[cfg(adc_f3)] |
| 78 | foreach_peripheral!( | 98 | fn frequency() -> crate::time::Hertz { |
| 79 | (adc, ADC3) => { | 99 | unsafe { crate::rcc::get_freqs() }.$clock.unwrap() |
| 80 | impl crate::adc::sealed::Instance for peripherals::ADC3 { | ||
| 81 | fn regs() -> crate::pac::adc::Adc { | ||
| 82 | crate::pac::ADC3 | ||
| 83 | } | 100 | } |
| 84 | #[cfg(all(not(adc_f1), not(adc_v1)))] | 101 | |
| 85 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | 102 | #[cfg(any(adc_f1, adc_f3, adc_v1))] |
| 86 | foreach_peripheral!{ | 103 | fn state() -> &'static sealed::State { |
| 87 | (adccommon, ADC3_COMMON) => { | 104 | static STATE: sealed::State = sealed::State::new(); |
| 88 | return crate::pac::ADC3_COMMON | 105 | &STATE |
| 89 | }; | ||
| 90 | } | ||
| 91 | } | 106 | } |
| 92 | } | 107 | } |
| 93 | 108 | ||
| 94 | impl crate::adc::Instance for peripherals::ADC3 {} | 109 | foreach_interrupt!( |
| 95 | }; | 110 | ($inst,adc,ADC,GLOBAL,$irq:ident) => { |
| 96 | (adc, $inst:ident) => { | 111 | impl sealed::InterruptableInstance for peripherals::$inst { |
| 97 | impl crate::adc::sealed::Instance for peripherals::$inst { | 112 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 98 | fn regs() -> crate::pac::adc::Adc { | ||
| 99 | crate::pac::$inst | ||
| 100 | } | ||
| 101 | #[cfg(all(not(adc_f1), not(adc_v1)))] | ||
| 102 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | ||
| 103 | foreach_peripheral!{ | ||
| 104 | (adccommon, ADC_COMMON) => { | ||
| 105 | return crate::pac::ADC_COMMON | ||
| 106 | }; | ||
| 107 | } | 113 | } |
| 108 | } | 114 | }; |
| 109 | } | 115 | ); |
| 110 | 116 | ||
| 111 | impl crate::adc::Instance for peripherals::$inst {} | 117 | impl crate::adc::Instance for peripherals::$inst {} |
| 112 | }; | 118 | }; |
| @@ -117,6 +123,11 @@ macro_rules! impl_adc_pin { | |||
| 117 | impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {} | 123 | impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {} |
| 118 | 124 | ||
| 119 | impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin { | 125 | impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin { |
| 126 | #[cfg(any(adc_v1, adc_v2))] | ||
| 127 | fn set_as_analog(&mut self) { | ||
| 128 | <Self as crate::gpio::sealed::Pin>::set_as_analog(self); | ||
| 129 | } | ||
| 130 | |||
| 120 | fn channel(&self) -> u8 { | 131 | fn channel(&self) -> u8 { |
| 121 | $ch | 132 | $ch |
| 122 | } | 133 | } |
diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs index 67fb9b8c0..5668137b5 100644 --- a/embassy-stm32/src/adc/resolution.rs +++ b/embassy-stm32/src/adc/resolution.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] | 1 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] |
| 2 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] | 2 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] |
| 3 | pub enum Resolution { | 3 | pub enum Resolution { |
| 4 | TwelveBit, | 4 | TwelveBit, |
| @@ -19,7 +19,7 @@ pub enum Resolution { | |||
| 19 | 19 | ||
| 20 | impl Default for Resolution { | 20 | impl Default for Resolution { |
| 21 | fn default() -> Self { | 21 | fn default() -> Self { |
| 22 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] | 22 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] |
| 23 | { | 23 | { |
| 24 | Self::TwelveBit | 24 | Self::TwelveBit |
| 25 | } | 25 | } |
| @@ -40,7 +40,7 @@ impl From<Resolution> for crate::pac::adc::vals::Res { | |||
| 40 | Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, | 40 | Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, |
| 41 | Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, | 41 | Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, |
| 42 | Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, | 42 | Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, |
| 43 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] | 43 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] |
| 44 | Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, | 44 | Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, |
| 45 | } | 45 | } |
| 46 | } | 46 | } |
| @@ -56,7 +56,7 @@ impl Resolution { | |||
| 56 | Resolution::TwelveBit => (1 << 12) - 1, | 56 | Resolution::TwelveBit => (1 << 12) - 1, |
| 57 | Resolution::TenBit => (1 << 10) - 1, | 57 | Resolution::TenBit => (1 << 10) - 1, |
| 58 | Resolution::EightBit => (1 << 8) - 1, | 58 | Resolution::EightBit => (1 << 8) - 1, |
| 59 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] | 59 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] |
| 60 | Resolution::SixBit => (1 << 6) - 1, | 60 | Resolution::SixBit => (1 << 6) - 1, |
| 61 | } | 61 | } |
| 62 | } | 62 | } |
diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs index 5480e7a77..6a6619299 100644 --- a/embassy-stm32/src/adc/sample_time.rs +++ b/embassy-stm32/src/adc/sample_time.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | #[cfg(not(any(adc_f3, adc_f3_v2)))] | 1 | #[cfg(not(adc_f3_v2))] |
| 2 | macro_rules! impl_sample_time { | 2 | macro_rules! impl_sample_time { |
| 3 | ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => { | 3 | ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => { |
| 4 | #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")] | 4 | #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")] |
| @@ -105,3 +105,19 @@ impl_sample_time!( | |||
| 105 | ("810.5", Cycles810_5, CYCLES810_5) | 105 | ("810.5", Cycles810_5, CYCLES810_5) |
| 106 | ) | 106 | ) |
| 107 | ); | 107 | ); |
| 108 | |||
| 109 | #[cfg(adc_f3)] | ||
| 110 | impl_sample_time!( | ||
| 111 | "1.5", | ||
| 112 | Cycles1_5, | ||
| 113 | ( | ||
| 114 | ("1.5", Cycles1_5, CYCLES1_5), | ||
| 115 | ("2.5", Cycles2_5, CYCLES2_5), | ||
| 116 | ("4.5", Cycles4_5, CYCLES4_5), | ||
| 117 | ("7.5", Cycles7_5, CYCLES7_5), | ||
| 118 | ("19.5", Cycles19_5, CYCLES19_5), | ||
| 119 | ("61.5", Cycles61_5, CYCLES61_5), | ||
| 120 | ("181.5", Cycles181_5, CYCLES181_5), | ||
| 121 | ("601.5", Cycles601_5, CYCLES601_5) | ||
| 122 | ) | ||
| 123 | ); | ||
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index e8245884e..fded26e40 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs | |||
| @@ -1,39 +1,65 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 2 | use core::marker::PhantomData; | ||
| 3 | use core::task::Poll; | ||
| 4 | |||
| 1 | use embassy_hal_internal::into_ref; | 5 | use embassy_hal_internal::into_ref; |
| 2 | use embedded_hal_02::blocking::delay::DelayUs; | 6 | use embedded_hal_02::blocking::delay::DelayUs; |
| 3 | 7 | ||
| 4 | use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; | 8 | use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; |
| 9 | use crate::interrupt::typelevel::Interrupt; | ||
| 5 | use crate::peripherals::ADC; | 10 | use crate::peripherals::ADC; |
| 6 | use crate::Peripheral; | 11 | use crate::{interrupt, Peripheral}; |
| 7 | 12 | ||
| 8 | pub const VDDA_CALIB_MV: u32 = 3300; | 13 | pub const VDDA_CALIB_MV: u32 = 3300; |
| 9 | pub const VREF_INT: u32 = 1230; | 14 | pub const VREF_INT: u32 = 1230; |
| 10 | 15 | ||
| 16 | /// Interrupt handler. | ||
| 17 | pub struct InterruptHandler<T: Instance> { | ||
| 18 | _phantom: PhantomData<T>, | ||
| 19 | } | ||
| 20 | |||
| 21 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 22 | unsafe fn on_interrupt() { | ||
| 23 | if T::regs().isr().read().eoc() { | ||
| 24 | T::regs().ier().modify(|w| w.set_eocie(false)); | ||
| 25 | } else { | ||
| 26 | return; | ||
| 27 | } | ||
| 28 | |||
| 29 | T::state().waker.wake(); | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 11 | pub struct Vbat; | 33 | pub struct Vbat; |
| 12 | impl InternalChannel<ADC> for Vbat {} | 34 | impl AdcPin<ADC> for Vbat {} |
| 13 | impl super::sealed::InternalChannel<ADC> for Vbat { | 35 | impl super::sealed::AdcPin<ADC> for Vbat { |
| 14 | fn channel(&self) -> u8 { | 36 | fn channel(&self) -> u8 { |
| 15 | 18 | 37 | 18 |
| 16 | } | 38 | } |
| 17 | } | 39 | } |
| 18 | 40 | ||
| 19 | pub struct Vref; | 41 | pub struct Vref; |
| 20 | impl InternalChannel<ADC> for Vref {} | 42 | impl AdcPin<ADC> for Vref {} |
| 21 | impl super::sealed::InternalChannel<ADC> for Vref { | 43 | impl super::sealed::AdcPin<ADC> for Vref { |
| 22 | fn channel(&self) -> u8 { | 44 | fn channel(&self) -> u8 { |
| 23 | 17 | 45 | 17 |
| 24 | } | 46 | } |
| 25 | } | 47 | } |
| 26 | 48 | ||
| 27 | pub struct Temperature; | 49 | pub struct Temperature; |
| 28 | impl InternalChannel<ADC> for Temperature {} | 50 | impl AdcPin<ADC> for Temperature {} |
| 29 | impl super::sealed::InternalChannel<ADC> for Temperature { | 51 | impl super::sealed::AdcPin<ADC> for Temperature { |
| 30 | fn channel(&self) -> u8 { | 52 | fn channel(&self) -> u8 { |
| 31 | 16 | 53 | 16 |
| 32 | } | 54 | } |
| 33 | } | 55 | } |
| 34 | 56 | ||
| 35 | impl<'d, T: Instance> Adc<'d, T> { | 57 | impl<'d, T: Instance> Adc<'d, T> { |
| 36 | pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { | 58 | pub fn new( |
| 59 | adc: impl Peripheral<P = T> + 'd, | ||
| 60 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 61 | delay: &mut impl DelayUs<u32>, | ||
| 62 | ) -> Self { | ||
| 37 | into_ref!(adc); | 63 | into_ref!(adc); |
| 38 | T::enable(); | 64 | T::enable(); |
| 39 | T::reset(); | 65 | T::reset(); |
| @@ -44,12 +70,32 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 44 | // tstab = 14 * 1/fadc | 70 | // tstab = 14 * 1/fadc |
| 45 | delay.delay_us(1); | 71 | delay.delay_us(1); |
| 46 | 72 | ||
| 47 | let s = Self { | 73 | // A.7.1 ADC calibration code example |
| 74 | T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); | ||
| 75 | T::regs().cr().modify(|reg| reg.set_adcal(true)); | ||
| 76 | while T::regs().cr().read().adcal() {} | ||
| 77 | |||
| 78 | // A.7.2 ADC enable sequence code example | ||
| 79 | if T::regs().isr().read().adrdy() { | ||
| 80 | T::regs().isr().modify(|reg| reg.set_adrdy(true)); | ||
| 81 | } | ||
| 82 | T::regs().cr().modify(|reg| reg.set_aden(true)); | ||
| 83 | while !T::regs().isr().read().adrdy() { | ||
| 84 | // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration | ||
| 85 | // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the | ||
| 86 | // ADEN bit until the ADRDY flag goes high. | ||
| 87 | T::regs().cr().modify(|reg| reg.set_aden(true)); | ||
| 88 | } | ||
| 89 | |||
| 90 | T::Interrupt::unpend(); | ||
| 91 | unsafe { | ||
| 92 | T::Interrupt::enable(); | ||
| 93 | } | ||
| 94 | |||
| 95 | Self { | ||
| 48 | adc, | 96 | adc, |
| 49 | sample_time: Default::default(), | 97 | sample_time: Default::default(), |
| 50 | }; | 98 | } |
| 51 | s.calibrate(); | ||
| 52 | s | ||
| 53 | } | 99 | } |
| 54 | 100 | ||
| 55 | pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat { | 101 | pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat { |
| @@ -80,21 +126,6 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 80 | Temperature | 126 | Temperature |
| 81 | } | 127 | } |
| 82 | 128 | ||
| 83 | fn calibrate(&self) { | ||
| 84 | // A.7.1 ADC calibration code example | ||
| 85 | if T::regs().cr().read().aden() { | ||
| 86 | T::regs().cr().modify(|reg| reg.set_addis(true)); | ||
| 87 | } | ||
| 88 | while T::regs().cr().read().aden() { | ||
| 89 | // spin | ||
| 90 | } | ||
| 91 | T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); | ||
| 92 | T::regs().cr().modify(|reg| reg.set_adcal(true)); | ||
| 93 | while T::regs().cr().read().adcal() { | ||
| 94 | // spin | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { | 129 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { |
| 99 | self.sample_time = sample_time; | 130 | self.sample_time = sample_time; |
| 100 | } | 131 | } |
| @@ -103,57 +134,50 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 103 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | 134 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); |
| 104 | } | 135 | } |
| 105 | 136 | ||
| 106 | pub fn read<P>(&mut self, pin: &mut P) -> u16 | 137 | pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { |
| 107 | where | ||
| 108 | P: AdcPin<T> + crate::gpio::sealed::Pin, | ||
| 109 | { | ||
| 110 | let channel = pin.channel(); | 138 | let channel = pin.channel(); |
| 111 | pin.set_as_analog(); | 139 | pin.set_as_analog(); |
| 112 | self.read_channel(channel) | ||
| 113 | } | ||
| 114 | 140 | ||
| 115 | pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { | 141 | // A.7.5 Single conversion sequence code example - Software trigger |
| 116 | let channel = channel.channel(); | 142 | T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true)); |
| 117 | self.read_channel(channel) | ||
| 118 | } | ||
| 119 | 143 | ||
| 120 | fn read_channel(&mut self, channel: u8) -> u16 { | 144 | self.convert().await |
| 121 | // A.7.2 ADC enable sequence code example | 145 | } |
| 122 | if T::regs().isr().read().adrdy() { | ||
| 123 | T::regs().isr().modify(|reg| reg.set_adrdy(true)); | ||
| 124 | } | ||
| 125 | T::regs().cr().modify(|reg| reg.set_aden(true)); | ||
| 126 | while !T::regs().isr().read().adrdy() { | ||
| 127 | // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration | ||
| 128 | // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the | ||
| 129 | // ADEN bit until the ADRDY flag goes high. | ||
| 130 | T::regs().cr().modify(|reg| reg.set_aden(true)); | ||
| 131 | } | ||
| 132 | 146 | ||
| 147 | async fn convert(&mut self) -> u16 { | ||
| 133 | T::regs().isr().modify(|reg| { | 148 | T::regs().isr().modify(|reg| { |
| 134 | reg.set_eoc(true); | 149 | reg.set_eoc(true); |
| 135 | reg.set_eosmp(true); | 150 | reg.set_eosmp(true); |
| 136 | }); | 151 | }); |
| 137 | 152 | ||
| 138 | // A.7.5 Single conversion sequence code example - Software trigger | ||
| 139 | T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true)); | ||
| 140 | T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into())); | 153 | T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into())); |
| 154 | T::regs().ier().modify(|w| w.set_eocie(true)); | ||
| 141 | T::regs().cr().modify(|reg| reg.set_adstart(true)); | 155 | T::regs().cr().modify(|reg| reg.set_adstart(true)); |
| 142 | while !T::regs().isr().read().eoc() { | ||
| 143 | // spin | ||
| 144 | } | ||
| 145 | let value = T::regs().dr().read().0 as u16; | ||
| 146 | 156 | ||
| 157 | poll_fn(|cx| { | ||
| 158 | T::state().waker.register(cx.waker()); | ||
| 159 | |||
| 160 | if T::regs().isr().read().eoc() { | ||
| 161 | Poll::Ready(()) | ||
| 162 | } else { | ||
| 163 | Poll::Pending | ||
| 164 | } | ||
| 165 | }) | ||
| 166 | .await; | ||
| 167 | |||
| 168 | T::regs().dr().read().data() | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | impl<'d, T: Instance> Drop for Adc<'d, T> { | ||
| 173 | fn drop(&mut self) { | ||
| 147 | // A.7.3 ADC disable code example | 174 | // A.7.3 ADC disable code example |
| 148 | T::regs().cr().modify(|reg| reg.set_adstp(true)); | 175 | T::regs().cr().modify(|reg| reg.set_adstp(true)); |
| 149 | while T::regs().cr().read().adstp() { | 176 | while T::regs().cr().read().adstp() {} |
| 150 | // spin | 177 | |
| 151 | } | ||
| 152 | T::regs().cr().modify(|reg| reg.set_addis(true)); | 178 | T::regs().cr().modify(|reg| reg.set_addis(true)); |
| 153 | while T::regs().cr().read().aden() { | 179 | while T::regs().cr().read().aden() {} |
| 154 | // spin | ||
| 155 | } | ||
| 156 | 180 | ||
| 157 | value | 181 | T::disable(); |
| 158 | } | 182 | } |
| 159 | } | 183 | } |
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 9a7acea53..a669013c9 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | use embassy_hal_internal::into_ref; | 1 | use embassy_hal_internal::into_ref; |
| 2 | use embedded_hal_02::blocking::delay::DelayUs; | 2 | use embedded_hal_02::blocking::delay::DelayUs; |
| 3 | 3 | ||
| 4 | use super::InternalChannel; | ||
| 5 | use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; | 4 | use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; |
| 6 | use crate::peripherals::ADC1; | 5 | use crate::peripherals::ADC1; |
| 7 | use crate::time::Hertz; | 6 | use crate::time::Hertz; |
| @@ -16,8 +15,8 @@ pub const VREF_CALIB_MV: u32 = 3300; | |||
| 16 | pub const ADC_POWERUP_TIME_US: u32 = 3; | 15 | pub const ADC_POWERUP_TIME_US: u32 = 3; |
| 17 | 16 | ||
| 18 | pub struct VrefInt; | 17 | pub struct VrefInt; |
| 19 | impl InternalChannel<ADC1> for VrefInt {} | 18 | impl AdcPin<ADC1> for VrefInt {} |
| 20 | impl super::sealed::InternalChannel<ADC1> for VrefInt { | 19 | impl super::sealed::AdcPin<ADC1> for VrefInt { |
| 21 | fn channel(&self) -> u8 { | 20 | fn channel(&self) -> u8 { |
| 22 | 17 | 21 | 17 |
| 23 | } | 22 | } |
| @@ -31,8 +30,8 @@ impl VrefInt { | |||
| 31 | } | 30 | } |
| 32 | 31 | ||
| 33 | pub struct Temperature; | 32 | pub struct Temperature; |
| 34 | impl InternalChannel<ADC1> for Temperature {} | 33 | impl AdcPin<ADC1> for Temperature {} |
| 35 | impl super::sealed::InternalChannel<ADC1> for Temperature { | 34 | impl super::sealed::AdcPin<ADC1> for Temperature { |
| 36 | fn channel(&self) -> u8 { | 35 | fn channel(&self) -> u8 { |
| 37 | cfg_if::cfg_if! { | 36 | cfg_if::cfg_if! { |
| 38 | if #[cfg(any(stm32f40, stm32f41))] { | 37 | if #[cfg(any(stm32f40, stm32f41))] { |
| @@ -52,8 +51,8 @@ impl Temperature { | |||
| 52 | } | 51 | } |
| 53 | 52 | ||
| 54 | pub struct Vbat; | 53 | pub struct Vbat; |
| 55 | impl InternalChannel<ADC1> for Vbat {} | 54 | impl AdcPin<ADC1> for Vbat {} |
| 56 | impl super::sealed::InternalChannel<ADC1> for Vbat { | 55 | impl super::sealed::AdcPin<ADC1> for Vbat { |
| 57 | fn channel(&self) -> u8 { | 56 | fn channel(&self) -> u8 { |
| 58 | 18 | 57 | 18 |
| 59 | } | 58 | } |
| @@ -102,7 +101,7 @@ where | |||
| 102 | let presc = Prescaler::from_pclk2(T::frequency()); | 101 | let presc = Prescaler::from_pclk2(T::frequency()); |
| 103 | T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); | 102 | T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); |
| 104 | T::regs().cr2().modify(|reg| { | 103 | T::regs().cr2().modify(|reg| { |
| 105 | reg.set_adon(crate::pac::adc::vals::Adon::ENABLED); | 104 | reg.set_adon(true); |
| 106 | }); | 105 | }); |
| 107 | 106 | ||
| 108 | delay.delay_us(ADC_POWERUP_TIME_US); | 107 | delay.delay_us(ADC_POWERUP_TIME_US); |
| @@ -125,7 +124,7 @@ where | |||
| 125 | /// [Adc::read_internal()] to perform conversion. | 124 | /// [Adc::read_internal()] to perform conversion. |
| 126 | pub fn enable_vrefint(&self) -> VrefInt { | 125 | pub fn enable_vrefint(&self) -> VrefInt { |
| 127 | T::common_regs().ccr().modify(|reg| { | 126 | T::common_regs().ccr().modify(|reg| { |
| 128 | reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); | 127 | reg.set_tsvrefe(true); |
| 129 | }); | 128 | }); |
| 130 | 129 | ||
| 131 | VrefInt {} | 130 | VrefInt {} |
| @@ -138,7 +137,7 @@ where | |||
| 138 | /// temperature sensor will return vbat value. | 137 | /// temperature sensor will return vbat value. |
| 139 | pub fn enable_temperature(&self) -> Temperature { | 138 | pub fn enable_temperature(&self) -> Temperature { |
| 140 | T::common_regs().ccr().modify(|reg| { | 139 | T::common_regs().ccr().modify(|reg| { |
| 141 | reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); | 140 | reg.set_tsvrefe(true); |
| 142 | }); | 141 | }); |
| 143 | 142 | ||
| 144 | Temperature {} | 143 | Temperature {} |
| @@ -148,7 +147,7 @@ where | |||
| 148 | /// [Adc::read_internal()] to perform conversion. | 147 | /// [Adc::read_internal()] to perform conversion. |
| 149 | pub fn enable_vbat(&self) -> Vbat { | 148 | pub fn enable_vbat(&self) -> Vbat { |
| 150 | T::common_regs().ccr().modify(|reg| { | 149 | T::common_regs().ccr().modify(|reg| { |
| 151 | reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED); | 150 | reg.set_vbate(true); |
| 152 | }); | 151 | }); |
| 153 | 152 | ||
| 154 | Vbat {} | 153 | Vbat {} |
| @@ -176,22 +175,11 @@ where | |||
| 176 | T::regs().dr().read().0 as u16 | 175 | T::regs().dr().read().0 as u16 |
| 177 | } | 176 | } |
| 178 | 177 | ||
| 179 | pub fn read<P>(&mut self, pin: &mut P) -> u16 | 178 | pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { |
| 180 | where | ||
| 181 | P: AdcPin<T>, | ||
| 182 | P: crate::gpio::sealed::Pin, | ||
| 183 | { | ||
| 184 | pin.set_as_analog(); | 179 | pin.set_as_analog(); |
| 185 | 180 | ||
| 186 | self.read_channel(pin.channel()) | ||
| 187 | } | ||
| 188 | |||
| 189 | pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { | ||
| 190 | self.read_channel(channel.channel()) | ||
| 191 | } | ||
| 192 | |||
| 193 | fn read_channel(&mut self, channel: u8) -> u16 { | ||
| 194 | // Configure ADC | 181 | // Configure ADC |
| 182 | let channel = pin.channel(); | ||
| 195 | 183 | ||
| 196 | // Select channel | 184 | // Select channel |
| 197 | T::regs().sqr3().write(|reg| reg.set_sq(0, channel)); | 185 | T::regs().sqr3().write(|reg| reg.set_sq(0, channel)); |
| @@ -199,9 +187,7 @@ where | |||
| 199 | // Configure channel | 187 | // Configure channel |
| 200 | Self::set_channel_sample_time(channel, self.sample_time); | 188 | Self::set_channel_sample_time(channel, self.sample_time); |
| 201 | 189 | ||
| 202 | let val = self.convert(); | 190 | self.convert() |
| 203 | |||
| 204 | val | ||
| 205 | } | 191 | } |
| 206 | 192 | ||
| 207 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | 193 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { |
| @@ -216,6 +202,10 @@ where | |||
| 216 | 202 | ||
| 217 | impl<'d, T: Instance> Drop for Adc<'d, T> { | 203 | impl<'d, T: Instance> Drop for Adc<'d, T> { |
| 218 | fn drop(&mut self) { | 204 | fn drop(&mut self) { |
| 205 | T::regs().cr2().modify(|reg| { | ||
| 206 | reg.set_adon(false); | ||
| 207 | }); | ||
| 208 | |||
| 219 | T::disable(); | 209 | T::disable(); |
| 220 | } | 210 | } |
| 221 | } | 211 | } |
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 821cc7f6a..011ecc281 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -13,7 +13,7 @@ pub const VREF_CALIB_MV: u32 = 3000; | |||
| 13 | /// configuration. | 13 | /// configuration. |
| 14 | fn enable() { | 14 | fn enable() { |
| 15 | critical_section::with(|_| { | 15 | critical_section::with(|_| { |
| 16 | #[cfg(stm32h7)] | 16 | #[cfg(any(stm32h7, stm32wl))] |
| 17 | crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); | 17 | crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); |
| 18 | #[cfg(stm32g0)] | 18 | #[cfg(stm32g0)] |
| 19 | crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true)); | 19 | crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true)); |
| @@ -26,9 +26,9 @@ pub struct VrefInt; | |||
| 26 | impl<T: Instance> AdcPin<T> for VrefInt {} | 26 | impl<T: Instance> AdcPin<T> for VrefInt {} |
| 27 | impl<T: Instance> super::sealed::AdcPin<T> for VrefInt { | 27 | impl<T: Instance> super::sealed::AdcPin<T> for VrefInt { |
| 28 | fn channel(&self) -> u8 { | 28 | fn channel(&self) -> u8 { |
| 29 | #[cfg(not(stm32g0))] | 29 | #[cfg(not(adc_g0))] |
| 30 | let val = 0; | 30 | let val = 0; |
| 31 | #[cfg(stm32g0)] | 31 | #[cfg(adc_g0)] |
| 32 | let val = 13; | 32 | let val = 13; |
| 33 | val | 33 | val |
| 34 | } | 34 | } |
| @@ -38,9 +38,9 @@ pub struct Temperature; | |||
| 38 | impl<T: Instance> AdcPin<T> for Temperature {} | 38 | impl<T: Instance> AdcPin<T> for Temperature {} |
| 39 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature { | 39 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature { |
| 40 | fn channel(&self) -> u8 { | 40 | fn channel(&self) -> u8 { |
| 41 | #[cfg(not(stm32g0))] | 41 | #[cfg(not(adc_g0))] |
| 42 | let val = 17; | 42 | let val = 17; |
| 43 | #[cfg(stm32g0)] | 43 | #[cfg(adc_g0)] |
| 44 | let val = 12; | 44 | let val = 12; |
| 45 | val | 45 | val |
| 46 | } | 46 | } |
| @@ -50,9 +50,9 @@ pub struct Vbat; | |||
| 50 | impl<T: Instance> AdcPin<T> for Vbat {} | 50 | impl<T: Instance> AdcPin<T> for Vbat {} |
| 51 | impl<T: Instance> super::sealed::AdcPin<T> for Vbat { | 51 | impl<T: Instance> super::sealed::AdcPin<T> for Vbat { |
| 52 | fn channel(&self) -> u8 { | 52 | fn channel(&self) -> u8 { |
| 53 | #[cfg(not(stm32g0))] | 53 | #[cfg(not(adc_g0))] |
| 54 | let val = 18; | 54 | let val = 18; |
| 55 | #[cfg(stm32g0)] | 55 | #[cfg(adc_g0)] |
| 56 | let val = 14; | 56 | let val = 14; |
| 57 | val | 57 | val |
| 58 | } | 58 | } |
| @@ -92,9 +92,14 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt { | 94 | pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt { |
| 95 | #[cfg(not(adc_g0))] | ||
| 95 | T::common_regs().ccr().modify(|reg| { | 96 | T::common_regs().ccr().modify(|reg| { |
| 96 | reg.set_vrefen(true); | 97 | reg.set_vrefen(true); |
| 97 | }); | 98 | }); |
| 99 | #[cfg(adc_g0)] | ||
| 100 | T::regs().ccr().modify(|reg| { | ||
| 101 | reg.set_vrefen(true); | ||
| 102 | }); | ||
| 98 | 103 | ||
| 99 | // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us | 104 | // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us |
| 100 | // to stabilize the internal voltage reference, we wait a little more. | 105 | // to stabilize the internal voltage reference, we wait a little more. |
| @@ -106,17 +111,27 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 106 | } | 111 | } |
| 107 | 112 | ||
| 108 | pub fn enable_temperature(&self) -> Temperature { | 113 | pub fn enable_temperature(&self) -> Temperature { |
| 114 | #[cfg(not(adc_g0))] | ||
| 109 | T::common_regs().ccr().modify(|reg| { | 115 | T::common_regs().ccr().modify(|reg| { |
| 110 | reg.set_ch17sel(true); | 116 | reg.set_ch17sel(true); |
| 111 | }); | 117 | }); |
| 118 | #[cfg(adc_g0)] | ||
| 119 | T::regs().ccr().modify(|reg| { | ||
| 120 | reg.set_tsen(true); | ||
| 121 | }); | ||
| 112 | 122 | ||
| 113 | Temperature {} | 123 | Temperature {} |
| 114 | } | 124 | } |
| 115 | 125 | ||
| 116 | pub fn enable_vbat(&self) -> Vbat { | 126 | pub fn enable_vbat(&self) -> Vbat { |
| 127 | #[cfg(not(adc_g0))] | ||
| 117 | T::common_regs().ccr().modify(|reg| { | 128 | T::common_regs().ccr().modify(|reg| { |
| 118 | reg.set_ch18sel(true); | 129 | reg.set_ch18sel(true); |
| 119 | }); | 130 | }); |
| 131 | #[cfg(adc_g0)] | ||
| 132 | T::regs().ccr().modify(|reg| { | ||
| 133 | reg.set_vbaten(true); | ||
| 134 | }); | ||
| 120 | 135 | ||
| 121 | Vbat {} | 136 | Vbat {} |
| 122 | } | 137 | } |
| @@ -126,9 +141,9 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 126 | } | 141 | } |
| 127 | 142 | ||
| 128 | pub fn set_resolution(&mut self, resolution: Resolution) { | 143 | pub fn set_resolution(&mut self, resolution: Resolution) { |
| 129 | #[cfg(not(stm32g0))] | 144 | #[cfg(not(adc_g0))] |
| 130 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | 145 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); |
| 131 | #[cfg(stm32g0)] | 146 | #[cfg(adc_g0)] |
| 132 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | 147 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); |
| 133 | } | 148 | } |
| 134 | 149 | ||
| @@ -182,9 +197,9 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 182 | Self::set_channel_sample_time(pin.channel(), self.sample_time); | 197 | Self::set_channel_sample_time(pin.channel(), self.sample_time); |
| 183 | 198 | ||
| 184 | // Select channel | 199 | // Select channel |
| 185 | #[cfg(not(stm32g0))] | 200 | #[cfg(not(adc_g0))] |
| 186 | T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); | 201 | T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); |
| 187 | #[cfg(stm32g0)] | 202 | #[cfg(adc_g0)] |
| 188 | T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); | 203 | T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); |
| 189 | 204 | ||
| 190 | // Some models are affected by an erratum: | 205 | // Some models are affected by an erratum: |
| @@ -203,12 +218,12 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 203 | val | 218 | val |
| 204 | } | 219 | } |
| 205 | 220 | ||
| 206 | #[cfg(stm32g0)] | 221 | #[cfg(adc_g0)] |
| 207 | fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { | 222 | fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { |
| 208 | T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); | 223 | T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); |
| 209 | } | 224 | } |
| 210 | 225 | ||
| 211 | #[cfg(not(stm32g0))] | 226 | #[cfg(not(adc_g0))] |
| 212 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | 227 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { |
| 213 | let sample_time = sample_time.into(); | 228 | let sample_time = sample_time.into(); |
| 214 | T::regs() | 229 | T::regs() |
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 64d0f0c75..655c0cb6a 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | use core::sync::atomic::{AtomicU8, Ordering}; | ||
| 2 | |||
| 3 | use embedded_hal_02::blocking::delay::DelayUs; | 1 | use embedded_hal_02::blocking::delay::DelayUs; |
| 2 | #[allow(unused)] | ||
| 4 | use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; | 3 | use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; |
| 5 | use pac::adccommon::vals::Presc; | 4 | use pac::adccommon::vals::Presc; |
| 6 | 5 | ||
| @@ -13,12 +12,31 @@ pub const VREF_DEFAULT_MV: u32 = 3300; | |||
| 13 | /// VREF voltage used for factory calibration of VREFINTCAL register. | 12 | /// VREF voltage used for factory calibration of VREFINTCAL register. |
| 14 | pub const VREF_CALIB_MV: u32 = 3300; | 13 | pub const VREF_CALIB_MV: u32 = 3300; |
| 15 | 14 | ||
| 16 | // NOTE: Vrefint/Temperature/Vbat are only available on ADC3 on H7, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs | 15 | /// Max single ADC operation clock frequency |
| 16 | #[cfg(stm32g4)] | ||
| 17 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); | ||
| 18 | #[cfg(stm32h7)] | ||
| 19 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); | ||
| 20 | |||
| 21 | #[cfg(stm32g4)] | ||
| 22 | const VREF_CHANNEL: u8 = 18; | ||
| 23 | #[cfg(stm32g4)] | ||
| 24 | const TEMP_CHANNEL: u8 = 16; | ||
| 25 | |||
| 26 | #[cfg(stm32h7)] | ||
| 27 | const VREF_CHANNEL: u8 = 19; | ||
| 28 | #[cfg(stm32h7)] | ||
| 29 | const TEMP_CHANNEL: u8 = 18; | ||
| 30 | |||
| 31 | // TODO this should be 14 for H7a/b/35 | ||
| 32 | const VBAT_CHANNEL: u8 = 17; | ||
| 33 | |||
| 34 | // NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs | ||
| 17 | pub struct VrefInt; | 35 | pub struct VrefInt; |
| 18 | impl<T: Instance> InternalChannel<T> for VrefInt {} | 36 | impl<T: Instance> InternalChannel<T> for VrefInt {} |
| 19 | impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt { | 37 | impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt { |
| 20 | fn channel(&self) -> u8 { | 38 | fn channel(&self) -> u8 { |
| 21 | 19 | 39 | VREF_CHANNEL |
| 22 | } | 40 | } |
| 23 | } | 41 | } |
| 24 | 42 | ||
| @@ -26,7 +44,7 @@ pub struct Temperature; | |||
| 26 | impl<T: Instance> InternalChannel<T> for Temperature {} | 44 | impl<T: Instance> InternalChannel<T> for Temperature {} |
| 27 | impl<T: Instance> super::sealed::InternalChannel<T> for Temperature { | 45 | impl<T: Instance> super::sealed::InternalChannel<T> for Temperature { |
| 28 | fn channel(&self) -> u8 { | 46 | fn channel(&self) -> u8 { |
| 29 | 18 | 47 | TEMP_CHANNEL |
| 30 | } | 48 | } |
| 31 | } | 49 | } |
| 32 | 50 | ||
| @@ -34,128 +52,10 @@ pub struct Vbat; | |||
| 34 | impl<T: Instance> InternalChannel<T> for Vbat {} | 52 | impl<T: Instance> InternalChannel<T> for Vbat {} |
| 35 | impl<T: Instance> super::sealed::InternalChannel<T> for Vbat { | 53 | impl<T: Instance> super::sealed::InternalChannel<T> for Vbat { |
| 36 | fn channel(&self) -> u8 { | 54 | fn channel(&self) -> u8 { |
| 37 | // TODO this should be 14 for H7a/b/35 | 55 | VBAT_CHANNEL |
| 38 | 17 | ||
| 39 | } | 56 | } |
| 40 | } | 57 | } |
| 41 | 58 | ||
| 42 | static ADC12_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0); | ||
| 43 | |||
| 44 | #[cfg(stm32h7)] | ||
| 45 | foreach_peripheral!( | ||
| 46 | (adc, ADC1) => { | ||
| 47 | impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 { | ||
| 48 | fn frequency() -> crate::time::Hertz { | ||
| 49 | critical_section::with(|_| { | ||
| 50 | match unsafe { crate::rcc::get_freqs() }.adc { | ||
| 51 | Some(ck) => ck, | ||
| 52 | None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") | ||
| 53 | } | ||
| 54 | }) | ||
| 55 | } | ||
| 56 | |||
| 57 | fn enable() { | ||
| 58 | critical_section::with(|_| { | ||
| 59 | crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) | ||
| 60 | }); | ||
| 61 | ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); | ||
| 62 | } | ||
| 63 | |||
| 64 | fn disable() { | ||
| 65 | if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { | ||
| 66 | critical_section::with(|_| { | ||
| 67 | crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); | ||
| 68 | }) | ||
| 69 | } | ||
| 70 | ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst); | ||
| 71 | } | ||
| 72 | |||
| 73 | fn reset() { | ||
| 74 | if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { | ||
| 75 | critical_section::with(|_| { | ||
| 76 | crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); | ||
| 77 | crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); | ||
| 78 | }); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | impl crate::rcc::RccPeripheral for crate::peripherals::ADC1 {} | ||
| 84 | }; | ||
| 85 | (adc, ADC2) => { | ||
| 86 | impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 { | ||
| 87 | fn frequency() -> crate::time::Hertz { | ||
| 88 | critical_section::with(|_| { | ||
| 89 | match unsafe { crate::rcc::get_freqs() }.adc { | ||
| 90 | Some(ck) => ck, | ||
| 91 | None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") | ||
| 92 | } | ||
| 93 | }) | ||
| 94 | } | ||
| 95 | |||
| 96 | fn enable() { | ||
| 97 | critical_section::with(|_| { | ||
| 98 | crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) | ||
| 99 | }); | ||
| 100 | ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); | ||
| 101 | } | ||
| 102 | |||
| 103 | fn disable() { | ||
| 104 | if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { | ||
| 105 | critical_section::with(|_| { | ||
| 106 | crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); | ||
| 107 | }) | ||
| 108 | } | ||
| 109 | ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst); | ||
| 110 | } | ||
| 111 | |||
| 112 | fn reset() { | ||
| 113 | if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { | ||
| 114 | critical_section::with(|_| { | ||
| 115 | crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); | ||
| 116 | crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); | ||
| 117 | }); | ||
| 118 | } | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | impl crate::rcc::RccPeripheral for crate::peripherals::ADC2 {} | ||
| 123 | }; | ||
| 124 | (adc, ADC3) => { | ||
| 125 | impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 { | ||
| 126 | fn frequency() -> crate::time::Hertz { | ||
| 127 | critical_section::with(|_| { | ||
| 128 | match unsafe { crate::rcc::get_freqs() }.adc { | ||
| 129 | Some(ck) => ck, | ||
| 130 | None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") | ||
| 131 | } | ||
| 132 | }) | ||
| 133 | } | ||
| 134 | |||
| 135 | fn enable() { | ||
| 136 | critical_section::with(|_| { | ||
| 137 | crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true)) | ||
| 138 | }); | ||
| 139 | } | ||
| 140 | |||
| 141 | fn disable() { | ||
| 142 | critical_section::with(|_| { | ||
| 143 | crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false)); | ||
| 144 | }) | ||
| 145 | } | ||
| 146 | |||
| 147 | fn reset() { | ||
| 148 | critical_section::with(|_| { | ||
| 149 | crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true)); | ||
| 150 | crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false)); | ||
| 151 | }); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | impl crate::rcc::RccPeripheral for crate::peripherals::ADC3 {} | ||
| 156 | }; | ||
| 157 | ); | ||
| 158 | |||
| 159 | // NOTE (unused): The prescaler enum closely copies the hardware capabilities, | 59 | // NOTE (unused): The prescaler enum closely copies the hardware capabilities, |
| 160 | // but high prescaling doesn't make a lot of sense in the current implementation and is ommited. | 60 | // but high prescaling doesn't make a lot of sense in the current implementation and is ommited. |
| 161 | #[allow(unused)] | 61 | #[allow(unused)] |
| @@ -176,7 +76,7 @@ enum Prescaler { | |||
| 176 | 76 | ||
| 177 | impl Prescaler { | 77 | impl Prescaler { |
| 178 | fn from_ker_ck(frequency: Hertz) -> Self { | 78 | fn from_ker_ck(frequency: Hertz) -> Self { |
| 179 | let raw_prescaler = frequency.0 / 50_000_000; | 79 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; |
| 180 | match raw_prescaler { | 80 | match raw_prescaler { |
| 181 | 0 => Self::NotDivided, | 81 | 0 => Self::NotDivided, |
| 182 | 1 => Self::DividedBy2, | 82 | 1 => Self::DividedBy2, |
| @@ -237,20 +137,23 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 237 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | 137 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); |
| 238 | info!("ADC frequency set to {} Hz", frequency.0); | 138 | info!("ADC frequency set to {} Hz", frequency.0); |
| 239 | 139 | ||
| 240 | if frequency > Hertz::mhz(50) { | 140 | if frequency > MAX_ADC_CLK_FREQ { |
| 241 | panic!("Maximal allowed frequency for the ADC is 50 MHz and it varies with different packages, refer to ST docs for more information."); | 141 | panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); |
| 242 | } | 142 | } |
| 243 | let boost = if frequency < Hertz::khz(6_250) { | ||
| 244 | Boost::LT6_25 | ||
| 245 | } else if frequency < Hertz::khz(12_500) { | ||
| 246 | Boost::LT12_5 | ||
| 247 | } else if frequency < Hertz::mhz(25) { | ||
| 248 | Boost::LT25 | ||
| 249 | } else { | ||
| 250 | Boost::LT50 | ||
| 251 | }; | ||
| 252 | T::regs().cr().modify(|w| w.set_boost(boost)); | ||
| 253 | 143 | ||
| 144 | #[cfg(stm32h7)] | ||
| 145 | { | ||
| 146 | let boost = if frequency < Hertz::khz(6_250) { | ||
| 147 | Boost::LT6_25 | ||
| 148 | } else if frequency < Hertz::khz(12_500) { | ||
| 149 | Boost::LT12_5 | ||
| 150 | } else if frequency < Hertz::mhz(25) { | ||
| 151 | Boost::LT25 | ||
| 152 | } else { | ||
| 153 | Boost::LT50 | ||
| 154 | }; | ||
| 155 | T::regs().cr().modify(|w| w.set_boost(boost)); | ||
| 156 | } | ||
| 254 | let mut s = Self { | 157 | let mut s = Self { |
| 255 | adc, | 158 | adc, |
| 256 | sample_time: Default::default(), | 159 | sample_time: Default::default(), |
| @@ -379,10 +282,14 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 379 | // Configure channel | 282 | // Configure channel |
| 380 | Self::set_channel_sample_time(channel, self.sample_time); | 283 | Self::set_channel_sample_time(channel, self.sample_time); |
| 381 | 284 | ||
| 382 | T::regs().cfgr2().modify(|w| w.set_lshift(0)); | 285 | #[cfg(stm32h7)] |
| 383 | T::regs() | 286 | { |
| 384 | .pcsel() | 287 | T::regs().cfgr2().modify(|w| w.set_lshift(0)); |
| 385 | .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); | 288 | T::regs() |
| 289 | .pcsel() | ||
| 290 | .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); | ||
| 291 | } | ||
| 292 | |||
| 386 | T::regs().sqr1().write(|reg| { | 293 | T::regs().sqr1().write(|reg| { |
| 387 | reg.set_sq(0, channel); | 294 | reg.set_sq(0, channel); |
| 388 | reg.set_l(0); | 295 | reg.set_l(0); |
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index a1e0240c8..4d19103dd 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs | |||
| @@ -129,7 +129,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | |||
| 129 | 129 | ||
| 130 | #[cfg(any(eth_v1b, eth_v1c))] | 130 | #[cfg(any(eth_v1b, eth_v1c))] |
| 131 | critical_section::with(|_| { | 131 | critical_section::with(|_| { |
| 132 | RCC.apb2enr().modify(|w| w.set_syscfgen(true)); | ||
| 133 | RCC.ahb1enr().modify(|w| { | 132 | RCC.ahb1enr().modify(|w| { |
| 134 | w.set_ethen(true); | 133 | w.set_ethen(true); |
| 135 | w.set_ethtxen(true); | 134 | w.set_ethtxen(true); |
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index ada495fdb..6efd40e3e 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs | |||
| @@ -34,8 +34,6 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl | |||
| 34 | } | 34 | } |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet | ||
| 38 | |||
| 39 | pub struct Ethernet<'d, T: Instance, P: PHY> { | 37 | pub struct Ethernet<'d, T: Instance, P: PHY> { |
| 40 | _peri: PeripheralRef<'d, T>, | 38 | _peri: PeripheralRef<'d, T>, |
| 41 | pub(crate) tx: TDesRing<'d>, | 39 | pub(crate) tx: TDesRing<'d>, |
| @@ -80,7 +78,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | |||
| 80 | // Enable the necessary Clocks | 78 | // Enable the necessary Clocks |
| 81 | #[cfg(not(rcc_h5))] | 79 | #[cfg(not(rcc_h5))] |
| 82 | critical_section::with(|_| { | 80 | critical_section::with(|_| { |
| 83 | crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true)); | ||
| 84 | crate::pac::RCC.ahb1enr().modify(|w| { | 81 | crate::pac::RCC.ahb1enr().modify(|w| { |
| 85 | w.set_eth1macen(true); | 82 | w.set_eth1macen(true); |
| 86 | w.set_eth1txen(true); | 83 | w.set_eth1txen(true); |
| @@ -102,9 +99,9 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | |||
| 102 | }); | 99 | }); |
| 103 | 100 | ||
| 104 | // RMII | 101 | // RMII |
| 105 | crate::pac::SBS | 102 | crate::pac::SYSCFG |
| 106 | .pmcr() | 103 | .pmcr() |
| 107 | .modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4)); | 104 | .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4)); |
| 108 | }); | 105 | }); |
| 109 | 106 | ||
| 110 | config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | 107 | config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); |
| @@ -164,7 +161,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | |||
| 164 | dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ? | 161 | dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ? |
| 165 | dma.dmacrx_cr().modify(|w| { | 162 | dma.dmacrx_cr().modify(|w| { |
| 166 | w.set_rxpbl(1); // 32 ? | 163 | w.set_rxpbl(1); // 32 ? |
| 167 | w.set_rbsz(MTU as u16); | 164 | w.set_rbsz(RX_BUFFER_SIZE as u16); |
| 168 | }); | 165 | }); |
| 169 | 166 | ||
| 170 | // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called | 167 | // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called |
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 925cf39be..62f321709 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs | |||
| @@ -6,7 +6,7 @@ use core::task::{Context, Poll}; | |||
| 6 | use embassy_hal_internal::impl_peripheral; | 6 | use embassy_hal_internal::impl_peripheral; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | 8 | ||
| 9 | use crate::gpio::{AnyPin, Input, Pin as GpioPin}; | 9 | use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin}; |
| 10 | use crate::pac::exti::regs::Lines; | 10 | use crate::pac::exti::regs::Lines; |
| 11 | use crate::pac::EXTI; | 11 | use crate::pac::EXTI; |
| 12 | use crate::{interrupt, pac, peripherals, Peripheral}; | 12 | use crate::{interrupt, pac, peripherals, Peripheral}; |
| @@ -39,6 +39,9 @@ fn exticr_regs() -> pac::afio::Afio { | |||
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | pub unsafe fn on_irq() { | 41 | pub unsafe fn on_irq() { |
| 42 | #[cfg(feature = "low-power")] | ||
| 43 | crate::low_power::on_wakeup_irq(); | ||
| 44 | |||
| 42 | #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))] | 45 | #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))] |
| 43 | let bits = EXTI.pr(0).read().0; | 46 | let bits = EXTI.pr(0).read().0; |
| 44 | #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] | 47 | #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] |
| @@ -98,6 +101,10 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> { | |||
| 98 | self.pin.is_low() | 101 | self.pin.is_low() |
| 99 | } | 102 | } |
| 100 | 103 | ||
| 104 | pub fn get_level(&self) -> Level { | ||
| 105 | self.pin.get_level() | ||
| 106 | } | ||
| 107 | |||
| 101 | pub async fn wait_for_high<'a>(&'a mut self) { | 108 | pub async fn wait_for_high<'a>(&'a mut self) { |
| 102 | let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false); | 109 | let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false); |
| 103 | if self.is_high() { | 110 | if self.is_high() { |
| @@ -364,9 +371,4 @@ pub(crate) unsafe fn init() { | |||
| 364 | use crate::interrupt::typelevel::Interrupt; | 371 | use crate::interrupt::typelevel::Interrupt; |
| 365 | 372 | ||
| 366 | foreach_exti_irq!(enable_irq); | 373 | foreach_exti_irq!(enable_irq); |
| 367 | |||
| 368 | #[cfg(not(any(rcc_wb, rcc_wl5, rcc_wle, stm32f1, exti_h5, exti_h50)))] | ||
| 369 | <crate::peripherals::SYSCFG as crate::rcc::sealed::RccPeripheral>::enable(); | ||
| 370 | #[cfg(stm32f1)] | ||
| 371 | <crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable(); | ||
| 372 | } | 374 | } |
diff --git a/embassy-stm32/src/fmt.rs b/embassy-stm32/src/fmt.rs index 066970813..78e583c1c 100644 --- a/embassy-stm32/src/fmt.rs +++ b/embassy-stm32/src/fmt.rs | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused_macros)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | ||
| 5 | |||
| 4 | #[cfg(all(feature = "defmt", feature = "log"))] | 6 | #[cfg(all(feature = "defmt", feature = "log"))] |
| 5 | compile_error!("You may not enable both `defmt` and `log` features."); | 7 | compile_error!("You may not enable both `defmt` and `log` features."); |
| 6 | 8 | ||
| @@ -81,14 +83,17 @@ macro_rules! todo { | |||
| 81 | }; | 83 | }; |
| 82 | } | 84 | } |
| 83 | 85 | ||
| 86 | #[cfg(not(feature = "defmt"))] | ||
| 84 | macro_rules! unreachable { | 87 | macro_rules! unreachable { |
| 85 | ($($x:tt)*) => { | 88 | ($($x:tt)*) => { |
| 86 | { | 89 | ::core::unreachable!($($x)*) |
| 87 | #[cfg(not(feature = "defmt"))] | 90 | }; |
| 88 | ::core::unreachable!($($x)*); | 91 | } |
| 89 | #[cfg(feature = "defmt")] | 92 | |
| 90 | ::defmt::unreachable!($($x)*); | 93 | #[cfg(feature = "defmt")] |
| 91 | } | 94 | macro_rules! unreachable { |
| 95 | ($($x:tt)*) => { | ||
| 96 | ::defmt::unreachable!($($x)*) | ||
| 92 | }; | 97 | }; |
| 93 | } | 98 | } |
| 94 | 99 | ||
| @@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> { | |||
| 223 | self | 228 | self |
| 224 | } | 229 | } |
| 225 | } | 230 | } |
| 231 | |||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | ||
| 234 | |||
| 235 | impl<'a> Debug for Bytes<'a> { | ||
| 236 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
| 237 | write!(f, "{:#02x?}", self.0) | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | impl<'a> Display for Bytes<'a> { | ||
| 242 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
| 243 | write!(f, "{:#02x?}", self.0) | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | impl<'a> LowerHex for Bytes<'a> { | ||
| 248 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
| 249 | write!(f, "{:#02x?}", self.0) | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 253 | #[cfg(feature = "defmt")] | ||
| 254 | impl<'a> defmt::Format for Bytes<'a> { | ||
| 255 | fn format(&self, fmt: defmt::Formatter) { | ||
| 256 | defmt::write!(fmt, "{:02x}", self.0) | ||
| 257 | } | ||
| 258 | } | ||
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index a382cb742..c709d46da 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs | |||
| @@ -758,6 +758,9 @@ foreach_pin!( | |||
| 758 | ); | 758 | ); |
| 759 | 759 | ||
| 760 | pub(crate) unsafe fn init() { | 760 | pub(crate) unsafe fn init() { |
| 761 | #[cfg(afio)] | ||
| 762 | <crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable(); | ||
| 763 | |||
| 761 | crate::_generated::init_gpio(); | 764 | crate::_generated::init_gpio(); |
| 762 | } | 765 | } |
| 763 | 766 | ||
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 31c488144..c47b0c092 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs | |||
| @@ -8,6 +8,8 @@ pub use traits::Instance; | |||
| 8 | #[allow(unused_imports)] | 8 | #[allow(unused_imports)] |
| 9 | use crate::gpio::sealed::{AFType, Pin}; | 9 | use crate::gpio::sealed::{AFType, Pin}; |
| 10 | use crate::gpio::AnyPin; | 10 | use crate::gpio::AnyPin; |
| 11 | #[cfg(stm32f334)] | ||
| 12 | use crate::rcc::get_freqs; | ||
| 11 | use crate::time::Hertz; | 13 | use crate::time::Hertz; |
| 12 | use crate::Peripheral; | 14 | use crate::Peripheral; |
| 13 | 15 | ||
| @@ -158,17 +160,29 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> { | |||
| 158 | T::enable(); | 160 | T::enable(); |
| 159 | <T as crate::rcc::sealed::RccPeripheral>::reset(); | 161 | <T as crate::rcc::sealed::RccPeripheral>::reset(); |
| 160 | 162 | ||
| 161 | // // Enable and and stabilize the DLL | 163 | #[cfg(stm32f334)] |
| 162 | // T::regs().dllcr().modify(|w| { | 164 | if unsafe { get_freqs() }.hrtim.is_some() { |
| 163 | // // w.set_calen(true); | 165 | // Enable and and stabilize the DLL |
| 164 | // // w.set_calrte(11); | 166 | T::regs().dllcr().modify(|w| { |
| 165 | // w.set_cal(true); | 167 | w.set_cal(true); |
| 166 | // }); | 168 | }); |
| 167 | // | 169 | |
| 168 | // debug!("wait for dll calibration"); | 170 | trace!("hrtim: wait for dll calibration"); |
| 169 | // while !T::regs().isr().read().dllrdy() {} | 171 | while !T::regs().isr().read().dllrdy() {} |
| 170 | // | 172 | |
| 171 | // debug!("dll calibration complete"); | 173 | trace!("hrtim: dll calibration complete"); |
| 174 | |||
| 175 | // Enable periodic calibration | ||
| 176 | // Cal must be disabled before we can enable it | ||
| 177 | T::regs().dllcr().modify(|w| { | ||
| 178 | w.set_cal(false); | ||
| 179 | }); | ||
| 180 | |||
| 181 | T::regs().dllcr().modify(|w| { | ||
| 182 | w.set_calen(true); | ||
| 183 | w.set_calrte(11); | ||
| 184 | }); | ||
| 185 | } | ||
| 172 | 186 | ||
| 173 | Self { | 187 | Self { |
| 174 | _inner: tim, | 188 | _inner: tim, |
diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index 158a68862..34a363a1f 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs | |||
| @@ -1,31 +1,17 @@ | |||
| 1 | use crate::rcc::sealed::RccPeripheral; | 1 | use crate::rcc::sealed::RccPeripheral; |
| 2 | use crate::time::Hertz; | 2 | use crate::time::Hertz; |
| 3 | 3 | ||
| 4 | #[repr(u8)] | ||
| 4 | #[derive(Clone, Copy)] | 5 | #[derive(Clone, Copy)] |
| 5 | pub(crate) enum Prescaler { | 6 | pub(crate) enum Prescaler { |
| 6 | Div1, | 7 | Div1 = 1, |
| 7 | Div2, | 8 | Div2 = 2, |
| 8 | Div4, | 9 | Div4 = 4, |
| 9 | Div8, | 10 | Div8 = 8, |
| 10 | Div16, | 11 | Div16 = 16, |
| 11 | Div32, | 12 | Div32 = 32, |
| 12 | Div64, | 13 | Div64 = 64, |
| 13 | Div128, | 14 | Div128 = 128, |
| 14 | } | ||
| 15 | |||
| 16 | impl From<Prescaler> for u32 { | ||
| 17 | fn from(val: Prescaler) -> Self { | ||
| 18 | match val { | ||
| 19 | Prescaler::Div1 => 1, | ||
| 20 | Prescaler::Div2 => 2, | ||
| 21 | Prescaler::Div4 => 4, | ||
| 22 | Prescaler::Div8 => 8, | ||
| 23 | Prescaler::Div16 => 16, | ||
| 24 | Prescaler::Div32 => 32, | ||
| 25 | Prescaler::Div64 => 64, | ||
| 26 | Prescaler::Div128 => 128, | ||
| 27 | } | ||
| 28 | } | ||
| 29 | } | 15 | } |
| 30 | 16 | ||
| 31 | impl From<Prescaler> for u8 { | 17 | impl From<Prescaler> for u8 { |
| @@ -72,7 +58,7 @@ impl Prescaler { | |||
| 72 | Prescaler::Div128, | 58 | Prescaler::Div128, |
| 73 | ] | 59 | ] |
| 74 | .iter() | 60 | .iter() |
| 75 | .skip_while(|psc| <Prescaler as Into<u32>>::into(**psc) <= val) | 61 | .skip_while(|psc| **psc as u32 <= val) |
| 76 | .next() | 62 | .next() |
| 77 | .unwrap() | 63 | .unwrap() |
| 78 | } | 64 | } |
| @@ -80,7 +66,7 @@ impl Prescaler { | |||
| 80 | pub fn compute_min_low_res(val: u32) -> Self { | 66 | pub fn compute_min_low_res(val: u32) -> Self { |
| 81 | *[Prescaler::Div32, Prescaler::Div64, Prescaler::Div128] | 67 | *[Prescaler::Div32, Prescaler::Div64, Prescaler::Div128] |
| 82 | .iter() | 68 | .iter() |
| 83 | .skip_while(|psc| <Prescaler as Into<u32>>::into(**psc) <= val) | 69 | .skip_while(|psc| **psc as u32 <= val) |
| 84 | .next() | 70 | .next() |
| 85 | .unwrap() | 71 | .unwrap() |
| 86 | } | 72 | } |
| @@ -92,97 +78,90 @@ pub(crate) mod sealed { | |||
| 92 | pub trait Instance: RccPeripheral { | 78 | pub trait Instance: RccPeripheral { |
| 93 | fn regs() -> crate::pac::hrtim::Hrtim; | 79 | fn regs() -> crate::pac::hrtim::Hrtim; |
| 94 | 80 | ||
| 95 | fn set_master_frequency(frequency: Hertz); | 81 | fn set_master_frequency(frequency: Hertz) { |
| 96 | 82 | let f = frequency.0; | |
| 97 | fn set_channel_frequency(channnel: usize, frequency: Hertz); | 83 | #[cfg(not(stm32f334))] |
| 98 | 84 | let timer_f = Self::frequency().0; | |
| 99 | /// Set the dead time as a proportion of max_duty | 85 | #[cfg(stm32f334)] |
| 100 | fn set_channel_dead_time(channnel: usize, dead_time: u16); | 86 | let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; |
| 101 | |||
| 102 | // fn enable_outputs(enable: bool); | ||
| 103 | // | ||
| 104 | // fn enable_channel(&mut self, channel: usize, enable: bool); | ||
| 105 | } | ||
| 106 | } | ||
| 107 | 87 | ||
| 108 | pub trait Instance: sealed::Instance + 'static {} | 88 | let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); |
| 109 | 89 | let psc = if Self::regs().isr().read().dllrdy() { | |
| 110 | foreach_interrupt! { | 90 | Prescaler::compute_min_high_res(psc_min) |
| 111 | ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { | 91 | } else { |
| 112 | impl sealed::Instance for crate::peripherals::$inst { | 92 | Prescaler::compute_min_low_res(psc_min) |
| 113 | fn regs() -> crate::pac::hrtim::Hrtim { | 93 | }; |
| 114 | crate::pac::$inst | ||
| 115 | } | ||
| 116 | 94 | ||
| 117 | fn set_master_frequency(frequency: Hertz) { | 95 | let timer_f = 32 * (timer_f / psc as u32); |
| 118 | use crate::rcc::sealed::RccPeripheral; | 96 | let per: u16 = (timer_f / f) as u16; |
| 119 | 97 | ||
| 120 | let f = frequency.0; | 98 | let regs = Self::regs(); |
| 121 | let timer_f = Self::frequency().0; | ||
| 122 | let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); | ||
| 123 | let psc = if Self::regs().isr().read().dllrdy() { | ||
| 124 | Prescaler::compute_min_high_res(psc_min) | ||
| 125 | } else { | ||
| 126 | Prescaler::compute_min_low_res(psc_min) | ||
| 127 | }; | ||
| 128 | 99 | ||
| 129 | let psc_val: u32 = psc.into(); | 100 | regs.mcr().modify(|w| w.set_ckpsc(psc.into())); |
| 130 | let timer_f = 32 * (timer_f / psc_val); | 101 | regs.mper().modify(|w| w.set_mper(per)); |
| 131 | let per: u16 = (timer_f / f) as u16; | 102 | } |
| 132 | 103 | ||
| 133 | let regs = Self::regs(); | 104 | fn set_channel_frequency(channel: usize, frequency: Hertz) { |
| 105 | let f = frequency.0; | ||
| 106 | #[cfg(not(stm32f334))] | ||
| 107 | let timer_f = Self::frequency().0; | ||
| 108 | #[cfg(stm32f334)] | ||
| 109 | let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; | ||
| 134 | 110 | ||
| 135 | regs.mcr().modify(|w| w.set_ckpsc(psc.into())); | 111 | let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); |
| 136 | regs.mper().modify(|w| w.set_mper(per)); | 112 | let psc = if Self::regs().isr().read().dllrdy() { |
| 137 | } | 113 | Prescaler::compute_min_high_res(psc_min) |
| 114 | } else { | ||
| 115 | Prescaler::compute_min_low_res(psc_min) | ||
| 116 | }; | ||
| 138 | 117 | ||
| 139 | fn set_channel_frequency(channel: usize, frequency: Hertz) { | 118 | let timer_f = 32 * (timer_f / psc as u32); |
| 140 | use crate::rcc::sealed::RccPeripheral; | 119 | let per: u16 = (timer_f / f) as u16; |
| 141 | 120 | ||
| 142 | let f = frequency.0; | 121 | let regs = Self::regs(); |
| 143 | let timer_f = Self::frequency().0; | ||
| 144 | let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); | ||
| 145 | let psc = if Self::regs().isr().read().dllrdy() { | ||
| 146 | Prescaler::compute_min_high_res(psc_min) | ||
| 147 | } else { | ||
| 148 | Prescaler::compute_min_low_res(psc_min) | ||
| 149 | }; | ||
| 150 | 122 | ||
| 151 | let psc_val: u32 = psc.into(); | 123 | regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into())); |
| 152 | let timer_f = 32 * (timer_f / psc_val); | 124 | regs.tim(channel).per().modify(|w| w.set_per(per)); |
| 153 | let per: u16 = (timer_f / f) as u16; | 125 | } |
| 154 | 126 | ||
| 155 | let regs = Self::regs(); | 127 | /// Set the dead time as a proportion of max_duty |
| 156 | 128 | ||
| 157 | regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into())); | 129 | fn set_channel_dead_time(channel: usize, dead_time: u16) { |
| 158 | regs.tim(channel).per().modify(|w| w.set_per(per)); | 130 | let regs = Self::regs(); |
| 159 | } | ||
| 160 | 131 | ||
| 161 | fn set_channel_dead_time(channel: usize, dead_time: u16) { | 132 | let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into(); |
| 162 | 133 | ||
| 163 | let regs = Self::regs(); | 134 | // The dead-time base clock runs 4 times slower than the hrtim base clock |
| 135 | // u9::MAX = 511 | ||
| 136 | let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511); | ||
| 137 | let psc = if Self::regs().isr().read().dllrdy() { | ||
| 138 | Prescaler::compute_min_high_res(psc_min) | ||
| 139 | } else { | ||
| 140 | Prescaler::compute_min_low_res(psc_min) | ||
| 141 | }; | ||
| 164 | 142 | ||
| 165 | let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into(); | 143 | let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32); |
| 166 | let psc_val: u32 = channel_psc.into(); | ||
| 167 | 144 | ||
| 145 | regs.tim(channel).dt().modify(|w| { | ||
| 146 | w.set_dtprsc(psc.into()); | ||
| 147 | w.set_dtf(dt_val as u16); | ||
| 148 | w.set_dtr(dt_val as u16); | ||
| 149 | }); | ||
| 150 | } | ||
| 168 | 151 | ||
| 169 | // The dead-time base clock runs 4 times slower than the hrtim base clock | 152 | // fn enable_outputs(enable: bool); |
| 170 | // u9::MAX = 511 | 153 | // |
| 171 | let psc_min = (psc_val * dead_time as u32) / (4 * 511); | 154 | // fn enable_channel(&mut self, channel: usize, enable: bool); |
| 172 | let psc = if Self::regs().isr().read().dllrdy() { | 155 | } |
| 173 | Prescaler::compute_min_high_res(psc_min) | 156 | } |
| 174 | } else { | ||
| 175 | Prescaler::compute_min_low_res(psc_min) | ||
| 176 | }; | ||
| 177 | 157 | ||
| 178 | let dt_psc_val: u32 = psc.into(); | 158 | pub trait Instance: sealed::Instance + 'static {} |
| 179 | let dt_val = (dt_psc_val * dead_time as u32) / (4 * psc_val); | ||
| 180 | 159 | ||
| 181 | regs.tim(channel).dt().modify(|w| { | 160 | foreach_interrupt! { |
| 182 | w.set_dtprsc(psc.into()); | 161 | ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { |
| 183 | w.set_dtf(dt_val as u16); | 162 | impl sealed::Instance for crate::peripherals::$inst { |
| 184 | w.set_dtr(dt_val as u16); | 163 | fn regs() -> crate::pac::hrtim::Hrtim { |
| 185 | }); | 164 | crate::pac::$inst |
| 186 | } | 165 | } |
| 187 | } | 166 | } |
| 188 | 167 | ||
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 618d85af2..f32dd0f0c 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -339,6 +339,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 339 | } | 339 | } |
| 340 | } | 340 | } |
| 341 | 341 | ||
| 342 | impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { | ||
| 343 | fn drop(&mut self) { | ||
| 344 | T::disable(); | ||
| 345 | } | ||
| 346 | } | ||
| 347 | |||
| 342 | impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { | 348 | impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { |
| 343 | type Error = Error; | 349 | type Error = Error; |
| 344 | 350 | ||
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 4327899bb..36f70e32e 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -838,6 +838,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 838 | } | 838 | } |
| 839 | } | 839 | } |
| 840 | 840 | ||
| 841 | impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { | ||
| 842 | fn drop(&mut self) { | ||
| 843 | T::disable(); | ||
| 844 | } | ||
| 845 | } | ||
| 846 | |||
| 841 | mod eh02 { | 847 | mod eh02 { |
| 842 | use super::*; | 848 | use super::*; |
| 843 | 849 | ||
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index b5a128596..2718c96da 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -90,6 +90,7 @@ pub use crate::_generated::interrupt; | |||
| 90 | #[macro_export] | 90 | #[macro_export] |
| 91 | macro_rules! bind_interrupts { | 91 | macro_rules! bind_interrupts { |
| 92 | ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { | 92 | ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { |
| 93 | #[derive(Copy, Clone)] | ||
| 93 | $vis struct $name; | 94 | $vis struct $name; |
| 94 | 95 | ||
| 95 | $( | 96 | $( |
| @@ -119,6 +120,7 @@ pub(crate) use stm32_metapac as pac; | |||
| 119 | use crate::interrupt::Priority; | 120 | use crate::interrupt::Priority; |
| 120 | #[cfg(feature = "rt")] | 121 | #[cfg(feature = "rt")] |
| 121 | pub use crate::pac::NVIC_PRIO_BITS; | 122 | pub use crate::pac::NVIC_PRIO_BITS; |
| 123 | use crate::rcc::sealed::RccPeripheral; | ||
| 122 | 124 | ||
| 123 | #[non_exhaustive] | 125 | #[non_exhaustive] |
| 124 | pub struct Config { | 126 | pub struct Config { |
| @@ -156,7 +158,7 @@ pub fn init(config: Config) -> Peripherals { | |||
| 156 | #[cfg(dbgmcu)] | 158 | #[cfg(dbgmcu)] |
| 157 | if config.enable_debug_during_sleep { | 159 | if config.enable_debug_during_sleep { |
| 158 | crate::pac::DBGMCU.cr().modify(|cr| { | 160 | crate::pac::DBGMCU.cr().modify(|cr| { |
| 159 | #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))] | 161 | #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))] |
| 160 | { | 162 | { |
| 161 | cr.set_dbg_stop(true); | 163 | cr.set_dbg_stop(true); |
| 162 | cr.set_dbg_standby(true); | 164 | cr.set_dbg_standby(true); |
| @@ -181,6 +183,13 @@ pub fn init(config: Config) -> Peripherals { | |||
| 181 | }); | 183 | }); |
| 182 | } | 184 | } |
| 183 | 185 | ||
| 186 | #[cfg(not(any(stm32f1, stm32wb, stm32wl)))] | ||
| 187 | peripherals::SYSCFG::enable(); | ||
| 188 | #[cfg(not(any(stm32h5, stm32h7, stm32wb, stm32wl)))] | ||
| 189 | peripherals::PWR::enable(); | ||
| 190 | #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] | ||
| 191 | peripherals::FLASH::enable(); | ||
| 192 | |||
| 184 | unsafe { | 193 | unsafe { |
| 185 | gpio::init(); | 194 | gpio::init(); |
| 186 | dma::init( | 195 | dma::init( |
| @@ -199,6 +208,11 @@ pub fn init(config: Config) -> Peripherals { | |||
| 199 | // must be after rcc init | 208 | // must be after rcc init |
| 200 | #[cfg(feature = "_time-driver")] | 209 | #[cfg(feature = "_time-driver")] |
| 201 | time_driver::init(); | 210 | time_driver::init(); |
| 211 | |||
| 212 | #[cfg(feature = "low-power")] | ||
| 213 | while !crate::rcc::low_power_ready() { | ||
| 214 | crate::rcc::clock_refcount_sub(); | ||
| 215 | } | ||
| 202 | } | 216 | } |
| 203 | 217 | ||
| 204 | p | 218 | p |
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 7814fa384..ce8afb578 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs | |||
| @@ -3,45 +3,33 @@ use core::marker::PhantomData; | |||
| 3 | 3 | ||
| 4 | use cortex_m::peripheral::SCB; | 4 | use cortex_m::peripheral::SCB; |
| 5 | use embassy_executor::*; | 5 | use embassy_executor::*; |
| 6 | use embassy_time::Duration; | ||
| 7 | 6 | ||
| 8 | use crate::interrupt; | 7 | use crate::interrupt; |
| 9 | use crate::interrupt::typelevel::Interrupt; | ||
| 10 | use crate::pac::EXTI; | ||
| 11 | use crate::rcc::low_power_ready; | 8 | use crate::rcc::low_power_ready; |
| 9 | use crate::time_driver::{get_driver, RtcDriver}; | ||
| 12 | 10 | ||
| 13 | const THREAD_PENDER: usize = usize::MAX; | 11 | const THREAD_PENDER: usize = usize::MAX; |
| 14 | const THRESHOLD: Duration = Duration::from_millis(500); | ||
| 15 | 12 | ||
| 16 | use crate::rtc::{Rtc, RtcInstant}; | 13 | use crate::rtc::Rtc; |
| 17 | 14 | ||
| 18 | static mut RTC: Option<&'static Rtc> = None; | 15 | static mut EXECUTOR: Option<Executor> = None; |
| 19 | 16 | ||
| 20 | foreach_interrupt! { | 17 | foreach_interrupt! { |
| 21 | (RTC, rtc, $block:ident, WKUP, $irq:ident) => { | 18 | (RTC, rtc, $block:ident, WKUP, $irq:ident) => { |
| 22 | #[interrupt] | 19 | #[interrupt] |
| 23 | unsafe fn $irq() { | 20 | unsafe fn $irq() { |
| 24 | Executor::on_wakeup_irq(); | 21 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); |
| 25 | } | 22 | } |
| 26 | }; | 23 | }; |
| 27 | } | 24 | } |
| 28 | 25 | ||
| 29 | pub fn stop_with_rtc(rtc: &'static Rtc) { | 26 | #[allow(dead_code)] |
| 30 | crate::interrupt::typelevel::RTC_WKUP::unpend(); | 27 | pub(crate) unsafe fn on_wakeup_irq() { |
| 31 | unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; | 28 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); |
| 32 | |||
| 33 | EXTI.rtsr(0).modify(|w| w.set_line(22, true)); | ||
| 34 | EXTI.imr(0).modify(|w| w.set_line(22, true)); | ||
| 35 | |||
| 36 | unsafe { RTC = Some(rtc) }; | ||
| 37 | } | 29 | } |
| 38 | 30 | ||
| 39 | pub fn start_wakeup_alarm(requested_duration: embassy_time::Duration) -> RtcInstant { | 31 | pub fn stop_with_rtc(rtc: &'static Rtc) { |
| 40 | unsafe { RTC }.unwrap().start_wakeup_alarm(requested_duration) | 32 | unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) |
| 41 | } | ||
| 42 | |||
| 43 | pub fn stop_wakeup_alarm() -> RtcInstant { | ||
| 44 | unsafe { RTC }.unwrap().stop_wakeup_alarm() | ||
| 45 | } | 33 | } |
| 46 | 34 | ||
| 47 | /// Thread mode executor, using WFE/SEV. | 35 | /// Thread mode executor, using WFE/SEV. |
| @@ -57,54 +45,58 @@ pub fn stop_wakeup_alarm() -> RtcInstant { | |||
| 57 | pub struct Executor { | 45 | pub struct Executor { |
| 58 | inner: raw::Executor, | 46 | inner: raw::Executor, |
| 59 | not_send: PhantomData<*mut ()>, | 47 | not_send: PhantomData<*mut ()>, |
| 48 | scb: SCB, | ||
| 49 | time_driver: &'static RtcDriver, | ||
| 60 | } | 50 | } |
| 61 | 51 | ||
| 62 | impl Executor { | 52 | impl Executor { |
| 63 | /// Create a new Executor. | 53 | /// Create a new Executor. |
| 64 | pub fn new() -> Self { | 54 | pub fn take() -> &'static mut Self { |
| 65 | Self { | 55 | unsafe { |
| 66 | inner: raw::Executor::new(THREAD_PENDER as *mut ()), | 56 | assert!(EXECUTOR.is_none()); |
| 67 | not_send: PhantomData, | 57 | |
| 58 | EXECUTOR = Some(Self { | ||
| 59 | inner: raw::Executor::new(THREAD_PENDER as *mut ()), | ||
| 60 | not_send: PhantomData, | ||
| 61 | scb: cortex_m::Peripherals::steal().SCB, | ||
| 62 | time_driver: get_driver(), | ||
| 63 | }); | ||
| 64 | |||
| 65 | EXECUTOR.as_mut().unwrap() | ||
| 68 | } | 66 | } |
| 69 | } | 67 | } |
| 70 | 68 | ||
| 71 | unsafe fn on_wakeup_irq() { | 69 | unsafe fn on_wakeup_irq(&mut self) { |
| 72 | info!("on wakeup irq"); | 70 | trace!("low power: on wakeup irq"); |
| 73 | 71 | ||
| 74 | cortex_m::asm::bkpt(); | 72 | self.time_driver.resume_time(); |
| 73 | trace!("low power: resume time"); | ||
| 75 | } | 74 | } |
| 76 | 75 | ||
| 77 | fn time_until_next_alarm(&self) -> Duration { | 76 | pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { |
| 78 | Duration::from_secs(3) | 77 | self.time_driver.set_rtc(rtc); |
| 79 | } | 78 | |
| 79 | rtc.enable_wakeup_line(); | ||
| 80 | 80 | ||
| 81 | fn get_scb() -> SCB { | 81 | trace!("low power: stop with rtc configured"); |
| 82 | unsafe { cortex_m::Peripherals::steal() }.SCB | ||
| 83 | } | 82 | } |
| 84 | 83 | ||
| 85 | fn configure_pwr(&self) { | 84 | fn configure_pwr(&mut self) { |
| 86 | trace!("configure_pwr"); | 85 | trace!("low power: configure_pwr"); |
| 87 | 86 | ||
| 87 | self.scb.clear_sleepdeep(); | ||
| 88 | if !low_power_ready() { | 88 | if !low_power_ready() { |
| 89 | trace!("low power: configure_pwr: low power not ready"); | ||
| 89 | return; | 90 | return; |
| 90 | } | 91 | } |
| 91 | 92 | ||
| 92 | let time_until_next_alarm = self.time_until_next_alarm(); | 93 | if self.time_driver.pause_time().is_err() { |
| 93 | if time_until_next_alarm < THRESHOLD { | 94 | trace!("low power: configure_pwr: time driver failed to pause"); |
| 94 | return; | 95 | return; |
| 95 | } | 96 | } |
| 96 | 97 | ||
| 97 | trace!("low power stop required"); | 98 | trace!("low power: enter stop..."); |
| 98 | 99 | self.scb.set_sleepdeep(); | |
| 99 | critical_section::with(|_| { | ||
| 100 | trace!("executor: set wakeup alarm..."); | ||
| 101 | |||
| 102 | start_wakeup_alarm(time_until_next_alarm); | ||
| 103 | |||
| 104 | trace!("low power wait for rtc ready..."); | ||
| 105 | |||
| 106 | Self::get_scb().set_sleepdeep(); | ||
| 107 | }); | ||
| 108 | } | 100 | } |
| 109 | 101 | ||
| 110 | /// Run the executor. | 102 | /// Run the executor. |
| @@ -126,11 +118,11 @@ impl Executor { | |||
| 126 | /// | 118 | /// |
| 127 | /// This function never returns. | 119 | /// This function never returns. |
| 128 | pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { | 120 | pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { |
| 129 | init(self.inner.spawner()); | 121 | init(unsafe { EXECUTOR.as_mut().unwrap() }.inner.spawner()); |
| 130 | 122 | ||
| 131 | loop { | 123 | loop { |
| 132 | unsafe { | 124 | unsafe { |
| 133 | self.inner.poll(); | 125 | EXECUTOR.as_mut().unwrap().inner.poll(); |
| 134 | self.configure_pwr(); | 126 | self.configure_pwr(); |
| 135 | asm!("wfe"); | 127 | asm!("wfe"); |
| 136 | }; | 128 | }; |
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs new file mode 100644 index 000000000..de27130f2 --- /dev/null +++ b/embassy-stm32/src/rcc/bd.rs | |||
| @@ -0,0 +1,176 @@ | |||
| 1 | #[allow(dead_code)] | ||
| 2 | #[derive(Default, Clone, Copy)] | ||
| 3 | pub enum LseDrive { | ||
| 4 | #[cfg(any(rtc_v2f7, rtc_v2l4))] | ||
| 5 | Low = 0, | ||
| 6 | MediumLow = 0x01, | ||
| 7 | #[default] | ||
| 8 | MediumHigh = 0x02, | ||
| 9 | #[cfg(any(rtc_v2f7, rtc_v2l4))] | ||
| 10 | High = 0x03, | ||
| 11 | } | ||
| 12 | |||
| 13 | #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] | ||
| 14 | impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv { | ||
| 15 | fn from(value: LseDrive) -> Self { | ||
| 16 | use crate::pac::rcc::vals::Lsedrv; | ||
| 17 | |||
| 18 | match value { | ||
| 19 | #[cfg(any(rtc_v2f7, rtc_v2l4))] | ||
| 20 | LseDrive::Low => Lsedrv::LOW, | ||
| 21 | LseDrive::MediumLow => Lsedrv::MEDIUMLOW, | ||
| 22 | LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH, | ||
| 23 | #[cfg(any(rtc_v2f7, rtc_v2l4))] | ||
| 24 | LseDrive::High => Lsedrv::HIGH, | ||
| 25 | } | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource; | ||
| 30 | |||
| 31 | #[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] | ||
| 32 | #[allow(dead_code)] | ||
| 33 | type Bdcr = crate::pac::rcc::regs::Bdcr; | ||
| 34 | |||
| 35 | #[cfg(any(rtc_v2l0, rtc_v2l1))] | ||
| 36 | #[allow(dead_code)] | ||
| 37 | type Bdcr = crate::pac::rcc::regs::Csr; | ||
| 38 | |||
| 39 | #[allow(dead_code)] | ||
| 40 | pub struct BackupDomain {} | ||
| 41 | |||
| 42 | impl BackupDomain { | ||
| 43 | #[cfg(any( | ||
| 44 | rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, | ||
| 45 | rtc_v3u5 | ||
| 46 | ))] | ||
| 47 | #[allow(dead_code, unused_variables)] | ||
| 48 | fn modify<R>(f: impl FnOnce(&mut Bdcr) -> R) -> R { | ||
| 49 | #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1, rtc_v2l0))] | ||
| 50 | let cr = crate::pac::PWR.cr(); | ||
| 51 | #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] | ||
| 52 | let cr = crate::pac::PWR.cr1(); | ||
| 53 | |||
| 54 | // TODO: Missing from PAC for l0 and f0? | ||
| 55 | #[cfg(not(any(rtc_v2f0, rtc_v3u5)))] | ||
| 56 | { | ||
| 57 | cr.modify(|w| w.set_dbp(true)); | ||
| 58 | while !cr.read().dbp() {} | ||
| 59 | } | ||
| 60 | |||
| 61 | #[cfg(any(rtc_v2l0, rtc_v2l1))] | ||
| 62 | let cr = crate::pac::RCC.csr(); | ||
| 63 | |||
| 64 | #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | ||
| 65 | let cr = crate::pac::RCC.bdcr(); | ||
| 66 | |||
| 67 | cr.modify(|w| f(w)) | ||
| 68 | } | ||
| 69 | |||
| 70 | #[cfg(any( | ||
| 71 | rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, | ||
| 72 | rtc_v3u5 | ||
| 73 | ))] | ||
| 74 | #[allow(dead_code)] | ||
| 75 | fn read() -> Bdcr { | ||
| 76 | #[cfg(any(rtc_v2l0, rtc_v2l1))] | ||
| 77 | let r = crate::pac::RCC.csr().read(); | ||
| 78 | |||
| 79 | #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | ||
| 80 | let r = crate::pac::RCC.bdcr().read(); | ||
| 81 | |||
| 82 | r | ||
| 83 | } | ||
| 84 | |||
| 85 | #[cfg(any( | ||
| 86 | rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, | ||
| 87 | rtc_v3u5 | ||
| 88 | ))] | ||
| 89 | #[allow(dead_code, unused_variables)] | ||
| 90 | pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option<LseDrive>) { | ||
| 91 | if lsi { | ||
| 92 | #[cfg(rtc_v3u5)] | ||
| 93 | let csr = crate::pac::RCC.bdcr(); | ||
| 94 | |||
| 95 | #[cfg(not(rtc_v3u5))] | ||
| 96 | let csr = crate::pac::RCC.csr(); | ||
| 97 | |||
| 98 | // Disable backup domain write protection | ||
| 99 | Self::modify(|_| {}); | ||
| 100 | |||
| 101 | #[cfg(not(any(rcc_wb, rcc_wba)))] | ||
| 102 | csr.modify(|w| w.set_lsion(true)); | ||
| 103 | |||
| 104 | #[cfg(any(rcc_wb, rcc_wba))] | ||
| 105 | csr.modify(|w| w.set_lsi1on(true)); | ||
| 106 | |||
| 107 | #[cfg(not(any(rcc_wb, rcc_wba)))] | ||
| 108 | while !csr.read().lsirdy() {} | ||
| 109 | |||
| 110 | #[cfg(any(rcc_wb, rcc_wba))] | ||
| 111 | while !csr.read().lsi1rdy() {} | ||
| 112 | } | ||
| 113 | |||
| 114 | if let Some(lse_drive) = lse { | ||
| 115 | Self::modify(|w| { | ||
| 116 | #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] | ||
| 117 | w.set_lsedrv(lse_drive.into()); | ||
| 118 | w.set_lseon(true); | ||
| 119 | }); | ||
| 120 | |||
| 121 | while !Self::read().lserdy() {} | ||
| 122 | } | ||
| 123 | |||
| 124 | match clock_source { | ||
| 125 | RtcClockSource::LSI => assert!(lsi), | ||
| 126 | RtcClockSource::LSE => assert!(&lse.is_some()), | ||
| 127 | _ => {} | ||
| 128 | }; | ||
| 129 | |||
| 130 | if clock_source == RtcClockSource::NOCLOCK { | ||
| 131 | // disable it | ||
| 132 | Self::modify(|w| { | ||
| 133 | #[cfg(not(rcc_wba))] | ||
| 134 | w.set_rtcen(false); | ||
| 135 | w.set_rtcsel(clock_source); | ||
| 136 | }); | ||
| 137 | } else { | ||
| 138 | // check if it's already enabled and in the source we want. | ||
| 139 | let reg = Self::read(); | ||
| 140 | let ok = reg.rtcsel() == clock_source; | ||
| 141 | #[cfg(not(rcc_wba))] | ||
| 142 | let ok = ok & reg.rtcen(); | ||
| 143 | |||
| 144 | // if not, configure it. | ||
| 145 | if !ok { | ||
| 146 | #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] | ||
| 147 | assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); | ||
| 148 | |||
| 149 | #[cfg(not(any(rcc_l0, rcc_l1)))] | ||
| 150 | Self::modify(|w| w.set_bdrst(true)); | ||
| 151 | |||
| 152 | Self::modify(|w| { | ||
| 153 | // Reset | ||
| 154 | #[cfg(not(any(rcc_l0, rcc_l1)))] | ||
| 155 | w.set_bdrst(false); | ||
| 156 | |||
| 157 | #[cfg(not(rcc_wba))] | ||
| 158 | w.set_rtcen(true); | ||
| 159 | w.set_rtcsel(clock_source); | ||
| 160 | |||
| 161 | // Restore bcdr | ||
| 162 | #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] | ||
| 163 | w.set_lscosel(reg.lscosel()); | ||
| 164 | #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] | ||
| 165 | w.set_lscoen(reg.lscoen()); | ||
| 166 | |||
| 167 | w.set_lseon(reg.lseon()); | ||
| 168 | |||
| 169 | #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] | ||
| 170 | w.set_lsedrv(reg.lsedrv()); | ||
| 171 | w.set_lsebyp(reg.lsebyp()); | ||
| 172 | }); | ||
| 173 | } | ||
| 174 | } | ||
| 175 | } | ||
| 176 | } | ||
diff --git a/embassy-stm32/src/rcc/bus.rs b/embassy-stm32/src/rcc/bus.rs new file mode 100644 index 000000000..495cf7fe1 --- /dev/null +++ b/embassy-stm32/src/rcc/bus.rs | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | use core::ops::Div; | ||
| 2 | |||
| 3 | #[allow(unused_imports)] | ||
| 4 | use crate::pac::rcc; | ||
| 5 | pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; | ||
| 6 | use crate::time::Hertz; | ||
| 7 | |||
| 8 | impl Div<AHBPrescaler> for Hertz { | ||
| 9 | type Output = Hertz; | ||
| 10 | |||
| 11 | fn div(self, rhs: AHBPrescaler) -> Self::Output { | ||
| 12 | let divisor = match rhs { | ||
| 13 | AHBPrescaler::DIV1 => 1, | ||
| 14 | AHBPrescaler::DIV2 => 2, | ||
| 15 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 16 | AHBPrescaler::DIV3 => 3, | ||
| 17 | AHBPrescaler::DIV4 => 4, | ||
| 18 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 19 | AHBPrescaler::DIV5 => 5, | ||
| 20 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 21 | AHBPrescaler::DIV6 => 6, | ||
| 22 | AHBPrescaler::DIV8 => 8, | ||
| 23 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 24 | AHBPrescaler::DIV10 => 10, | ||
| 25 | AHBPrescaler::DIV16 => 16, | ||
| 26 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 27 | AHBPrescaler::DIV32 => 32, | ||
| 28 | #[cfg(not(rcc_wba))] | ||
| 29 | AHBPrescaler::DIV64 => 64, | ||
| 30 | #[cfg(not(rcc_wba))] | ||
| 31 | AHBPrescaler::DIV128 => 128, | ||
| 32 | #[cfg(not(rcc_wba))] | ||
| 33 | AHBPrescaler::DIV256 => 256, | ||
| 34 | #[cfg(not(rcc_wba))] | ||
| 35 | AHBPrescaler::DIV512 => 512, | ||
| 36 | _ => unreachable!(), | ||
| 37 | }; | ||
| 38 | Hertz(self.0 / divisor) | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | impl Div<APBPrescaler> for Hertz { | ||
| 43 | type Output = Hertz; | ||
| 44 | |||
| 45 | fn div(self, rhs: APBPrescaler) -> Self::Output { | ||
| 46 | let divisor = match rhs { | ||
| 47 | APBPrescaler::DIV1 => 1, | ||
| 48 | APBPrescaler::DIV2 => 2, | ||
| 49 | APBPrescaler::DIV4 => 4, | ||
| 50 | APBPrescaler::DIV8 => 8, | ||
| 51 | APBPrescaler::DIV16 => 16, | ||
| 52 | _ => unreachable!(), | ||
| 53 | }; | ||
| 54 | Hertz(self.0 / divisor) | ||
| 55 | } | ||
| 56 | } | ||
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 6a9326347..8f45e7c0f 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | pub use super::common::{AHBPrescaler, APBPrescaler}; | 1 | pub use super::bus::{AHBPrescaler, APBPrescaler}; |
| 2 | use crate::pac::flash::vals::Latency; | 2 | use crate::pac::flash::vals::Latency; |
| 3 | use crate::pac::rcc::vals::{Hsidiv, Ppre, Sw}; | 3 | use crate::pac::rcc::vals::{Hsidiv, Ppre, Sw}; |
| 4 | use crate::pac::{FLASH, RCC}; | 4 | use crate::pac::{FLASH, RCC}; |
| @@ -58,8 +58,8 @@ impl Default for Config { | |||
| 58 | fn default() -> Config { | 58 | fn default() -> Config { |
| 59 | Config { | 59 | Config { |
| 60 | mux: ClockSrc::HSI(HSIPrescaler::NotDivided), | 60 | mux: ClockSrc::HSI(HSIPrescaler::NotDivided), |
| 61 | ahb_pre: AHBPrescaler::NotDivided, | 61 | ahb_pre: AHBPrescaler::DIV1, |
| 62 | apb_pre: APBPrescaler::NotDivided, | 62 | apb_pre: APBPrescaler::DIV1, |
| 63 | } | 63 | } |
| 64 | } | 64 | } |
| 65 | } | 65 | } |
| @@ -151,20 +151,21 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | let ahb_div = match config.ahb_pre { | 153 | let ahb_div = match config.ahb_pre { |
| 154 | AHBPrescaler::NotDivided => 1, | 154 | AHBPrescaler::DIV1 => 1, |
| 155 | AHBPrescaler::Div2 => 2, | 155 | AHBPrescaler::DIV2 => 2, |
| 156 | AHBPrescaler::Div4 => 4, | 156 | AHBPrescaler::DIV4 => 4, |
| 157 | AHBPrescaler::Div8 => 8, | 157 | AHBPrescaler::DIV8 => 8, |
| 158 | AHBPrescaler::Div16 => 16, | 158 | AHBPrescaler::DIV16 => 16, |
| 159 | AHBPrescaler::Div64 => 64, | 159 | AHBPrescaler::DIV64 => 64, |
| 160 | AHBPrescaler::Div128 => 128, | 160 | AHBPrescaler::DIV128 => 128, |
| 161 | AHBPrescaler::Div256 => 256, | 161 | AHBPrescaler::DIV256 => 256, |
| 162 | AHBPrescaler::Div512 => 512, | 162 | AHBPrescaler::DIV512 => 512, |
| 163 | _ => unreachable!(), | ||
| 163 | }; | 164 | }; |
| 164 | let ahb_freq = sys_clk / ahb_div; | 165 | let ahb_freq = sys_clk / ahb_div; |
| 165 | 166 | ||
| 166 | let (apb_freq, apb_tim_freq) = match config.apb_pre { | 167 | let (apb_freq, apb_tim_freq) = match config.apb_pre { |
| 167 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 168 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 168 | pre => { | 169 | pre => { |
| 169 | let pre: Ppre = pre.into(); | 170 | let pre: Ppre = pre.into(); |
| 170 | let pre: u8 = 1 << (pre.to_bits() - 3); | 171 | let pre: u8 = 1 << (pre.to_bits() - 3); |
diff --git a/embassy-stm32/src/rcc/common.rs b/embassy-stm32/src/rcc/common.rs deleted file mode 100644 index 62736a43a..000000000 --- a/embassy-stm32/src/rcc/common.rs +++ /dev/null | |||
| @@ -1,174 +0,0 @@ | |||
| 1 | use core::ops::Div; | ||
| 2 | |||
| 3 | #[allow(unused_imports)] | ||
| 4 | use crate::pac::rcc; | ||
| 5 | use crate::time::Hertz; | ||
| 6 | |||
| 7 | /// Voltage Scale | ||
| 8 | /// | ||
| 9 | /// Represents the voltage range feeding the CPU core. The maximum core | ||
| 10 | /// clock frequency depends on this value. | ||
| 11 | /// | ||
| 12 | /// Scale0 represents the highest voltage range | ||
| 13 | #[derive(Copy, Clone, PartialEq)] | ||
| 14 | pub enum VoltageScale { | ||
| 15 | Scale0, | ||
| 16 | Scale1, | ||
| 17 | #[cfg(not(any(rcc_wl5, rcc_wle)))] | ||
| 18 | Scale2, | ||
| 19 | #[cfg(not(any(rcc_wl5, rcc_wle)))] | ||
| 20 | Scale3, | ||
| 21 | } | ||
| 22 | |||
| 23 | /// AHB prescaler | ||
| 24 | #[derive(Clone, Copy, PartialEq)] | ||
| 25 | pub enum AHBPrescaler { | ||
| 26 | NotDivided, | ||
| 27 | Div2, | ||
| 28 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 29 | Div3, | ||
| 30 | Div4, | ||
| 31 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 32 | Div5, | ||
| 33 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 34 | Div6, | ||
| 35 | Div8, | ||
| 36 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 37 | Div10, | ||
| 38 | Div16, | ||
| 39 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 40 | Div32, | ||
| 41 | Div64, | ||
| 42 | Div128, | ||
| 43 | Div256, | ||
| 44 | Div512, | ||
| 45 | } | ||
| 46 | |||
| 47 | impl Div<AHBPrescaler> for Hertz { | ||
| 48 | type Output = Hertz; | ||
| 49 | |||
| 50 | fn div(self, rhs: AHBPrescaler) -> Self::Output { | ||
| 51 | let divisor = match rhs { | ||
| 52 | AHBPrescaler::NotDivided => 1, | ||
| 53 | AHBPrescaler::Div2 => 2, | ||
| 54 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 55 | AHBPrescaler::Div3 => 3, | ||
| 56 | AHBPrescaler::Div4 => 4, | ||
| 57 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 58 | AHBPrescaler::Div5 => 5, | ||
| 59 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 60 | AHBPrescaler::Div6 => 6, | ||
| 61 | AHBPrescaler::Div8 => 8, | ||
| 62 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 63 | AHBPrescaler::Div10 => 10, | ||
| 64 | AHBPrescaler::Div16 => 16, | ||
| 65 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 66 | AHBPrescaler::Div32 => 32, | ||
| 67 | AHBPrescaler::Div64 => 64, | ||
| 68 | AHBPrescaler::Div128 => 128, | ||
| 69 | AHBPrescaler::Div256 => 256, | ||
| 70 | AHBPrescaler::Div512 => 512, | ||
| 71 | }; | ||
| 72 | Hertz(self.0 / divisor) | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | #[cfg(not(any(rcc_g4, rcc_wb, rcc_wl5, rcc_wle)))] | ||
| 77 | impl From<AHBPrescaler> for rcc::vals::Hpre { | ||
| 78 | fn from(val: AHBPrescaler) -> rcc::vals::Hpre { | ||
| 79 | use rcc::vals::Hpre; | ||
| 80 | |||
| 81 | match val { | ||
| 82 | #[cfg(not(rcc_u5))] | ||
| 83 | AHBPrescaler::NotDivided => Hpre::DIV1, | ||
| 84 | #[cfg(rcc_u5)] | ||
| 85 | AHBPrescaler::NotDivided => Hpre::NONE, | ||
| 86 | AHBPrescaler::Div2 => Hpre::DIV2, | ||
| 87 | AHBPrescaler::Div4 => Hpre::DIV4, | ||
| 88 | AHBPrescaler::Div8 => Hpre::DIV8, | ||
| 89 | AHBPrescaler::Div16 => Hpre::DIV16, | ||
| 90 | AHBPrescaler::Div64 => Hpre::DIV64, | ||
| 91 | AHBPrescaler::Div128 => Hpre::DIV128, | ||
| 92 | AHBPrescaler::Div256 => Hpre::DIV256, | ||
| 93 | AHBPrescaler::Div512 => Hpre::DIV512, | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 99 | impl From<AHBPrescaler> for u8 { | ||
| 100 | fn from(val: AHBPrescaler) -> u8 { | ||
| 101 | match val { | ||
| 102 | AHBPrescaler::NotDivided => 0x0, | ||
| 103 | AHBPrescaler::Div2 => 0x08, | ||
| 104 | AHBPrescaler::Div3 => 0x01, | ||
| 105 | AHBPrescaler::Div4 => 0x09, | ||
| 106 | AHBPrescaler::Div5 => 0x02, | ||
| 107 | AHBPrescaler::Div6 => 0x05, | ||
| 108 | AHBPrescaler::Div8 => 0x0a, | ||
| 109 | AHBPrescaler::Div10 => 0x06, | ||
| 110 | AHBPrescaler::Div16 => 0x0b, | ||
| 111 | AHBPrescaler::Div32 => 0x07, | ||
| 112 | AHBPrescaler::Div64 => 0x0c, | ||
| 113 | AHBPrescaler::Div128 => 0x0d, | ||
| 114 | AHBPrescaler::Div256 => 0x0e, | ||
| 115 | AHBPrescaler::Div512 => 0x0f, | ||
| 116 | } | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | /// APB prescaler | ||
| 121 | #[derive(Clone, Copy)] | ||
| 122 | pub enum APBPrescaler { | ||
| 123 | NotDivided, | ||
| 124 | Div2, | ||
| 125 | Div4, | ||
| 126 | Div8, | ||
| 127 | Div16, | ||
| 128 | } | ||
| 129 | |||
| 130 | impl Div<APBPrescaler> for Hertz { | ||
| 131 | type Output = Hertz; | ||
| 132 | |||
| 133 | fn div(self, rhs: APBPrescaler) -> Self::Output { | ||
| 134 | let divisor = match rhs { | ||
| 135 | APBPrescaler::NotDivided => 1, | ||
| 136 | APBPrescaler::Div2 => 2, | ||
| 137 | APBPrescaler::Div4 => 4, | ||
| 138 | APBPrescaler::Div8 => 8, | ||
| 139 | APBPrescaler::Div16 => 16, | ||
| 140 | }; | ||
| 141 | Hertz(self.0 / divisor) | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | #[cfg(not(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_g4, rcc_h7, rcc_h7ab, rcc_wb, rcc_wl5, rcc_wle)))] | ||
| 146 | impl From<APBPrescaler> for rcc::vals::Ppre { | ||
| 147 | fn from(val: APBPrescaler) -> rcc::vals::Ppre { | ||
| 148 | use rcc::vals::Ppre; | ||
| 149 | |||
| 150 | match val { | ||
| 151 | #[cfg(not(rcc_u5))] | ||
| 152 | APBPrescaler::NotDivided => Ppre::DIV1, | ||
| 153 | #[cfg(rcc_u5)] | ||
| 154 | APBPrescaler::NotDivided => Ppre::NONE, | ||
| 155 | APBPrescaler::Div2 => Ppre::DIV2, | ||
| 156 | APBPrescaler::Div4 => Ppre::DIV4, | ||
| 157 | APBPrescaler::Div8 => Ppre::DIV8, | ||
| 158 | APBPrescaler::Div16 => Ppre::DIV16, | ||
| 159 | } | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] | ||
| 164 | impl From<APBPrescaler> for u8 { | ||
| 165 | fn from(val: APBPrescaler) -> u8 { | ||
| 166 | match val { | ||
| 167 | APBPrescaler::NotDivided => 1, | ||
| 168 | APBPrescaler::Div2 => 0x04, | ||
| 169 | APBPrescaler::Div4 => 0x05, | ||
| 170 | APBPrescaler::Div8 => 0x06, | ||
| 171 | APBPrescaler::Div16 => 0x07, | ||
| 172 | } | ||
| 173 | } | ||
| 174 | } | ||
diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs index b6200231e..081c0c767 100644 --- a/embassy-stm32/src/rcc/f1.rs +++ b/embassy-stm32/src/rcc/f1.rs | |||
| @@ -163,8 +163,8 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 163 | // Only needed for stm32f103? | 163 | // Only needed for stm32f103? |
| 164 | RCC.cfgr().modify(|w| { | 164 | RCC.cfgr().modify(|w| { |
| 165 | w.set_adcpre(Adcpre::from_bits(apre_bits)); | 165 | w.set_adcpre(Adcpre::from_bits(apre_bits)); |
| 166 | w.set_ppre2(Ppre1::from_bits(ppre2_bits)); | 166 | w.set_ppre2(Ppre::from_bits(ppre2_bits)); |
| 167 | w.set_ppre1(Ppre1::from_bits(ppre1_bits)); | 167 | w.set_ppre1(Ppre::from_bits(ppre1_bits)); |
| 168 | w.set_hpre(Hpre::from_bits(hpre_bits)); | 168 | w.set_hpre(Hpre::from_bits(hpre_bits)); |
| 169 | #[cfg(not(rcc_f100))] | 169 | #[cfg(not(rcc_f100))] |
| 170 | w.set_usbpre(Usbpre::from_bits(usbpre as u8)); | 170 | w.set_usbpre(Usbpre::from_bits(usbpre as u8)); |
| @@ -184,6 +184,6 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 184 | apb1_tim: Hertz(pclk1 * timer_mul1), | 184 | apb1_tim: Hertz(pclk1 * timer_mul1), |
| 185 | apb2_tim: Hertz(pclk2 * timer_mul2), | 185 | apb2_tim: Hertz(pclk2 * timer_mul2), |
| 186 | ahb1: Hertz(hclk), | 186 | ahb1: Hertz(hclk), |
| 187 | adc: Hertz(adcclk), | 187 | adc: Some(Hertz(adcclk)), |
| 188 | }); | 188 | }); |
| 189 | } | 189 | } |
diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index ec4ed99b8..44de5bf19 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs | |||
| @@ -1,11 +1,13 @@ | |||
| 1 | use core::convert::TryFrom; | 1 | use core::convert::TryFrom; |
| 2 | use core::ops::{Div, Mul}; | 2 | use core::ops::{Div, Mul}; |
| 3 | 3 | ||
| 4 | pub use super::common::{AHBPrescaler, APBPrescaler}; | 4 | pub use super::bus::{AHBPrescaler, APBPrescaler}; |
| 5 | use crate::pac::flash::vals::Latency; | 5 | use crate::pac::flash::vals::Latency; |
| 6 | use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw}; | 6 | use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw}; |
| 7 | use crate::pac::{FLASH, RCC}; | 7 | use crate::pac::{FLASH, RCC}; |
| 8 | use crate::rcc::bd::BackupDomain; | ||
| 8 | use crate::rcc::{set_freqs, Clocks}; | 9 | use crate::rcc::{set_freqs, Clocks}; |
| 10 | use crate::rtc::RtcClockSource; | ||
| 9 | use crate::time::Hertz; | 11 | use crate::time::Hertz; |
| 10 | 12 | ||
| 11 | /// HSI speed | 13 | /// HSI speed |
| @@ -201,7 +203,20 @@ pub struct PLLClocks { | |||
| 201 | pub pll48_freq: Hertz, | 203 | pub pll48_freq: Hertz, |
| 202 | } | 204 | } |
| 203 | 205 | ||
| 204 | pub use super::common::VoltageScale; | 206 | /// Voltage range of the power supply used. |
| 207 | /// | ||
| 208 | /// Used to calculate flash waitstates. See | ||
| 209 | /// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency | ||
| 210 | pub enum VoltageScale { | ||
| 211 | /// 2.7 to 3.6 V | ||
| 212 | Range0, | ||
| 213 | /// 2.4 to 2.7 V | ||
| 214 | Range1, | ||
| 215 | /// 2.1 to 2.4 V | ||
| 216 | Range2, | ||
| 217 | /// 1.8 to 2.1 V | ||
| 218 | Range3, | ||
| 219 | } | ||
| 205 | 220 | ||
| 206 | impl VoltageScale { | 221 | impl VoltageScale { |
| 207 | const fn wait_states(&self, ahb_freq: Hertz) -> Option<Latency> { | 222 | const fn wait_states(&self, ahb_freq: Hertz) -> Option<Latency> { |
| @@ -209,7 +224,7 @@ impl VoltageScale { | |||
| 209 | // Reference: RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock | 224 | // Reference: RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock |
| 210 | // frequency | 225 | // frequency |
| 211 | match self { | 226 | match self { |
| 212 | VoltageScale::Scale3 => { | 227 | VoltageScale::Range3 => { |
| 213 | if ahb_freq <= 16_000_000 { | 228 | if ahb_freq <= 16_000_000 { |
| 214 | Some(Latency::WS0) | 229 | Some(Latency::WS0) |
| 215 | } else if ahb_freq <= 32_000_000 { | 230 | } else if ahb_freq <= 32_000_000 { |
| @@ -230,7 +245,7 @@ impl VoltageScale { | |||
| 230 | None | 245 | None |
| 231 | } | 246 | } |
| 232 | } | 247 | } |
| 233 | VoltageScale::Scale2 => { | 248 | VoltageScale::Range2 => { |
| 234 | if ahb_freq <= 18_000_000 { | 249 | if ahb_freq <= 18_000_000 { |
| 235 | Some(Latency::WS0) | 250 | Some(Latency::WS0) |
| 236 | } else if ahb_freq <= 36_000_000 { | 251 | } else if ahb_freq <= 36_000_000 { |
| @@ -249,7 +264,7 @@ impl VoltageScale { | |||
| 249 | None | 264 | None |
| 250 | } | 265 | } |
| 251 | } | 266 | } |
| 252 | VoltageScale::Scale1 => { | 267 | VoltageScale::Range1 => { |
| 253 | if ahb_freq <= 24_000_000 { | 268 | if ahb_freq <= 24_000_000 { |
| 254 | Some(Latency::WS0) | 269 | Some(Latency::WS0) |
| 255 | } else if ahb_freq <= 48_000_000 { | 270 | } else if ahb_freq <= 48_000_000 { |
| @@ -264,7 +279,7 @@ impl VoltageScale { | |||
| 264 | None | 279 | None |
| 265 | } | 280 | } |
| 266 | } | 281 | } |
| 267 | VoltageScale::Scale0 => { | 282 | VoltageScale::Range0 => { |
| 268 | if ahb_freq <= 30_000_000 { | 283 | if ahb_freq <= 30_000_000 { |
| 269 | Some(Latency::WS0) | 284 | Some(Latency::WS0) |
| 270 | } else if ahb_freq <= 60_000_000 { | 285 | } else if ahb_freq <= 60_000_000 { |
| @@ -288,6 +303,9 @@ pub struct Config { | |||
| 288 | pub pll_mux: PLLSrc, | 303 | pub pll_mux: PLLSrc, |
| 289 | pub pll: PLLConfig, | 304 | pub pll: PLLConfig, |
| 290 | pub mux: ClockSrc, | 305 | pub mux: ClockSrc, |
| 306 | pub rtc: Option<RtcClockSource>, | ||
| 307 | pub lsi: bool, | ||
| 308 | pub lse: Option<Hertz>, | ||
| 291 | pub voltage: VoltageScale, | 309 | pub voltage: VoltageScale, |
| 292 | pub ahb_pre: AHBPrescaler, | 310 | pub ahb_pre: AHBPrescaler, |
| 293 | pub apb1_pre: APBPrescaler, | 311 | pub apb1_pre: APBPrescaler, |
| @@ -302,11 +320,14 @@ impl Default for Config { | |||
| 302 | hsi: true, | 320 | hsi: true, |
| 303 | pll_mux: PLLSrc::HSI, | 321 | pll_mux: PLLSrc::HSI, |
| 304 | pll: PLLConfig::default(), | 322 | pll: PLLConfig::default(), |
| 305 | voltage: VoltageScale::Scale3, | 323 | voltage: VoltageScale::Range3, |
| 306 | mux: ClockSrc::HSI, | 324 | mux: ClockSrc::HSI, |
| 307 | ahb_pre: AHBPrescaler::NotDivided, | 325 | rtc: None, |
| 308 | apb1_pre: APBPrescaler::NotDivided, | 326 | lsi: false, |
| 309 | apb2_pre: APBPrescaler::NotDivided, | 327 | lse: None, |
| 328 | ahb_pre: AHBPrescaler::DIV1, | ||
| 329 | apb1_pre: APBPrescaler::DIV1, | ||
| 330 | apb2_pre: APBPrescaler::DIV1, | ||
| 310 | } | 331 | } |
| 311 | } | 332 | } |
| 312 | } | 333 | } |
| @@ -379,7 +400,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 379 | assert!(ahb_freq <= Hertz(120_000_000)); | 400 | assert!(ahb_freq <= Hertz(120_000_000)); |
| 380 | 401 | ||
| 381 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | 402 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { |
| 382 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 403 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 383 | pre => { | 404 | pre => { |
| 384 | let freq = ahb_freq / pre; | 405 | let freq = ahb_freq / pre; |
| 385 | (freq, Hertz(freq.0 * 2)) | 406 | (freq, Hertz(freq.0 * 2)) |
| @@ -389,7 +410,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 389 | assert!(apb1_freq <= Hertz(30_000_000)); | 410 | assert!(apb1_freq <= Hertz(30_000_000)); |
| 390 | 411 | ||
| 391 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | 412 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { |
| 392 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 413 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 393 | pre => { | 414 | pre => { |
| 394 | let freq = ahb_freq / pre; | 415 | let freq = ahb_freq / pre; |
| 395 | (freq, Hertz(freq.0 * 2)) | 416 | (freq, Hertz(freq.0 * 2)) |
| @@ -414,6 +435,12 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 414 | RCC.cr().modify(|w| w.set_hsion(false)); | 435 | RCC.cr().modify(|w| w.set_hsion(false)); |
| 415 | } | 436 | } |
| 416 | 437 | ||
| 438 | BackupDomain::configure_ls( | ||
| 439 | config.rtc.unwrap_or(RtcClockSource::NOCLOCK), | ||
| 440 | config.lsi, | ||
| 441 | config.lse.map(|_| Default::default()), | ||
| 442 | ); | ||
| 443 | |||
| 417 | set_freqs(Clocks { | 444 | set_freqs(Clocks { |
| 418 | sys: sys_clk, | 445 | sys: sys_clk, |
| 419 | ahb1: ahb_freq, | 446 | ahb1: ahb_freq, |
diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index 321270a70..630dbd4fe 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | #[cfg(rcc_f3)] | ||
| 2 | use crate::pac::adccommon::vals::Ckmode; | ||
| 1 | use crate::pac::flash::vals::Latency; | 3 | use crate::pac::flash::vals::Latency; |
| 2 | use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; | 4 | use crate::pac::rcc::vals::{Adcpres, Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; |
| 3 | use crate::pac::{FLASH, RCC}; | 5 | use crate::pac::{FLASH, RCC}; |
| 4 | use crate::rcc::{set_freqs, Clocks}; | 6 | use crate::rcc::{set_freqs, Clocks}; |
| 5 | use crate::time::Hertz; | 7 | use crate::time::Hertz; |
| @@ -10,6 +12,82 @@ pub const HSI_FREQ: Hertz = Hertz(8_000_000); | |||
| 10 | /// LSI speed | 12 | /// LSI speed |
| 11 | pub const LSI_FREQ: Hertz = Hertz(40_000); | 13 | pub const LSI_FREQ: Hertz = Hertz(40_000); |
| 12 | 14 | ||
| 15 | impl From<AdcClockSource> for Adcpres { | ||
| 16 | fn from(value: AdcClockSource) -> Self { | ||
| 17 | match value { | ||
| 18 | AdcClockSource::PllDiv1 => Adcpres::DIV1, | ||
| 19 | AdcClockSource::PllDiv2 => Adcpres::DIV2, | ||
| 20 | AdcClockSource::PllDiv4 => Adcpres::DIV4, | ||
| 21 | AdcClockSource::PllDiv6 => Adcpres::DIV6, | ||
| 22 | AdcClockSource::PllDiv8 => Adcpres::DIV8, | ||
| 23 | AdcClockSource::PllDiv12 => Adcpres::DIV12, | ||
| 24 | AdcClockSource::PllDiv16 => Adcpres::DIV16, | ||
| 25 | AdcClockSource::PllDiv32 => Adcpres::DIV32, | ||
| 26 | AdcClockSource::PllDiv64 => Adcpres::DIV64, | ||
| 27 | AdcClockSource::PllDiv128 => Adcpres::DIV128, | ||
| 28 | AdcClockSource::PllDiv256 => Adcpres::DIV256, | ||
| 29 | _ => unreachable!(), | ||
| 30 | } | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | #[cfg(rcc_f3)] | ||
| 35 | impl From<AdcClockSource> for Ckmode { | ||
| 36 | fn from(value: AdcClockSource) -> Self { | ||
| 37 | match value { | ||
| 38 | AdcClockSource::BusDiv1 => Ckmode::SYNCDIV1, | ||
| 39 | AdcClockSource::BusDiv2 => Ckmode::SYNCDIV2, | ||
| 40 | AdcClockSource::BusDiv4 => Ckmode::SYNCDIV4, | ||
| 41 | _ => unreachable!(), | ||
| 42 | } | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | #[derive(Clone, Copy)] | ||
| 47 | pub enum AdcClockSource { | ||
| 48 | PllDiv1 = 1, | ||
| 49 | PllDiv2 = 2, | ||
| 50 | PllDiv4 = 4, | ||
| 51 | PllDiv6 = 6, | ||
| 52 | PllDiv8 = 8, | ||
| 53 | PllDiv12 = 12, | ||
| 54 | PllDiv16 = 16, | ||
| 55 | PllDiv32 = 32, | ||
| 56 | PllDiv64 = 64, | ||
| 57 | PllDiv128 = 128, | ||
| 58 | PllDiv256 = 256, | ||
| 59 | BusDiv1, | ||
| 60 | BusDiv2, | ||
| 61 | BusDiv4, | ||
| 62 | } | ||
| 63 | |||
| 64 | impl AdcClockSource { | ||
| 65 | pub fn is_bus(&self) -> bool { | ||
| 66 | match self { | ||
| 67 | Self::BusDiv1 => true, | ||
| 68 | Self::BusDiv2 => true, | ||
| 69 | Self::BusDiv4 => true, | ||
| 70 | _ => false, | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | pub fn bus_div(&self) -> u32 { | ||
| 75 | match self { | ||
| 76 | Self::BusDiv1 => 1, | ||
| 77 | Self::BusDiv2 => 2, | ||
| 78 | Self::BusDiv4 => 4, | ||
| 79 | _ => unreachable!(), | ||
| 80 | } | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | #[derive(Default)] | ||
| 85 | pub enum HrtimClockSource { | ||
| 86 | #[default] | ||
| 87 | BusClk, | ||
| 88 | PllClk, | ||
| 89 | } | ||
| 90 | |||
| 13 | /// Clocks configutation | 91 | /// Clocks configutation |
| 14 | #[non_exhaustive] | 92 | #[non_exhaustive] |
| 15 | #[derive(Default)] | 93 | #[derive(Default)] |
| @@ -36,9 +114,20 @@ pub struct Config { | |||
| 36 | /// - The System clock frequency is either 48MHz or 72MHz | 114 | /// - The System clock frequency is either 48MHz or 72MHz |
| 37 | /// - APB1 clock has a minimum frequency of 10MHz | 115 | /// - APB1 clock has a minimum frequency of 10MHz |
| 38 | pub pll48: bool, | 116 | pub pll48: bool, |
| 117 | #[cfg(rcc_f3)] | ||
| 118 | /// ADC clock setup | ||
| 119 | /// - For AHB, a psc of 4 or less must be used | ||
| 120 | pub adc: Option<AdcClockSource>, | ||
| 121 | #[cfg(rcc_f3)] | ||
| 122 | /// ADC clock setup | ||
| 123 | /// - For AHB, a psc of 4 or less must be used | ||
| 124 | pub adc34: Option<AdcClockSource>, | ||
| 125 | #[cfg(stm32f334)] | ||
| 126 | pub hrtim: HrtimClockSource, | ||
| 39 | } | 127 | } |
| 40 | 128 | ||
| 41 | // Information required to setup the PLL clock | 129 | // Information required to setup the PLL clock |
| 130 | #[derive(Clone, Copy)] | ||
| 42 | struct PllConfig { | 131 | struct PllConfig { |
| 43 | pll_src: Pllsrc, | 132 | pll_src: Pllsrc, |
| 44 | pll_mul: Pllmul, | 133 | pll_mul: Pllmul, |
| @@ -170,6 +259,65 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 170 | }) | 259 | }) |
| 171 | }); | 260 | }); |
| 172 | 261 | ||
| 262 | #[cfg(rcc_f3)] | ||
| 263 | let adc = config.adc.map(|adc| { | ||
| 264 | if !adc.is_bus() { | ||
| 265 | RCC.cfgr2().modify(|w| { | ||
| 266 | // Make sure that we're using the PLL | ||
| 267 | pll_config.unwrap(); | ||
| 268 | w.set_adc12pres(adc.into()); | ||
| 269 | |||
| 270 | Hertz(sysclk / adc as u32) | ||
| 271 | }) | ||
| 272 | } else { | ||
| 273 | crate::pac::ADC_COMMON.ccr().modify(|w| { | ||
| 274 | assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1)); | ||
| 275 | |||
| 276 | w.set_ckmode(adc.into()); | ||
| 277 | |||
| 278 | Hertz(sysclk / adc.bus_div() as u32) | ||
| 279 | }) | ||
| 280 | } | ||
| 281 | }); | ||
| 282 | |||
| 283 | #[cfg(all(rcc_f3, adc3_common))] | ||
| 284 | let adc34 = config.adc.map(|adc| { | ||
| 285 | if !adc.is_bus() { | ||
| 286 | RCC.cfgr2().modify(|w| { | ||
| 287 | // Make sure that we're using the PLL | ||
| 288 | pll_config.unwrap(); | ||
| 289 | w.set_adc12pres(adc.into()); | ||
| 290 | |||
| 291 | Hertz(sysclk / adc as u32) | ||
| 292 | }) | ||
| 293 | } else { | ||
| 294 | crate::pac::ADC3_COMMON.ccr().modify(|w| { | ||
| 295 | assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1)); | ||
| 296 | |||
| 297 | w.set_ckmode(adc.into()); | ||
| 298 | |||
| 299 | Hertz(sysclk / adc.bus_div() as u32) | ||
| 300 | }) | ||
| 301 | } | ||
| 302 | }); | ||
| 303 | |||
| 304 | #[cfg(stm32f334)] | ||
| 305 | let hrtim = match config.hrtim { | ||
| 306 | // Must be configured after the bus is ready, otherwise it won't work | ||
| 307 | HrtimClockSource::BusClk => None, | ||
| 308 | HrtimClockSource::PllClk => { | ||
| 309 | use crate::pac::rcc::vals::Timsw; | ||
| 310 | |||
| 311 | // Make sure that we're using the PLL | ||
| 312 | pll_config.unwrap(); | ||
| 313 | assert!((pclk2 == sysclk) || (pclk2 * 2 == sysclk)); | ||
| 314 | |||
| 315 | RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL)); | ||
| 316 | |||
| 317 | Some(Hertz(sysclk * 2)) | ||
| 318 | } | ||
| 319 | }; | ||
| 320 | |||
| 173 | set_freqs(Clocks { | 321 | set_freqs(Clocks { |
| 174 | sys: Hertz(sysclk), | 322 | sys: Hertz(sysclk), |
| 175 | apb1: Hertz(pclk1), | 323 | apb1: Hertz(pclk1), |
| @@ -177,6 +325,14 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 177 | apb1_tim: Hertz(pclk1 * timer_mul1), | 325 | apb1_tim: Hertz(pclk1 * timer_mul1), |
| 178 | apb2_tim: Hertz(pclk2 * timer_mul2), | 326 | apb2_tim: Hertz(pclk2 * timer_mul2), |
| 179 | ahb1: Hertz(hclk), | 327 | ahb1: Hertz(hclk), |
| 328 | #[cfg(rcc_f3)] | ||
| 329 | adc: adc, | ||
| 330 | #[cfg(all(rcc_f3, adc3_common))] | ||
| 331 | adc34: adc34, | ||
| 332 | #[cfg(all(rcc_f3, not(adc3_common)))] | ||
| 333 | adc34: None, | ||
| 334 | #[cfg(stm32f334)] | ||
| 335 | hrtim: hrtim, | ||
| 180 | }); | 336 | }); |
| 181 | } | 337 | } |
| 182 | 338 | ||
| @@ -201,9 +357,9 @@ fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) { | |||
| 201 | // Calculates the Multiplier and the Divisor to arrive at | 357 | // Calculates the Multiplier and the Divisor to arrive at |
| 202 | // the required System clock from PLL source frequency | 358 | // the required System clock from PLL source frequency |
| 203 | let get_mul_div = |sysclk, pllsrcclk| { | 359 | let get_mul_div = |sysclk, pllsrcclk| { |
| 204 | let common_div = gcd(sysclk, pllsrcclk); | 360 | let bus_div = gcd(sysclk, pllsrcclk); |
| 205 | let mut multiplier = sysclk / common_div; | 361 | let mut multiplier = sysclk / bus_div; |
| 206 | let mut divisor = pllsrcclk / common_div; | 362 | let mut divisor = pllsrcclk / bus_div; |
| 207 | // Minimum PLL multiplier is two | 363 | // Minimum PLL multiplier is two |
| 208 | if multiplier == 1 { | 364 | if multiplier == 1 { |
| 209 | multiplier *= 2; | 365 | multiplier *= 2; |
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index 72bdbd5db..2c027ebed 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs | |||
| @@ -3,13 +3,12 @@ use core::marker::PhantomData; | |||
| 3 | use embassy_hal_internal::into_ref; | 3 | use embassy_hal_internal::into_ref; |
| 4 | use stm32_metapac::rcc::vals::{Mco1, Mco2, Mcopre}; | 4 | use stm32_metapac::rcc::vals::{Mco1, Mco2, Mcopre}; |
| 5 | 5 | ||
| 6 | use super::sealed::RccPeripheral; | ||
| 7 | use crate::gpio::sealed::AFType; | 6 | use crate::gpio::sealed::AFType; |
| 8 | use crate::gpio::Speed; | 7 | use crate::gpio::Speed; |
| 9 | use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; | 8 | use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; |
| 10 | use crate::pac::{FLASH, PWR, RCC}; | 9 | use crate::pac::{FLASH, PWR, RCC}; |
| 10 | use crate::rcc::bd::{BackupDomain, RtcClockSource}; | ||
| 11 | use crate::rcc::{set_freqs, Clocks}; | 11 | use crate::rcc::{set_freqs, Clocks}; |
| 12 | use crate::rtc::{Rtc, RtcClockSource}; | ||
| 13 | use crate::time::Hertz; | 12 | use crate::time::Hertz; |
| 14 | use crate::{peripherals, Peripheral}; | 13 | use crate::{peripherals, Peripheral}; |
| 15 | 14 | ||
| @@ -38,6 +37,8 @@ pub struct Config { | |||
| 38 | 37 | ||
| 39 | pub pll48: bool, | 38 | pub pll48: bool, |
| 40 | pub rtc: Option<RtcClockSource>, | 39 | pub rtc: Option<RtcClockSource>, |
| 40 | pub lsi: bool, | ||
| 41 | pub lse: Option<Hertz>, | ||
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | #[cfg(stm32f410)] | 44 | #[cfg(stm32f410)] |
| @@ -360,8 +361,6 @@ fn flash_setup(sysclk: u32) { | |||
| 360 | } | 361 | } |
| 361 | 362 | ||
| 362 | pub(crate) unsafe fn init(config: Config) { | 363 | pub(crate) unsafe fn init(config: Config) { |
| 363 | crate::peripherals::PWR::enable(); | ||
| 364 | |||
| 365 | let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0); | 364 | let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0); |
| 366 | let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); | 365 | let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); |
| 367 | let sysclk_on_pll = sysclk != pllsrcclk; | 366 | let sysclk_on_pll = sysclk != pllsrcclk; |
| @@ -501,20 +500,15 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 501 | }) | 500 | }) |
| 502 | }); | 501 | }); |
| 503 | 502 | ||
| 504 | match config.rtc { | 503 | BackupDomain::configure_ls( |
| 505 | Some(RtcClockSource::LSI) => { | 504 | config.rtc.unwrap_or(RtcClockSource::NOCLOCK), |
| 506 | RCC.csr().modify(|w| w.set_lsion(true)); | 505 | config.lsi, |
| 507 | while !RCC.csr().read().lsirdy() {} | 506 | config.lse.map(|_| Default::default()), |
| 508 | } | 507 | ); |
| 509 | _ => {} | ||
| 510 | } | ||
| 511 | |||
| 512 | config.rtc.map(|clock_source| { | ||
| 513 | Rtc::set_clock_source(clock_source); | ||
| 514 | }); | ||
| 515 | 508 | ||
| 516 | let rtc = match config.rtc { | 509 | let rtc = match config.rtc { |
| 517 | Some(RtcClockSource::LSI) => Some(LSI_FREQ), | 510 | Some(RtcClockSource::LSI) => Some(LSI_FREQ), |
| 511 | Some(RtcClockSource::LSE) => Some(config.lse.unwrap()), | ||
| 518 | _ => None, | 512 | _ => None, |
| 519 | }; | 513 | }; |
| 520 | 514 | ||
| @@ -539,6 +533,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 539 | pllsai: plls.pllsaiclk.map(Hertz), | 533 | pllsai: plls.pllsaiclk.map(Hertz), |
| 540 | 534 | ||
| 541 | rtc: rtc, | 535 | rtc: rtc, |
| 536 | rtc_hse: None, | ||
| 542 | }); | 537 | }); |
| 543 | } | 538 | } |
| 544 | 539 | ||
diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs index 85cb9c661..f32559e26 100644 --- a/embassy-stm32/src/rcc/f7.rs +++ b/embassy-stm32/src/rcc/f7.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | use super::sealed::RccPeripheral; | ||
| 2 | use crate::pac::pwr::vals::Vos; | 1 | use crate::pac::pwr::vals::Vos; |
| 3 | use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; | 2 | use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; |
| 4 | use crate::pac::{FLASH, PWR, RCC}; | 3 | use crate::pac::{FLASH, PWR, RCC}; |
| 4 | use crate::rcc::bd::{BackupDomain, RtcClockSource}; | ||
| 5 | use crate::rcc::{set_freqs, Clocks}; | 5 | use crate::rcc::{set_freqs, Clocks}; |
| 6 | use crate::time::Hertz; | 6 | use crate::time::Hertz; |
| 7 | 7 | ||
| @@ -23,6 +23,9 @@ pub struct Config { | |||
| 23 | pub pclk2: Option<Hertz>, | 23 | pub pclk2: Option<Hertz>, |
| 24 | 24 | ||
| 25 | pub pll48: bool, | 25 | pub pll48: bool, |
| 26 | pub rtc: Option<RtcClockSource>, | ||
| 27 | pub lsi: bool, | ||
| 28 | pub lse: Option<Hertz>, | ||
| 26 | } | 29 | } |
| 27 | 30 | ||
| 28 | fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults { | 31 | fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults { |
| @@ -111,8 +114,6 @@ fn flash_setup(sysclk: u32) { | |||
| 111 | } | 114 | } |
| 112 | 115 | ||
| 113 | pub(crate) unsafe fn init(config: Config) { | 116 | pub(crate) unsafe fn init(config: Config) { |
| 114 | crate::peripherals::PWR::enable(); | ||
| 115 | |||
| 116 | if let Some(hse) = config.hse { | 117 | if let Some(hse) = config.hse { |
| 117 | if config.bypass_hse { | 118 | if config.bypass_hse { |
| 118 | assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0)); | 119 | assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0)); |
| @@ -212,10 +213,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 212 | if plls.use_pll { | 213 | if plls.use_pll { |
| 213 | RCC.cr().modify(|w| w.set_pllon(false)); | 214 | RCC.cr().modify(|w| w.set_pllon(false)); |
| 214 | 215 | ||
| 215 | // enable PWR and setup VOSScale | 216 | // setup VOSScale |
| 216 | |||
| 217 | RCC.apb1enr().modify(|w| w.set_pwren(true)); | ||
| 218 | |||
| 219 | let vos_scale = if sysclk <= 144_000_000 { | 217 | let vos_scale = if sysclk <= 144_000_000 { |
| 220 | 3 | 218 | 3 |
| 221 | } else if sysclk <= 168_000_000 { | 219 | } else if sysclk <= 168_000_000 { |
| @@ -265,6 +263,18 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 265 | }) | 263 | }) |
| 266 | }); | 264 | }); |
| 267 | 265 | ||
| 266 | BackupDomain::configure_ls( | ||
| 267 | config.rtc.unwrap_or(RtcClockSource::NOCLOCK), | ||
| 268 | config.lsi, | ||
| 269 | config.lse.map(|_| Default::default()), | ||
| 270 | ); | ||
| 271 | |||
| 272 | let rtc = match config.rtc { | ||
| 273 | Some(RtcClockSource::LSI) => Some(LSI_FREQ), | ||
| 274 | Some(RtcClockSource::LSE) => Some(config.lse.unwrap()), | ||
| 275 | _ => None, | ||
| 276 | }; | ||
| 277 | |||
| 268 | set_freqs(Clocks { | 278 | set_freqs(Clocks { |
| 269 | sys: Hertz(sysclk), | 279 | sys: Hertz(sysclk), |
| 270 | apb1: Hertz(pclk1), | 280 | apb1: Hertz(pclk1), |
| @@ -278,6 +288,8 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 278 | ahb3: Hertz(hclk), | 288 | ahb3: Hertz(hclk), |
| 279 | 289 | ||
| 280 | pll48: plls.pll48clk.map(Hertz), | 290 | pll48: plls.pll48clk.map(Hertz), |
| 291 | |||
| 292 | rtc, | ||
| 281 | }); | 293 | }); |
| 282 | } | 294 | } |
| 283 | 295 | ||
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index bf2d5199e..7f0a2c7fb 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | pub use super::common::{AHBPrescaler, APBPrescaler}; | 1 | pub use super::bus::{AHBPrescaler, APBPrescaler}; |
| 2 | use crate::pac::flash::vals::Latency; | 2 | use crate::pac::flash::vals::Latency; |
| 3 | use crate::pac::rcc::vals::{self, Hsidiv, Ppre, Sw}; | 3 | use crate::pac::rcc::vals::{self, Hsidiv, Ppre, Sw}; |
| 4 | use crate::pac::{FLASH, PWR, RCC}; | 4 | use crate::pac::{FLASH, PWR, RCC}; |
| @@ -186,8 +186,8 @@ impl Default for Config { | |||
| 186 | fn default() -> Config { | 186 | fn default() -> Config { |
| 187 | Config { | 187 | Config { |
| 188 | mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided), | 188 | mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided), |
| 189 | ahb_pre: AHBPrescaler::NotDivided, | 189 | ahb_pre: AHBPrescaler::DIV1, |
| 190 | apb_pre: APBPrescaler::NotDivided, | 190 | apb_pre: APBPrescaler::DIV1, |
| 191 | low_power_run: false, | 191 | low_power_run: false, |
| 192 | } | 192 | } |
| 193 | } | 193 | } |
| @@ -377,7 +377,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 377 | let ahb_freq = Hertz(sys_clk) / config.ahb_pre; | 377 | let ahb_freq = Hertz(sys_clk) / config.ahb_pre; |
| 378 | 378 | ||
| 379 | let (apb_freq, apb_tim_freq) = match config.apb_pre { | 379 | let (apb_freq, apb_tim_freq) = match config.apb_pre { |
| 380 | APBPrescaler::NotDivided => (ahb_freq.0, ahb_freq.0), | 380 | APBPrescaler::DIV1 => (ahb_freq.0, ahb_freq.0), |
| 381 | pre => { | 381 | pre => { |
| 382 | let pre: Ppre = pre.into(); | 382 | let pre: Ppre = pre.into(); |
| 383 | let pre: u8 = 1 << (pre.to_bits() - 3); | 383 | let pre: u8 = 1 << (pre.to_bits() - 3); |
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index dff04023e..41bebc918 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | use stm32_metapac::flash::vals::Latency; | 1 | use stm32_metapac::flash::vals::Latency; |
| 2 | use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw}; | 2 | use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw}; |
| 3 | use stm32_metapac::FLASH; | 3 | use stm32_metapac::FLASH; |
| 4 | 4 | ||
| 5 | pub use super::common::{AHBPrescaler, APBPrescaler}; | 5 | pub use super::bus::{AHBPrescaler, APBPrescaler}; |
| 6 | use crate::pac::{PWR, RCC}; | 6 | use crate::pac::{PWR, RCC}; |
| 7 | use crate::rcc::sealed::RccPeripheral; | 7 | use crate::rcc::sealed::RccPeripheral; |
| 8 | use crate::rcc::{set_freqs, Clocks}; | 8 | use crate::rcc::{set_freqs, Clocks}; |
| @@ -14,6 +14,29 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000); | |||
| 14 | /// LSI speed | 14 | /// LSI speed |
| 15 | pub const LSI_FREQ: Hertz = Hertz(32_000); | 15 | pub const LSI_FREQ: Hertz = Hertz(32_000); |
| 16 | 16 | ||
| 17 | #[derive(Clone, Copy)] | ||
| 18 | pub enum AdcClockSource { | ||
| 19 | NoClk, | ||
| 20 | SysClk, | ||
| 21 | PllP, | ||
| 22 | } | ||
| 23 | |||
| 24 | impl AdcClockSource { | ||
| 25 | pub fn adcsel(&self) -> Adcsel { | ||
| 26 | match self { | ||
| 27 | AdcClockSource::NoClk => Adcsel::NOCLK, | ||
| 28 | AdcClockSource::SysClk => Adcsel::SYSCLK, | ||
| 29 | AdcClockSource::PllP => Adcsel::PLLP, | ||
| 30 | } | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | impl Default for AdcClockSource { | ||
| 35 | fn default() -> Self { | ||
| 36 | Self::NoClk | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 17 | /// System clock mux source | 40 | /// System clock mux source |
| 18 | #[derive(Clone, Copy)] | 41 | #[derive(Clone, Copy)] |
| 19 | pub enum ClockSrc { | 42 | pub enum ClockSrc { |
| @@ -238,59 +261,29 @@ pub struct Pll { | |||
| 238 | pub div_r: Option<PllR>, | 261 | pub div_r: Option<PllR>, |
| 239 | } | 262 | } |
| 240 | 263 | ||
| 241 | impl AHBPrescaler { | 264 | fn ahb_div(ahb: AHBPrescaler) -> u32 { |
| 242 | const fn div(self) -> u32 { | 265 | match ahb { |
| 243 | match self { | 266 | AHBPrescaler::DIV1 => 1, |
| 244 | AHBPrescaler::NotDivided => 1, | 267 | AHBPrescaler::DIV2 => 2, |
| 245 | AHBPrescaler::Div2 => 2, | 268 | AHBPrescaler::DIV4 => 4, |
| 246 | AHBPrescaler::Div4 => 4, | 269 | AHBPrescaler::DIV8 => 8, |
| 247 | AHBPrescaler::Div8 => 8, | 270 | AHBPrescaler::DIV16 => 16, |
| 248 | AHBPrescaler::Div16 => 16, | 271 | AHBPrescaler::DIV64 => 64, |
| 249 | AHBPrescaler::Div64 => 64, | 272 | AHBPrescaler::DIV128 => 128, |
| 250 | AHBPrescaler::Div128 => 128, | 273 | AHBPrescaler::DIV256 => 256, |
| 251 | AHBPrescaler::Div256 => 256, | 274 | AHBPrescaler::DIV512 => 512, |
| 252 | AHBPrescaler::Div512 => 512, | 275 | _ => unreachable!(), |
| 253 | } | ||
| 254 | } | 276 | } |
| 255 | } | 277 | } |
| 256 | 278 | ||
| 257 | impl APBPrescaler { | 279 | fn apb_div(apb: APBPrescaler) -> u32 { |
| 258 | const fn div(self) -> u32 { | 280 | match apb { |
| 259 | match self { | 281 | APBPrescaler::DIV1 => 1, |
| 260 | APBPrescaler::NotDivided => 1, | 282 | APBPrescaler::DIV2 => 2, |
| 261 | APBPrescaler::Div2 => 2, | 283 | APBPrescaler::DIV4 => 4, |
| 262 | APBPrescaler::Div4 => 4, | 284 | APBPrescaler::DIV8 => 8, |
| 263 | APBPrescaler::Div8 => 8, | 285 | APBPrescaler::DIV16 => 16, |
| 264 | APBPrescaler::Div16 => 16, | 286 | _ => unreachable!(), |
| 265 | } | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 269 | impl Into<Ppre> for APBPrescaler { | ||
| 270 | fn into(self) -> Ppre { | ||
| 271 | match self { | ||
| 272 | APBPrescaler::NotDivided => Ppre::DIV1, | ||
| 273 | APBPrescaler::Div2 => Ppre::DIV2, | ||
| 274 | APBPrescaler::Div4 => Ppre::DIV4, | ||
| 275 | APBPrescaler::Div8 => Ppre::DIV8, | ||
| 276 | APBPrescaler::Div16 => Ppre::DIV16, | ||
| 277 | } | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | impl Into<Hpre> for AHBPrescaler { | ||
| 282 | fn into(self) -> Hpre { | ||
| 283 | match self { | ||
| 284 | AHBPrescaler::NotDivided => Hpre::DIV1, | ||
| 285 | AHBPrescaler::Div2 => Hpre::DIV2, | ||
| 286 | AHBPrescaler::Div4 => Hpre::DIV4, | ||
| 287 | AHBPrescaler::Div8 => Hpre::DIV8, | ||
| 288 | AHBPrescaler::Div16 => Hpre::DIV16, | ||
| 289 | AHBPrescaler::Div64 => Hpre::DIV64, | ||
| 290 | AHBPrescaler::Div128 => Hpre::DIV128, | ||
| 291 | AHBPrescaler::Div256 => Hpre::DIV256, | ||
| 292 | AHBPrescaler::Div512 => Hpre::DIV512, | ||
| 293 | } | ||
| 294 | } | 287 | } |
| 295 | } | 288 | } |
| 296 | 289 | ||
| @@ -327,6 +320,8 @@ pub struct Config { | |||
| 327 | pub pll: Option<Pll>, | 320 | pub pll: Option<Pll>, |
| 328 | /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals. | 321 | /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals. |
| 329 | pub clock_48mhz_src: Option<Clock48MhzSrc>, | 322 | pub clock_48mhz_src: Option<Clock48MhzSrc>, |
| 323 | pub adc12_clock_source: AdcClockSource, | ||
| 324 | pub adc345_clock_source: AdcClockSource, | ||
| 330 | } | 325 | } |
| 331 | 326 | ||
| 332 | /// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator. | 327 | /// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator. |
| @@ -340,12 +335,14 @@ impl Default for Config { | |||
| 340 | fn default() -> Config { | 335 | fn default() -> Config { |
| 341 | Config { | 336 | Config { |
| 342 | mux: ClockSrc::HSI16, | 337 | mux: ClockSrc::HSI16, |
| 343 | ahb_pre: AHBPrescaler::NotDivided, | 338 | ahb_pre: AHBPrescaler::DIV1, |
| 344 | apb1_pre: APBPrescaler::NotDivided, | 339 | apb1_pre: APBPrescaler::DIV1, |
| 345 | apb2_pre: APBPrescaler::NotDivided, | 340 | apb2_pre: APBPrescaler::DIV1, |
| 346 | low_power_run: false, | 341 | low_power_run: false, |
| 347 | pll: None, | 342 | pll: None, |
| 348 | clock_48mhz_src: None, | 343 | clock_48mhz_src: None, |
| 344 | adc12_clock_source: Default::default(), | ||
| 345 | adc345_clock_source: Default::default(), | ||
| 349 | } | 346 | } |
| 350 | } | 347 | } |
| 351 | } | 348 | } |
| @@ -485,22 +482,22 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 485 | }); | 482 | }); |
| 486 | 483 | ||
| 487 | let ahb_freq: u32 = match config.ahb_pre { | 484 | let ahb_freq: u32 = match config.ahb_pre { |
| 488 | AHBPrescaler::NotDivided => sys_clk, | 485 | AHBPrescaler::DIV1 => sys_clk, |
| 489 | pre => sys_clk / pre.div(), | 486 | pre => sys_clk / ahb_div(pre), |
| 490 | }; | 487 | }; |
| 491 | 488 | ||
| 492 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | 489 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { |
| 493 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 490 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 494 | pre => { | 491 | pre => { |
| 495 | let freq = ahb_freq / pre.div(); | 492 | let freq = ahb_freq / apb_div(pre); |
| 496 | (freq, freq * 2) | 493 | (freq, freq * 2) |
| 497 | } | 494 | } |
| 498 | }; | 495 | }; |
| 499 | 496 | ||
| 500 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | 497 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { |
| 501 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 498 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 502 | pre => { | 499 | pre => { |
| 503 | let freq = ahb_freq / pre.div(); | 500 | let freq = ahb_freq / apb_div(pre); |
| 504 | (freq, freq * 2) | 501 | (freq, freq * 2) |
| 505 | } | 502 | } |
| 506 | }; | 503 | }; |
| @@ -549,6 +546,29 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 549 | RCC.ccipr().modify(|w| w.set_clk48sel(source)); | 546 | RCC.ccipr().modify(|w| w.set_clk48sel(source)); |
| 550 | } | 547 | } |
| 551 | 548 | ||
| 549 | RCC.ccipr() | ||
| 550 | .modify(|w| w.set_adc12sel(config.adc12_clock_source.adcsel())); | ||
| 551 | RCC.ccipr() | ||
| 552 | .modify(|w| w.set_adc345sel(config.adc345_clock_source.adcsel())); | ||
| 553 | |||
| 554 | let adc12_ck = match config.adc12_clock_source { | ||
| 555 | AdcClockSource::NoClk => None, | ||
| 556 | AdcClockSource::PllP => match &pll_freq { | ||
| 557 | Some(pll) => pll.pll_p, | ||
| 558 | None => None, | ||
| 559 | }, | ||
| 560 | AdcClockSource::SysClk => Some(Hertz(sys_clk)), | ||
| 561 | }; | ||
| 562 | |||
| 563 | let adc345_ck = match config.adc345_clock_source { | ||
| 564 | AdcClockSource::NoClk => None, | ||
| 565 | AdcClockSource::PllP => match &pll_freq { | ||
| 566 | Some(pll) => pll.pll_p, | ||
| 567 | None => None, | ||
| 568 | }, | ||
| 569 | AdcClockSource::SysClk => Some(Hertz(sys_clk)), | ||
| 570 | }; | ||
| 571 | |||
| 552 | if config.low_power_run { | 572 | if config.low_power_run { |
| 553 | assert!(sys_clk <= 2_000_000); | 573 | assert!(sys_clk <= 2_000_000); |
| 554 | PWR.cr1().modify(|w| w.set_lpr(true)); | 574 | PWR.cr1().modify(|w| w.set_lpr(true)); |
| @@ -562,5 +582,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 562 | apb1_tim: Hertz(apb1_tim_freq), | 582 | apb1_tim: Hertz(apb1_tim_freq), |
| 563 | apb2: Hertz(apb2_freq), | 583 | apb2: Hertz(apb2_freq), |
| 564 | apb2_tim: Hertz(apb2_tim_freq), | 584 | apb2_tim: Hertz(apb2_tim_freq), |
| 585 | adc: adc12_ck, | ||
| 586 | adc34: adc345_ck, | ||
| 565 | }); | 587 | }); |
| 566 | } | 588 | } |
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs new file mode 100644 index 000000000..43e8db22e --- /dev/null +++ b/embassy-stm32/src/rcc/h.rs | |||
| @@ -0,0 +1,772 @@ | |||
| 1 | use core::ops::RangeInclusive; | ||
| 2 | |||
| 3 | use crate::pac; | ||
| 4 | use crate::pac::pwr::vals::Vos; | ||
| 5 | #[cfg(stm32h5)] | ||
| 6 | pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource; | ||
| 7 | #[cfg(stm32h7)] | ||
| 8 | pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; | ||
| 9 | pub use crate::pac::rcc::vals::Ckpersel as PerClockSource; | ||
| 10 | use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre}; | ||
| 11 | use crate::pac::{FLASH, PWR, RCC}; | ||
| 12 | use crate::rcc::{set_freqs, Clocks}; | ||
| 13 | use crate::time::Hertz; | ||
| 14 | |||
| 15 | /// HSI speed | ||
| 16 | pub const HSI_FREQ: Hertz = Hertz(64_000_000); | ||
| 17 | |||
| 18 | /// CSI speed | ||
| 19 | pub const CSI_FREQ: Hertz = Hertz(4_000_000); | ||
| 20 | |||
| 21 | /// HSI48 speed | ||
| 22 | pub const HSI48_FREQ: Hertz = Hertz(48_000_000); | ||
| 23 | |||
| 24 | /// LSI speed | ||
| 25 | pub const LSI_FREQ: Hertz = Hertz(32_000); | ||
| 26 | |||
| 27 | const VCO_RANGE: RangeInclusive<u32> = 150_000_000..=420_000_000; | ||
| 28 | #[cfg(any(stm32h5, pwr_h7rm0455))] | ||
| 29 | const VCO_WIDE_RANGE: RangeInclusive<u32> = 128_000_000..=560_000_000; | ||
| 30 | #[cfg(pwr_h7rm0468)] | ||
| 31 | const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=836_000_000; | ||
| 32 | #[cfg(any(pwr_h7rm0399, pwr_h7rm0433))] | ||
| 33 | const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=960_000_000; | ||
| 34 | |||
| 35 | pub use super::bus::{AHBPrescaler, APBPrescaler}; | ||
| 36 | |||
| 37 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 38 | pub enum VoltageScale { | ||
| 39 | Scale0, | ||
| 40 | Scale1, | ||
| 41 | Scale2, | ||
| 42 | Scale3, | ||
| 43 | } | ||
| 44 | |||
| 45 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 46 | pub enum HseMode { | ||
| 47 | /// crystal/ceramic oscillator (HSEBYP=0) | ||
| 48 | Oscillator, | ||
| 49 | /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) | ||
| 50 | Bypass, | ||
| 51 | /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1) | ||
| 52 | #[cfg(any(rcc_h5, rcc_h50))] | ||
| 53 | BypassDigital, | ||
| 54 | } | ||
| 55 | |||
| 56 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 57 | pub struct Hse { | ||
| 58 | /// HSE frequency. | ||
| 59 | pub freq: Hertz, | ||
| 60 | /// HSE mode. | ||
| 61 | pub mode: HseMode, | ||
| 62 | } | ||
| 63 | |||
| 64 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 65 | pub enum Hsi { | ||
| 66 | /// 64Mhz | ||
| 67 | Mhz64, | ||
| 68 | /// 32Mhz (divided by 2) | ||
| 69 | Mhz32, | ||
| 70 | /// 16Mhz (divided by 4) | ||
| 71 | Mhz16, | ||
| 72 | /// 8Mhz (divided by 8) | ||
| 73 | Mhz8, | ||
| 74 | } | ||
| 75 | |||
| 76 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 77 | pub enum Sysclk { | ||
| 78 | /// HSI selected as sysclk | ||
| 79 | HSI, | ||
| 80 | /// HSE selected as sysclk | ||
| 81 | HSE, | ||
| 82 | /// CSI selected as sysclk | ||
| 83 | CSI, | ||
| 84 | /// PLL1_P selected as sysclk | ||
| 85 | Pll1P, | ||
| 86 | } | ||
| 87 | |||
| 88 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 89 | pub enum PllSource { | ||
| 90 | Hsi, | ||
| 91 | Csi, | ||
| 92 | Hse, | ||
| 93 | } | ||
| 94 | |||
| 95 | #[derive(Clone, Copy)] | ||
| 96 | pub struct Pll { | ||
| 97 | /// Source clock selection. | ||
| 98 | #[cfg(stm32h5)] | ||
| 99 | pub source: PllSource, | ||
| 100 | |||
| 101 | /// PLL pre-divider (DIVM). Must be between 1 and 63. | ||
| 102 | pub prediv: u8, | ||
| 103 | |||
| 104 | /// PLL multiplication factor. Must be between 4 and 512. | ||
| 105 | pub mul: u16, | ||
| 106 | |||
| 107 | /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128. | ||
| 108 | /// On PLL1, it must be even (in particular, it cannot be 1.) | ||
| 109 | pub divp: Option<u16>, | ||
| 110 | /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128. | ||
| 111 | pub divq: Option<u16>, | ||
| 112 | /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128. | ||
| 113 | pub divr: Option<u16>, | ||
| 114 | } | ||
| 115 | |||
| 116 | fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz { | ||
| 117 | match (tim, apb) { | ||
| 118 | (TimerPrescaler::DefaultX2, APBPrescaler::DIV1) => clk, | ||
| 119 | (TimerPrescaler::DefaultX2, APBPrescaler::DIV2) => clk, | ||
| 120 | (TimerPrescaler::DefaultX2, APBPrescaler::DIV4) => clk / 2u32, | ||
| 121 | (TimerPrescaler::DefaultX2, APBPrescaler::DIV8) => clk / 4u32, | ||
| 122 | (TimerPrescaler::DefaultX2, APBPrescaler::DIV16) => clk / 8u32, | ||
| 123 | |||
| 124 | (TimerPrescaler::DefaultX4, APBPrescaler::DIV1) => clk, | ||
| 125 | (TimerPrescaler::DefaultX4, APBPrescaler::DIV2) => clk, | ||
| 126 | (TimerPrescaler::DefaultX4, APBPrescaler::DIV4) => clk, | ||
| 127 | (TimerPrescaler::DefaultX4, APBPrescaler::DIV8) => clk / 2u32, | ||
| 128 | (TimerPrescaler::DefaultX4, APBPrescaler::DIV16) => clk / 4u32, | ||
| 129 | |||
| 130 | _ => unreachable!(), | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | /// Timer prescaler | ||
| 135 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 136 | pub enum TimerPrescaler { | ||
| 137 | /// The timers kernel clock is equal to hclk if PPREx corresponds to a | ||
| 138 | /// division by 1 or 2, else it is equal to 2*pclk | ||
| 139 | DefaultX2, | ||
| 140 | |||
| 141 | /// The timers kernel clock is equal to hclk if PPREx corresponds to a | ||
| 142 | /// division by 1, 2 or 4, else it is equal to 4*pclk | ||
| 143 | DefaultX4, | ||
| 144 | } | ||
| 145 | |||
| 146 | impl From<TimerPrescaler> for Timpre { | ||
| 147 | fn from(value: TimerPrescaler) -> Self { | ||
| 148 | match value { | ||
| 149 | TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2, | ||
| 150 | TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4, | ||
| 151 | } | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | /// Configuration of the core clocks | ||
| 156 | #[non_exhaustive] | ||
| 157 | pub struct Config { | ||
| 158 | pub hsi: Option<Hsi>, | ||
| 159 | pub hse: Option<Hse>, | ||
| 160 | pub csi: bool, | ||
| 161 | pub hsi48: bool, | ||
| 162 | pub sys: Sysclk, | ||
| 163 | |||
| 164 | #[cfg(stm32h7)] | ||
| 165 | pub pll_src: PllSource, | ||
| 166 | |||
| 167 | pub pll1: Option<Pll>, | ||
| 168 | pub pll2: Option<Pll>, | ||
| 169 | #[cfg(any(rcc_h5, stm32h7))] | ||
| 170 | pub pll3: Option<Pll>, | ||
| 171 | |||
| 172 | pub d1c_pre: AHBPrescaler, | ||
| 173 | pub ahb_pre: AHBPrescaler, | ||
| 174 | pub apb1_pre: APBPrescaler, | ||
| 175 | pub apb2_pre: APBPrescaler, | ||
| 176 | pub apb3_pre: APBPrescaler, | ||
| 177 | #[cfg(stm32h7)] | ||
| 178 | pub apb4_pre: APBPrescaler, | ||
| 179 | |||
| 180 | pub per_clock_source: PerClockSource, | ||
| 181 | pub adc_clock_source: AdcClockSource, | ||
| 182 | pub timer_prescaler: TimerPrescaler, | ||
| 183 | pub voltage_scale: VoltageScale, | ||
| 184 | } | ||
| 185 | |||
| 186 | impl Default for Config { | ||
| 187 | fn default() -> Self { | ||
| 188 | Self { | ||
| 189 | hsi: Some(Hsi::Mhz64), | ||
| 190 | hse: None, | ||
| 191 | csi: false, | ||
| 192 | hsi48: false, | ||
| 193 | sys: Sysclk::HSI, | ||
| 194 | #[cfg(stm32h7)] | ||
| 195 | pll_src: PllSource::Hsi, | ||
| 196 | pll1: None, | ||
| 197 | pll2: None, | ||
| 198 | #[cfg(any(rcc_h5, stm32h7))] | ||
| 199 | pll3: None, | ||
| 200 | |||
| 201 | d1c_pre: AHBPrescaler::DIV1, | ||
| 202 | ahb_pre: AHBPrescaler::DIV1, | ||
| 203 | apb1_pre: APBPrescaler::DIV1, | ||
| 204 | apb2_pre: APBPrescaler::DIV1, | ||
| 205 | apb3_pre: APBPrescaler::DIV1, | ||
| 206 | #[cfg(stm32h7)] | ||
| 207 | apb4_pre: APBPrescaler::DIV1, | ||
| 208 | |||
| 209 | per_clock_source: PerClockSource::HSI, | ||
| 210 | adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5 | ||
| 211 | timer_prescaler: TimerPrescaler::DefaultX2, | ||
| 212 | voltage_scale: VoltageScale::Scale0, | ||
| 213 | } | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | pub(crate) unsafe fn init(config: Config) { | ||
| 218 | // NB. The lower bytes of CR3 can only be written once after | ||
| 219 | // POR, and must be written with a valid combination. Refer to | ||
| 220 | // RM0433 Rev 7 6.8.4. This is partially enforced by dropping | ||
| 221 | // `self` at the end of this method, but of course we cannot | ||
| 222 | // know what happened between the previous POR and here. | ||
| 223 | #[cfg(pwr_h7rm0433)] | ||
| 224 | PWR.cr3().modify(|w| { | ||
| 225 | w.set_scuen(true); | ||
| 226 | w.set_ldoen(true); | ||
| 227 | w.set_bypass(false); | ||
| 228 | }); | ||
| 229 | |||
| 230 | #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] | ||
| 231 | PWR.cr3().modify(|w| { | ||
| 232 | // hardcode "Direct SPMS" for now, this is what works on nucleos with the | ||
| 233 | // default solderbridge configuration. | ||
| 234 | w.set_sden(true); | ||
| 235 | w.set_ldoen(false); | ||
| 236 | }); | ||
| 237 | |||
| 238 | // Validate the supply configuration. If you are stuck here, it is | ||
| 239 | // because the voltages on your board do not match those specified | ||
| 240 | // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset | ||
| 241 | // VOS = Scale 3, so check that the voltage on the VCAP pins = | ||
| 242 | // 1.0V. | ||
| 243 | #[cfg(any(pwr_h7rm0433, pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] | ||
| 244 | while !PWR.csr1().read().actvosrdy() {} | ||
| 245 | |||
| 246 | // Configure voltage scale. | ||
| 247 | #[cfg(any(pwr_h5, pwr_h50))] | ||
| 248 | { | ||
| 249 | PWR.voscr().modify(|w| { | ||
| 250 | w.set_vos(match config.voltage_scale { | ||
| 251 | VoltageScale::Scale0 => Vos::SCALE0, | ||
| 252 | VoltageScale::Scale1 => Vos::SCALE1, | ||
| 253 | VoltageScale::Scale2 => Vos::SCALE2, | ||
| 254 | VoltageScale::Scale3 => Vos::SCALE3, | ||
| 255 | }) | ||
| 256 | }); | ||
| 257 | while !PWR.vossr().read().vosrdy() {} | ||
| 258 | } | ||
| 259 | |||
| 260 | #[cfg(syscfg_h7)] | ||
| 261 | { | ||
| 262 | // in chips without the overdrive bit, we can go from any scale to any scale directly. | ||
| 263 | PWR.d3cr().modify(|w| { | ||
| 264 | w.set_vos(match config.voltage_scale { | ||
| 265 | VoltageScale::Scale0 => Vos::SCALE0, | ||
| 266 | VoltageScale::Scale1 => Vos::SCALE1, | ||
| 267 | VoltageScale::Scale2 => Vos::SCALE2, | ||
| 268 | VoltageScale::Scale3 => Vos::SCALE3, | ||
| 269 | }) | ||
| 270 | }); | ||
| 271 | while !PWR.d3cr().read().vosrdy() {} | ||
| 272 | } | ||
| 273 | |||
| 274 | #[cfg(syscfg_h7od)] | ||
| 275 | { | ||
| 276 | match config.voltage_scale { | ||
| 277 | VoltageScale::Scale0 => { | ||
| 278 | // to go to scale0, we must go to Scale1 first... | ||
| 279 | PWR.d3cr().modify(|w| w.set_vos(Vos::SCALE1)); | ||
| 280 | while !PWR.d3cr().read().vosrdy() {} | ||
| 281 | |||
| 282 | // Then enable overdrive. | ||
| 283 | critical_section::with(|_| pac::SYSCFG.pwrcr().modify(|w| w.set_oden(1))); | ||
| 284 | while !PWR.d3cr().read().vosrdy() {} | ||
| 285 | } | ||
| 286 | _ => { | ||
| 287 | // for all other scales, we can go directly. | ||
| 288 | PWR.d3cr().modify(|w| { | ||
| 289 | w.set_vos(match config.voltage_scale { | ||
| 290 | VoltageScale::Scale0 => unreachable!(), | ||
| 291 | VoltageScale::Scale1 => Vos::SCALE1, | ||
| 292 | VoltageScale::Scale2 => Vos::SCALE2, | ||
| 293 | VoltageScale::Scale3 => Vos::SCALE3, | ||
| 294 | }) | ||
| 295 | }); | ||
| 296 | while !PWR.d3cr().read().vosrdy() {} | ||
| 297 | } | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | // Configure HSI | ||
| 302 | let hsi = match config.hsi { | ||
| 303 | None => { | ||
| 304 | RCC.cr().modify(|w| w.set_hsion(false)); | ||
| 305 | None | ||
| 306 | } | ||
| 307 | Some(hsi) => { | ||
| 308 | let (freq, hsidiv) = match hsi { | ||
| 309 | Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1), | ||
| 310 | Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2), | ||
| 311 | Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4), | ||
| 312 | Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8), | ||
| 313 | }; | ||
| 314 | RCC.cr().modify(|w| { | ||
| 315 | w.set_hsidiv(hsidiv); | ||
| 316 | w.set_hsion(true); | ||
| 317 | }); | ||
| 318 | while !RCC.cr().read().hsirdy() {} | ||
| 319 | Some(freq) | ||
| 320 | } | ||
| 321 | }; | ||
| 322 | |||
| 323 | // Configure HSE | ||
| 324 | let hse = match config.hse { | ||
| 325 | None => { | ||
| 326 | RCC.cr().modify(|w| w.set_hseon(false)); | ||
| 327 | None | ||
| 328 | } | ||
| 329 | Some(hse) => { | ||
| 330 | RCC.cr().modify(|w| { | ||
| 331 | w.set_hsebyp(hse.mode != HseMode::Oscillator); | ||
| 332 | #[cfg(any(rcc_h5, rcc_h50))] | ||
| 333 | w.set_hseext(match hse.mode { | ||
| 334 | HseMode::Oscillator | HseMode::Bypass => pac::rcc::vals::Hseext::ANALOG, | ||
| 335 | HseMode::BypassDigital => pac::rcc::vals::Hseext::DIGITAL, | ||
| 336 | }); | ||
| 337 | }); | ||
| 338 | RCC.cr().modify(|w| w.set_hseon(true)); | ||
| 339 | while !RCC.cr().read().hserdy() {} | ||
| 340 | Some(hse.freq) | ||
| 341 | } | ||
| 342 | }; | ||
| 343 | |||
| 344 | // Configure HSI48. | ||
| 345 | RCC.cr().modify(|w| w.set_hsi48on(config.hsi48)); | ||
| 346 | let _hsi48 = match config.hsi48 { | ||
| 347 | false => None, | ||
| 348 | true => { | ||
| 349 | while !RCC.cr().read().hsi48rdy() {} | ||
| 350 | Some(CSI_FREQ) | ||
| 351 | } | ||
| 352 | }; | ||
| 353 | |||
| 354 | // Configure CSI. | ||
| 355 | RCC.cr().modify(|w| w.set_csion(config.csi)); | ||
| 356 | let csi = match config.csi { | ||
| 357 | false => None, | ||
| 358 | true => { | ||
| 359 | while !RCC.cr().read().csirdy() {} | ||
| 360 | Some(CSI_FREQ) | ||
| 361 | } | ||
| 362 | }; | ||
| 363 | |||
| 364 | // Configure PLLs. | ||
| 365 | let pll_input = PllInput { | ||
| 366 | csi, | ||
| 367 | hse, | ||
| 368 | hsi, | ||
| 369 | #[cfg(stm32h7)] | ||
| 370 | source: config.pll_src, | ||
| 371 | }; | ||
| 372 | let pll1 = init_pll(0, config.pll1, &pll_input); | ||
| 373 | let pll2 = init_pll(1, config.pll2, &pll_input); | ||
| 374 | #[cfg(any(rcc_h5, stm32h7))] | ||
| 375 | let _pll3 = init_pll(2, config.pll3, &pll_input); | ||
| 376 | |||
| 377 | // Configure sysclk | ||
| 378 | let (sys, sw) = match config.sys { | ||
| 379 | Sysclk::HSI => (unwrap!(hsi), Sw::HSI), | ||
| 380 | Sysclk::HSE => (unwrap!(hse), Sw::HSE), | ||
| 381 | Sysclk::CSI => (unwrap!(csi), Sw::CSI), | ||
| 382 | Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1), | ||
| 383 | }; | ||
| 384 | |||
| 385 | // Check limits. | ||
| 386 | #[cfg(stm32h5)] | ||
| 387 | let (hclk_max, pclk_max) = match config.voltage_scale { | ||
| 388 | VoltageScale::Scale0 => (Hertz(250_000_000), Hertz(250_000_000)), | ||
| 389 | VoltageScale::Scale1 => (Hertz(200_000_000), Hertz(200_000_000)), | ||
| 390 | VoltageScale::Scale2 => (Hertz(150_000_000), Hertz(150_000_000)), | ||
| 391 | VoltageScale::Scale3 => (Hertz(100_000_000), Hertz(100_000_000)), | ||
| 392 | }; | ||
| 393 | #[cfg(stm32h7)] | ||
| 394 | let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { | ||
| 395 | VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)), | ||
| 396 | VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), | ||
| 397 | VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)), | ||
| 398 | VoltageScale::Scale3 => (Hertz(200_000_000), Hertz(100_000_000), Hertz(50_000_000)), | ||
| 399 | }; | ||
| 400 | |||
| 401 | #[cfg(stm32h7)] | ||
| 402 | let hclk = { | ||
| 403 | let d1cpre_clk = sys / config.d1c_pre; | ||
| 404 | assert!(d1cpre_clk <= d1cpre_clk_max); | ||
| 405 | sys / config.ahb_pre | ||
| 406 | }; | ||
| 407 | #[cfg(stm32h5)] | ||
| 408 | let hclk = sys / config.ahb_pre; | ||
| 409 | assert!(hclk <= hclk_max); | ||
| 410 | |||
| 411 | let apb1 = hclk / config.apb1_pre; | ||
| 412 | let apb1_tim = apb_div_tim(&config.apb1_pre, hclk, config.timer_prescaler); | ||
| 413 | assert!(apb1 <= pclk_max); | ||
| 414 | let apb2 = hclk / config.apb2_pre; | ||
| 415 | let apb2_tim = apb_div_tim(&config.apb2_pre, hclk, config.timer_prescaler); | ||
| 416 | assert!(apb2 <= pclk_max); | ||
| 417 | let apb3 = hclk / config.apb3_pre; | ||
| 418 | assert!(apb3 <= pclk_max); | ||
| 419 | #[cfg(stm32h7)] | ||
| 420 | let apb4 = hclk / config.apb4_pre; | ||
| 421 | #[cfg(stm32h7)] | ||
| 422 | assert!(apb4 <= pclk_max); | ||
| 423 | |||
| 424 | let _per_ck = match config.per_clock_source { | ||
| 425 | Ckpersel::HSI => hsi, | ||
| 426 | Ckpersel::CSI => csi, | ||
| 427 | Ckpersel::HSE => hse, | ||
| 428 | _ => unreachable!(), | ||
| 429 | }; | ||
| 430 | |||
| 431 | #[cfg(stm32h7)] | ||
| 432 | let adc = match config.adc_clock_source { | ||
| 433 | AdcClockSource::PLL2_P => pll2.p, | ||
| 434 | AdcClockSource::PLL3_R => _pll3.r, | ||
| 435 | AdcClockSource::PER => _per_ck, | ||
| 436 | _ => unreachable!(), | ||
| 437 | }; | ||
| 438 | #[cfg(stm32h5)] | ||
| 439 | let adc = match config.adc_clock_source { | ||
| 440 | AdcClockSource::HCLK => Some(hclk), | ||
| 441 | AdcClockSource::SYSCLK => Some(sys), | ||
| 442 | AdcClockSource::PLL2_R => pll2.r, | ||
| 443 | AdcClockSource::HSE => hse, | ||
| 444 | AdcClockSource::HSI_KER => hsi, | ||
| 445 | AdcClockSource::CSI_KER => csi, | ||
| 446 | _ => unreachable!(), | ||
| 447 | }; | ||
| 448 | |||
| 449 | flash_setup(hclk, config.voltage_scale); | ||
| 450 | |||
| 451 | #[cfg(stm32h7)] | ||
| 452 | { | ||
| 453 | RCC.d1cfgr().modify(|w| { | ||
| 454 | w.set_d1cpre(config.d1c_pre); | ||
| 455 | w.set_d1ppre(config.apb3_pre); | ||
| 456 | w.set_hpre(config.ahb_pre); | ||
| 457 | }); | ||
| 458 | // Ensure core prescaler value is valid before future lower core voltage | ||
| 459 | while RCC.d1cfgr().read().d1cpre() != config.d1c_pre {} | ||
| 460 | |||
| 461 | RCC.d2cfgr().modify(|w| { | ||
| 462 | w.set_d2ppre1(config.apb1_pre); | ||
| 463 | w.set_d2ppre2(config.apb2_pre); | ||
| 464 | }); | ||
| 465 | RCC.d3cfgr().modify(|w| { | ||
| 466 | w.set_d3ppre(config.apb4_pre); | ||
| 467 | }); | ||
| 468 | |||
| 469 | RCC.d1ccipr().modify(|w| { | ||
| 470 | w.set_ckpersel(config.per_clock_source); | ||
| 471 | }); | ||
| 472 | RCC.d3ccipr().modify(|w| { | ||
| 473 | w.set_adcsel(config.adc_clock_source); | ||
| 474 | }); | ||
| 475 | } | ||
| 476 | #[cfg(stm32h5)] | ||
| 477 | { | ||
| 478 | // Set hpre | ||
| 479 | RCC.cfgr2().modify(|w| w.set_hpre(config.ahb_pre)); | ||
| 480 | while RCC.cfgr2().read().hpre() != config.ahb_pre {} | ||
| 481 | |||
| 482 | // set ppre | ||
| 483 | RCC.cfgr2().modify(|w| { | ||
| 484 | w.set_ppre1(config.apb1_pre); | ||
| 485 | w.set_ppre2(config.apb2_pre); | ||
| 486 | w.set_ppre3(config.apb3_pre); | ||
| 487 | }); | ||
| 488 | |||
| 489 | RCC.ccipr5().modify(|w| { | ||
| 490 | w.set_ckpersel(config.per_clock_source); | ||
| 491 | w.set_adcdacsel(config.adc_clock_source) | ||
| 492 | }); | ||
| 493 | } | ||
| 494 | |||
| 495 | RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into())); | ||
| 496 | |||
| 497 | RCC.cfgr().modify(|w| w.set_sw(sw)); | ||
| 498 | while RCC.cfgr().read().sws() != sw {} | ||
| 499 | |||
| 500 | // IO compensation cell - Requires CSI clock and SYSCFG | ||
| 501 | #[cfg(stm32h7)] // TODO h5 | ||
| 502 | if csi.is_some() { | ||
| 503 | // Enable the compensation cell, using back-bias voltage code | ||
| 504 | // provide by the cell. | ||
| 505 | critical_section::with(|_| { | ||
| 506 | pac::SYSCFG.cccsr().modify(|w| { | ||
| 507 | w.set_en(true); | ||
| 508 | w.set_cs(false); | ||
| 509 | w.set_hslv(false); | ||
| 510 | }) | ||
| 511 | }); | ||
| 512 | while !pac::SYSCFG.cccsr().read().ready() {} | ||
| 513 | } | ||
| 514 | |||
| 515 | set_freqs(Clocks { | ||
| 516 | sys, | ||
| 517 | ahb1: hclk, | ||
| 518 | ahb2: hclk, | ||
| 519 | ahb3: hclk, | ||
| 520 | ahb4: hclk, | ||
| 521 | apb1, | ||
| 522 | apb2, | ||
| 523 | apb3, | ||
| 524 | #[cfg(stm32h7)] | ||
| 525 | apb4, | ||
| 526 | apb1_tim, | ||
| 527 | apb2_tim, | ||
| 528 | adc: adc, | ||
| 529 | }); | ||
| 530 | } | ||
| 531 | |||
| 532 | struct PllInput { | ||
| 533 | hsi: Option<Hertz>, | ||
| 534 | hse: Option<Hertz>, | ||
| 535 | csi: Option<Hertz>, | ||
| 536 | #[cfg(stm32h7)] | ||
| 537 | source: PllSource, | ||
| 538 | } | ||
| 539 | |||
| 540 | struct PllOutput { | ||
| 541 | p: Option<Hertz>, | ||
| 542 | #[allow(dead_code)] | ||
| 543 | q: Option<Hertz>, | ||
| 544 | #[allow(dead_code)] | ||
| 545 | r: Option<Hertz>, | ||
| 546 | } | ||
| 547 | |||
| 548 | fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput { | ||
| 549 | let Some(config) = config else { | ||
| 550 | // Stop PLL | ||
| 551 | RCC.cr().modify(|w| w.set_pllon(num, false)); | ||
| 552 | while RCC.cr().read().pllrdy(num) {} | ||
| 553 | |||
| 554 | // "To save power when PLL1 is not used, the value of PLL1M must be set to 0."" | ||
| 555 | #[cfg(stm32h7)] | ||
| 556 | RCC.pllckselr().write(|w| w.set_divm(num, 0)); | ||
| 557 | #[cfg(stm32h5)] | ||
| 558 | RCC.pllcfgr(num).write(|w| w.set_divm(0)); | ||
| 559 | |||
| 560 | return PllOutput { | ||
| 561 | p: None, | ||
| 562 | q: None, | ||
| 563 | r: None, | ||
| 564 | }; | ||
| 565 | }; | ||
| 566 | |||
| 567 | assert!(1 <= config.prediv && config.prediv <= 63); | ||
| 568 | assert!(4 <= config.mul && config.mul <= 512); | ||
| 569 | |||
| 570 | #[cfg(stm32h5)] | ||
| 571 | let source = config.source; | ||
| 572 | #[cfg(stm32h7)] | ||
| 573 | let source = input.source; | ||
| 574 | |||
| 575 | let (in_clk, src) = match source { | ||
| 576 | PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI), | ||
| 577 | PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE), | ||
| 578 | PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI), | ||
| 579 | }; | ||
| 580 | |||
| 581 | let ref_clk = in_clk / config.prediv as u32; | ||
| 582 | |||
| 583 | let ref_range = match ref_clk.0 { | ||
| 584 | ..=1_999_999 => Pllrge::RANGE1, | ||
| 585 | ..=3_999_999 => Pllrge::RANGE2, | ||
| 586 | ..=7_999_999 => Pllrge::RANGE4, | ||
| 587 | ..=16_000_000 => Pllrge::RANGE8, | ||
| 588 | x => panic!("pll ref_clk out of range: {} mhz", x), | ||
| 589 | }; | ||
| 590 | |||
| 591 | // The smaller range (150 to 420 MHz) must | ||
| 592 | // be chosen when the reference clock frequency is lower than 2 MHz. | ||
| 593 | let wide_allowed = ref_range != Pllrge::RANGE1; | ||
| 594 | |||
| 595 | let vco_clk = ref_clk * config.mul; | ||
| 596 | let vco_range = if VCO_RANGE.contains(&vco_clk.0) { | ||
| 597 | Pllvcosel::MEDIUMVCO | ||
| 598 | } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk.0) { | ||
| 599 | Pllvcosel::WIDEVCO | ||
| 600 | } else { | ||
| 601 | panic!("pll vco_clk out of range: {} mhz", vco_clk.0) | ||
| 602 | }; | ||
| 603 | |||
| 604 | let p = config.divp.map(|div| { | ||
| 605 | assert!(1 <= div && div <= 128); | ||
| 606 | if num == 0 { | ||
| 607 | // on PLL1, DIVP must be even. | ||
| 608 | assert!(div % 2 == 0); | ||
| 609 | } | ||
| 610 | |||
| 611 | vco_clk / div | ||
| 612 | }); | ||
| 613 | let q = config.divq.map(|div| { | ||
| 614 | assert!(1 <= div && div <= 128); | ||
| 615 | vco_clk / div | ||
| 616 | }); | ||
| 617 | let r = config.divr.map(|div| { | ||
| 618 | assert!(1 <= div && div <= 128); | ||
| 619 | vco_clk / div | ||
| 620 | }); | ||
| 621 | |||
| 622 | #[cfg(stm32h5)] | ||
| 623 | RCC.pllcfgr(num).write(|w| { | ||
| 624 | w.set_pllsrc(src); | ||
| 625 | w.set_divm(config.prediv); | ||
| 626 | w.set_pllvcosel(vco_range); | ||
| 627 | w.set_pllrge(ref_range); | ||
| 628 | w.set_pllfracen(false); | ||
| 629 | w.set_pllpen(p.is_some()); | ||
| 630 | w.set_pllqen(q.is_some()); | ||
| 631 | w.set_pllren(r.is_some()); | ||
| 632 | }); | ||
| 633 | |||
| 634 | #[cfg(stm32h7)] | ||
| 635 | { | ||
| 636 | RCC.pllckselr().modify(|w| { | ||
| 637 | w.set_divm(num, config.prediv); | ||
| 638 | w.set_pllsrc(src); | ||
| 639 | }); | ||
| 640 | RCC.pllcfgr().modify(|w| { | ||
| 641 | w.set_pllvcosel(num, vco_range); | ||
| 642 | w.set_pllrge(num, ref_range); | ||
| 643 | w.set_pllfracen(num, false); | ||
| 644 | w.set_divpen(num, p.is_some()); | ||
| 645 | w.set_divqen(num, q.is_some()); | ||
| 646 | w.set_divren(num, r.is_some()); | ||
| 647 | }); | ||
| 648 | } | ||
| 649 | |||
| 650 | RCC.plldivr(num).write(|w| { | ||
| 651 | w.set_plln(config.mul - 1); | ||
| 652 | w.set_pllp((config.divp.unwrap_or(1) - 1) as u8); | ||
| 653 | w.set_pllq((config.divq.unwrap_or(1) - 1) as u8); | ||
| 654 | w.set_pllr((config.divr.unwrap_or(1) - 1) as u8); | ||
| 655 | }); | ||
| 656 | |||
| 657 | RCC.cr().modify(|w| w.set_pllon(num, true)); | ||
| 658 | while !RCC.cr().read().pllrdy(num) {} | ||
| 659 | |||
| 660 | PllOutput { p, q, r } | ||
| 661 | } | ||
| 662 | |||
| 663 | fn flash_setup(clk: Hertz, vos: VoltageScale) { | ||
| 664 | // RM0481 Rev 1, table 37 | ||
| 665 | // LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0 | ||
| 666 | // 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz | ||
| 667 | // 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz | ||
| 668 | // 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz | ||
| 669 | // 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz | ||
| 670 | // 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz | ||
| 671 | // 5 2 170 to 200 MHz 210 to 250 MHz | ||
| 672 | #[cfg(stm32h5)] | ||
| 673 | let (latency, wrhighfreq) = match (vos, clk.0) { | ||
| 674 | (VoltageScale::Scale0, ..=42_000_000) => (0, 0), | ||
| 675 | (VoltageScale::Scale0, ..=84_000_000) => (1, 0), | ||
| 676 | (VoltageScale::Scale0, ..=126_000_000) => (2, 1), | ||
| 677 | (VoltageScale::Scale0, ..=168_000_000) => (3, 1), | ||
| 678 | (VoltageScale::Scale0, ..=210_000_000) => (4, 2), | ||
| 679 | (VoltageScale::Scale0, ..=250_000_000) => (5, 2), | ||
| 680 | |||
| 681 | (VoltageScale::Scale1, ..=34_000_000) => (0, 0), | ||
| 682 | (VoltageScale::Scale1, ..=68_000_000) => (1, 0), | ||
| 683 | (VoltageScale::Scale1, ..=102_000_000) => (2, 1), | ||
| 684 | (VoltageScale::Scale1, ..=136_000_000) => (3, 1), | ||
| 685 | (VoltageScale::Scale1, ..=170_000_000) => (4, 2), | ||
| 686 | (VoltageScale::Scale1, ..=200_000_000) => (5, 2), | ||
| 687 | |||
| 688 | (VoltageScale::Scale2, ..=30_000_000) => (0, 0), | ||
| 689 | (VoltageScale::Scale2, ..=60_000_000) => (1, 0), | ||
| 690 | (VoltageScale::Scale2, ..=90_000_000) => (2, 1), | ||
| 691 | (VoltageScale::Scale2, ..=120_000_000) => (3, 1), | ||
| 692 | (VoltageScale::Scale2, ..=150_000_000) => (4, 2), | ||
| 693 | |||
| 694 | (VoltageScale::Scale3, ..=20_000_000) => (0, 0), | ||
| 695 | (VoltageScale::Scale3, ..=40_000_000) => (1, 0), | ||
| 696 | (VoltageScale::Scale3, ..=60_000_000) => (2, 1), | ||
| 697 | (VoltageScale::Scale3, ..=80_000_000) => (3, 1), | ||
| 698 | (VoltageScale::Scale3, ..=100_000_000) => (4, 2), | ||
| 699 | |||
| 700 | _ => unreachable!(), | ||
| 701 | }; | ||
| 702 | |||
| 703 | #[cfg(flash_h7)] | ||
| 704 | let (latency, wrhighfreq) = match (vos, clk.0) { | ||
| 705 | // VOS 0 range VCORE 1.26V - 1.40V | ||
| 706 | (VoltageScale::Scale0, ..=70_000_000) => (0, 0), | ||
| 707 | (VoltageScale::Scale0, ..=140_000_000) => (1, 1), | ||
| 708 | (VoltageScale::Scale0, ..=185_000_000) => (2, 1), | ||
| 709 | (VoltageScale::Scale0, ..=210_000_000) => (2, 2), | ||
| 710 | (VoltageScale::Scale0, ..=225_000_000) => (3, 2), | ||
| 711 | (VoltageScale::Scale0, ..=240_000_000) => (4, 2), | ||
| 712 | // VOS 1 range VCORE 1.15V - 1.26V | ||
| 713 | (VoltageScale::Scale1, ..=70_000_000) => (0, 0), | ||
| 714 | (VoltageScale::Scale1, ..=140_000_000) => (1, 1), | ||
| 715 | (VoltageScale::Scale1, ..=185_000_000) => (2, 1), | ||
| 716 | (VoltageScale::Scale1, ..=210_000_000) => (2, 2), | ||
| 717 | (VoltageScale::Scale1, ..=225_000_000) => (3, 2), | ||
| 718 | // VOS 2 range VCORE 1.05V - 1.15V | ||
| 719 | (VoltageScale::Scale2, ..=55_000_000) => (0, 0), | ||
| 720 | (VoltageScale::Scale2, ..=110_000_000) => (1, 1), | ||
| 721 | (VoltageScale::Scale2, ..=165_000_000) => (2, 1), | ||
| 722 | (VoltageScale::Scale2, ..=224_000_000) => (3, 2), | ||
| 723 | // VOS 3 range VCORE 0.95V - 1.05V | ||
| 724 | (VoltageScale::Scale3, ..=45_000_000) => (0, 0), | ||
| 725 | (VoltageScale::Scale3, ..=90_000_000) => (1, 1), | ||
| 726 | (VoltageScale::Scale3, ..=135_000_000) => (2, 1), | ||
| 727 | (VoltageScale::Scale3, ..=180_000_000) => (3, 2), | ||
| 728 | (VoltageScale::Scale3, ..=224_000_000) => (4, 2), | ||
| 729 | _ => unreachable!(), | ||
| 730 | }; | ||
| 731 | |||
| 732 | // See RM0455 Rev 10 Table 16. FLASH recommended number of wait | ||
| 733 | // states and programming delay | ||
| 734 | #[cfg(flash_h7ab)] | ||
| 735 | let (latency, wrhighfreq) = match (vos, clk.0) { | ||
| 736 | // VOS 0 range VCORE 1.25V - 1.35V | ||
| 737 | (VoltageScale::Scale0, ..=42_000_000) => (0, 0), | ||
| 738 | (VoltageScale::Scale0, ..=84_000_000) => (1, 0), | ||
| 739 | (VoltageScale::Scale0, ..=126_000_000) => (2, 1), | ||
| 740 | (VoltageScale::Scale0, ..=168_000_000) => (3, 1), | ||
| 741 | (VoltageScale::Scale0, ..=210_000_000) => (4, 2), | ||
| 742 | (VoltageScale::Scale0, ..=252_000_000) => (5, 2), | ||
| 743 | (VoltageScale::Scale0, ..=280_000_000) => (6, 3), | ||
| 744 | // VOS 1 range VCORE 1.15V - 1.25V | ||
| 745 | (VoltageScale::Scale1, ..=38_000_000) => (0, 0), | ||
| 746 | (VoltageScale::Scale1, ..=76_000_000) => (1, 0), | ||
| 747 | (VoltageScale::Scale1, ..=114_000_000) => (2, 1), | ||
| 748 | (VoltageScale::Scale1, ..=152_000_000) => (3, 1), | ||
| 749 | (VoltageScale::Scale1, ..=190_000_000) => (4, 2), | ||
| 750 | (VoltageScale::Scale1, ..=225_000_000) => (5, 2), | ||
| 751 | // VOS 2 range VCORE 1.05V - 1.15V | ||
| 752 | (VoltageScale::Scale2, ..=34) => (0, 0), | ||
| 753 | (VoltageScale::Scale2, ..=68) => (1, 0), | ||
| 754 | (VoltageScale::Scale2, ..=102) => (2, 1), | ||
| 755 | (VoltageScale::Scale2, ..=136) => (3, 1), | ||
| 756 | (VoltageScale::Scale2, ..=160) => (4, 2), | ||
| 757 | // VOS 3 range VCORE 0.95V - 1.05V | ||
| 758 | (VoltageScale::Scale3, ..=22) => (0, 0), | ||
| 759 | (VoltageScale::Scale3, ..=44) => (1, 0), | ||
| 760 | (VoltageScale::Scale3, ..=66) => (2, 1), | ||
| 761 | (VoltageScale::Scale3, ..=88) => (3, 1), | ||
| 762 | _ => unreachable!(), | ||
| 763 | }; | ||
| 764 | |||
| 765 | debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); | ||
| 766 | |||
| 767 | FLASH.acr().write(|w| { | ||
| 768 | w.set_wrhighfreq(wrhighfreq); | ||
| 769 | w.set_latency(latency); | ||
| 770 | }); | ||
| 771 | while FLASH.acr().read().latency() != latency {} | ||
| 772 | } | ||
diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs deleted file mode 100644 index 2e72b1931..000000000 --- a/embassy-stm32/src/rcc/h5.rs +++ /dev/null | |||
| @@ -1,511 +0,0 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use stm32_metapac::rcc::vals::Timpre; | ||
| 4 | |||
| 5 | use crate::pac::pwr::vals::Vos; | ||
| 6 | use crate::pac::rcc::vals::{Hseext, Hsidiv, Mco1, Mco2, Pllrge, Pllsrc, Pllvcosel, Sw}; | ||
| 7 | use crate::pac::{FLASH, PWR, RCC}; | ||
| 8 | use crate::rcc::{set_freqs, Clocks}; | ||
| 9 | use crate::time::Hertz; | ||
| 10 | use crate::{peripherals, Peripheral}; | ||
| 11 | |||
| 12 | /// HSI speed | ||
| 13 | pub const HSI_FREQ: Hertz = Hertz(64_000_000); | ||
| 14 | |||
| 15 | /// CSI speed | ||
| 16 | pub const CSI_FREQ: Hertz = Hertz(4_000_000); | ||
| 17 | |||
| 18 | /// HSI48 speed | ||
| 19 | pub const HSI48_FREQ: Hertz = Hertz(48_000_000); | ||
| 20 | |||
| 21 | /// LSI speed | ||
| 22 | pub const LSI_FREQ: Hertz = Hertz(32_000); | ||
| 23 | |||
| 24 | const VCO_MIN: u32 = 150_000_000; | ||
| 25 | const VCO_MAX: u32 = 420_000_000; | ||
| 26 | const VCO_WIDE_MIN: u32 = 128_000_000; | ||
| 27 | const VCO_WIDE_MAX: u32 = 560_000_000; | ||
| 28 | |||
| 29 | pub use super::common::{AHBPrescaler, APBPrescaler, VoltageScale}; | ||
| 30 | |||
| 31 | pub enum HseMode { | ||
| 32 | /// crystal/ceramic oscillator (HSEBYP=0) | ||
| 33 | Oscillator, | ||
| 34 | /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) | ||
| 35 | BypassAnalog, | ||
| 36 | /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1) | ||
| 37 | BypassDigital, | ||
| 38 | } | ||
| 39 | |||
| 40 | pub struct Hse { | ||
| 41 | /// HSE frequency. | ||
| 42 | pub freq: Hertz, | ||
| 43 | /// HSE mode. | ||
| 44 | pub mode: HseMode, | ||
| 45 | } | ||
| 46 | |||
| 47 | pub enum Hsi { | ||
| 48 | /// 64Mhz | ||
| 49 | Mhz64, | ||
| 50 | /// 32Mhz (divided by 2) | ||
| 51 | Mhz32, | ||
| 52 | /// 16Mhz (divided by 4) | ||
| 53 | Mhz16, | ||
| 54 | /// 8Mhz (divided by 8) | ||
| 55 | Mhz8, | ||
| 56 | } | ||
| 57 | |||
| 58 | pub enum Sysclk { | ||
| 59 | /// HSI selected as sysclk | ||
| 60 | HSI, | ||
| 61 | /// HSE selected as sysclk | ||
| 62 | HSE, | ||
| 63 | /// CSI selected as sysclk | ||
| 64 | CSI, | ||
| 65 | /// PLL1_P selected as sysclk | ||
| 66 | Pll1P, | ||
| 67 | } | ||
| 68 | |||
| 69 | pub enum PllSource { | ||
| 70 | Hsi, | ||
| 71 | Csi, | ||
| 72 | Hse, | ||
| 73 | } | ||
| 74 | |||
| 75 | pub struct Pll { | ||
| 76 | /// Source clock selection. | ||
| 77 | pub source: PllSource, | ||
| 78 | |||
| 79 | /// PLL pre-divider (DIVM). Must be between 1 and 63. | ||
| 80 | pub prediv: u8, | ||
| 81 | |||
| 82 | /// PLL multiplication factor. Must be between 4 and 512. | ||
| 83 | pub mul: u16, | ||
| 84 | |||
| 85 | /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128. | ||
| 86 | /// On PLL1, it must be even (in particular, it cannot be 1.) | ||
| 87 | pub divp: Option<u16>, | ||
| 88 | /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128. | ||
| 89 | pub divq: Option<u16>, | ||
| 90 | /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128. | ||
| 91 | pub divr: Option<u16>, | ||
| 92 | } | ||
| 93 | |||
| 94 | impl APBPrescaler { | ||
| 95 | fn div_tim(&self, clk: Hertz, tim: TimerPrescaler) -> Hertz { | ||
| 96 | match (tim, self) { | ||
| 97 | // The timers kernel clock is equal to rcc_hclk1 if PPRE1 or PPRE2 corresponds to a | ||
| 98 | // division by 1 or 2, else it is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 | ||
| 99 | (TimerPrescaler::DefaultX2, Self::NotDivided) => clk, | ||
| 100 | (TimerPrescaler::DefaultX2, Self::Div2) => clk, | ||
| 101 | (TimerPrescaler::DefaultX2, Self::Div4) => clk / 2u32, | ||
| 102 | (TimerPrescaler::DefaultX2, Self::Div8) => clk / 4u32, | ||
| 103 | (TimerPrescaler::DefaultX2, Self::Div16) => clk / 8u32, | ||
| 104 | // The timers kernel clock is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 if PPRE1 or PPRE2 | ||
| 105 | // corresponds to a division by 1, 2 or 4, else it is equal to 4 x Frcc_pclk1 or 4 x Frcc_pclk2 | ||
| 106 | // this makes NO SENSE and is different than in the H7. Mistake in the RM?? | ||
| 107 | (TimerPrescaler::DefaultX4, Self::NotDivided) => clk * 2u32, | ||
| 108 | (TimerPrescaler::DefaultX4, Self::Div2) => clk, | ||
| 109 | (TimerPrescaler::DefaultX4, Self::Div4) => clk / 2u32, | ||
| 110 | (TimerPrescaler::DefaultX4, Self::Div8) => clk / 2u32, | ||
| 111 | (TimerPrescaler::DefaultX4, Self::Div16) => clk / 4u32, | ||
| 112 | } | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | /// APB prescaler | ||
| 117 | #[derive(Clone, Copy)] | ||
| 118 | pub enum TimerPrescaler { | ||
| 119 | DefaultX2, | ||
| 120 | DefaultX4, | ||
| 121 | } | ||
| 122 | |||
| 123 | impl From<TimerPrescaler> for Timpre { | ||
| 124 | fn from(value: TimerPrescaler) -> Self { | ||
| 125 | match value { | ||
| 126 | TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2, | ||
| 127 | TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4, | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | /// Configuration of the core clocks | ||
| 133 | #[non_exhaustive] | ||
| 134 | pub struct Config { | ||
| 135 | pub hsi: Option<Hsi>, | ||
| 136 | pub hse: Option<Hse>, | ||
| 137 | pub csi: bool, | ||
| 138 | pub hsi48: bool, | ||
| 139 | pub sys: Sysclk, | ||
| 140 | |||
| 141 | pub pll1: Option<Pll>, | ||
| 142 | pub pll2: Option<Pll>, | ||
| 143 | #[cfg(rcc_h5)] | ||
| 144 | pub pll3: Option<Pll>, | ||
| 145 | |||
| 146 | pub ahb_pre: AHBPrescaler, | ||
| 147 | pub apb1_pre: APBPrescaler, | ||
| 148 | pub apb2_pre: APBPrescaler, | ||
| 149 | pub apb3_pre: APBPrescaler, | ||
| 150 | pub timer_prescaler: TimerPrescaler, | ||
| 151 | |||
| 152 | pub voltage_scale: VoltageScale, | ||
| 153 | } | ||
| 154 | |||
| 155 | impl Default for Config { | ||
| 156 | fn default() -> Self { | ||
| 157 | Self { | ||
| 158 | hsi: Some(Hsi::Mhz64), | ||
| 159 | hse: None, | ||
| 160 | csi: false, | ||
| 161 | hsi48: false, | ||
| 162 | sys: Sysclk::HSI, | ||
| 163 | pll1: None, | ||
| 164 | pll2: None, | ||
| 165 | #[cfg(rcc_h5)] | ||
| 166 | pll3: None, | ||
| 167 | |||
| 168 | ahb_pre: AHBPrescaler::NotDivided, | ||
| 169 | apb1_pre: APBPrescaler::NotDivided, | ||
| 170 | apb2_pre: APBPrescaler::NotDivided, | ||
| 171 | apb3_pre: APBPrescaler::NotDivided, | ||
| 172 | timer_prescaler: TimerPrescaler::DefaultX2, | ||
| 173 | |||
| 174 | voltage_scale: VoltageScale::Scale3, | ||
| 175 | } | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | pub(crate) mod sealed { | ||
| 180 | pub trait McoInstance { | ||
| 181 | type Source; | ||
| 182 | unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8); | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | pub trait McoInstance: sealed::McoInstance + 'static {} | ||
| 187 | |||
| 188 | pin_trait!(McoPin, McoInstance); | ||
| 189 | |||
| 190 | macro_rules! impl_peri { | ||
| 191 | ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => { | ||
| 192 | impl sealed::McoInstance for peripherals::$peri { | ||
| 193 | type Source = $source; | ||
| 194 | |||
| 195 | unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) { | ||
| 196 | RCC.cfgr().modify(|w| { | ||
| 197 | w.$set_source(source); | ||
| 198 | w.$set_prescaler(prescaler); | ||
| 199 | }); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | impl McoInstance for peripherals::$peri {} | ||
| 204 | }; | ||
| 205 | } | ||
| 206 | |||
| 207 | impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre); | ||
| 208 | impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre); | ||
| 209 | |||
| 210 | pub struct Mco<'d, T: McoInstance> { | ||
| 211 | phantom: PhantomData<&'d mut T>, | ||
| 212 | } | ||
| 213 | |||
| 214 | impl<'d, T: McoInstance> Mco<'d, T> { | ||
| 215 | pub fn new( | ||
| 216 | _peri: impl Peripheral<P = T> + 'd, | ||
| 217 | _pin: impl Peripheral<P = impl McoPin<T>> + 'd, | ||
| 218 | _source: T::Source, | ||
| 219 | ) -> Self { | ||
| 220 | todo!(); | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | pub(crate) unsafe fn init(config: Config) { | ||
| 225 | let (vos, max_clk) = match config.voltage_scale { | ||
| 226 | VoltageScale::Scale0 => (Vos::SCALE0, Hertz(250_000_000)), | ||
| 227 | VoltageScale::Scale1 => (Vos::SCALE1, Hertz(200_000_000)), | ||
| 228 | VoltageScale::Scale2 => (Vos::SCALE2, Hertz(150_000_000)), | ||
| 229 | VoltageScale::Scale3 => (Vos::SCALE3, Hertz(100_000_000)), | ||
| 230 | }; | ||
| 231 | |||
| 232 | // Configure voltage scale. | ||
| 233 | PWR.voscr().modify(|w| w.set_vos(vos)); | ||
| 234 | while !PWR.vossr().read().vosrdy() {} | ||
| 235 | |||
| 236 | // Configure HSI | ||
| 237 | let hsi = match config.hsi { | ||
| 238 | None => { | ||
| 239 | RCC.cr().modify(|w| w.set_hsion(false)); | ||
| 240 | None | ||
| 241 | } | ||
| 242 | Some(hsi) => { | ||
| 243 | let (freq, hsidiv) = match hsi { | ||
| 244 | Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1), | ||
| 245 | Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2), | ||
| 246 | Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4), | ||
| 247 | Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8), | ||
| 248 | }; | ||
| 249 | RCC.cr().modify(|w| { | ||
| 250 | w.set_hsidiv(hsidiv); | ||
| 251 | w.set_hsion(true); | ||
| 252 | }); | ||
| 253 | while !RCC.cr().read().hsirdy() {} | ||
| 254 | Some(freq) | ||
| 255 | } | ||
| 256 | }; | ||
| 257 | |||
| 258 | // Configure HSE | ||
| 259 | let hse = match config.hse { | ||
| 260 | None => { | ||
| 261 | RCC.cr().modify(|w| w.set_hseon(false)); | ||
| 262 | None | ||
| 263 | } | ||
| 264 | Some(hse) => { | ||
| 265 | let (byp, ext) = match hse.mode { | ||
| 266 | HseMode::Oscillator => (false, Hseext::ANALOG), | ||
| 267 | HseMode::BypassAnalog => (true, Hseext::ANALOG), | ||
| 268 | HseMode::BypassDigital => (true, Hseext::DIGITAL), | ||
| 269 | }; | ||
| 270 | |||
| 271 | RCC.cr().modify(|w| { | ||
| 272 | w.set_hsebyp(byp); | ||
| 273 | w.set_hseext(ext); | ||
| 274 | }); | ||
| 275 | RCC.cr().modify(|w| w.set_hseon(true)); | ||
| 276 | while !RCC.cr().read().hserdy() {} | ||
| 277 | Some(hse.freq) | ||
| 278 | } | ||
| 279 | }; | ||
| 280 | |||
| 281 | // Configure HSI48. | ||
| 282 | RCC.cr().modify(|w| w.set_hsi48on(config.hsi48)); | ||
| 283 | let _hsi48 = match config.hsi48 { | ||
| 284 | false => None, | ||
| 285 | true => { | ||
| 286 | while !RCC.cr().read().hsi48rdy() {} | ||
| 287 | Some(CSI_FREQ) | ||
| 288 | } | ||
| 289 | }; | ||
| 290 | |||
| 291 | // Configure CSI. | ||
| 292 | RCC.cr().modify(|w| w.set_csion(config.csi)); | ||
| 293 | let csi = match config.csi { | ||
| 294 | false => None, | ||
| 295 | true => { | ||
| 296 | while !RCC.cr().read().csirdy() {} | ||
| 297 | Some(CSI_FREQ) | ||
| 298 | } | ||
| 299 | }; | ||
| 300 | |||
| 301 | // Configure PLLs. | ||
| 302 | let pll_input = PllInput { csi, hse, hsi }; | ||
| 303 | let pll1 = init_pll(0, config.pll1, &pll_input); | ||
| 304 | let _pll2 = init_pll(1, config.pll2, &pll_input); | ||
| 305 | #[cfg(rcc_h5)] | ||
| 306 | let _pll3 = init_pll(2, config.pll3, &pll_input); | ||
| 307 | |||
| 308 | // Configure sysclk | ||
| 309 | let (sys, sw) = match config.sys { | ||
| 310 | Sysclk::HSI => (unwrap!(hsi), Sw::HSI), | ||
| 311 | Sysclk::HSE => (unwrap!(hse), Sw::HSE), | ||
| 312 | Sysclk::CSI => (unwrap!(csi), Sw::CSI), | ||
| 313 | Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1), | ||
| 314 | }; | ||
| 315 | assert!(sys <= max_clk); | ||
| 316 | |||
| 317 | let hclk = sys / config.ahb_pre; | ||
| 318 | |||
| 319 | let apb1 = hclk / config.apb1_pre; | ||
| 320 | let apb1_tim = config.apb1_pre.div_tim(hclk, config.timer_prescaler); | ||
| 321 | let apb2 = hclk / config.apb2_pre; | ||
| 322 | let apb2_tim = config.apb2_pre.div_tim(hclk, config.timer_prescaler); | ||
| 323 | let apb3 = hclk / config.apb3_pre; | ||
| 324 | |||
| 325 | flash_setup(hclk, config.voltage_scale); | ||
| 326 | |||
| 327 | // Set hpre | ||
| 328 | let hpre = config.ahb_pre.into(); | ||
| 329 | RCC.cfgr2().modify(|w| w.set_hpre(hpre)); | ||
| 330 | while RCC.cfgr2().read().hpre() != hpre {} | ||
| 331 | |||
| 332 | // set ppre | ||
| 333 | RCC.cfgr2().modify(|w| { | ||
| 334 | w.set_ppre1(config.apb1_pre.into()); | ||
| 335 | w.set_ppre2(config.apb2_pre.into()); | ||
| 336 | w.set_ppre3(config.apb3_pre.into()); | ||
| 337 | }); | ||
| 338 | |||
| 339 | RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into())); | ||
| 340 | |||
| 341 | RCC.cfgr().modify(|w| w.set_sw(sw)); | ||
| 342 | while RCC.cfgr().read().sws() != sw {} | ||
| 343 | |||
| 344 | set_freqs(Clocks { | ||
| 345 | sys, | ||
| 346 | ahb1: hclk, | ||
| 347 | ahb2: hclk, | ||
| 348 | ahb3: hclk, | ||
| 349 | ahb4: hclk, | ||
| 350 | apb1, | ||
| 351 | apb2, | ||
| 352 | apb3, | ||
| 353 | apb1_tim, | ||
| 354 | apb2_tim, | ||
| 355 | adc: None, | ||
| 356 | }); | ||
| 357 | } | ||
| 358 | |||
| 359 | struct PllInput { | ||
| 360 | hsi: Option<Hertz>, | ||
| 361 | hse: Option<Hertz>, | ||
| 362 | csi: Option<Hertz>, | ||
| 363 | } | ||
| 364 | |||
| 365 | struct PllOutput { | ||
| 366 | p: Option<Hertz>, | ||
| 367 | #[allow(dead_code)] | ||
| 368 | q: Option<Hertz>, | ||
| 369 | #[allow(dead_code)] | ||
| 370 | r: Option<Hertz>, | ||
| 371 | } | ||
| 372 | |||
| 373 | fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput { | ||
| 374 | let Some(config) = config else { | ||
| 375 | // Stop PLL | ||
| 376 | RCC.cr().modify(|w| w.set_pllon(num, false)); | ||
| 377 | while RCC.cr().read().pllrdy(num) {} | ||
| 378 | |||
| 379 | // "To save power when PLL1 is not used, the value of PLL1M must be set to 0."" | ||
| 380 | RCC.pllcfgr(num).write(|w| { | ||
| 381 | w.set_divm(0); | ||
| 382 | }); | ||
| 383 | |||
| 384 | return PllOutput { | ||
| 385 | p: None, | ||
| 386 | q: None, | ||
| 387 | r: None, | ||
| 388 | }; | ||
| 389 | }; | ||
| 390 | |||
| 391 | assert!(1 <= config.prediv && config.prediv <= 63); | ||
| 392 | assert!(4 <= config.mul && config.mul <= 512); | ||
| 393 | |||
| 394 | let (in_clk, src) = match config.source { | ||
| 395 | PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI), | ||
| 396 | PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE), | ||
| 397 | PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI), | ||
| 398 | }; | ||
| 399 | |||
| 400 | let ref_clk = in_clk / config.prediv as u32; | ||
| 401 | |||
| 402 | let ref_range = match ref_clk.0 { | ||
| 403 | ..=1_999_999 => Pllrge::RANGE1, | ||
| 404 | ..=3_999_999 => Pllrge::RANGE2, | ||
| 405 | ..=7_999_999 => Pllrge::RANGE4, | ||
| 406 | ..=16_000_000 => Pllrge::RANGE8, | ||
| 407 | x => panic!("pll ref_clk out of range: {} mhz", x), | ||
| 408 | }; | ||
| 409 | |||
| 410 | // The smaller range (150 to 420 MHz) must | ||
| 411 | // be chosen when the reference clock frequency is lower than 2 MHz. | ||
| 412 | let wide_allowed = ref_range != Pllrge::RANGE1; | ||
| 413 | |||
| 414 | let vco_clk = ref_clk * config.mul; | ||
| 415 | let vco_range = match vco_clk.0 { | ||
| 416 | VCO_MIN..=VCO_MAX => Pllvcosel::MEDIUMVCO, | ||
| 417 | VCO_WIDE_MIN..=VCO_WIDE_MAX if wide_allowed => Pllvcosel::WIDEVCO, | ||
| 418 | x => panic!("pll vco_clk out of range: {} mhz", x), | ||
| 419 | }; | ||
| 420 | |||
| 421 | let p = config.divp.map(|div| { | ||
| 422 | assert!(1 <= div && div <= 128); | ||
| 423 | if num == 0 { | ||
| 424 | // on PLL1, DIVP must be even. | ||
| 425 | assert!(div % 2 == 0); | ||
| 426 | } | ||
| 427 | |||
| 428 | vco_clk / div | ||
| 429 | }); | ||
| 430 | let q = config.divq.map(|div| { | ||
| 431 | assert!(1 <= div && div <= 128); | ||
| 432 | vco_clk / div | ||
| 433 | }); | ||
| 434 | let r = config.divr.map(|div| { | ||
| 435 | assert!(1 <= div && div <= 128); | ||
| 436 | vco_clk / div | ||
| 437 | }); | ||
| 438 | |||
| 439 | RCC.pllcfgr(num).write(|w| { | ||
| 440 | w.set_pllsrc(src); | ||
| 441 | w.set_divm(config.prediv); | ||
| 442 | w.set_pllvcosel(vco_range); | ||
| 443 | w.set_pllrge(ref_range); | ||
| 444 | w.set_pllfracen(false); | ||
| 445 | w.set_pllpen(p.is_some()); | ||
| 446 | w.set_pllqen(q.is_some()); | ||
| 447 | w.set_pllren(r.is_some()); | ||
| 448 | }); | ||
| 449 | RCC.plldivr(num).write(|w| { | ||
| 450 | w.set_plln(config.mul - 1); | ||
| 451 | w.set_pllp((config.divp.unwrap_or(1) - 1) as u8); | ||
| 452 | w.set_pllq((config.divq.unwrap_or(1) - 1) as u8); | ||
| 453 | w.set_pllr((config.divr.unwrap_or(1) - 1) as u8); | ||
| 454 | }); | ||
| 455 | |||
| 456 | RCC.cr().modify(|w| w.set_pllon(num, true)); | ||
| 457 | while !RCC.cr().read().pllrdy(num) {} | ||
| 458 | |||
| 459 | PllOutput { p, q, r } | ||
| 460 | } | ||
| 461 | |||
| 462 | fn flash_setup(clk: Hertz, vos: VoltageScale) { | ||
| 463 | // RM0481 Rev 1, table 37 | ||
| 464 | // LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0 | ||
| 465 | // 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz | ||
| 466 | // 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz | ||
| 467 | // 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz | ||
| 468 | // 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz | ||
| 469 | // 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz | ||
| 470 | // 5 2 170 to 200 MHz 210 to 250 MHz | ||
| 471 | |||
| 472 | // See RM0433 Rev 7 Table 17. FLASH recommended number of wait | ||
| 473 | // states and programming delay | ||
| 474 | let (latency, wrhighfreq) = match (vos, clk.0) { | ||
| 475 | (VoltageScale::Scale0, ..=42_000_000) => (0, 0), | ||
| 476 | (VoltageScale::Scale0, ..=84_000_000) => (1, 0), | ||
| 477 | (VoltageScale::Scale0, ..=126_000_000) => (2, 1), | ||
| 478 | (VoltageScale::Scale0, ..=168_000_000) => (3, 1), | ||
| 479 | (VoltageScale::Scale0, ..=210_000_000) => (4, 2), | ||
| 480 | (VoltageScale::Scale0, ..=250_000_000) => (5, 2), | ||
| 481 | |||
| 482 | (VoltageScale::Scale1, ..=34_000_000) => (0, 0), | ||
| 483 | (VoltageScale::Scale1, ..=68_000_000) => (1, 0), | ||
| 484 | (VoltageScale::Scale1, ..=102_000_000) => (2, 1), | ||
| 485 | (VoltageScale::Scale1, ..=136_000_000) => (3, 1), | ||
| 486 | (VoltageScale::Scale1, ..=170_000_000) => (4, 2), | ||
| 487 | (VoltageScale::Scale1, ..=200_000_000) => (5, 2), | ||
| 488 | |||
| 489 | (VoltageScale::Scale2, ..=30_000_000) => (0, 0), | ||
| 490 | (VoltageScale::Scale2, ..=60_000_000) => (1, 0), | ||
| 491 | (VoltageScale::Scale2, ..=90_000_000) => (2, 1), | ||
| 492 | (VoltageScale::Scale2, ..=120_000_000) => (3, 1), | ||
| 493 | (VoltageScale::Scale2, ..=150_000_000) => (4, 2), | ||
| 494 | |||
| 495 | (VoltageScale::Scale3, ..=20_000_000) => (0, 0), | ||
| 496 | (VoltageScale::Scale3, ..=40_000_000) => (1, 0), | ||
| 497 | (VoltageScale::Scale3, ..=60_000_000) => (2, 1), | ||
| 498 | (VoltageScale::Scale3, ..=80_000_000) => (3, 1), | ||
| 499 | (VoltageScale::Scale3, ..=100_000_000) => (4, 2), | ||
| 500 | |||
| 501 | _ => unreachable!(), | ||
| 502 | }; | ||
| 503 | |||
| 504 | defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); | ||
| 505 | |||
| 506 | FLASH.acr().write(|w| { | ||
| 507 | w.set_wrhighfreq(wrhighfreq); | ||
| 508 | w.set_latency(latency); | ||
| 509 | }); | ||
| 510 | while FLASH.acr().read().latency() != latency {} | ||
| 511 | } | ||
diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs deleted file mode 100644 index 7fb4fb95b..000000000 --- a/embassy-stm32/src/rcc/h7.rs +++ /dev/null | |||
| @@ -1,879 +0,0 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy_hal_internal::into_ref; | ||
| 4 | pub use pll::PllConfig; | ||
| 5 | use stm32_metapac::rcc::vals::{Mco1, Mco2}; | ||
| 6 | |||
| 7 | use crate::gpio::sealed::AFType; | ||
| 8 | use crate::gpio::Speed; | ||
| 9 | use crate::pac::rcc::vals::{Adcsel, Ckpersel, Dppre, Hpre, Hsidiv, Pllsrc, Sw, Timpre}; | ||
| 10 | use crate::pac::{PWR, RCC, SYSCFG}; | ||
| 11 | use crate::rcc::{set_freqs, Clocks}; | ||
| 12 | use crate::time::Hertz; | ||
| 13 | use crate::{peripherals, Peripheral}; | ||
| 14 | |||
| 15 | /// HSI speed | ||
| 16 | pub const HSI_FREQ: Hertz = Hertz(64_000_000); | ||
| 17 | |||
| 18 | /// CSI speed | ||
| 19 | pub const CSI_FREQ: Hertz = Hertz(4_000_000); | ||
| 20 | |||
| 21 | /// HSI48 speed | ||
| 22 | pub const HSI48_FREQ: Hertz = Hertz(48_000_000); | ||
| 23 | |||
| 24 | /// LSI speed | ||
| 25 | pub const LSI_FREQ: Hertz = Hertz(32_000); | ||
| 26 | |||
| 27 | pub use super::common::VoltageScale; | ||
| 28 | |||
| 29 | #[derive(Clone, Copy)] | ||
| 30 | pub enum AdcClockSource { | ||
| 31 | Pll2PCk, | ||
| 32 | Pll3RCk, | ||
| 33 | PerCk, | ||
| 34 | } | ||
| 35 | |||
| 36 | impl AdcClockSource { | ||
| 37 | pub fn adcsel(&self) -> Adcsel { | ||
| 38 | match self { | ||
| 39 | AdcClockSource::Pll2PCk => Adcsel::PLL2_P, | ||
| 40 | AdcClockSource::Pll3RCk => Adcsel::PLL3_R, | ||
| 41 | AdcClockSource::PerCk => Adcsel::PER, | ||
| 42 | } | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | impl Default for AdcClockSource { | ||
| 47 | fn default() -> Self { | ||
| 48 | Self::Pll2PCk | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | /// Core clock frequencies | ||
| 53 | #[derive(Clone, Copy)] | ||
| 54 | pub struct CoreClocks { | ||
| 55 | pub hclk: Hertz, | ||
| 56 | pub pclk1: Hertz, | ||
| 57 | pub pclk2: Hertz, | ||
| 58 | pub pclk3: Hertz, | ||
| 59 | pub pclk4: Hertz, | ||
| 60 | pub ppre1: u8, | ||
| 61 | pub ppre2: u8, | ||
| 62 | pub ppre3: u8, | ||
| 63 | pub ppre4: u8, | ||
| 64 | pub csi_ck: Option<Hertz>, | ||
| 65 | pub hsi_ck: Option<Hertz>, | ||
| 66 | pub hsi48_ck: Option<Hertz>, | ||
| 67 | pub lsi_ck: Option<Hertz>, | ||
| 68 | pub per_ck: Option<Hertz>, | ||
| 69 | pub hse_ck: Option<Hertz>, | ||
| 70 | pub pll1_p_ck: Option<Hertz>, | ||
| 71 | pub pll1_q_ck: Option<Hertz>, | ||
| 72 | pub pll1_r_ck: Option<Hertz>, | ||
| 73 | pub pll2_p_ck: Option<Hertz>, | ||
| 74 | pub pll2_q_ck: Option<Hertz>, | ||
| 75 | pub pll2_r_ck: Option<Hertz>, | ||
| 76 | pub pll3_p_ck: Option<Hertz>, | ||
| 77 | pub pll3_q_ck: Option<Hertz>, | ||
| 78 | pub pll3_r_ck: Option<Hertz>, | ||
| 79 | pub timx_ker_ck: Option<Hertz>, | ||
| 80 | pub timy_ker_ck: Option<Hertz>, | ||
| 81 | pub adc_ker_ck: Option<Hertz>, | ||
| 82 | pub sys_ck: Hertz, | ||
| 83 | pub c_ck: Hertz, | ||
| 84 | } | ||
| 85 | |||
| 86 | /// Configuration of the core clocks | ||
| 87 | #[non_exhaustive] | ||
| 88 | #[derive(Default)] | ||
| 89 | pub struct Config { | ||
| 90 | pub hse: Option<Hertz>, | ||
| 91 | pub bypass_hse: bool, | ||
| 92 | pub sys_ck: Option<Hertz>, | ||
| 93 | pub per_ck: Option<Hertz>, | ||
| 94 | pub hclk: Option<Hertz>, | ||
| 95 | pub pclk1: Option<Hertz>, | ||
| 96 | pub pclk2: Option<Hertz>, | ||
| 97 | pub pclk3: Option<Hertz>, | ||
| 98 | pub pclk4: Option<Hertz>, | ||
| 99 | pub pll1: PllConfig, | ||
| 100 | pub pll2: PllConfig, | ||
| 101 | pub pll3: PllConfig, | ||
| 102 | pub adc_clock_source: AdcClockSource, | ||
| 103 | } | ||
| 104 | |||
| 105 | /// Setup traceclk | ||
| 106 | /// Returns a pll1_r_ck | ||
| 107 | fn traceclk_setup(config: &mut Config, sys_use_pll1_p: bool) { | ||
| 108 | let pll1_r_ck = match (sys_use_pll1_p, config.pll1.r_ck) { | ||
| 109 | // pll1_p_ck selected as system clock but pll1_r_ck not | ||
| 110 | // set. The traceclk mux is synchronous with the system | ||
| 111 | // clock mux, but has pll1_r_ck as an input. In order to | ||
| 112 | // keep traceclk running, we force a pll1_r_ck. | ||
| 113 | (true, None) => Some(Hertz(unwrap!(config.pll1.p_ck).0 / 2)), | ||
| 114 | |||
| 115 | // Either pll1 not selected as system clock, free choice | ||
| 116 | // of pll1_r_ck. Or pll1 is selected, assume user has set | ||
| 117 | // a suitable pll1_r_ck frequency. | ||
| 118 | _ => config.pll1.r_ck, | ||
| 119 | }; | ||
| 120 | config.pll1.r_ck = pll1_r_ck; | ||
| 121 | } | ||
| 122 | |||
| 123 | /// Divider calculator for pclk 1 - 4 | ||
| 124 | /// | ||
| 125 | /// Returns real pclk, bits, ppre and the timer kernel clock | ||
| 126 | fn ppre_calculate( | ||
| 127 | requested_pclk: u32, | ||
| 128 | hclk: u32, | ||
| 129 | max_pclk: u32, | ||
| 130 | tim_pre: Option<Timpre>, | ||
| 131 | ) -> (u32, u8, u8, Option<u32>) { | ||
| 132 | let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk { | ||
| 133 | 0 => panic!(), | ||
| 134 | 1 => (0b000, 1), | ||
| 135 | 2 => (0b100, 2), | ||
| 136 | 3..=5 => (0b101, 4), | ||
| 137 | 6..=11 => (0b110, 8), | ||
| 138 | _ => (0b111, 16), | ||
| 139 | }; | ||
| 140 | let real_pclk = hclk / u32::from(ppre); | ||
| 141 | assert!(real_pclk <= max_pclk); | ||
| 142 | |||
| 143 | let tim_ker_clk = if let Some(tim_pre) = tim_pre { | ||
| 144 | let clk = match (bits, tim_pre) { | ||
| 145 | (0b101, Timpre::DEFAULTX2) => hclk / 2, | ||
| 146 | (0b110, Timpre::DEFAULTX4) => hclk / 2, | ||
| 147 | (0b110, Timpre::DEFAULTX2) => hclk / 4, | ||
| 148 | (0b111, Timpre::DEFAULTX4) => hclk / 4, | ||
| 149 | (0b111, Timpre::DEFAULTX2) => hclk / 8, | ||
| 150 | _ => hclk, | ||
| 151 | }; | ||
| 152 | Some(clk) | ||
| 153 | } else { | ||
| 154 | None | ||
| 155 | }; | ||
| 156 | (real_pclk, bits, ppre, tim_ker_clk) | ||
| 157 | } | ||
| 158 | |||
| 159 | /// Setup sys_ck | ||
| 160 | /// Returns sys_ck frequency, and a pll1_p_ck | ||
| 161 | fn sys_ck_setup(config: &mut Config, srcclk: Hertz) -> (Hertz, bool) { | ||
| 162 | // Compare available with wanted clocks | ||
| 163 | let sys_ck = config.sys_ck.unwrap_or(srcclk); | ||
| 164 | |||
| 165 | if sys_ck != srcclk { | ||
| 166 | // The requested system clock is not the immediately available | ||
| 167 | // HSE/HSI clock. Perhaps there are other ways of obtaining | ||
| 168 | // the requested system clock (such as `HSIDIV`) but we will | ||
| 169 | // ignore those for now. | ||
| 170 | // | ||
| 171 | // Therefore we must use pll1_p_ck | ||
| 172 | let pll1_p_ck = match config.pll1.p_ck { | ||
| 173 | Some(p_ck) => { | ||
| 174 | assert!( | ||
| 175 | p_ck == sys_ck, | ||
| 176 | "Error: Cannot set pll1_p_ck independently as it must be used to generate sys_ck" | ||
| 177 | ); | ||
| 178 | Some(p_ck) | ||
| 179 | } | ||
| 180 | None => Some(sys_ck), | ||
| 181 | }; | ||
| 182 | config.pll1.p_ck = pll1_p_ck; | ||
| 183 | |||
| 184 | (sys_ck, true) | ||
| 185 | } else { | ||
| 186 | // sys_ck is derived directly from a source clock | ||
| 187 | // (HSE/HSI). pll1_p_ck can be as requested | ||
| 188 | (sys_ck, false) | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | fn flash_setup(rcc_aclk: u32, vos: VoltageScale) { | ||
| 193 | use crate::pac::FLASH; | ||
| 194 | |||
| 195 | // ACLK in MHz, round down and subtract 1 from integers. eg. | ||
| 196 | // 61_999_999 -> 61MHz | ||
| 197 | // 62_000_000 -> 61MHz | ||
| 198 | // 62_000_001 -> 62MHz | ||
| 199 | let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000; | ||
| 200 | |||
| 201 | // See RM0433 Rev 7 Table 17. FLASH recommended number of wait | ||
| 202 | // states and programming delay | ||
| 203 | #[cfg(flash_h7)] | ||
| 204 | let (wait_states, progr_delay) = match vos { | ||
| 205 | // VOS 0 range VCORE 1.26V - 1.40V | ||
| 206 | VoltageScale::Scale0 => match rcc_aclk_mhz { | ||
| 207 | 0..=69 => (0, 0), | ||
| 208 | 70..=139 => (1, 1), | ||
| 209 | 140..=184 => (2, 1), | ||
| 210 | 185..=209 => (2, 2), | ||
| 211 | 210..=224 => (3, 2), | ||
| 212 | 225..=239 => (4, 2), | ||
| 213 | _ => (7, 3), | ||
| 214 | }, | ||
| 215 | // VOS 1 range VCORE 1.15V - 1.26V | ||
| 216 | VoltageScale::Scale1 => match rcc_aclk_mhz { | ||
| 217 | 0..=69 => (0, 0), | ||
| 218 | 70..=139 => (1, 1), | ||
| 219 | 140..=184 => (2, 1), | ||
| 220 | 185..=209 => (2, 2), | ||
| 221 | 210..=224 => (3, 2), | ||
| 222 | _ => (7, 3), | ||
| 223 | }, | ||
| 224 | // VOS 2 range VCORE 1.05V - 1.15V | ||
| 225 | VoltageScale::Scale2 => match rcc_aclk_mhz { | ||
| 226 | 0..=54 => (0, 0), | ||
| 227 | 55..=109 => (1, 1), | ||
| 228 | 110..=164 => (2, 1), | ||
| 229 | 165..=224 => (3, 2), | ||
| 230 | _ => (7, 3), | ||
| 231 | }, | ||
| 232 | // VOS 3 range VCORE 0.95V - 1.05V | ||
| 233 | VoltageScale::Scale3 => match rcc_aclk_mhz { | ||
| 234 | 0..=44 => (0, 0), | ||
| 235 | 45..=89 => (1, 1), | ||
| 236 | 90..=134 => (2, 1), | ||
| 237 | 135..=179 => (3, 2), | ||
| 238 | 180..=224 => (4, 2), | ||
| 239 | _ => (7, 3), | ||
| 240 | }, | ||
| 241 | }; | ||
| 242 | |||
| 243 | // See RM0455 Rev 10 Table 16. FLASH recommended number of wait | ||
| 244 | // states and programming delay | ||
| 245 | #[cfg(flash_h7ab)] | ||
| 246 | let (wait_states, progr_delay) = match vos { | ||
| 247 | // VOS 0 range VCORE 1.25V - 1.35V | ||
| 248 | VoltageScale::Scale0 => match rcc_aclk_mhz { | ||
| 249 | 0..=42 => (0, 0), | ||
| 250 | 43..=84 => (1, 0), | ||
| 251 | 85..=126 => (2, 1), | ||
| 252 | 127..=168 => (3, 1), | ||
| 253 | 169..=210 => (4, 2), | ||
| 254 | 211..=252 => (5, 2), | ||
| 255 | 253..=280 => (6, 3), | ||
| 256 | _ => (7, 3), | ||
| 257 | }, | ||
| 258 | // VOS 1 range VCORE 1.15V - 1.25V | ||
| 259 | VoltageScale::Scale1 => match rcc_aclk_mhz { | ||
| 260 | 0..=38 => (0, 0), | ||
| 261 | 39..=76 => (1, 0), | ||
| 262 | 77..=114 => (2, 1), | ||
| 263 | 115..=152 => (3, 1), | ||
| 264 | 153..=190 => (4, 2), | ||
| 265 | 191..=225 => (5, 2), | ||
| 266 | _ => (7, 3), | ||
| 267 | }, | ||
| 268 | // VOS 2 range VCORE 1.05V - 1.15V | ||
| 269 | VoltageScale::Scale2 => match rcc_aclk_mhz { | ||
| 270 | 0..=34 => (0, 0), | ||
| 271 | 35..=68 => (1, 0), | ||
| 272 | 69..=102 => (2, 1), | ||
| 273 | 103..=136 => (3, 1), | ||
| 274 | 137..=160 => (4, 2), | ||
| 275 | _ => (7, 3), | ||
| 276 | }, | ||
| 277 | // VOS 3 range VCORE 0.95V - 1.05V | ||
| 278 | VoltageScale::Scale3 => match rcc_aclk_mhz { | ||
| 279 | 0..=22 => (0, 0), | ||
| 280 | 23..=44 => (1, 0), | ||
| 281 | 45..=66 => (2, 1), | ||
| 282 | 67..=88 => (3, 1), | ||
| 283 | _ => (7, 3), | ||
| 284 | }, | ||
| 285 | }; | ||
| 286 | |||
| 287 | FLASH.acr().write(|w| { | ||
| 288 | w.set_wrhighfreq(progr_delay); | ||
| 289 | w.set_latency(wait_states) | ||
| 290 | }); | ||
| 291 | while FLASH.acr().read().latency() != wait_states {} | ||
| 292 | } | ||
| 293 | |||
| 294 | pub enum McoClock { | ||
| 295 | Disabled, | ||
| 296 | Bypassed, | ||
| 297 | Divided(u8), | ||
| 298 | } | ||
| 299 | |||
| 300 | impl McoClock { | ||
| 301 | fn into_raw(&self) -> u8 { | ||
| 302 | match self { | ||
| 303 | McoClock::Disabled => 0, | ||
| 304 | McoClock::Bypassed => 1, | ||
| 305 | McoClock::Divided(divisor) => { | ||
| 306 | if *divisor > 15 { | ||
| 307 | panic!("Mco divisor must be less than 15. Refer to the reference manual for more information.") | ||
| 308 | } | ||
| 309 | *divisor | ||
| 310 | } | ||
| 311 | } | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 315 | #[derive(Copy, Clone)] | ||
| 316 | pub enum Mco1Source { | ||
| 317 | Hsi, | ||
| 318 | Lse, | ||
| 319 | Hse, | ||
| 320 | Pll1Q, | ||
| 321 | Hsi48, | ||
| 322 | } | ||
| 323 | |||
| 324 | impl Default for Mco1Source { | ||
| 325 | fn default() -> Self { | ||
| 326 | Self::Hsi | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | pub trait McoSource { | ||
| 331 | type Raw; | ||
| 332 | |||
| 333 | fn into_raw(&self) -> Self::Raw; | ||
| 334 | } | ||
| 335 | |||
| 336 | impl McoSource for Mco1Source { | ||
| 337 | type Raw = Mco1; | ||
| 338 | fn into_raw(&self) -> Self::Raw { | ||
| 339 | match self { | ||
| 340 | Mco1Source::Hsi => Mco1::HSI, | ||
| 341 | Mco1Source::Lse => Mco1::LSE, | ||
| 342 | Mco1Source::Hse => Mco1::HSE, | ||
| 343 | Mco1Source::Pll1Q => Mco1::PLL1_Q, | ||
| 344 | Mco1Source::Hsi48 => Mco1::HSI48, | ||
| 345 | } | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | #[derive(Copy, Clone)] | ||
| 350 | pub enum Mco2Source { | ||
| 351 | SysClk, | ||
| 352 | Pll2Q, | ||
| 353 | Hse, | ||
| 354 | Pll1Q, | ||
| 355 | Csi, | ||
| 356 | Lsi, | ||
| 357 | } | ||
| 358 | |||
| 359 | impl Default for Mco2Source { | ||
| 360 | fn default() -> Self { | ||
| 361 | Self::SysClk | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | impl McoSource for Mco2Source { | ||
| 366 | type Raw = Mco2; | ||
| 367 | fn into_raw(&self) -> Self::Raw { | ||
| 368 | match self { | ||
| 369 | Mco2Source::SysClk => Mco2::SYSCLK, | ||
| 370 | Mco2Source::Pll2Q => Mco2::PLL2_P, | ||
| 371 | Mco2Source::Hse => Mco2::HSE, | ||
| 372 | Mco2Source::Pll1Q => Mco2::PLL1_P, | ||
| 373 | Mco2Source::Csi => Mco2::CSI, | ||
| 374 | Mco2Source::Lsi => Mco2::LSI, | ||
| 375 | } | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | pub(crate) mod sealed { | ||
| 380 | pub trait McoInstance { | ||
| 381 | type Source; | ||
| 382 | unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8); | ||
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | pub trait McoInstance: sealed::McoInstance + 'static {} | ||
| 387 | |||
| 388 | pin_trait!(McoPin, McoInstance); | ||
| 389 | |||
| 390 | macro_rules! impl_peri { | ||
| 391 | ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => { | ||
| 392 | impl sealed::McoInstance for peripherals::$peri { | ||
| 393 | type Source = $source; | ||
| 394 | |||
| 395 | unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) { | ||
| 396 | RCC.cfgr().modify(|w| { | ||
| 397 | w.$set_source(source); | ||
| 398 | w.$set_prescaler(prescaler); | ||
| 399 | }); | ||
| 400 | } | ||
| 401 | } | ||
| 402 | |||
| 403 | impl McoInstance for peripherals::$peri {} | ||
| 404 | }; | ||
| 405 | } | ||
| 406 | |||
| 407 | impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre); | ||
| 408 | impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre); | ||
| 409 | |||
| 410 | pub struct Mco<'d, T: McoInstance> { | ||
| 411 | phantom: PhantomData<&'d mut T>, | ||
| 412 | } | ||
| 413 | |||
| 414 | impl<'d, T: McoInstance> Mco<'d, T> { | ||
| 415 | pub fn new( | ||
| 416 | _peri: impl Peripheral<P = T> + 'd, | ||
| 417 | pin: impl Peripheral<P = impl McoPin<T>> + 'd, | ||
| 418 | source: impl McoSource<Raw = T::Source>, | ||
| 419 | prescaler: McoClock, | ||
| 420 | ) -> Self { | ||
| 421 | into_ref!(pin); | ||
| 422 | |||
| 423 | critical_section::with(|_| unsafe { | ||
| 424 | T::apply_clock_settings(source.into_raw(), prescaler.into_raw()); | ||
| 425 | pin.set_as_af(pin.af_num(), AFType::OutputPushPull); | ||
| 426 | pin.set_speed(Speed::VeryHigh); | ||
| 427 | }); | ||
| 428 | |||
| 429 | Self { phantom: PhantomData } | ||
| 430 | } | ||
| 431 | } | ||
| 432 | |||
| 433 | pub(crate) unsafe fn init(mut config: Config) { | ||
| 434 | // TODO make configurable? | ||
| 435 | let enable_overdrive = false; | ||
| 436 | |||
| 437 | // NB. The lower bytes of CR3 can only be written once after | ||
| 438 | // POR, and must be written with a valid combination. Refer to | ||
| 439 | // RM0433 Rev 7 6.8.4. This is partially enforced by dropping | ||
| 440 | // `self` at the end of this method, but of course we cannot | ||
| 441 | // know what happened between the previous POR and here. | ||
| 442 | #[cfg(pwr_h7)] | ||
| 443 | PWR.cr3().modify(|w| { | ||
| 444 | w.set_scuen(true); | ||
| 445 | w.set_ldoen(true); | ||
| 446 | w.set_bypass(false); | ||
| 447 | }); | ||
| 448 | |||
| 449 | #[cfg(pwr_h7smps)] | ||
| 450 | PWR.cr3().modify(|w| { | ||
| 451 | // hardcode "Direct SPMS" for now, this is what works on nucleos with the | ||
| 452 | // default solderbridge configuration. | ||
| 453 | w.set_sden(true); | ||
| 454 | w.set_ldoen(false); | ||
| 455 | }); | ||
| 456 | |||
| 457 | // Validate the supply configuration. If you are stuck here, it is | ||
| 458 | // because the voltages on your board do not match those specified | ||
| 459 | // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset | ||
| 460 | // VOS = Scale 3, so check that the voltage on the VCAP pins = | ||
| 461 | // 1.0V. | ||
| 462 | while !PWR.csr1().read().actvosrdy() {} | ||
| 463 | |||
| 464 | // Go to Scale 1 | ||
| 465 | PWR.d3cr().modify(|w| w.set_vos(0b11)); | ||
| 466 | while !PWR.d3cr().read().vosrdy() {} | ||
| 467 | |||
| 468 | let pwr_vos = if !enable_overdrive { | ||
| 469 | VoltageScale::Scale1 | ||
| 470 | } else { | ||
| 471 | critical_section::with(|_| { | ||
| 472 | RCC.apb4enr().modify(|w| w.set_syscfgen(true)); | ||
| 473 | |||
| 474 | SYSCFG.pwrcr().modify(|w| w.set_oden(1)); | ||
| 475 | }); | ||
| 476 | while !PWR.d3cr().read().vosrdy() {} | ||
| 477 | VoltageScale::Scale0 | ||
| 478 | }; | ||
| 479 | |||
| 480 | // Freeze the core clocks, returning a Core Clocks Distribution | ||
| 481 | // and Reset (CCDR) structure. The actual frequency of the clocks | ||
| 482 | // configured is returned in the `clocks` member of the CCDR | ||
| 483 | // structure. | ||
| 484 | // | ||
| 485 | // Note that `freeze` will never result in a clock _faster_ than | ||
| 486 | // that specified. It may result in a clock that is a factor of [1, | ||
| 487 | // 2) slower. | ||
| 488 | // | ||
| 489 | // `syscfg` is required to enable the I/O compensation cell. | ||
| 490 | // | ||
| 491 | // # Panics | ||
| 492 | // | ||
| 493 | // If a clock specification cannot be achieved within the | ||
| 494 | // hardware specification then this function will panic. This | ||
| 495 | // function may also panic if a clock specification can be | ||
| 496 | // achieved, but the mechanism for doing so is not yet | ||
| 497 | // implemented here. | ||
| 498 | |||
| 499 | let srcclk = config.hse.unwrap_or(HSI_FREQ); // Available clocks | ||
| 500 | let (sys_ck, sys_use_pll1_p) = sys_ck_setup(&mut config, srcclk); | ||
| 501 | |||
| 502 | // Configure traceclk from PLL if needed | ||
| 503 | traceclk_setup(&mut config, sys_use_pll1_p); | ||
| 504 | |||
| 505 | let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0); | ||
| 506 | let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1); | ||
| 507 | let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2); | ||
| 508 | |||
| 509 | let sys_ck = if sys_use_pll1_p { | ||
| 510 | Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup | ||
| 511 | } else { | ||
| 512 | sys_ck | ||
| 513 | }; | ||
| 514 | |||
| 515 | // This routine does not support HSIDIV != 1. To | ||
| 516 | // do so it would need to ensure all PLLxON bits are clear | ||
| 517 | // before changing the value of HSIDIV | ||
| 518 | let cr = RCC.cr().read(); | ||
| 519 | assert!(cr.hsion()); | ||
| 520 | assert!(cr.hsidiv() == Hsidiv::DIV1); | ||
| 521 | |||
| 522 | RCC.csr().modify(|w| w.set_lsion(true)); | ||
| 523 | while !RCC.csr().read().lsirdy() {} | ||
| 524 | |||
| 525 | // per_ck from HSI by default | ||
| 526 | let (per_ck, ckpersel) = match (config.per_ck == config.hse, config.per_ck) { | ||
| 527 | (true, Some(hse)) => (hse, Ckpersel::HSE), // HSE | ||
| 528 | (_, Some(CSI_FREQ)) => (CSI_FREQ, Ckpersel::CSI), // CSI | ||
| 529 | _ => (HSI_FREQ, Ckpersel::HSI), // HSI | ||
| 530 | }; | ||
| 531 | |||
| 532 | // D1 Core Prescaler | ||
| 533 | // Set to 1 | ||
| 534 | let d1cpre_bits = 0; | ||
| 535 | let d1cpre_div = 1; | ||
| 536 | let sys_d1cpre_ck = sys_ck.0 / d1cpre_div; | ||
| 537 | |||
| 538 | // Refer to part datasheet "General operating conditions" | ||
| 539 | // table for (rev V). We do not assert checks for earlier | ||
| 540 | // revisions which may have lower limits. | ||
| 541 | let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr_vos { | ||
| 542 | VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000), | ||
| 543 | VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000), | ||
| 544 | VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000), | ||
| 545 | _ => (200_000_000, 100_000_000, 50_000_000), | ||
| 546 | }; | ||
| 547 | assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max); | ||
| 548 | |||
| 549 | let rcc_hclk = config.hclk.map(|v| v.0).unwrap_or(sys_d1cpre_ck / 2); | ||
| 550 | assert!(rcc_hclk <= rcc_hclk_max); | ||
| 551 | |||
| 552 | // Estimate divisor | ||
| 553 | let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk { | ||
| 554 | 0 => panic!(), | ||
| 555 | 1 => (Hpre::DIV1, 1), | ||
| 556 | 2 => (Hpre::DIV2, 2), | ||
| 557 | 3..=5 => (Hpre::DIV4, 4), | ||
| 558 | 6..=11 => (Hpre::DIV8, 8), | ||
| 559 | 12..=39 => (Hpre::DIV16, 16), | ||
| 560 | 40..=95 => (Hpre::DIV64, 64), | ||
| 561 | 96..=191 => (Hpre::DIV128, 128), | ||
| 562 | 192..=383 => (Hpre::DIV256, 256), | ||
| 563 | _ => (Hpre::DIV512, 512), | ||
| 564 | }; | ||
| 565 | // Calculate real AXI and AHB clock | ||
| 566 | let rcc_hclk = sys_d1cpre_ck / hpre_div; | ||
| 567 | assert!(rcc_hclk <= rcc_hclk_max); | ||
| 568 | let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7 | ||
| 569 | // Timer prescaler selection | ||
| 570 | let timpre = Timpre::DEFAULTX2; | ||
| 571 | |||
| 572 | let requested_pclk1 = config.pclk1.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 573 | let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) = | ||
| 574 | ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre)); | ||
| 575 | |||
| 576 | let requested_pclk2 = config.pclk2.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 577 | let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) = | ||
| 578 | ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre)); | ||
| 579 | |||
| 580 | let requested_pclk3 = config.pclk3.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 581 | let (rcc_pclk3, ppre3_bits, ppre3, _) = ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None); | ||
| 582 | |||
| 583 | let requested_pclk4 = config.pclk4.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 584 | let (rcc_pclk4, ppre4_bits, ppre4, _) = ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None); | ||
| 585 | |||
| 586 | // Start switching clocks ------------------- | ||
| 587 | |||
| 588 | // Ensure CSI is on and stable | ||
| 589 | RCC.cr().modify(|w| w.set_csion(true)); | ||
| 590 | while !RCC.cr().read().csirdy() {} | ||
| 591 | |||
| 592 | // Ensure HSI48 is on and stable | ||
| 593 | RCC.cr().modify(|w| w.set_hsi48on(true)); | ||
| 594 | while !RCC.cr().read().hsi48on() {} | ||
| 595 | |||
| 596 | // XXX: support MCO ? | ||
| 597 | |||
| 598 | let hse_ck = match config.hse { | ||
| 599 | Some(hse) => { | ||
| 600 | // Ensure HSE is on and stable | ||
| 601 | RCC.cr().modify(|w| { | ||
| 602 | w.set_hseon(true); | ||
| 603 | w.set_hsebyp(config.bypass_hse); | ||
| 604 | }); | ||
| 605 | while !RCC.cr().read().hserdy() {} | ||
| 606 | Some(hse) | ||
| 607 | } | ||
| 608 | None => None, | ||
| 609 | }; | ||
| 610 | |||
| 611 | let pllsrc = if config.hse.is_some() { Pllsrc::HSE } else { Pllsrc::HSI }; | ||
| 612 | RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc)); | ||
| 613 | |||
| 614 | let enable_pll = |pll| { | ||
| 615 | RCC.cr().modify(|w| w.set_pllon(pll, true)); | ||
| 616 | while !RCC.cr().read().pllrdy(pll) {} | ||
| 617 | }; | ||
| 618 | |||
| 619 | if pll1_p_ck.is_some() { | ||
| 620 | enable_pll(0); | ||
| 621 | } | ||
| 622 | |||
| 623 | if pll2_p_ck.is_some() { | ||
| 624 | enable_pll(1); | ||
| 625 | } | ||
| 626 | |||
| 627 | if pll3_p_ck.is_some() { | ||
| 628 | enable_pll(2); | ||
| 629 | } | ||
| 630 | |||
| 631 | // Core Prescaler / AHB Prescaler / APB3 Prescaler | ||
| 632 | RCC.d1cfgr().modify(|w| { | ||
| 633 | w.set_d1cpre(Hpre::from_bits(d1cpre_bits)); | ||
| 634 | w.set_d1ppre(Dppre::from_bits(ppre3_bits)); | ||
| 635 | w.set_hpre(hpre_bits) | ||
| 636 | }); | ||
| 637 | // Ensure core prescaler value is valid before future lower | ||
| 638 | // core voltage | ||
| 639 | while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {} | ||
| 640 | |||
| 641 | flash_setup(rcc_aclk, pwr_vos); | ||
| 642 | |||
| 643 | // APB1 / APB2 Prescaler | ||
| 644 | RCC.d2cfgr().modify(|w| { | ||
| 645 | w.set_d2ppre1(Dppre::from_bits(ppre1_bits)); | ||
| 646 | w.set_d2ppre2(Dppre::from_bits(ppre2_bits)); | ||
| 647 | }); | ||
| 648 | |||
| 649 | // APB4 Prescaler | ||
| 650 | RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre::from_bits(ppre4_bits))); | ||
| 651 | |||
| 652 | // Peripheral Clock (per_ck) | ||
| 653 | RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel)); | ||
| 654 | |||
| 655 | // ADC clock MUX | ||
| 656 | RCC.d3ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel())); | ||
| 657 | |||
| 658 | let adc_ker_ck = match config.adc_clock_source { | ||
| 659 | AdcClockSource::Pll2PCk => pll2_p_ck.map(Hertz), | ||
| 660 | AdcClockSource::Pll3RCk => pll3_r_ck.map(Hertz), | ||
| 661 | AdcClockSource::PerCk => Some(per_ck), | ||
| 662 | }; | ||
| 663 | |||
| 664 | // Set timer clocks prescaler setting | ||
| 665 | RCC.cfgr().modify(|w| w.set_timpre(timpre)); | ||
| 666 | |||
| 667 | // Select system clock source | ||
| 668 | let sw = match (sys_use_pll1_p, config.hse.is_some()) { | ||
| 669 | (true, _) => Sw::PLL1, | ||
| 670 | (false, true) => Sw::HSE, | ||
| 671 | _ => Sw::HSI, | ||
| 672 | }; | ||
| 673 | RCC.cfgr().modify(|w| w.set_sw(sw)); | ||
| 674 | while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {} | ||
| 675 | |||
| 676 | // IO compensation cell - Requires CSI clock and SYSCFG | ||
| 677 | assert!(RCC.cr().read().csirdy()); | ||
| 678 | RCC.apb4enr().modify(|w| w.set_syscfgen(true)); | ||
| 679 | |||
| 680 | // Enable the compensation cell, using back-bias voltage code | ||
| 681 | // provide by the cell. | ||
| 682 | critical_section::with(|_| { | ||
| 683 | SYSCFG.cccsr().modify(|w| { | ||
| 684 | w.set_en(true); | ||
| 685 | w.set_cs(false); | ||
| 686 | w.set_hslv(false); | ||
| 687 | }) | ||
| 688 | }); | ||
| 689 | while !SYSCFG.cccsr().read().ready() {} | ||
| 690 | |||
| 691 | let core_clocks = CoreClocks { | ||
| 692 | hclk: Hertz(rcc_hclk), | ||
| 693 | pclk1: Hertz(rcc_pclk1), | ||
| 694 | pclk2: Hertz(rcc_pclk2), | ||
| 695 | pclk3: Hertz(rcc_pclk3), | ||
| 696 | pclk4: Hertz(rcc_pclk4), | ||
| 697 | ppre1, | ||
| 698 | ppre2, | ||
| 699 | ppre3, | ||
| 700 | ppre4, | ||
| 701 | csi_ck: Some(CSI_FREQ), | ||
| 702 | hsi_ck: Some(HSI_FREQ), | ||
| 703 | hsi48_ck: Some(HSI48_FREQ), | ||
| 704 | lsi_ck: Some(LSI_FREQ), | ||
| 705 | per_ck: Some(per_ck), | ||
| 706 | hse_ck, | ||
| 707 | pll1_p_ck: pll1_p_ck.map(Hertz), | ||
| 708 | pll1_q_ck: pll1_q_ck.map(Hertz), | ||
| 709 | pll1_r_ck: pll1_r_ck.map(Hertz), | ||
| 710 | pll2_p_ck: pll2_p_ck.map(Hertz), | ||
| 711 | pll2_q_ck: pll2_q_ck.map(Hertz), | ||
| 712 | pll2_r_ck: pll2_r_ck.map(Hertz), | ||
| 713 | pll3_p_ck: pll3_p_ck.map(Hertz), | ||
| 714 | pll3_q_ck: pll3_q_ck.map(Hertz), | ||
| 715 | pll3_r_ck: pll3_r_ck.map(Hertz), | ||
| 716 | timx_ker_ck: rcc_timerx_ker_ck.map(Hertz), | ||
| 717 | timy_ker_ck: rcc_timery_ker_ck.map(Hertz), | ||
| 718 | adc_ker_ck, | ||
| 719 | sys_ck, | ||
| 720 | c_ck: Hertz(sys_d1cpre_ck), | ||
| 721 | }; | ||
| 722 | |||
| 723 | set_freqs(Clocks { | ||
| 724 | sys: core_clocks.c_ck, | ||
| 725 | ahb1: core_clocks.hclk, | ||
| 726 | ahb2: core_clocks.hclk, | ||
| 727 | ahb3: core_clocks.hclk, | ||
| 728 | ahb4: core_clocks.hclk, | ||
| 729 | apb1: core_clocks.pclk1, | ||
| 730 | apb2: core_clocks.pclk2, | ||
| 731 | apb4: core_clocks.pclk4, | ||
| 732 | apb1_tim: core_clocks.timx_ker_ck.unwrap_or(core_clocks.pclk1), | ||
| 733 | apb2_tim: core_clocks.timy_ker_ck.unwrap_or(core_clocks.pclk2), | ||
| 734 | adc: core_clocks.adc_ker_ck, | ||
| 735 | }); | ||
| 736 | } | ||
| 737 | |||
| 738 | mod pll { | ||
| 739 | use super::{Hertz, RCC}; | ||
| 740 | |||
| 741 | const VCO_MIN: u32 = 150_000_000; | ||
| 742 | const VCO_MAX: u32 = 420_000_000; | ||
| 743 | |||
| 744 | #[derive(Default)] | ||
| 745 | pub struct PllConfig { | ||
| 746 | pub p_ck: Option<Hertz>, | ||
| 747 | pub q_ck: Option<Hertz>, | ||
| 748 | pub r_ck: Option<Hertz>, | ||
| 749 | } | ||
| 750 | |||
| 751 | pub(super) struct PllConfigResults { | ||
| 752 | pub ref_x_ck: u32, | ||
| 753 | pub pll_x_m: u32, | ||
| 754 | pub pll_x_p: u32, | ||
| 755 | pub vco_ck_target: u32, | ||
| 756 | } | ||
| 757 | |||
| 758 | fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) { | ||
| 759 | let pll_x_p = if plln == 0 { | ||
| 760 | if output > VCO_MAX / 2 { | ||
| 761 | 1 | ||
| 762 | } else { | ||
| 763 | ((VCO_MAX / output) | 1) - 1 // Must be even or unity | ||
| 764 | } | ||
| 765 | } else { | ||
| 766 | // Specific to PLL2/3, will subtract 1 later | ||
| 767 | if output > VCO_MAX / 2 { | ||
| 768 | 1 | ||
| 769 | } else { | ||
| 770 | VCO_MAX / output | ||
| 771 | } | ||
| 772 | }; | ||
| 773 | |||
| 774 | let vco_ck = output * pll_x_p; | ||
| 775 | |||
| 776 | assert!(pll_x_p < 128); | ||
| 777 | assert!(vco_ck >= VCO_MIN); | ||
| 778 | assert!(vco_ck <= VCO_MAX); | ||
| 779 | |||
| 780 | (vco_ck, pll_x_p) | ||
| 781 | } | ||
| 782 | |||
| 783 | /// # Safety | ||
| 784 | /// | ||
| 785 | /// Must have exclusive access to the RCC register block | ||
| 786 | fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults { | ||
| 787 | use crate::pac::rcc::vals::{Pllrge, Pllvcosel}; | ||
| 788 | |||
| 789 | let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln); | ||
| 790 | |||
| 791 | // Input divisor, resulting in a reference clock in the range | ||
| 792 | // 1 to 2 MHz. Choose the highest reference clock (lowest m) | ||
| 793 | let pll_x_m = (pll_src + 1_999_999) / 2_000_000; | ||
| 794 | assert!(pll_x_m < 64); | ||
| 795 | |||
| 796 | // Calculate resulting reference clock | ||
| 797 | let ref_x_ck = pll_src / pll_x_m; | ||
| 798 | assert!((1_000_000..=2_000_000).contains(&ref_x_ck)); | ||
| 799 | |||
| 800 | RCC.pllcfgr().modify(|w| { | ||
| 801 | w.set_pllvcosel(plln, Pllvcosel::MEDIUMVCO); | ||
| 802 | w.set_pllrge(plln, Pllrge::RANGE1); | ||
| 803 | }); | ||
| 804 | PllConfigResults { | ||
| 805 | ref_x_ck, | ||
| 806 | pll_x_m, | ||
| 807 | pll_x_p, | ||
| 808 | vco_ck_target, | ||
| 809 | } | ||
| 810 | } | ||
| 811 | |||
| 812 | /// # Safety | ||
| 813 | /// | ||
| 814 | /// Must have exclusive access to the RCC register block | ||
| 815 | pub(super) fn pll_setup(pll_src: u32, config: &PllConfig, plln: usize) -> (Option<u32>, Option<u32>, Option<u32>) { | ||
| 816 | use crate::pac::rcc::vals::Divp; | ||
| 817 | |||
| 818 | match config.p_ck { | ||
| 819 | Some(requested_output) => { | ||
| 820 | let config_results = vco_setup(pll_src, requested_output.0, plln); | ||
| 821 | let PllConfigResults { | ||
| 822 | ref_x_ck, | ||
| 823 | pll_x_m, | ||
| 824 | pll_x_p, | ||
| 825 | vco_ck_target, | ||
| 826 | } = config_results; | ||
| 827 | |||
| 828 | RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8)); | ||
| 829 | |||
| 830 | // Feedback divider. Integer only | ||
| 831 | let pll_x_n = vco_ck_target / ref_x_ck; | ||
| 832 | assert!(pll_x_n >= 4); | ||
| 833 | assert!(pll_x_n <= 512); | ||
| 834 | RCC.plldivr(plln).modify(|w| w.set_divn1((pll_x_n - 1) as u16)); | ||
| 835 | |||
| 836 | // No FRACN | ||
| 837 | RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false)); | ||
| 838 | let vco_ck = ref_x_ck * pll_x_n; | ||
| 839 | |||
| 840 | RCC.plldivr(plln) | ||
| 841 | .modify(|w| w.set_divp1(Divp::from_bits((pll_x_p - 1) as u8))); | ||
| 842 | RCC.pllcfgr().modify(|w| w.set_divpen(plln, true)); | ||
| 843 | |||
| 844 | // Calulate additional output dividers | ||
| 845 | let q_ck = match config.q_ck { | ||
| 846 | Some(Hertz(ck)) if ck > 0 => { | ||
| 847 | let div = (vco_ck + ck - 1) / ck; | ||
| 848 | RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8)); | ||
| 849 | RCC.pllcfgr().modify(|w| w.set_divqen(plln, true)); | ||
| 850 | Some(vco_ck / div) | ||
| 851 | } | ||
| 852 | _ => None, | ||
| 853 | }; | ||
| 854 | let r_ck = match config.r_ck { | ||
| 855 | Some(Hertz(ck)) if ck > 0 => { | ||
| 856 | let div = (vco_ck + ck - 1) / ck; | ||
| 857 | RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8)); | ||
| 858 | RCC.pllcfgr().modify(|w| w.set_divren(plln, true)); | ||
| 859 | Some(vco_ck / div) | ||
| 860 | } | ||
| 861 | _ => None, | ||
| 862 | }; | ||
| 863 | |||
| 864 | (Some(vco_ck / pll_x_p), q_ck, r_ck) | ||
| 865 | } | ||
| 866 | None => { | ||
| 867 | assert!( | ||
| 868 | config.q_ck.is_none(), | ||
| 869 | "Must set PLL P clock for Q clock to take effect!" | ||
| 870 | ); | ||
| 871 | assert!( | ||
| 872 | config.r_ck.is_none(), | ||
| 873 | "Must set PLL P clock for R clock to take effect!" | ||
| 874 | ); | ||
| 875 | (None, None, None) | ||
| 876 | } | ||
| 877 | } | ||
| 878 | } | ||
| 879 | } | ||
diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index 46b58ca7c..7358be31b 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs | |||
| @@ -1,8 +1,11 @@ | |||
| 1 | pub use super::common::{AHBPrescaler, APBPrescaler}; | 1 | use super::bd::BackupDomain; |
| 2 | pub use super::bus::{AHBPrescaler, APBPrescaler}; | ||
| 3 | use super::RtcClockSource; | ||
| 4 | pub use crate::pac::pwr::vals::Vos as VoltageScale; | ||
| 2 | use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; | 5 | use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; |
| 3 | use crate::pac::RCC; | ||
| 4 | #[cfg(crs)] | 6 | #[cfg(crs)] |
| 5 | use crate::pac::{crs, CRS, SYSCFG}; | 7 | use crate::pac::{crs, CRS, SYSCFG}; |
| 8 | use crate::pac::{FLASH, PWR, RCC}; | ||
| 6 | use crate::rcc::{set_freqs, Clocks}; | 9 | use crate::rcc::{set_freqs, Clocks}; |
| 7 | use crate::time::Hertz; | 10 | use crate::time::Hertz; |
| 8 | 11 | ||
| @@ -135,6 +138,10 @@ pub struct Config { | |||
| 135 | pub apb2_pre: APBPrescaler, | 138 | pub apb2_pre: APBPrescaler, |
| 136 | #[cfg(crs)] | 139 | #[cfg(crs)] |
| 137 | pub enable_hsi48: bool, | 140 | pub enable_hsi48: bool, |
| 141 | pub rtc: Option<RtcClockSource>, | ||
| 142 | pub lse: Option<Hertz>, | ||
| 143 | pub lsi: bool, | ||
| 144 | pub voltage_scale: VoltageScale, | ||
| 138 | } | 145 | } |
| 139 | 146 | ||
| 140 | impl Default for Config { | 147 | impl Default for Config { |
| @@ -142,16 +149,25 @@ impl Default for Config { | |||
| 142 | fn default() -> Config { | 149 | fn default() -> Config { |
| 143 | Config { | 150 | Config { |
| 144 | mux: ClockSrc::MSI(MSIRange::default()), | 151 | mux: ClockSrc::MSI(MSIRange::default()), |
| 145 | ahb_pre: AHBPrescaler::NotDivided, | 152 | ahb_pre: AHBPrescaler::DIV1, |
| 146 | apb1_pre: APBPrescaler::NotDivided, | 153 | apb1_pre: APBPrescaler::DIV1, |
| 147 | apb2_pre: APBPrescaler::NotDivided, | 154 | apb2_pre: APBPrescaler::DIV1, |
| 148 | #[cfg(crs)] | 155 | #[cfg(crs)] |
| 149 | enable_hsi48: false, | 156 | enable_hsi48: false, |
| 157 | rtc: None, | ||
| 158 | lse: None, | ||
| 159 | lsi: false, | ||
| 160 | voltage_scale: VoltageScale::RANGE1, | ||
| 150 | } | 161 | } |
| 151 | } | 162 | } |
| 152 | } | 163 | } |
| 153 | 164 | ||
| 154 | pub(crate) unsafe fn init(config: Config) { | 165 | pub(crate) unsafe fn init(config: Config) { |
| 166 | // Set voltage scale | ||
| 167 | while PWR.csr().read().vosf() {} | ||
| 168 | PWR.cr().write(|w| w.set_vos(config.voltage_scale)); | ||
| 169 | while PWR.csr().read().vosf() {} | ||
| 170 | |||
| 155 | let (sys_clk, sw) = match config.mux { | 171 | let (sys_clk, sw) = match config.mux { |
| 156 | ClockSrc::MSI(range) => { | 172 | ClockSrc::MSI(range) => { |
| 157 | // Set MSI range | 173 | // Set MSI range |
| @@ -231,6 +247,28 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 231 | } | 247 | } |
| 232 | }; | 248 | }; |
| 233 | 249 | ||
| 250 | BackupDomain::configure_ls( | ||
| 251 | config.rtc.unwrap_or(RtcClockSource::NOCLOCK), | ||
| 252 | config.lsi, | ||
| 253 | config.lse.map(|_| Default::default()), | ||
| 254 | ); | ||
| 255 | |||
| 256 | let wait_states = match config.voltage_scale { | ||
| 257 | VoltageScale::RANGE1 => match sys_clk { | ||
| 258 | ..=16_000_000 => 0, | ||
| 259 | _ => 1, | ||
| 260 | }, | ||
| 261 | VoltageScale::RANGE2 => match sys_clk { | ||
| 262 | ..=8_000_000 => 0, | ||
| 263 | _ => 1, | ||
| 264 | }, | ||
| 265 | VoltageScale::RANGE3 => 0, | ||
| 266 | _ => unreachable!(), | ||
| 267 | }; | ||
| 268 | FLASH.acr().modify(|w| { | ||
| 269 | w.set_latency(wait_states != 0); | ||
| 270 | }); | ||
| 271 | |||
| 234 | RCC.cfgr().modify(|w| { | 272 | RCC.cfgr().modify(|w| { |
| 235 | w.set_sw(sw); | 273 | w.set_sw(sw); |
| 236 | w.set_hpre(config.ahb_pre.into()); | 274 | w.set_hpre(config.ahb_pre.into()); |
| @@ -239,7 +277,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 239 | }); | 277 | }); |
| 240 | 278 | ||
| 241 | let ahb_freq: u32 = match config.ahb_pre { | 279 | let ahb_freq: u32 = match config.ahb_pre { |
| 242 | AHBPrescaler::NotDivided => sys_clk, | 280 | AHBPrescaler::DIV1 => sys_clk, |
| 243 | pre => { | 281 | pre => { |
| 244 | let pre: Hpre = pre.into(); | 282 | let pre: Hpre = pre.into(); |
| 245 | let pre = 1 << (pre.to_bits() as u32 - 7); | 283 | let pre = 1 << (pre.to_bits() as u32 - 7); |
| @@ -248,7 +286,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 248 | }; | 286 | }; |
| 249 | 287 | ||
| 250 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | 288 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { |
| 251 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 289 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 252 | pre => { | 290 | pre => { |
| 253 | let pre: Ppre = pre.into(); | 291 | let pre: Ppre = pre.into(); |
| 254 | let pre: u8 = 1 << (pre.to_bits() - 3); | 292 | let pre: u8 = 1 << (pre.to_bits() - 3); |
| @@ -258,7 +296,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 258 | }; | 296 | }; |
| 259 | 297 | ||
| 260 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | 298 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { |
| 261 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 299 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 262 | pre => { | 300 | pre => { |
| 263 | let pre: Ppre = pre.into(); | 301 | let pre: Ppre = pre.into(); |
| 264 | let pre: u8 = 1 << (pre.to_bits() - 3); | 302 | let pre: u8 = 1 << (pre.to_bits() - 3); |
| @@ -269,13 +307,6 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 269 | 307 | ||
| 270 | #[cfg(crs)] | 308 | #[cfg(crs)] |
| 271 | if config.enable_hsi48 { | 309 | if config.enable_hsi48 { |
| 272 | // Reset SYSCFG peripheral | ||
| 273 | RCC.apb2rstr().modify(|w| w.set_syscfgrst(true)); | ||
| 274 | RCC.apb2rstr().modify(|w| w.set_syscfgrst(false)); | ||
| 275 | |||
| 276 | // Enable SYSCFG peripheral | ||
| 277 | RCC.apb2enr().modify(|w| w.set_syscfgen(true)); | ||
| 278 | |||
| 279 | // Reset CRS peripheral | 310 | // Reset CRS peripheral |
| 280 | RCC.apb1rstr().modify(|w| w.set_crsrst(true)); | 311 | RCC.apb1rstr().modify(|w| w.set_crsrst(true)); |
| 281 | RCC.apb1rstr().modify(|w| w.set_crsrst(false)); | 312 | RCC.apb1rstr().modify(|w| w.set_crsrst(false)); |
diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs index bdfc5b87a..90524fb37 100644 --- a/embassy-stm32/src/rcc/l1.rs +++ b/embassy-stm32/src/rcc/l1.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | pub use super::common::{AHBPrescaler, APBPrescaler}; | 1 | pub use super::bus::{AHBPrescaler, APBPrescaler}; |
| 2 | use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; | 2 | use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; |
| 3 | use crate::pac::{FLASH, RCC}; | 3 | use crate::pac::{FLASH, RCC}; |
| 4 | use crate::rcc::{set_freqs, Clocks}; | 4 | use crate::rcc::{set_freqs, Clocks}; |
| @@ -138,9 +138,9 @@ impl Default for Config { | |||
| 138 | fn default() -> Config { | 138 | fn default() -> Config { |
| 139 | Config { | 139 | Config { |
| 140 | mux: ClockSrc::MSI(MSIRange::default()), | 140 | mux: ClockSrc::MSI(MSIRange::default()), |
| 141 | ahb_pre: AHBPrescaler::NotDivided, | 141 | ahb_pre: AHBPrescaler::DIV1, |
| 142 | apb1_pre: APBPrescaler::NotDivided, | 142 | apb1_pre: APBPrescaler::DIV1, |
| 143 | apb2_pre: APBPrescaler::NotDivided, | 143 | apb2_pre: APBPrescaler::DIV1, |
| 144 | } | 144 | } |
| 145 | } | 145 | } |
| 146 | } | 146 | } |
| @@ -240,7 +240,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 240 | }); | 240 | }); |
| 241 | 241 | ||
| 242 | let ahb_freq: u32 = match config.ahb_pre { | 242 | let ahb_freq: u32 = match config.ahb_pre { |
| 243 | AHBPrescaler::NotDivided => sys_clk, | 243 | AHBPrescaler::DIV1 => sys_clk, |
| 244 | pre => { | 244 | pre => { |
| 245 | let pre: Hpre = pre.into(); | 245 | let pre: Hpre = pre.into(); |
| 246 | let pre = 1 << (pre.to_bits() as u32 - 7); | 246 | let pre = 1 << (pre.to_bits() as u32 - 7); |
| @@ -249,7 +249,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 249 | }; | 249 | }; |
| 250 | 250 | ||
| 251 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | 251 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { |
| 252 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 252 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 253 | pre => { | 253 | pre => { |
| 254 | let pre: Ppre = pre.into(); | 254 | let pre: Ppre = pre.into(); |
| 255 | let pre: u8 = 1 << (pre.to_bits() - 3); | 255 | let pre: u8 = 1 << (pre.to_bits() - 3); |
| @@ -259,7 +259,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 259 | }; | 259 | }; |
| 260 | 260 | ||
| 261 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | 261 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { |
| 262 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 262 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 263 | pre => { | 263 | pre => { |
| 264 | let pre: Ppre = pre.into(); | 264 | let pre: Ppre = pre.into(); |
| 265 | let pre: u8 = 1 << (pre.to_bits() - 3); | 265 | let pre: u8 = 1 << (pre.to_bits() - 3); |
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index b34b8caab..6f1f7458c 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs | |||
| @@ -2,15 +2,15 @@ use core::marker::PhantomData; | |||
| 2 | 2 | ||
| 3 | use embassy_hal_internal::into_ref; | 3 | use embassy_hal_internal::into_ref; |
| 4 | use stm32_metapac::rcc::regs::Cfgr; | 4 | use stm32_metapac::rcc::regs::Cfgr; |
| 5 | use stm32_metapac::rcc::vals::{Lsedrv, Mcopre, Mcosel}; | 5 | use stm32_metapac::rcc::vals::{Mcopre, Mcosel}; |
| 6 | 6 | ||
| 7 | pub use super::common::{AHBPrescaler, APBPrescaler}; | 7 | pub use super::bus::{AHBPrescaler, APBPrescaler}; |
| 8 | use crate::gpio::sealed::AFType; | 8 | use crate::gpio::sealed::AFType; |
| 9 | use crate::gpio::Speed; | 9 | use crate::gpio::Speed; |
| 10 | use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; | 10 | use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; |
| 11 | use crate::pac::{FLASH, PWR, RCC}; | 11 | use crate::pac::{FLASH, RCC}; |
| 12 | use crate::rcc::bd::{BackupDomain, RtcClockSource}; | ||
| 12 | use crate::rcc::{set_freqs, Clocks}; | 13 | use crate::rcc::{set_freqs, Clocks}; |
| 13 | use crate::rtc::{Rtc, RtcClockSource as RCS}; | ||
| 14 | use crate::time::Hertz; | 14 | use crate::time::Hertz; |
| 15 | use crate::{peripherals, Peripheral}; | 15 | use crate::{peripherals, Peripheral}; |
| 16 | 16 | ||
| @@ -241,6 +241,8 @@ pub struct Config { | |||
| 241 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] | 241 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] |
| 242 | pub hsi48: bool, | 242 | pub hsi48: bool, |
| 243 | pub rtc_mux: RtcClockSource, | 243 | pub rtc_mux: RtcClockSource, |
| 244 | pub lse: Option<Hertz>, | ||
| 245 | pub lsi: bool, | ||
| 244 | } | 246 | } |
| 245 | 247 | ||
| 246 | impl Default for Config { | 248 | impl Default for Config { |
| @@ -248,22 +250,19 @@ impl Default for Config { | |||
| 248 | fn default() -> Config { | 250 | fn default() -> Config { |
| 249 | Config { | 251 | Config { |
| 250 | mux: ClockSrc::MSI(MSIRange::Range6), | 252 | mux: ClockSrc::MSI(MSIRange::Range6), |
| 251 | ahb_pre: AHBPrescaler::NotDivided, | 253 | ahb_pre: AHBPrescaler::DIV1, |
| 252 | apb1_pre: APBPrescaler::NotDivided, | 254 | apb1_pre: APBPrescaler::DIV1, |
| 253 | apb2_pre: APBPrescaler::NotDivided, | 255 | apb2_pre: APBPrescaler::DIV1, |
| 254 | pllsai1: None, | 256 | pllsai1: None, |
| 255 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] | 257 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] |
| 256 | hsi48: false, | 258 | hsi48: false, |
| 257 | rtc_mux: RtcClockSource::LSI32, | 259 | rtc_mux: RtcClockSource::LSI, |
| 260 | lsi: true, | ||
| 261 | lse: None, | ||
| 258 | } | 262 | } |
| 259 | } | 263 | } |
| 260 | } | 264 | } |
| 261 | 265 | ||
| 262 | pub enum RtcClockSource { | ||
| 263 | LSE32, | ||
| 264 | LSI32, | ||
| 265 | } | ||
| 266 | |||
| 267 | pub enum McoClock { | 266 | pub enum McoClock { |
| 268 | DIV1, | 267 | DIV1, |
| 269 | DIV2, | 268 | DIV2, |
| @@ -410,37 +409,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 410 | while RCC.cfgr().read().sws() != Sw::MSI {} | 409 | while RCC.cfgr().read().sws() != Sw::MSI {} |
| 411 | } | 410 | } |
| 412 | 411 | ||
| 413 | RCC.apb1enr1().modify(|w| w.set_pwren(true)); | 412 | BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default())); |
| 414 | |||
| 415 | match config.rtc_mux { | ||
| 416 | RtcClockSource::LSE32 => { | ||
| 417 | // 1. Unlock the backup domain | ||
| 418 | PWR.cr1().modify(|w| w.set_dbp(true)); | ||
| 419 | |||
| 420 | // 2. Setup the LSE | ||
| 421 | RCC.bdcr().modify(|w| { | ||
| 422 | // Enable LSE | ||
| 423 | w.set_lseon(true); | ||
| 424 | // Max drive strength | ||
| 425 | // TODO: should probably be settable | ||
| 426 | w.set_lsedrv(Lsedrv::HIGH); | ||
| 427 | }); | ||
| 428 | |||
| 429 | // Wait until LSE is running | ||
| 430 | while !RCC.bdcr().read().lserdy() {} | ||
| 431 | |||
| 432 | Rtc::set_clock_source(RCS::LSE); | ||
| 433 | } | ||
| 434 | RtcClockSource::LSI32 => { | ||
| 435 | // Turn on the internal 32 kHz LSI oscillator | ||
| 436 | RCC.csr().modify(|w| w.set_lsion(true)); | ||
| 437 | |||
| 438 | // Wait until LSI is running | ||
| 439 | while !RCC.csr().read().lsirdy() {} | ||
| 440 | |||
| 441 | Rtc::set_clock_source(RCS::LSI); | ||
| 442 | } | ||
| 443 | } | ||
| 444 | 413 | ||
| 445 | let (sys_clk, sw) = match config.mux { | 414 | let (sys_clk, sw) = match config.mux { |
| 446 | ClockSrc::MSI(range) => { | 415 | ClockSrc::MSI(range) => { |
| @@ -451,7 +420,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 451 | w.set_msirgsel(true); | 420 | w.set_msirgsel(true); |
| 452 | w.set_msion(true); | 421 | w.set_msion(true); |
| 453 | 422 | ||
| 454 | if let RtcClockSource::LSE32 = config.rtc_mux { | 423 | if let RtcClockSource::LSE = config.rtc_mux { |
| 455 | // If LSE is enabled, enable calibration of MSI | 424 | // If LSE is enabled, enable calibration of MSI |
| 456 | w.set_msipllen(true); | 425 | w.set_msipllen(true); |
| 457 | } else { | 426 | } else { |
| @@ -609,7 +578,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 609 | }); | 578 | }); |
| 610 | 579 | ||
| 611 | let ahb_freq: u32 = match config.ahb_pre { | 580 | let ahb_freq: u32 = match config.ahb_pre { |
| 612 | AHBPrescaler::NotDivided => sys_clk, | 581 | AHBPrescaler::DIV1 => sys_clk, |
| 613 | pre => { | 582 | pre => { |
| 614 | let pre: Hpre = pre.into(); | 583 | let pre: Hpre = pre.into(); |
| 615 | let pre = 1 << (pre.to_bits() as u32 - 7); | 584 | let pre = 1 << (pre.to_bits() as u32 - 7); |
| @@ -618,7 +587,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 618 | }; | 587 | }; |
| 619 | 588 | ||
| 620 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | 589 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { |
| 621 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 590 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 622 | pre => { | 591 | pre => { |
| 623 | let pre: Ppre = pre.into(); | 592 | let pre: Ppre = pre.into(); |
| 624 | let pre: u8 = 1 << (pre.to_bits() - 3); | 593 | let pre: u8 = 1 << (pre.to_bits() - 3); |
| @@ -628,7 +597,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 628 | }; | 597 | }; |
| 629 | 598 | ||
| 630 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | 599 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { |
| 631 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 600 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 632 | pre => { | 601 | pre => { |
| 633 | let pre: Ppre = pre.into(); | 602 | let pre: Ppre = pre.into(); |
| 634 | let pre: u8 = 1 << (pre.to_bits() - 3); | 603 | let pre: u8 = 1 << (pre.to_bits() - 3); |
| @@ -637,8 +606,6 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 637 | } | 606 | } |
| 638 | }; | 607 | }; |
| 639 | 608 | ||
| 640 | RCC.apb1enr1().modify(|w| w.set_pwren(true)); | ||
| 641 | |||
| 642 | set_freqs(Clocks { | 609 | set_freqs(Clocks { |
| 643 | sys: Hertz(sys_clk), | 610 | sys: Hertz(sys_clk), |
| 644 | ahb1: Hertz(ahb_freq), | 611 | ahb1: Hertz(ahb_freq), |
diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs index a85e14889..652bdcb7b 100644 --- a/embassy-stm32/src/rcc/l5.rs +++ b/embassy-stm32/src/rcc/l5.rs | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | use stm32_metapac::PWR; | 1 | use stm32_metapac::PWR; |
| 2 | 2 | ||
| 3 | pub use super::common::{AHBPrescaler, APBPrescaler}; | 3 | pub use super::bus::{AHBPrescaler, APBPrescaler}; |
| 4 | use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; | 4 | use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; |
| 5 | use crate::pac::{FLASH, RCC}; | 5 | use crate::pac::{FLASH, RCC}; |
| 6 | use crate::rcc::{set_freqs, Clocks}; | 6 | use crate::rcc::{set_freqs, Clocks}; |
| @@ -238,9 +238,9 @@ impl Default for Config { | |||
| 238 | fn default() -> Config { | 238 | fn default() -> Config { |
| 239 | Config { | 239 | Config { |
| 240 | mux: ClockSrc::MSI(MSIRange::Range6), | 240 | mux: ClockSrc::MSI(MSIRange::Range6), |
| 241 | ahb_pre: AHBPrescaler::NotDivided, | 241 | ahb_pre: AHBPrescaler::DIV1, |
| 242 | apb1_pre: APBPrescaler::NotDivided, | 242 | apb1_pre: APBPrescaler::DIV1, |
| 243 | apb2_pre: APBPrescaler::NotDivided, | 243 | apb2_pre: APBPrescaler::DIV1, |
| 244 | pllsai1: None, | 244 | pllsai1: None, |
| 245 | hsi48: false, | 245 | hsi48: false, |
| 246 | } | 246 | } |
| @@ -317,11 +317,6 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 317 | 317 | ||
| 318 | let freq = (src_freq / prediv.to_div() * mul.to_mul()) / div.to_div(); | 318 | let freq = (src_freq / prediv.to_div() * mul.to_mul()) / div.to_div(); |
| 319 | 319 | ||
| 320 | #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))] | ||
| 321 | assert!(freq <= 120_000_000); | ||
| 322 | #[cfg(not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx)))] | ||
| 323 | assert!(freq <= 80_000_000); | ||
| 324 | |||
| 325 | RCC.pllcfgr().write(move |w| { | 320 | RCC.pllcfgr().write(move |w| { |
| 326 | w.set_plln(mul.into()); | 321 | w.set_plln(mul.into()); |
| 327 | w.set_pllm(prediv.into()); | 322 | w.set_pllm(prediv.into()); |
| @@ -407,7 +402,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 407 | }); | 402 | }); |
| 408 | 403 | ||
| 409 | let ahb_freq: u32 = match config.ahb_pre { | 404 | let ahb_freq: u32 = match config.ahb_pre { |
| 410 | AHBPrescaler::NotDivided => sys_clk, | 405 | AHBPrescaler::DIV1 => sys_clk, |
| 411 | pre => { | 406 | pre => { |
| 412 | let pre: Hpre = pre.into(); | 407 | let pre: Hpre = pre.into(); |
| 413 | let pre = 1 << (pre.to_bits() as u32 - 7); | 408 | let pre = 1 << (pre.to_bits() as u32 - 7); |
| @@ -416,7 +411,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 416 | }; | 411 | }; |
| 417 | 412 | ||
| 418 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | 413 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { |
| 419 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 414 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 420 | pre => { | 415 | pre => { |
| 421 | let pre: Ppre = pre.into(); | 416 | let pre: Ppre = pre.into(); |
| 422 | let pre: u8 = 1 << (pre.to_bits() - 3); | 417 | let pre: u8 = 1 << (pre.to_bits() - 3); |
| @@ -426,7 +421,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 426 | }; | 421 | }; |
| 427 | 422 | ||
| 428 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | 423 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { |
| 429 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 424 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 430 | pre => { | 425 | pre => { |
| 431 | let pre: Ppre = pre.into(); | 426 | let pre: Ppre = pre.into(); |
| 432 | let pre: u8 = 1 << (pre.to_bits() - 3); | 427 | let pre: u8 = 1 << (pre.to_bits() - 3); |
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs new file mode 100644 index 000000000..2453ed821 --- /dev/null +++ b/embassy-stm32/src/rcc/mco.rs | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy_hal_internal::into_ref; | ||
| 4 | |||
| 5 | use crate::gpio::sealed::AFType; | ||
| 6 | use crate::gpio::Speed; | ||
| 7 | pub use crate::pac::rcc::vals::{Mco1 as Mco1Source, Mco2 as Mco2Source}; | ||
| 8 | use crate::pac::RCC; | ||
| 9 | use crate::{peripherals, Peripheral}; | ||
| 10 | |||
| 11 | pub(crate) mod sealed { | ||
| 12 | pub trait McoInstance { | ||
| 13 | type Source; | ||
| 14 | unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8); | ||
| 15 | } | ||
| 16 | } | ||
| 17 | |||
| 18 | pub trait McoInstance: sealed::McoInstance + 'static {} | ||
| 19 | |||
| 20 | pin_trait!(McoPin, McoInstance); | ||
| 21 | |||
| 22 | macro_rules! impl_peri { | ||
| 23 | ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => { | ||
| 24 | impl sealed::McoInstance for peripherals::$peri { | ||
| 25 | type Source = $source; | ||
| 26 | |||
| 27 | unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) { | ||
| 28 | RCC.cfgr().modify(|w| { | ||
| 29 | w.$set_source(source); | ||
| 30 | w.$set_prescaler(prescaler); | ||
| 31 | }); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | impl McoInstance for peripherals::$peri {} | ||
| 36 | }; | ||
| 37 | } | ||
| 38 | |||
| 39 | impl_peri!(MCO1, Mco1Source, set_mco1, set_mco1pre); | ||
| 40 | impl_peri!(MCO2, Mco2Source, set_mco2, set_mco2pre); | ||
| 41 | |||
| 42 | pub struct Mco<'d, T: McoInstance> { | ||
| 43 | phantom: PhantomData<&'d mut T>, | ||
| 44 | } | ||
| 45 | |||
| 46 | impl<'d, T: McoInstance> Mco<'d, T> { | ||
| 47 | /// Create a new MCO instance. | ||
| 48 | /// | ||
| 49 | /// `prescaler` must be between 1 and 15. | ||
| 50 | pub fn new( | ||
| 51 | _peri: impl Peripheral<P = T> + 'd, | ||
| 52 | pin: impl Peripheral<P = impl McoPin<T>> + 'd, | ||
| 53 | source: T::Source, | ||
| 54 | prescaler: u8, | ||
| 55 | ) -> Self { | ||
| 56 | into_ref!(pin); | ||
| 57 | |||
| 58 | assert!( | ||
| 59 | 1 <= prescaler && prescaler <= 15, | ||
| 60 | "Mco prescaler must be between 1 and 15. Refer to the reference manual for more information." | ||
| 61 | ); | ||
| 62 | |||
| 63 | critical_section::with(|_| unsafe { | ||
| 64 | T::apply_clock_settings(source, prescaler); | ||
| 65 | pin.set_as_af(pin.af_num(), AFType::OutputPushPull); | ||
| 66 | pin.set_speed(Speed::VeryHigh); | ||
| 67 | }); | ||
| 68 | |||
| 69 | Self { phantom: PhantomData } | ||
| 70 | } | ||
| 71 | } | ||
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 3c75923e5..9ccf2ac4f 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -1,11 +1,17 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | pub mod common; | ||
| 4 | |||
| 5 | use core::mem::MaybeUninit; | 3 | use core::mem::MaybeUninit; |
| 6 | 4 | ||
| 5 | pub use crate::rcc::bd::RtcClockSource; | ||
| 7 | use crate::time::Hertz; | 6 | use crate::time::Hertz; |
| 8 | 7 | ||
| 8 | pub(crate) mod bd; | ||
| 9 | mod bus; | ||
| 10 | #[cfg(any(stm32h5, stm32h7))] | ||
| 11 | mod mco; | ||
| 12 | #[cfg(any(stm32h5, stm32h7))] | ||
| 13 | pub use mco::*; | ||
| 14 | |||
| 9 | #[cfg_attr(rcc_f0, path = "f0.rs")] | 15 | #[cfg_attr(rcc_f0, path = "f0.rs")] |
| 10 | #[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")] | 16 | #[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")] |
| 11 | #[cfg_attr(rcc_f2, path = "f2.rs")] | 17 | #[cfg_attr(rcc_f2, path = "f2.rs")] |
| @@ -15,20 +21,30 @@ use crate::time::Hertz; | |||
| 15 | #[cfg_attr(rcc_c0, path = "c0.rs")] | 21 | #[cfg_attr(rcc_c0, path = "c0.rs")] |
| 16 | #[cfg_attr(rcc_g0, path = "g0.rs")] | 22 | #[cfg_attr(rcc_g0, path = "g0.rs")] |
| 17 | #[cfg_attr(rcc_g4, path = "g4.rs")] | 23 | #[cfg_attr(rcc_g4, path = "g4.rs")] |
| 18 | #[cfg_attr(any(rcc_h7, rcc_h7ab), path = "h7.rs")] | 24 | #[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab), path = "h.rs")] |
| 19 | #[cfg_attr(rcc_l0, path = "l0.rs")] | 25 | #[cfg_attr(rcc_l0, path = "l0.rs")] |
| 20 | #[cfg_attr(rcc_l1, path = "l1.rs")] | 26 | #[cfg_attr(rcc_l1, path = "l1.rs")] |
| 21 | #[cfg_attr(rcc_l4, path = "l4.rs")] | 27 | #[cfg_attr(rcc_l4, path = "l4.rs")] |
| 22 | #[cfg_attr(rcc_l5, path = "l5.rs")] | 28 | #[cfg_attr(rcc_l5, path = "l5.rs")] |
| 23 | #[cfg_attr(rcc_u5, path = "u5.rs")] | 29 | #[cfg_attr(rcc_u5, path = "u5.rs")] |
| 24 | #[cfg_attr(rcc_wb, path = "wb.rs")] | 30 | #[cfg_attr(rcc_wb, path = "wb.rs")] |
| 31 | #[cfg_attr(rcc_wba, path = "wba.rs")] | ||
| 25 | #[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")] | 32 | #[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")] |
| 26 | #[cfg_attr(any(rcc_h5, rcc_h50), path = "h5.rs")] | ||
| 27 | mod _version; | 33 | mod _version; |
| 28 | pub use _version::*; | 34 | pub use _version::*; |
| 29 | #[cfg(feature = "low-power")] | 35 | #[cfg(feature = "low-power")] |
| 30 | use atomic_polyfill::{AtomicU32, Ordering}; | 36 | use atomic_polyfill::{AtomicU32, Ordering}; |
| 31 | 37 | ||
| 38 | // Model Clock Configuration | ||
| 39 | // | ||
| 40 | // pub struct Clocks { | ||
| 41 | // hse: Option<Hertz>, | ||
| 42 | // hsi: bool, | ||
| 43 | // lse: Option<Hertz>, | ||
| 44 | // lsi: bool, | ||
| 45 | // rtc: RtcSource, | ||
| 46 | // } | ||
| 47 | |||
| 32 | #[derive(Clone, Copy, Debug)] | 48 | #[derive(Clone, Copy, Debug)] |
| 33 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 49 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 34 | pub struct Clocks { | 50 | pub struct Clocks { |
| @@ -41,16 +57,18 @@ pub struct Clocks { | |||
| 41 | pub apb2: Hertz, | 57 | pub apb2: Hertz, |
| 42 | #[cfg(not(any(rcc_c0, rcc_g0)))] | 58 | #[cfg(not(any(rcc_c0, rcc_g0)))] |
| 43 | pub apb2_tim: Hertz, | 59 | pub apb2_tim: Hertz, |
| 44 | #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_u5))] | 60 | #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_u5))] |
| 45 | pub apb3: Hertz, | 61 | pub apb3: Hertz, |
| 46 | #[cfg(any(rcc_h7, rcc_h7ab))] | 62 | #[cfg(any(rcc_h7, rcc_h7ab))] |
| 47 | pub apb4: Hertz, | 63 | pub apb4: Hertz, |
| 64 | #[cfg(any(rcc_wba))] | ||
| 65 | pub apb7: Hertz, | ||
| 48 | 66 | ||
| 49 | // AHB | 67 | // AHB |
| 50 | pub ahb1: Hertz, | 68 | pub ahb1: Hertz, |
| 51 | #[cfg(any( | 69 | #[cfg(any( |
| 52 | rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb, | 70 | rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb, |
| 53 | rcc_wl5, rcc_wle | 71 | rcc_wba, rcc_wl5, rcc_wle |
| 54 | ))] | 72 | ))] |
| 55 | pub ahb2: Hertz, | 73 | pub ahb2: Hertz, |
| 56 | #[cfg(any( | 74 | #[cfg(any( |
| @@ -58,7 +76,7 @@ pub struct Clocks { | |||
| 58 | rcc_wle | 76 | rcc_wle |
| 59 | ))] | 77 | ))] |
| 60 | pub ahb3: Hertz, | 78 | pub ahb3: Hertz, |
| 61 | #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))] | 79 | #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_wba))] |
| 62 | pub ahb4: Hertz, | 80 | pub ahb4: Hertz, |
| 63 | 81 | ||
| 64 | #[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))] | 82 | #[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))] |
| @@ -70,15 +88,22 @@ pub struct Clocks { | |||
| 70 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] | 88 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] |
| 71 | pub pllsai: Option<Hertz>, | 89 | pub pllsai: Option<Hertz>, |
| 72 | 90 | ||
| 73 | #[cfg(stm32f1)] | 91 | #[cfg(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3, rcc_g4))] |
| 74 | pub adc: Hertz, | ||
| 75 | |||
| 76 | #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))] | ||
| 77 | pub adc: Option<Hertz>, | 92 | pub adc: Option<Hertz>, |
| 78 | 93 | ||
| 79 | #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] | 94 | #[cfg(any(rcc_f3, rcc_g4))] |
| 80 | /// Set only if the lsi or lse is configured | 95 | pub adc34: Option<Hertz>, |
| 96 | |||
| 97 | #[cfg(stm32f334)] | ||
| 98 | pub hrtim: Option<Hertz>, | ||
| 99 | |||
| 100 | #[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_f7))] | ||
| 101 | /// Set only if the lsi or lse is configured, indicates stop is supported | ||
| 81 | pub rtc: Option<Hertz>, | 102 | pub rtc: Option<Hertz>, |
| 103 | |||
| 104 | #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] | ||
| 105 | /// Set if the hse is configured, indicates stop is not supported | ||
| 106 | pub rtc_hse: Option<Hertz>, | ||
| 82 | } | 107 | } |
| 83 | 108 | ||
| 84 | #[cfg(feature = "low-power")] | 109 | #[cfg(feature = "low-power")] |
| @@ -86,6 +111,8 @@ static CLOCK_REFCOUNT: AtomicU32 = AtomicU32::new(0); | |||
| 86 | 111 | ||
| 87 | #[cfg(feature = "low-power")] | 112 | #[cfg(feature = "low-power")] |
| 88 | pub fn low_power_ready() -> bool { | 113 | pub fn low_power_ready() -> bool { |
| 114 | trace!("clock refcount: {}", CLOCK_REFCOUNT.load(Ordering::SeqCst)); | ||
| 115 | |||
| 89 | CLOCK_REFCOUNT.load(Ordering::SeqCst) == 0 | 116 | CLOCK_REFCOUNT.load(Ordering::SeqCst) == 0 |
| 90 | } | 117 | } |
| 91 | 118 | ||
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index b5feeb0c4..d9a531285 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | use stm32_metapac::rcc::vals::{Msirange, Msirgsel, Pllm, Pllsrc, Sw}; | 1 | use stm32_metapac::rcc::vals::{Msirange, Msirgsel, Pllm, Pllsrc, Sw}; |
| 2 | 2 | ||
| 3 | pub use super::common::{AHBPrescaler, APBPrescaler}; | 3 | pub use super::bus::{AHBPrescaler, APBPrescaler}; |
| 4 | use crate::pac::{FLASH, RCC}; | 4 | use crate::pac::{FLASH, RCC}; |
| 5 | use crate::rcc::{set_freqs, Clocks}; | 5 | use crate::rcc::{set_freqs, Clocks}; |
| 6 | use crate::time::Hertz; | 6 | use crate::time::Hertz; |
| @@ -11,7 +11,7 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000); | |||
| 11 | /// LSI speed | 11 | /// LSI speed |
| 12 | pub const LSI_FREQ: Hertz = Hertz(32_000); | 12 | pub const LSI_FREQ: Hertz = Hertz(32_000); |
| 13 | 13 | ||
| 14 | pub use super::common::VoltageScale; | 14 | pub use crate::pac::pwr::vals::Vos as VoltageScale; |
| 15 | 15 | ||
| 16 | #[derive(Copy, Clone)] | 16 | #[derive(Copy, Clone)] |
| 17 | pub enum ClockSrc { | 17 | pub enum ClockSrc { |
| @@ -119,53 +119,13 @@ impl Into<Pllm> for PllM { | |||
| 119 | } | 119 | } |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | impl Into<u8> for AHBPrescaler { | ||
| 123 | fn into(self) -> u8 { | ||
| 124 | match self { | ||
| 125 | AHBPrescaler::NotDivided => 1, | ||
| 126 | AHBPrescaler::Div2 => 0x08, | ||
| 127 | AHBPrescaler::Div4 => 0x09, | ||
| 128 | AHBPrescaler::Div8 => 0x0a, | ||
| 129 | AHBPrescaler::Div16 => 0x0b, | ||
| 130 | AHBPrescaler::Div64 => 0x0c, | ||
| 131 | AHBPrescaler::Div128 => 0x0d, | ||
| 132 | AHBPrescaler::Div256 => 0x0e, | ||
| 133 | AHBPrescaler::Div512 => 0x0f, | ||
| 134 | } | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | impl Default for AHBPrescaler { | ||
| 139 | fn default() -> Self { | ||
| 140 | AHBPrescaler::NotDivided | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | impl Default for APBPrescaler { | ||
| 145 | fn default() -> Self { | ||
| 146 | APBPrescaler::NotDivided | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | impl Into<u8> for APBPrescaler { | ||
| 151 | fn into(self) -> u8 { | ||
| 152 | match self { | ||
| 153 | APBPrescaler::NotDivided => 1, | ||
| 154 | APBPrescaler::Div2 => 0x04, | ||
| 155 | APBPrescaler::Div4 => 0x05, | ||
| 156 | APBPrescaler::Div8 => 0x06, | ||
| 157 | APBPrescaler::Div16 => 0x07, | ||
| 158 | } | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | impl Into<Sw> for ClockSrc { | 122 | impl Into<Sw> for ClockSrc { |
| 163 | fn into(self) -> Sw { | 123 | fn into(self) -> Sw { |
| 164 | match self { | 124 | match self { |
| 165 | ClockSrc::MSI(..) => Sw::MSIS, | 125 | ClockSrc::MSI(..) => Sw::MSIS, |
| 166 | ClockSrc::HSE(..) => Sw::HSE, | 126 | ClockSrc::HSE(..) => Sw::HSE, |
| 167 | ClockSrc::HSI16 => Sw::HSI16, | 127 | ClockSrc::HSI16 => Sw::HSI16, |
| 168 | ClockSrc::PLL1R(..) => Sw::PLL1R, | 128 | ClockSrc::PLL1R(..) => Sw::PLL1_R, |
| 169 | } | 129 | } |
| 170 | } | 130 | } |
| 171 | } | 131 | } |
| @@ -239,10 +199,10 @@ impl Default for Config { | |||
| 239 | fn default() -> Self { | 199 | fn default() -> Self { |
| 240 | Self { | 200 | Self { |
| 241 | mux: ClockSrc::MSI(MSIRange::default()), | 201 | mux: ClockSrc::MSI(MSIRange::default()), |
| 242 | ahb_pre: Default::default(), | 202 | ahb_pre: AHBPrescaler::DIV1, |
| 243 | apb1_pre: Default::default(), | 203 | apb1_pre: APBPrescaler::DIV1, |
| 244 | apb2_pre: Default::default(), | 204 | apb2_pre: APBPrescaler::DIV1, |
| 245 | apb3_pre: Default::default(), | 205 | apb3_pre: APBPrescaler::DIV1, |
| 246 | hsi48: false, | 206 | hsi48: false, |
| 247 | } | 207 | } |
| 248 | } | 208 | } |
| @@ -326,12 +286,12 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 326 | } | 286 | } |
| 327 | 287 | ||
| 328 | // TODO make configurable | 288 | // TODO make configurable |
| 329 | let power_vos = VoltageScale::Scale3; | 289 | let power_vos = VoltageScale::RANGE3; |
| 330 | 290 | ||
| 331 | // states and programming delay | 291 | // states and programming delay |
| 332 | let wait_states = match power_vos { | 292 | let wait_states = match power_vos { |
| 333 | // VOS 0 range VCORE 1.26V - 1.40V | 293 | // VOS 1 range VCORE 1.26V - 1.40V |
| 334 | VoltageScale::Scale0 => { | 294 | VoltageScale::RANGE1 => { |
| 335 | if sys_clk < 32_000_000 { | 295 | if sys_clk < 32_000_000 { |
| 336 | 0 | 296 | 0 |
| 337 | } else if sys_clk < 64_000_000 { | 297 | } else if sys_clk < 64_000_000 { |
| @@ -344,8 +304,8 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 344 | 4 | 304 | 4 |
| 345 | } | 305 | } |
| 346 | } | 306 | } |
| 347 | // VOS 1 range VCORE 1.15V - 1.26V | 307 | // VOS 2 range VCORE 1.15V - 1.26V |
| 348 | VoltageScale::Scale1 => { | 308 | VoltageScale::RANGE2 => { |
| 349 | if sys_clk < 30_000_000 { | 309 | if sys_clk < 30_000_000 { |
| 350 | 0 | 310 | 0 |
| 351 | } else if sys_clk < 60_000_000 { | 311 | } else if sys_clk < 60_000_000 { |
| @@ -356,8 +316,8 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 356 | 3 | 316 | 3 |
| 357 | } | 317 | } |
| 358 | } | 318 | } |
| 359 | // VOS 2 range VCORE 1.05V - 1.15V | 319 | // VOS 3 range VCORE 1.05V - 1.15V |
| 360 | VoltageScale::Scale2 => { | 320 | VoltageScale::RANGE3 => { |
| 361 | if sys_clk < 24_000_000 { | 321 | if sys_clk < 24_000_000 { |
| 362 | 0 | 322 | 0 |
| 363 | } else if sys_clk < 48_000_000 { | 323 | } else if sys_clk < 48_000_000 { |
| @@ -366,8 +326,8 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 366 | 2 | 326 | 2 |
| 367 | } | 327 | } |
| 368 | } | 328 | } |
| 369 | // VOS 3 range VCORE 0.95V - 1.05V | 329 | // VOS 4 range VCORE 0.95V - 1.05V |
| 370 | VoltageScale::Scale3 => { | 330 | VoltageScale::RANGE4 => { |
| 371 | if sys_clk < 12_000_000 { | 331 | if sys_clk < 12_000_000 { |
| 372 | 0 | 332 | 0 |
| 373 | } else { | 333 | } else { |
| @@ -395,7 +355,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 395 | }); | 355 | }); |
| 396 | 356 | ||
| 397 | let ahb_freq: u32 = match config.ahb_pre { | 357 | let ahb_freq: u32 = match config.ahb_pre { |
| 398 | AHBPrescaler::NotDivided => sys_clk, | 358 | AHBPrescaler::DIV1 => sys_clk, |
| 399 | pre => { | 359 | pre => { |
| 400 | let pre: u8 = pre.into(); | 360 | let pre: u8 = pre.into(); |
| 401 | let pre = 1 << (pre as u32 - 7); | 361 | let pre = 1 << (pre as u32 - 7); |
| @@ -404,7 +364,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 404 | }; | 364 | }; |
| 405 | 365 | ||
| 406 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | 366 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { |
| 407 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 367 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 408 | pre => { | 368 | pre => { |
| 409 | let pre: u8 = pre.into(); | 369 | let pre: u8 = pre.into(); |
| 410 | let pre: u8 = 1 << (pre - 3); | 370 | let pre: u8 = 1 << (pre - 3); |
| @@ -414,7 +374,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 414 | }; | 374 | }; |
| 415 | 375 | ||
| 416 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | 376 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { |
| 417 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 377 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 418 | pre => { | 378 | pre => { |
| 419 | let pre: u8 = pre.into(); | 379 | let pre: u8 = pre.into(); |
| 420 | let pre: u8 = 1 << (pre - 3); | 380 | let pre: u8 = 1 << (pre - 3); |
| @@ -424,7 +384,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 424 | }; | 384 | }; |
| 425 | 385 | ||
| 426 | let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre { | 386 | let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre { |
| 427 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 387 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 428 | pre => { | 388 | pre => { |
| 429 | let pre: u8 = pre.into(); | 389 | let pre: u8 = pre.into(); |
| 430 | let pre: u8 = 1 << (pre - 3); | 390 | let pre: u8 = 1 << (pre - 3); |
diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index ae708b37f..ee45a342b 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | pub use super::common::{AHBPrescaler, APBPrescaler}; | 1 | pub use super::bus::{AHBPrescaler, APBPrescaler}; |
| 2 | use crate::rcc::bd::{BackupDomain, RtcClockSource}; | ||
| 2 | use crate::rcc::Clocks; | 3 | use crate::rcc::Clocks; |
| 3 | use crate::rtc::{Rtc, RtcClockSource}; | ||
| 4 | use crate::time::{khz, mhz, Hertz}; | 4 | use crate::time::{khz, mhz, Hertz}; |
| 5 | 5 | ||
| 6 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, | 6 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, |
| @@ -108,6 +108,7 @@ pub struct Pll { | |||
| 108 | pub struct Config { | 108 | pub struct Config { |
| 109 | pub hse: Option<Hse>, | 109 | pub hse: Option<Hse>, |
| 110 | pub lse: Option<Hertz>, | 110 | pub lse: Option<Hertz>, |
| 111 | pub lsi: bool, | ||
| 111 | pub sys: Sysclk, | 112 | pub sys: Sysclk, |
| 112 | pub mux: Option<PllMux>, | 113 | pub mux: Option<PllMux>, |
| 113 | pub pll48: Option<Pll48Source>, | 114 | pub pll48: Option<Pll48Source>, |
| @@ -135,7 +136,8 @@ pub const WPAN_DEFAULT: Config = Config { | |||
| 135 | prediv: 2, | 136 | prediv: 2, |
| 136 | }), | 137 | }), |
| 137 | pll48: None, | 138 | pll48: None, |
| 138 | rtc: None, | 139 | rtc: Some(RtcClockSource::LSE), |
| 140 | lsi: false, | ||
| 139 | 141 | ||
| 140 | pll: Some(Pll { | 142 | pll: Some(Pll { |
| 141 | mul: 12, | 143 | mul: 12, |
| @@ -145,11 +147,11 @@ pub const WPAN_DEFAULT: Config = Config { | |||
| 145 | }), | 147 | }), |
| 146 | pllsai: None, | 148 | pllsai: None, |
| 147 | 149 | ||
| 148 | ahb1_pre: AHBPrescaler::NotDivided, | 150 | ahb1_pre: AHBPrescaler::DIV1, |
| 149 | ahb2_pre: AHBPrescaler::Div2, | 151 | ahb2_pre: AHBPrescaler::DIV2, |
| 150 | ahb3_pre: AHBPrescaler::NotDivided, | 152 | ahb3_pre: AHBPrescaler::DIV1, |
| 151 | apb1_pre: APBPrescaler::NotDivided, | 153 | apb1_pre: APBPrescaler::DIV1, |
| 152 | apb2_pre: APBPrescaler::NotDivided, | 154 | apb2_pre: APBPrescaler::DIV1, |
| 153 | }; | 155 | }; |
| 154 | 156 | ||
| 155 | impl Default for Config { | 157 | impl Default for Config { |
| @@ -164,12 +166,13 @@ impl Default for Config { | |||
| 164 | pll: None, | 166 | pll: None, |
| 165 | pllsai: None, | 167 | pllsai: None, |
| 166 | rtc: None, | 168 | rtc: None, |
| 169 | lsi: false, | ||
| 167 | 170 | ||
| 168 | ahb1_pre: AHBPrescaler::NotDivided, | 171 | ahb1_pre: AHBPrescaler::DIV1, |
| 169 | ahb2_pre: AHBPrescaler::NotDivided, | 172 | ahb2_pre: AHBPrescaler::DIV1, |
| 170 | ahb3_pre: AHBPrescaler::NotDivided, | 173 | ahb3_pre: AHBPrescaler::DIV1, |
| 171 | apb1_pre: APBPrescaler::NotDivided, | 174 | apb1_pre: APBPrescaler::DIV1, |
| 172 | apb2_pre: APBPrescaler::NotDivided, | 175 | apb2_pre: APBPrescaler::DIV1, |
| 173 | } | 176 | } |
| 174 | } | 177 | } |
| 175 | } | 178 | } |
| @@ -209,7 +212,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { | |||
| 209 | }; | 212 | }; |
| 210 | 213 | ||
| 211 | let ahb1_clk = match config.ahb1_pre { | 214 | let ahb1_clk = match config.ahb1_pre { |
| 212 | AHBPrescaler::NotDivided => sys_clk, | 215 | AHBPrescaler::DIV1 => sys_clk, |
| 213 | pre => { | 216 | pre => { |
| 214 | let pre: u8 = pre.into(); | 217 | let pre: u8 = pre.into(); |
| 215 | let pre = 1u32 << (pre as u32 - 7); | 218 | let pre = 1u32 << (pre as u32 - 7); |
| @@ -218,7 +221,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { | |||
| 218 | }; | 221 | }; |
| 219 | 222 | ||
| 220 | let ahb2_clk = match config.ahb2_pre { | 223 | let ahb2_clk = match config.ahb2_pre { |
| 221 | AHBPrescaler::NotDivided => sys_clk, | 224 | AHBPrescaler::DIV1 => sys_clk, |
| 222 | pre => { | 225 | pre => { |
| 223 | let pre: u8 = pre.into(); | 226 | let pre: u8 = pre.into(); |
| 224 | let pre = 1u32 << (pre as u32 - 7); | 227 | let pre = 1u32 << (pre as u32 - 7); |
| @@ -227,7 +230,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { | |||
| 227 | }; | 230 | }; |
| 228 | 231 | ||
| 229 | let ahb3_clk = match config.ahb3_pre { | 232 | let ahb3_clk = match config.ahb3_pre { |
| 230 | AHBPrescaler::NotDivided => sys_clk, | 233 | AHBPrescaler::DIV1 => sys_clk, |
| 231 | pre => { | 234 | pre => { |
| 232 | let pre: u8 = pre.into(); | 235 | let pre: u8 = pre.into(); |
| 233 | let pre = 1u32 << (pre as u32 - 7); | 236 | let pre = 1u32 << (pre as u32 - 7); |
| @@ -236,7 +239,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { | |||
| 236 | }; | 239 | }; |
| 237 | 240 | ||
| 238 | let (apb1_clk, apb1_tim_clk) = match config.apb1_pre { | 241 | let (apb1_clk, apb1_tim_clk) = match config.apb1_pre { |
| 239 | APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk), | 242 | APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk), |
| 240 | pre => { | 243 | pre => { |
| 241 | let pre: u8 = pre.into(); | 244 | let pre: u8 = pre.into(); |
| 242 | let pre: u8 = 1 << (pre - 3); | 245 | let pre: u8 = 1 << (pre - 3); |
| @@ -246,7 +249,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { | |||
| 246 | }; | 249 | }; |
| 247 | 250 | ||
| 248 | let (apb2_clk, apb2_tim_clk) = match config.apb2_pre { | 251 | let (apb2_clk, apb2_tim_clk) = match config.apb2_pre { |
| 249 | APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk), | 252 | APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk), |
| 250 | pre => { | 253 | pre => { |
| 251 | let pre: u8 = pre.into(); | 254 | let pre: u8 = pre.into(); |
| 252 | let pre: u8 = 1 << (pre - 3); | 255 | let pre: u8 = 1 << (pre - 3); |
| @@ -271,11 +274,11 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { | |||
| 271 | apb1_tim: apb1_tim_clk, | 274 | apb1_tim: apb1_tim_clk, |
| 272 | apb2_tim: apb2_tim_clk, | 275 | apb2_tim: apb2_tim_clk, |
| 273 | rtc: rtc_clk, | 276 | rtc: rtc_clk, |
| 277 | rtc_hse: None, | ||
| 274 | } | 278 | } |
| 275 | } | 279 | } |
| 276 | 280 | ||
| 277 | pub(crate) fn configure_clocks(config: &Config) { | 281 | pub(crate) fn configure_clocks(config: &Config) { |
| 278 | let pwr = crate::pac::PWR; | ||
| 279 | let rcc = crate::pac::RCC; | 282 | let rcc = crate::pac::RCC; |
| 280 | 283 | ||
| 281 | let needs_hsi = if let Some(pll_mux) = &config.mux { | 284 | let needs_hsi = if let Some(pll_mux) = &config.mux { |
| @@ -292,29 +295,13 @@ pub(crate) fn configure_clocks(config: &Config) { | |||
| 292 | while !rcc.cr().read().hsirdy() {} | 295 | while !rcc.cr().read().hsirdy() {} |
| 293 | } | 296 | } |
| 294 | 297 | ||
| 295 | let needs_lsi = if let Some(rtc_mux) = &config.rtc { | 298 | rcc.cfgr().modify(|w| w.set_stopwuck(true)); |
| 296 | *rtc_mux == RtcClockSource::LSI | ||
| 297 | } else { | ||
| 298 | false | ||
| 299 | }; | ||
| 300 | |||
| 301 | if needs_lsi { | ||
| 302 | rcc.csr().modify(|w| w.set_lsi1on(true)); | ||
| 303 | |||
| 304 | while !rcc.csr().read().lsi1rdy() {} | ||
| 305 | } | ||
| 306 | 299 | ||
| 307 | match &config.lse { | 300 | BackupDomain::configure_ls( |
| 308 | Some(_) => { | 301 | config.rtc.unwrap_or(RtcClockSource::NOCLOCK), |
| 309 | rcc.cfgr().modify(|w| w.set_stopwuck(true)); | 302 | config.lsi, |
| 310 | 303 | config.lse.map(|_| Default::default()), | |
| 311 | pwr.cr1().modify(|w| w.set_dbp(true)); | 304 | ); |
| 312 | pwr.cr1().modify(|w| w.set_dbp(true)); | ||
| 313 | |||
| 314 | rcc.bdcr().modify(|w| w.set_lseon(true)); | ||
| 315 | } | ||
| 316 | _ => {} | ||
| 317 | } | ||
| 318 | 305 | ||
| 319 | match &config.hse { | 306 | match &config.hse { |
| 320 | Some(hse) => { | 307 | Some(hse) => { |
| @@ -374,6 +361,4 @@ pub(crate) fn configure_clocks(config: &Config) { | |||
| 374 | w.set_c2hpre(config.ahb2_pre.into()); | 361 | w.set_c2hpre(config.ahb2_pre.into()); |
| 375 | w.set_shdhpre(config.ahb3_pre.into()); | 362 | w.set_shdhpre(config.ahb3_pre.into()); |
| 376 | }); | 363 | }); |
| 377 | |||
| 378 | config.rtc.map(|clock_source| Rtc::set_clock_source(clock_source)); | ||
| 379 | } | 364 | } |
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs new file mode 100644 index 000000000..c5d7ab62f --- /dev/null +++ b/embassy-stm32/src/rcc/wba.rs | |||
| @@ -0,0 +1,154 @@ | |||
| 1 | use stm32_metapac::rcc::vals::{Pllsrc, Sw}; | ||
| 2 | |||
| 3 | use crate::pac::{FLASH, RCC}; | ||
| 4 | use crate::rcc::{set_freqs, Clocks}; | ||
| 5 | use crate::time::Hertz; | ||
| 6 | |||
| 7 | /// HSI speed | ||
| 8 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); | ||
| 9 | |||
| 10 | /// LSI speed | ||
| 11 | pub const LSI_FREQ: Hertz = Hertz(32_000); | ||
| 12 | |||
| 13 | pub use crate::pac::pwr::vals::Vos as VoltageScale; | ||
| 14 | pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; | ||
| 15 | |||
| 16 | #[derive(Copy, Clone)] | ||
| 17 | pub enum ClockSrc { | ||
| 18 | HSE(Hertz), | ||
| 19 | HSI16, | ||
| 20 | } | ||
| 21 | |||
| 22 | #[derive(Clone, Copy, Debug)] | ||
| 23 | pub enum PllSrc { | ||
| 24 | HSE(Hertz), | ||
| 25 | HSI16, | ||
| 26 | } | ||
| 27 | |||
| 28 | impl Into<Pllsrc> for PllSrc { | ||
| 29 | fn into(self) -> Pllsrc { | ||
| 30 | match self { | ||
| 31 | PllSrc::HSE(..) => Pllsrc::HSE32, | ||
| 32 | PllSrc::HSI16 => Pllsrc::HSI16, | ||
| 33 | } | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | impl Into<Sw> for ClockSrc { | ||
| 38 | fn into(self) -> Sw { | ||
| 39 | match self { | ||
| 40 | ClockSrc::HSE(..) => Sw::HSE32, | ||
| 41 | ClockSrc::HSI16 => Sw::HSI16, | ||
| 42 | } | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | #[derive(Copy, Clone)] | ||
| 47 | pub struct Config { | ||
| 48 | pub mux: ClockSrc, | ||
| 49 | pub ahb_pre: AHBPrescaler, | ||
| 50 | pub apb1_pre: APBPrescaler, | ||
| 51 | pub apb2_pre: APBPrescaler, | ||
| 52 | pub apb7_pre: APBPrescaler, | ||
| 53 | } | ||
| 54 | |||
| 55 | impl Default for Config { | ||
| 56 | fn default() -> Self { | ||
| 57 | Self { | ||
| 58 | mux: ClockSrc::HSI16, | ||
| 59 | ahb_pre: AHBPrescaler::DIV1, | ||
| 60 | apb1_pre: APBPrescaler::DIV1, | ||
| 61 | apb2_pre: APBPrescaler::DIV1, | ||
| 62 | apb7_pre: APBPrescaler::DIV1, | ||
| 63 | } | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | pub(crate) unsafe fn init(config: Config) { | ||
| 68 | let sys_clk = match config.mux { | ||
| 69 | ClockSrc::HSE(freq) => { | ||
| 70 | RCC.cr().write(|w| w.set_hseon(true)); | ||
| 71 | while !RCC.cr().read().hserdy() {} | ||
| 72 | |||
| 73 | freq | ||
| 74 | } | ||
| 75 | ClockSrc::HSI16 => { | ||
| 76 | RCC.cr().write(|w| w.set_hsion(true)); | ||
| 77 | while !RCC.cr().read().hsirdy() {} | ||
| 78 | |||
| 79 | HSI_FREQ | ||
| 80 | } | ||
| 81 | }; | ||
| 82 | |||
| 83 | // TODO make configurable | ||
| 84 | let power_vos = VoltageScale::RANGE1; | ||
| 85 | |||
| 86 | // states and programming delay | ||
| 87 | let wait_states = match power_vos { | ||
| 88 | VoltageScale::RANGE1 => match sys_clk.0 { | ||
| 89 | ..=32_000_000 => 0, | ||
| 90 | ..=64_000_000 => 1, | ||
| 91 | ..=96_000_000 => 2, | ||
| 92 | ..=100_000_000 => 3, | ||
| 93 | _ => 4, | ||
| 94 | }, | ||
| 95 | VoltageScale::RANGE2 => match sys_clk.0 { | ||
| 96 | ..=8_000_000 => 0, | ||
| 97 | ..=16_000_000 => 1, | ||
| 98 | _ => 2, | ||
| 99 | }, | ||
| 100 | }; | ||
| 101 | |||
| 102 | FLASH.acr().modify(|w| { | ||
| 103 | w.set_latency(wait_states); | ||
| 104 | }); | ||
| 105 | |||
| 106 | RCC.cfgr1().modify(|w| { | ||
| 107 | w.set_sw(config.mux.into()); | ||
| 108 | }); | ||
| 109 | |||
| 110 | RCC.cfgr2().modify(|w| { | ||
| 111 | w.set_hpre(config.ahb_pre.into()); | ||
| 112 | w.set_ppre1(config.apb1_pre.into()); | ||
| 113 | w.set_ppre2(config.apb2_pre.into()); | ||
| 114 | }); | ||
| 115 | |||
| 116 | RCC.cfgr3().modify(|w| { | ||
| 117 | w.set_ppre7(config.apb7_pre.into()); | ||
| 118 | }); | ||
| 119 | |||
| 120 | let ahb_freq = sys_clk / config.ahb_pre; | ||
| 121 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | ||
| 122 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | ||
| 123 | pre => { | ||
| 124 | let freq = ahb_freq / pre; | ||
| 125 | (freq, freq * 2u32) | ||
| 126 | } | ||
| 127 | }; | ||
| 128 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | ||
| 129 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | ||
| 130 | pre => { | ||
| 131 | let freq = ahb_freq / pre; | ||
| 132 | (freq, freq * 2u32) | ||
| 133 | } | ||
| 134 | }; | ||
| 135 | let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre { | ||
| 136 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | ||
| 137 | pre => { | ||
| 138 | let freq = ahb_freq / pre; | ||
| 139 | (freq, freq * 2u32) | ||
| 140 | } | ||
| 141 | }; | ||
| 142 | |||
| 143 | set_freqs(Clocks { | ||
| 144 | sys: sys_clk, | ||
| 145 | ahb1: ahb_freq, | ||
| 146 | ahb2: ahb_freq, | ||
| 147 | ahb4: ahb_freq, | ||
| 148 | apb1: apb1_freq, | ||
| 149 | apb2: apb2_freq, | ||
| 150 | apb7: apb7_freq, | ||
| 151 | apb1_tim: apb1_tim_freq, | ||
| 152 | apb2_tim: apb2_tim_freq, | ||
| 153 | }); | ||
| 154 | } | ||
diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index f1dd2bd7e..6643d278a 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs | |||
| @@ -1,8 +1,9 @@ | |||
| 1 | pub use super::common::{AHBPrescaler, APBPrescaler, VoltageScale}; | 1 | pub use super::bus::{AHBPrescaler, APBPrescaler}; |
| 2 | use crate::pac::pwr::vals::Dbp; | 2 | pub use crate::pac::pwr::vals::Vos as VoltageScale; |
| 3 | use crate::pac::{FLASH, PWR, RCC}; | 3 | use crate::pac::rcc::vals::Adcsel; |
| 4 | use crate::pac::{FLASH, RCC}; | ||
| 5 | use crate::rcc::bd::{BackupDomain, RtcClockSource}; | ||
| 4 | use crate::rcc::{set_freqs, Clocks}; | 6 | use crate::rcc::{set_freqs, Clocks}; |
| 5 | use crate::rtc::{Rtc, RtcClockSource as RCS}; | ||
| 6 | use crate::time::Hertz; | 7 | use crate::time::Hertz; |
| 7 | 8 | ||
| 8 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, | 9 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, |
| @@ -75,9 +76,9 @@ impl MSIRange { | |||
| 75 | 76 | ||
| 76 | fn vos(&self) -> VoltageScale { | 77 | fn vos(&self) -> VoltageScale { |
| 77 | if self > &MSIRange::Range8 { | 78 | if self > &MSIRange::Range8 { |
| 78 | VoltageScale::Scale0 | 79 | VoltageScale::RANGE1 |
| 79 | } else { | 80 | } else { |
| 80 | VoltageScale::Scale1 | 81 | VoltageScale::RANGE2 |
| 81 | } | 82 | } |
| 82 | } | 83 | } |
| 83 | } | 84 | } |
| @@ -107,6 +108,29 @@ impl Into<u8> for MSIRange { | |||
| 107 | } | 108 | } |
| 108 | } | 109 | } |
| 109 | 110 | ||
| 111 | #[derive(Clone, Copy)] | ||
| 112 | pub enum AdcClockSource { | ||
| 113 | HSI16, | ||
| 114 | PLLPCLK, | ||
| 115 | SYSCLK, | ||
| 116 | } | ||
| 117 | |||
| 118 | impl AdcClockSource { | ||
| 119 | pub fn adcsel(&self) -> Adcsel { | ||
| 120 | match self { | ||
| 121 | AdcClockSource::HSI16 => Adcsel::HSI16, | ||
| 122 | AdcClockSource::PLLPCLK => Adcsel::PLLPCLK, | ||
| 123 | AdcClockSource::SYSCLK => Adcsel::SYSCLK, | ||
| 124 | } | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | impl Default for AdcClockSource { | ||
| 129 | fn default() -> Self { | ||
| 130 | Self::HSI16 | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 110 | /// Clocks configutation | 134 | /// Clocks configutation |
| 111 | pub struct Config { | 135 | pub struct Config { |
| 112 | pub mux: ClockSrc, | 136 | pub mux: ClockSrc, |
| @@ -114,9 +138,10 @@ pub struct Config { | |||
| 114 | pub shd_ahb_pre: AHBPrescaler, | 138 | pub shd_ahb_pre: AHBPrescaler, |
| 115 | pub apb1_pre: APBPrescaler, | 139 | pub apb1_pre: APBPrescaler, |
| 116 | pub apb2_pre: APBPrescaler, | 140 | pub apb2_pre: APBPrescaler, |
| 117 | pub enable_lsi: bool, | ||
| 118 | pub enable_rtc_apb: bool, | ||
| 119 | pub rtc_mux: RtcClockSource, | 141 | pub rtc_mux: RtcClockSource, |
| 142 | pub lse: Option<Hertz>, | ||
| 143 | pub lsi: bool, | ||
| 144 | pub adc_clock_source: AdcClockSource, | ||
| 120 | } | 145 | } |
| 121 | 146 | ||
| 122 | impl Default for Config { | 147 | impl Default for Config { |
| @@ -124,22 +149,18 @@ impl Default for Config { | |||
| 124 | fn default() -> Config { | 149 | fn default() -> Config { |
| 125 | Config { | 150 | Config { |
| 126 | mux: ClockSrc::MSI(MSIRange::default()), | 151 | mux: ClockSrc::MSI(MSIRange::default()), |
| 127 | ahb_pre: AHBPrescaler::NotDivided, | 152 | ahb_pre: AHBPrescaler::DIV1, |
| 128 | shd_ahb_pre: AHBPrescaler::NotDivided, | 153 | shd_ahb_pre: AHBPrescaler::DIV1, |
| 129 | apb1_pre: APBPrescaler::NotDivided, | 154 | apb1_pre: APBPrescaler::DIV1, |
| 130 | apb2_pre: APBPrescaler::NotDivided, | 155 | apb2_pre: APBPrescaler::DIV1, |
| 131 | enable_lsi: false, | 156 | rtc_mux: RtcClockSource::LSI, |
| 132 | enable_rtc_apb: false, | 157 | lsi: true, |
| 133 | rtc_mux: RtcClockSource::LSI32, | 158 | lse: None, |
| 159 | adc_clock_source: AdcClockSource::default(), | ||
| 134 | } | 160 | } |
| 135 | } | 161 | } |
| 136 | } | 162 | } |
| 137 | 163 | ||
| 138 | pub enum RtcClockSource { | ||
| 139 | LSE32, | ||
| 140 | LSI32, | ||
| 141 | } | ||
| 142 | |||
| 143 | #[repr(u8)] | 164 | #[repr(u8)] |
| 144 | pub enum Lsedrv { | 165 | pub enum Lsedrv { |
| 145 | Low = 0, | 166 | Low = 0, |
| @@ -150,13 +171,13 @@ pub enum Lsedrv { | |||
| 150 | 171 | ||
| 151 | pub(crate) unsafe fn init(config: Config) { | 172 | pub(crate) unsafe fn init(config: Config) { |
| 152 | let (sys_clk, sw, vos) = match config.mux { | 173 | let (sys_clk, sw, vos) = match config.mux { |
| 153 | ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::Scale1), | 174 | ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::RANGE2), |
| 154 | ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::Scale0), | 175 | ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::RANGE1), |
| 155 | ClockSrc::MSI(range) => (range.freq(), 0x00, range.vos()), | 176 | ClockSrc::MSI(range) => (range.freq(), 0x00, range.vos()), |
| 156 | }; | 177 | }; |
| 157 | 178 | ||
| 158 | let ahb_freq: u32 = match config.ahb_pre { | 179 | let ahb_freq: u32 = match config.ahb_pre { |
| 159 | AHBPrescaler::NotDivided => sys_clk, | 180 | AHBPrescaler::DIV1 => sys_clk, |
| 160 | pre => { | 181 | pre => { |
| 161 | let pre: u8 = pre.into(); | 182 | let pre: u8 = pre.into(); |
| 162 | let pre = 1 << (pre as u32 - 7); | 183 | let pre = 1 << (pre as u32 - 7); |
| @@ -165,7 +186,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 165 | }; | 186 | }; |
| 166 | 187 | ||
| 167 | let shd_ahb_freq: u32 = match config.shd_ahb_pre { | 188 | let shd_ahb_freq: u32 = match config.shd_ahb_pre { |
| 168 | AHBPrescaler::NotDivided => sys_clk, | 189 | AHBPrescaler::DIV1 => sys_clk, |
| 169 | pre => { | 190 | pre => { |
| 170 | let pre: u8 = pre.into(); | 191 | let pre: u8 = pre.into(); |
| 171 | let pre = 1 << (pre as u32 - 7); | 192 | let pre = 1 << (pre as u32 - 7); |
| @@ -174,7 +195,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 174 | }; | 195 | }; |
| 175 | 196 | ||
| 176 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | 197 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { |
| 177 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 198 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 178 | pre => { | 199 | pre => { |
| 179 | let pre: u8 = pre.into(); | 200 | let pre: u8 = pre.into(); |
| 180 | let pre: u8 = 1 << (pre - 3); | 201 | let pre: u8 = 1 << (pre - 3); |
| @@ -184,7 +205,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 184 | }; | 205 | }; |
| 185 | 206 | ||
| 186 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | 207 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { |
| 187 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 208 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), |
| 188 | pre => { | 209 | pre => { |
| 189 | let pre: u8 = pre.into(); | 210 | let pre: u8 = pre.into(); |
| 190 | let pre: u8 = 1 << (pre - 3); | 211 | let pre: u8 = 1 << (pre - 3); |
| @@ -196,16 +217,17 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 196 | // Adjust flash latency | 217 | // Adjust flash latency |
| 197 | let flash_clk_src_freq: u32 = shd_ahb_freq; | 218 | let flash_clk_src_freq: u32 = shd_ahb_freq; |
| 198 | let ws = match vos { | 219 | let ws = match vos { |
| 199 | VoltageScale::Scale0 => match flash_clk_src_freq { | 220 | VoltageScale::RANGE1 => match flash_clk_src_freq { |
| 200 | 0..=18_000_000 => 0b000, | 221 | 0..=18_000_000 => 0b000, |
| 201 | 18_000_001..=36_000_000 => 0b001, | 222 | 18_000_001..=36_000_000 => 0b001, |
| 202 | _ => 0b010, | 223 | _ => 0b010, |
| 203 | }, | 224 | }, |
| 204 | VoltageScale::Scale1 => match flash_clk_src_freq { | 225 | VoltageScale::RANGE2 => match flash_clk_src_freq { |
| 205 | 0..=6_000_000 => 0b000, | 226 | 0..=6_000_000 => 0b000, |
| 206 | 6_000_001..=12_000_000 => 0b001, | 227 | 6_000_001..=12_000_000 => 0b001, |
| 207 | _ => 0b010, | 228 | _ => 0b010, |
| 208 | }, | 229 | }, |
| 230 | _ => unreachable!(), | ||
| 209 | }; | 231 | }; |
| 210 | 232 | ||
| 211 | FLASH.acr().modify(|w| { | 233 | FLASH.acr().modify(|w| { |
| @@ -214,35 +236,8 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 214 | 236 | ||
| 215 | while FLASH.acr().read().latency() != ws {} | 237 | while FLASH.acr().read().latency() != ws {} |
| 216 | 238 | ||
| 217 | match config.rtc_mux { | 239 | // Enables the LSI if configured |
| 218 | RtcClockSource::LSE32 => { | 240 | BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default())); |
| 219 | // 1. Unlock the backup domain | ||
| 220 | PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); | ||
| 221 | |||
| 222 | // 2. Setup the LSE | ||
| 223 | RCC.bdcr().modify(|w| { | ||
| 224 | // Enable LSE | ||
| 225 | w.set_lseon(true); | ||
| 226 | // Max drive strength | ||
| 227 | // TODO: should probably be settable | ||
| 228 | w.set_lsedrv(Lsedrv::High as u8); //---// PAM - should not be commented | ||
| 229 | }); | ||
| 230 | |||
| 231 | // Wait until LSE is running | ||
| 232 | while !RCC.bdcr().read().lserdy() {} | ||
| 233 | |||
| 234 | Rtc::set_clock_source(RCS::LSE); | ||
| 235 | } | ||
| 236 | RtcClockSource::LSI32 => { | ||
| 237 | // Turn on the internal 32 kHz LSI oscillator | ||
| 238 | RCC.csr().modify(|w| w.set_lsion(true)); | ||
| 239 | |||
| 240 | // Wait until LSI is running | ||
| 241 | while !RCC.csr().read().lsirdy() {} | ||
| 242 | |||
| 243 | Rtc::set_clock_source(RCS::LSI); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | 241 | ||
| 247 | match config.mux { | 242 | match config.mux { |
| 248 | ClockSrc::HSI16 => { | 243 | ClockSrc::HSI16 => { |
| @@ -266,7 +261,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 266 | w.set_msirange(range.into()); | 261 | w.set_msirange(range.into()); |
| 267 | w.set_msion(true); | 262 | w.set_msion(true); |
| 268 | 263 | ||
| 269 | if let RtcClockSource::LSE32 = config.rtc_mux { | 264 | if let RtcClockSource::LSE = config.rtc_mux { |
| 270 | // If LSE is enabled, enable calibration of MSI | 265 | // If LSE is enabled, enable calibration of MSI |
| 271 | w.set_msipllen(true); | 266 | w.set_msipllen(true); |
| 272 | } else { | 267 | } else { |
| @@ -277,16 +272,8 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 277 | } | 272 | } |
| 278 | } | 273 | } |
| 279 | 274 | ||
| 280 | if config.enable_rtc_apb { | ||
| 281 | // enable peripheral clock for communication | ||
| 282 | crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true)); | ||
| 283 | |||
| 284 | // read to allow the pwr clock to enable | ||
| 285 | crate::pac::PWR.cr1().read(); | ||
| 286 | } | ||
| 287 | |||
| 288 | RCC.extcfgr().modify(|w| { | 275 | RCC.extcfgr().modify(|w| { |
| 289 | if config.shd_ahb_pre == AHBPrescaler::NotDivided { | 276 | if config.shd_ahb_pre == AHBPrescaler::DIV1 { |
| 290 | w.set_shdhpre(0); | 277 | w.set_shdhpre(0); |
| 291 | } else { | 278 | } else { |
| 292 | w.set_shdhpre(config.shd_ahb_pre.into()); | 279 | w.set_shdhpre(config.shd_ahb_pre.into()); |
| @@ -295,24 +282,15 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 295 | 282 | ||
| 296 | RCC.cfgr().modify(|w| { | 283 | RCC.cfgr().modify(|w| { |
| 297 | w.set_sw(sw.into()); | 284 | w.set_sw(sw.into()); |
| 298 | if config.ahb_pre == AHBPrescaler::NotDivided { | 285 | w.set_hpre(config.ahb_pre); |
| 299 | w.set_hpre(0); | ||
| 300 | } else { | ||
| 301 | w.set_hpre(config.ahb_pre.into()); | ||
| 302 | } | ||
| 303 | w.set_ppre1(config.apb1_pre.into()); | 286 | w.set_ppre1(config.apb1_pre.into()); |
| 304 | w.set_ppre2(config.apb2_pre.into()); | 287 | w.set_ppre2(config.apb2_pre.into()); |
| 305 | }); | 288 | }); |
| 306 | 289 | ||
| 307 | // TODO: switch voltage range | 290 | // ADC clock MUX |
| 291 | RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel())); | ||
| 308 | 292 | ||
| 309 | if config.enable_lsi { | 293 | // TODO: switch voltage range |
| 310 | let csr = RCC.csr().read(); | ||
| 311 | if !csr.lsion() { | ||
| 312 | RCC.csr().modify(|w| w.set_lsion(true)); | ||
| 313 | while !RCC.csr().read().lsirdy() {} | ||
| 314 | } | ||
| 315 | } | ||
| 316 | 294 | ||
| 317 | set_freqs(Clocks { | 295 | set_freqs(Clocks { |
| 318 | sys: Hertz(sys_clk), | 296 | sys: Hertz(sys_clk), |
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 30816e436..0979dce8c 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs | |||
| @@ -119,7 +119,31 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 119 | 119 | ||
| 120 | pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { | 120 | pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { |
| 121 | for chunk in dest.chunks_mut(4) { | 121 | for chunk in dest.chunks_mut(4) { |
| 122 | let bits = T::regs().sr().read(); | 122 | let mut bits = T::regs().sr().read(); |
| 123 | if !bits.seis() && !bits.ceis() && !bits.drdy() { | ||
| 124 | // wait for interrupt | ||
| 125 | poll_fn(|cx| { | ||
| 126 | // quick check to avoid registration if already done. | ||
| 127 | let bits = T::regs().sr().read(); | ||
| 128 | if bits.drdy() || bits.seis() || bits.ceis() { | ||
| 129 | return Poll::Ready(()); | ||
| 130 | } | ||
| 131 | RNG_WAKER.register(cx.waker()); | ||
| 132 | T::regs().cr().modify(|reg| reg.set_ie(true)); | ||
| 133 | // Need to check condition **after** `register` to avoid a race | ||
| 134 | // condition that would result in lost notifications. | ||
| 135 | let bits = T::regs().sr().read(); | ||
| 136 | if bits.drdy() || bits.seis() || bits.ceis() { | ||
| 137 | Poll::Ready(()) | ||
| 138 | } else { | ||
| 139 | Poll::Pending | ||
| 140 | } | ||
| 141 | }) | ||
| 142 | .await; | ||
| 143 | |||
| 144 | // Re-read the status register after wait. | ||
| 145 | bits = T::regs().sr().read() | ||
| 146 | } | ||
| 123 | if bits.seis() { | 147 | if bits.seis() { |
| 124 | // in case of noise-source or seed error we try to recover here | 148 | // in case of noise-source or seed error we try to recover here |
| 125 | // but we must not use the data in DR and we return an error | 149 | // but we must not use the data in DR and we return an error |
| @@ -143,26 +167,6 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 143 | for (dest, src) in chunk.iter_mut().zip(random_word.to_be_bytes().iter()) { | 167 | for (dest, src) in chunk.iter_mut().zip(random_word.to_be_bytes().iter()) { |
| 144 | *dest = *src | 168 | *dest = *src |
| 145 | } | 169 | } |
| 146 | } else { | ||
| 147 | // wait for interrupt | ||
| 148 | poll_fn(|cx| { | ||
| 149 | // quick check to avoid registration if already done. | ||
| 150 | let bits = T::regs().sr().read(); | ||
| 151 | if bits.drdy() || bits.seis() || bits.ceis() { | ||
| 152 | return Poll::Ready(()); | ||
| 153 | } | ||
| 154 | RNG_WAKER.register(cx.waker()); | ||
| 155 | T::regs().cr().modify(|reg| reg.set_ie(true)); | ||
| 156 | // Need to check condition **after** `register` to avoid a race | ||
| 157 | // condition that would result in lost notifications. | ||
| 158 | let bits = T::regs().sr().read(); | ||
| 159 | if bits.drdy() || bits.seis() || bits.ceis() { | ||
| 160 | Poll::Ready(()) | ||
| 161 | } else { | ||
| 162 | Poll::Pending | ||
| 163 | } | ||
| 164 | }) | ||
| 165 | .await; | ||
| 166 | } | 170 | } |
| 167 | } | 171 | } |
| 168 | 172 | ||
diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs index a9c48d88d..3efe9be5d 100644 --- a/embassy-stm32/src/rtc/datetime.rs +++ b/embassy-stm32/src/rtc/datetime.rs | |||
| @@ -89,7 +89,7 @@ pub enum DayOfWeek { | |||
| 89 | #[cfg(feature = "chrono")] | 89 | #[cfg(feature = "chrono")] |
| 90 | impl From<chrono::Weekday> for DayOfWeek { | 90 | impl From<chrono::Weekday> for DayOfWeek { |
| 91 | fn from(weekday: Weekday) -> Self { | 91 | fn from(weekday: Weekday) -> Self { |
| 92 | day_of_week_from_u8(weekday.number_from_monday() as u8).unwrap() | 92 | day_of_week_from_u8(weekday.num_days_from_monday() as u8).unwrap() |
| 93 | } | 93 | } |
| 94 | } | 94 | } |
| 95 | 95 | ||
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index a6102077a..73b78f253 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs | |||
| @@ -1,7 +1,17 @@ | |||
| 1 | //! RTC peripheral abstraction | 1 | //! RTC peripheral abstraction |
| 2 | mod datetime; | 2 | mod datetime; |
| 3 | 3 | ||
| 4 | #[cfg(feature = "low-power")] | ||
| 5 | use core::cell::Cell; | ||
| 6 | |||
| 7 | #[cfg(feature = "low-power")] | ||
| 8 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 9 | #[cfg(feature = "low-power")] | ||
| 10 | use embassy_sync::blocking_mutex::Mutex; | ||
| 11 | |||
| 4 | pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; | 12 | pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; |
| 13 | pub use crate::rcc::RtcClockSource; | ||
| 14 | use crate::time::Hertz; | ||
| 5 | 15 | ||
| 6 | /// refer to AN4759 to compare features of RTC2 and RTC3 | 16 | /// refer to AN4759 to compare features of RTC2 and RTC3 |
| 7 | #[cfg_attr(any(rtc_v1), path = "v1.rs")] | 17 | #[cfg_attr(any(rtc_v1), path = "v1.rs")] |
| @@ -30,60 +40,99 @@ pub enum RtcError { | |||
| 30 | NotRunning, | 40 | NotRunning, |
| 31 | } | 41 | } |
| 32 | 42 | ||
| 33 | /// RTC Abstraction | 43 | #[cfg(feature = "low-power")] |
| 34 | pub struct Rtc { | 44 | /// Represents an instant in time that can be substracted to compute a duration |
| 35 | rtc_config: RtcConfig, | 45 | struct RtcInstant { |
| 46 | second: u8, | ||
| 47 | subsecond: u16, | ||
| 36 | } | 48 | } |
| 37 | 49 | ||
| 38 | #[derive(Copy, Clone, Debug, PartialEq)] | 50 | #[cfg(all(feature = "low-power", feature = "defmt"))] |
| 39 | #[repr(u8)] | 51 | impl defmt::Format for RtcInstant { |
| 40 | pub enum RtcClockSource { | 52 | fn format(&self, fmt: defmt::Formatter) { |
| 41 | /// 00: No clock | 53 | defmt::write!( |
| 42 | NoClock = 0b00, | 54 | fmt, |
| 43 | /// 01: LSE oscillator clock used as RTC clock | 55 | "{}:{}", |
| 44 | LSE = 0b01, | 56 | self.second, |
| 45 | /// 10: LSI oscillator clock used as RTC clock | 57 | RTC::regs().prer().read().prediv_s() - self.subsecond, |
| 46 | LSI = 0b10, | 58 | ) |
| 47 | /// 11: HSE oscillator clock divided by 32 used as RTC clock | 59 | } |
| 48 | HSE = 0b11, | 60 | } |
| 61 | |||
| 62 | #[cfg(feature = "low-power")] | ||
| 63 | impl core::ops::Sub for RtcInstant { | ||
| 64 | type Output = embassy_time::Duration; | ||
| 65 | |||
| 66 | fn sub(self, rhs: Self) -> Self::Output { | ||
| 67 | use embassy_time::{Duration, TICK_HZ}; | ||
| 68 | |||
| 69 | let second = if self.second < rhs.second { | ||
| 70 | self.second + 60 | ||
| 71 | } else { | ||
| 72 | self.second | ||
| 73 | }; | ||
| 74 | |||
| 75 | let psc = RTC::regs().prer().read().prediv_s() as u32; | ||
| 76 | |||
| 77 | let self_ticks = second as u32 * (psc + 1) + (psc - self.subsecond as u32); | ||
| 78 | let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32); | ||
| 79 | let rtc_ticks = self_ticks - other_ticks; | ||
| 80 | |||
| 81 | Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / (psc + 1)) as u64) | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | pub struct RtcTimeProvider { | ||
| 86 | _private: (), | ||
| 87 | } | ||
| 88 | |||
| 89 | impl RtcTimeProvider { | ||
| 90 | /// Return the current datetime. | ||
| 91 | /// | ||
| 92 | /// # Errors | ||
| 93 | /// | ||
| 94 | /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. | ||
| 95 | pub fn now(&self) -> Result<DateTime, RtcError> { | ||
| 96 | let r = RTC::regs(); | ||
| 97 | let tr = r.tr().read(); | ||
| 98 | let second = bcd2_to_byte((tr.st(), tr.su())); | ||
| 99 | let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); | ||
| 100 | let hour = bcd2_to_byte((tr.ht(), tr.hu())); | ||
| 101 | // Reading either RTC_SSR or RTC_TR locks the values in the higher-order | ||
| 102 | // calendar shadow registers until RTC_DR is read. | ||
| 103 | let dr = r.dr().read(); | ||
| 104 | |||
| 105 | let weekday = dr.wdu(); | ||
| 106 | let day = bcd2_to_byte((dr.dt(), dr.du())); | ||
| 107 | let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); | ||
| 108 | let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; | ||
| 109 | |||
| 110 | self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | /// RTC Abstraction | ||
| 115 | pub struct Rtc { | ||
| 116 | #[cfg(feature = "low-power")] | ||
| 117 | stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>, | ||
| 118 | #[cfg(not(feature = "low-power"))] | ||
| 119 | _private: (), | ||
| 49 | } | 120 | } |
| 50 | 121 | ||
| 122 | #[non_exhaustive] | ||
| 51 | #[derive(Copy, Clone, PartialEq)] | 123 | #[derive(Copy, Clone, PartialEq)] |
| 52 | pub struct RtcConfig { | 124 | pub struct RtcConfig { |
| 53 | /// Asynchronous prescaler factor | 125 | /// The subsecond counter frequency; default is 256 |
| 54 | /// This is the asynchronous division factor: | 126 | /// |
| 55 | /// ck_apre frequency = RTCCLK frequency/(PREDIV_A+1) | 127 | /// A high counter frequency may impact stop power consumption |
| 56 | /// ck_apre drives the subsecond register | 128 | pub frequency: Hertz, |
| 57 | async_prescaler: u8, | ||
| 58 | /// Synchronous prescaler factor | ||
| 59 | /// This is the synchronous division factor: | ||
| 60 | /// ck_spre frequency = ck_apre frequency/(PREDIV_S+1) | ||
| 61 | /// ck_spre must be 1Hz | ||
| 62 | sync_prescaler: u16, | ||
| 63 | } | 129 | } |
| 64 | 130 | ||
| 65 | impl Default for RtcConfig { | 131 | impl Default for RtcConfig { |
| 66 | /// LSI with prescalers assuming 32.768 kHz. | 132 | /// LSI with prescalers assuming 32.768 kHz. |
| 67 | /// Raw sub-seconds in 1/256. | 133 | /// Raw sub-seconds in 1/256. |
| 68 | fn default() -> Self { | 134 | fn default() -> Self { |
| 69 | RtcConfig { | 135 | RtcConfig { frequency: Hertz(256) } |
| 70 | async_prescaler: 127, | ||
| 71 | sync_prescaler: 255, | ||
| 72 | } | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | impl RtcConfig { | ||
| 77 | /// Set the asynchronous prescaler of RTC config | ||
| 78 | pub fn async_prescaler(mut self, prescaler: u8) -> Self { | ||
| 79 | self.async_prescaler = prescaler; | ||
| 80 | self | ||
| 81 | } | ||
| 82 | |||
| 83 | /// Set the synchronous prescaler of RTC config | ||
| 84 | pub fn sync_prescaler(mut self, prescaler: u16) -> Self { | ||
| 85 | self.sync_prescaler = prescaler; | ||
| 86 | self | ||
| 87 | } | 136 | } |
| 88 | } | 137 | } |
| 89 | 138 | ||
| @@ -106,16 +155,44 @@ impl Default for RtcCalibrationCyclePeriod { | |||
| 106 | 155 | ||
| 107 | impl Rtc { | 156 | impl Rtc { |
| 108 | pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { | 157 | pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { |
| 109 | RTC::enable_peripheral_clk(); | 158 | #[cfg(any(rcc_wle, rcc_wl5, rcc_g4, rcc_g0, rtc_v2l4, rtc_v2wb))] |
| 159 | <RTC as crate::rcc::sealed::RccPeripheral>::enable(); | ||
| 160 | |||
| 161 | let mut this = Self { | ||
| 162 | #[cfg(feature = "low-power")] | ||
| 163 | stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), | ||
| 164 | #[cfg(not(feature = "low-power"))] | ||
| 165 | _private: (), | ||
| 166 | }; | ||
| 167 | |||
| 168 | let frequency = Self::frequency(); | ||
| 169 | let async_psc = ((frequency.0 / rtc_config.frequency.0) - 1) as u8; | ||
| 170 | let sync_psc = (rtc_config.frequency.0 - 1) as u16; | ||
| 110 | 171 | ||
| 111 | let mut rtc_struct = Self { rtc_config }; | 172 | this.configure(async_psc, sync_psc); |
| 112 | 173 | ||
| 113 | Self::enable(); | 174 | this |
| 175 | } | ||
| 176 | |||
| 177 | fn frequency() -> Hertz { | ||
| 178 | #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] | ||
| 179 | let freqs = unsafe { crate::rcc::get_freqs() }; | ||
| 180 | |||
| 181 | // Load the clock frequency from the rcc mod, if supported | ||
| 182 | #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] | ||
| 183 | match freqs.rtc { | ||
| 184 | Some(hertz) => hertz, | ||
| 185 | None => freqs.rtc_hse.unwrap(), | ||
| 186 | } | ||
| 114 | 187 | ||
| 115 | rtc_struct.configure(rtc_config); | 188 | // Assume the default value, if not supported |
| 116 | rtc_struct.rtc_config = rtc_config; | 189 | #[cfg(not(any(rcc_wb, rcc_f4, rcc_f410)))] |
| 190 | Hertz(32_768) | ||
| 191 | } | ||
| 117 | 192 | ||
| 118 | rtc_struct | 193 | /// Acquire a [`RtcTimeProvider`] instance. |
| 194 | pub const fn time_provider(&self) -> RtcTimeProvider { | ||
| 195 | RtcTimeProvider { _private: () } | ||
| 119 | } | 196 | } |
| 120 | 197 | ||
| 121 | /// Set the datetime to a new value. | 198 | /// Set the datetime to a new value. |
| @@ -130,27 +207,27 @@ impl Rtc { | |||
| 130 | Ok(()) | 207 | Ok(()) |
| 131 | } | 208 | } |
| 132 | 209 | ||
| 210 | #[cfg(feature = "low-power")] | ||
| 211 | /// Return the current instant. | ||
| 212 | fn instant(&self) -> RtcInstant { | ||
| 213 | let r = RTC::regs(); | ||
| 214 | let tr = r.tr().read(); | ||
| 215 | let subsecond = r.ssr().read().ss(); | ||
| 216 | let second = bcd2_to_byte((tr.st(), tr.su())); | ||
| 217 | |||
| 218 | // Unlock the registers | ||
| 219 | r.dr().read(); | ||
| 220 | |||
| 221 | RtcInstant { second, subsecond } | ||
| 222 | } | ||
| 223 | |||
| 133 | /// Return the current datetime. | 224 | /// Return the current datetime. |
| 134 | /// | 225 | /// |
| 135 | /// # Errors | 226 | /// # Errors |
| 136 | /// | 227 | /// |
| 137 | /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. | 228 | /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. |
| 138 | pub fn now(&self) -> Result<DateTime, RtcError> { | 229 | pub fn now(&self) -> Result<DateTime, RtcError> { |
| 139 | let r = RTC::regs(); | 230 | self.time_provider().now() |
| 140 | let tr = r.tr().read(); | ||
| 141 | let second = bcd2_to_byte((tr.st(), tr.su())); | ||
| 142 | let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); | ||
| 143 | let hour = bcd2_to_byte((tr.ht(), tr.hu())); | ||
| 144 | // Reading either RTC_SSR or RTC_TR locks the values in the higher-order | ||
| 145 | // calendar shadow registers until RTC_DR is read. | ||
| 146 | let dr = r.dr().read(); | ||
| 147 | |||
| 148 | let weekday = dr.wdu(); | ||
| 149 | let day = bcd2_to_byte((dr.dt(), dr.du())); | ||
| 150 | let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); | ||
| 151 | let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; | ||
| 152 | |||
| 153 | self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) | ||
| 154 | } | 231 | } |
| 155 | 232 | ||
| 156 | /// Check if daylight savings time is active. | 233 | /// Check if daylight savings time is active. |
| @@ -166,10 +243,6 @@ impl Rtc { | |||
| 166 | }) | 243 | }) |
| 167 | } | 244 | } |
| 168 | 245 | ||
| 169 | pub fn get_config(&self) -> RtcConfig { | ||
| 170 | self.rtc_config | ||
| 171 | } | ||
| 172 | |||
| 173 | pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT; | 246 | pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT; |
| 174 | 247 | ||
| 175 | /// Read content of the backup register. | 248 | /// Read content of the backup register. |
| @@ -215,12 +288,16 @@ pub(crate) mod sealed { | |||
| 215 | pub trait Instance { | 288 | pub trait Instance { |
| 216 | const BACKUP_REGISTER_COUNT: usize; | 289 | const BACKUP_REGISTER_COUNT: usize; |
| 217 | 290 | ||
| 291 | #[cfg(feature = "low-power")] | ||
| 292 | const EXTI_WAKEUP_LINE: usize; | ||
| 293 | |||
| 294 | #[cfg(feature = "low-power")] | ||
| 295 | type WakeupInterrupt: crate::interrupt::typelevel::Interrupt; | ||
| 296 | |||
| 218 | fn regs() -> Rtc { | 297 | fn regs() -> Rtc { |
| 219 | crate::pac::RTC | 298 | crate::pac::RTC |
| 220 | } | 299 | } |
| 221 | 300 | ||
| 222 | fn enable_peripheral_clk() {} | ||
| 223 | |||
| 224 | /// Read content of the backup register. | 301 | /// Read content of the backup register. |
| 225 | /// | 302 | /// |
| 226 | /// The registers retain their values during wakes from standby mode or system resets. They also | 303 | /// The registers retain their values during wakes from standby mode or system resets. They also |
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index bcb127ecb..4608d3114 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs | |||
| @@ -1,77 +1,21 @@ | |||
| 1 | use stm32_metapac::rtc::vals::{Init, Osel, Pol}; | 1 | use stm32_metapac::rtc::vals::{Init, Osel, Pol}; |
| 2 | 2 | ||
| 3 | use super::{sealed, RtcClockSource, RtcConfig}; | 3 | use super::sealed; |
| 4 | use crate::pac::rtc::Rtc; | 4 | use crate::pac::rtc::Rtc; |
| 5 | use crate::peripherals::RTC; | 5 | use crate::peripherals::RTC; |
| 6 | use crate::rtc::sealed::Instance; | 6 | use crate::rtc::sealed::Instance; |
| 7 | 7 | ||
| 8 | #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] | ||
| 9 | pub struct RtcInstant { | ||
| 10 | ssr: u16, | ||
| 11 | st: u8, | ||
| 12 | } | ||
| 13 | |||
| 14 | #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] | ||
| 15 | impl RtcInstant { | ||
| 16 | pub fn now() -> Self { | ||
| 17 | // TODO: read value twice | ||
| 18 | use crate::rtc::bcd2_to_byte; | ||
| 19 | |||
| 20 | let tr = RTC::regs().tr().read(); | ||
| 21 | let tr2 = RTC::regs().tr().read(); | ||
| 22 | let ssr = RTC::regs().ssr().read().ss(); | ||
| 23 | let ssr2 = RTC::regs().ssr().read().ss(); | ||
| 24 | |||
| 25 | let st = bcd2_to_byte((tr.st(), tr.su())); | ||
| 26 | let st2 = bcd2_to_byte((tr2.st(), tr2.su())); | ||
| 27 | |||
| 28 | assert!(st == st2); | ||
| 29 | assert!(ssr == ssr2); | ||
| 30 | |||
| 31 | let _ = RTC::regs().dr().read(); | ||
| 32 | |||
| 33 | trace!("ssr: {}", ssr); | ||
| 34 | trace!("st: {}", st); | ||
| 35 | |||
| 36 | Self { ssr, st } | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] | ||
| 41 | impl core::ops::Sub for RtcInstant { | ||
| 42 | type Output = embassy_time::Duration; | ||
| 43 | |||
| 44 | fn sub(self, rhs: Self) -> Self::Output { | ||
| 45 | use embassy_time::{Duration, TICK_HZ}; | ||
| 46 | |||
| 47 | let st = if self.st < rhs.st { self.st + 60 } else { self.st }; | ||
| 48 | |||
| 49 | // TODO: read prescaler | ||
| 50 | |||
| 51 | let self_ticks = st as u32 * 256 + (255 - self.ssr as u32); | ||
| 52 | let other_ticks = rhs.st as u32 * 256 + (255 - rhs.ssr as u32); | ||
| 53 | let rtc_ticks = self_ticks - other_ticks; | ||
| 54 | |||
| 55 | trace!("self, other, rtc ticks: {}, {}, {}", self_ticks, other_ticks, rtc_ticks); | ||
| 56 | |||
| 57 | Duration::from_ticks( | ||
| 58 | ((((st as u32 * 256 + (255u32 - self.ssr as u32)) - (rhs.st as u32 * 256 + (255u32 - rhs.ssr as u32))) | ||
| 59 | * TICK_HZ as u32) as u32 | ||
| 60 | / 256u32) as u64, | ||
| 61 | ) | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | #[allow(dead_code)] | 8 | #[allow(dead_code)] |
| 9 | #[repr(u8)] | ||
| 66 | #[derive(Clone, Copy, Debug)] | 10 | #[derive(Clone, Copy, Debug)] |
| 67 | pub(crate) enum WakeupPrescaler { | 11 | pub(crate) enum WakeupPrescaler { |
| 68 | Div2, | 12 | Div2 = 2, |
| 69 | Div4, | 13 | Div4 = 4, |
| 70 | Div8, | 14 | Div8 = 8, |
| 71 | Div16, | 15 | Div16 = 16, |
| 72 | } | 16 | } |
| 73 | 17 | ||
| 74 | #[cfg(any(stm32wb, stm32f4))] | 18 | #[cfg(any(stm32wb, stm32f4, stm32l0))] |
| 75 | impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { | 19 | impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { |
| 76 | fn from(val: WakeupPrescaler) -> Self { | 20 | fn from(val: WakeupPrescaler) -> Self { |
| 77 | use crate::pac::rtc::vals::Wucksel; | 21 | use crate::pac::rtc::vals::Wucksel; |
| @@ -85,7 +29,7 @@ impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { | |||
| 85 | } | 29 | } |
| 86 | } | 30 | } |
| 87 | 31 | ||
| 88 | #[cfg(any(stm32wb, stm32f4))] | 32 | #[cfg(any(stm32wb, stm32f4, stm32l0))] |
| 89 | impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { | 33 | impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { |
| 90 | fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { | 34 | fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { |
| 91 | use crate::pac::rtc::vals::Wucksel; | 35 | use crate::pac::rtc::vals::Wucksel; |
| @@ -100,17 +44,6 @@ impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { | |||
| 100 | } | 44 | } |
| 101 | } | 45 | } |
| 102 | 46 | ||
| 103 | impl From<WakeupPrescaler> for u32 { | ||
| 104 | fn from(val: WakeupPrescaler) -> Self { | ||
| 105 | match val { | ||
| 106 | WakeupPrescaler::Div2 => 2, | ||
| 107 | WakeupPrescaler::Div4 => 4, | ||
| 108 | WakeupPrescaler::Div8 => 8, | ||
| 109 | WakeupPrescaler::Div16 => 16, | ||
| 110 | } | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | #[allow(dead_code)] | 47 | #[allow(dead_code)] |
| 115 | impl WakeupPrescaler { | 48 | impl WakeupPrescaler { |
| 116 | pub fn compute_min(val: u32) -> Self { | 49 | pub fn compute_min(val: u32) -> Self { |
| @@ -121,158 +54,100 @@ impl WakeupPrescaler { | |||
| 121 | WakeupPrescaler::Div16, | 54 | WakeupPrescaler::Div16, |
| 122 | ] | 55 | ] |
| 123 | .iter() | 56 | .iter() |
| 124 | .skip_while(|psc| <WakeupPrescaler as Into<u32>>::into(**psc) <= val) | 57 | .skip_while(|psc| **psc as u32 <= val) |
| 125 | .next() | 58 | .next() |
| 126 | .unwrap_or(&WakeupPrescaler::Div16) | 59 | .unwrap_or(&WakeupPrescaler::Div16) |
| 127 | } | 60 | } |
| 128 | } | 61 | } |
| 129 | 62 | ||
| 130 | impl super::Rtc { | 63 | impl super::Rtc { |
| 131 | fn unlock_registers() { | 64 | #[cfg(feature = "low-power")] |
| 132 | #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] | 65 | /// start the wakeup alarm and wtih a duration that is as close to but less than |
| 133 | let cr = crate::pac::PWR.cr(); | 66 | /// the requested duration, and record the instant the wakeup alarm was started |
| 134 | #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] | 67 | pub(crate) fn start_wakeup_alarm( |
| 135 | let cr = crate::pac::PWR.cr1(); | 68 | &self, |
| 136 | 69 | requested_duration: embassy_time::Duration, | |
| 137 | // TODO: Missing from PAC for l0 and f0? | 70 | cs: critical_section::CriticalSection, |
| 138 | #[cfg(not(any(rtc_v2f0, rtc_v2l0)))] | 71 | ) { |
| 139 | { | ||
| 140 | if !cr.read().dbp() { | ||
| 141 | cr.modify(|w| w.set_dbp(true)); | ||
| 142 | while !cr.read().dbp() {} | ||
| 143 | } | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | #[allow(dead_code)] | ||
| 148 | #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] | ||
| 149 | /// start the wakeup alarm and return the actual duration of the alarm | ||
| 150 | /// the actual duration will be the closest value possible that is less | ||
| 151 | /// than the requested duration. | ||
| 152 | /// | ||
| 153 | /// note: this api is exposed for testing purposes until low power is implemented. | ||
| 154 | /// it is not intended to be public | ||
| 155 | pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) -> RtcInstant { | ||
| 156 | use embassy_time::{Duration, TICK_HZ}; | 72 | use embassy_time::{Duration, TICK_HZ}; |
| 157 | 73 | ||
| 158 | use crate::rcc::get_freqs; | 74 | // Panic if the rcc mod knows we're not using low-power rtc |
| 75 | #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] | ||
| 76 | unsafe { crate::rcc::get_freqs() }.rtc.unwrap(); | ||
| 159 | 77 | ||
| 160 | let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64; | 78 | let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); |
| 161 | 79 | let rtc_hz = Self::frequency().0 as u64; | |
| 162 | let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ; | 80 | let rtc_ticks = requested_duration * rtc_hz / TICK_HZ; |
| 163 | let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); | 81 | let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); |
| 164 | 82 | ||
| 165 | // adjust the rtc ticks to the prescaler | 83 | // adjust the rtc ticks to the prescaler and subtract one rtc tick |
| 166 | let rtc_ticks = rtc_ticks / (<WakeupPrescaler as Into<u32>>::into(prescaler) as u64); | 84 | let rtc_ticks = rtc_ticks / prescaler as u64; |
| 167 | let rtc_ticks = if rtc_ticks >= u16::MAX as u64 { | 85 | let rtc_ticks = rtc_ticks.clamp(0, (u16::MAX - 1) as u64).saturating_sub(1) as u16; |
| 168 | u16::MAX - 1 | ||
| 169 | } else { | ||
| 170 | rtc_ticks as u16 | ||
| 171 | }; | ||
| 172 | |||
| 173 | let duration = Duration::from_ticks( | ||
| 174 | rtc_ticks as u64 * TICK_HZ * (<WakeupPrescaler as Into<u32>>::into(prescaler) as u64) / rtc_hz, | ||
| 175 | ); | ||
| 176 | |||
| 177 | trace!("set wakeup timer for {} ms", duration.as_millis()); | ||
| 178 | 86 | ||
| 179 | self.write(false, |regs| { | 87 | self.write(false, |regs| { |
| 180 | regs.cr().modify(|w| w.set_wutie(true)); | ||
| 181 | |||
| 182 | regs.cr().modify(|w| w.set_wute(false)); | 88 | regs.cr().modify(|w| w.set_wute(false)); |
| 183 | regs.isr().modify(|w| w.set_wutf(false)); | 89 | regs.isr().modify(|w| w.set_wutf(false)); |
| 184 | while !regs.isr().read().wutwf() {} | 90 | while !regs.isr().read().wutwf() {} |
| 185 | 91 | ||
| 186 | regs.cr().modify(|w| w.set_wucksel(prescaler.into())); | 92 | regs.cr().modify(|w| w.set_wucksel(prescaler.into())); |
| 93 | regs.wutr().write(|w| w.set_wut(rtc_ticks)); | ||
| 187 | regs.cr().modify(|w| w.set_wute(true)); | 94 | regs.cr().modify(|w| w.set_wute(true)); |
| 95 | regs.cr().modify(|w| w.set_wutie(true)); | ||
| 188 | }); | 96 | }); |
| 189 | 97 | ||
| 190 | RtcInstant::now() | 98 | trace!( |
| 99 | "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}", | ||
| 100 | Duration::from_ticks(rtc_ticks as u64 * TICK_HZ * prescaler as u64 / rtc_hz).as_millis(), | ||
| 101 | prescaler as u32, | ||
| 102 | rtc_ticks, | ||
| 103 | self.instant(), | ||
| 104 | ); | ||
| 105 | |||
| 106 | assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none()) | ||
| 191 | } | 107 | } |
| 192 | 108 | ||
| 193 | #[allow(dead_code)] | 109 | #[cfg(feature = "low-power")] |
| 194 | #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] | 110 | /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` |
| 195 | /// stop the wakeup alarm and return the time remaining | 111 | /// was called, otherwise none |
| 196 | /// | 112 | pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> { |
| 197 | /// note: this api is exposed for testing purposes until low power is implemented. | 113 | use crate::interrupt::typelevel::Interrupt; |
| 198 | /// it is not intended to be public | 114 | |
| 199 | pub(crate) fn stop_wakeup_alarm(&self) -> RtcInstant { | 115 | trace!("rtc: stop wakeup alarm at {}", self.instant()); |
| 200 | trace!("disable wakeup timer..."); | ||
| 201 | 116 | ||
| 202 | self.write(false, |regs| { | 117 | self.write(false, |regs| { |
| 118 | regs.cr().modify(|w| w.set_wutie(false)); | ||
| 203 | regs.cr().modify(|w| w.set_wute(false)); | 119 | regs.cr().modify(|w| w.set_wute(false)); |
| 204 | regs.isr().modify(|w| w.set_wutf(false)); | 120 | regs.isr().modify(|w| w.set_wutf(false)); |
| 205 | }); | ||
| 206 | |||
| 207 | RtcInstant::now() | ||
| 208 | } | ||
| 209 | |||
| 210 | #[allow(dead_code)] | ||
| 211 | pub(crate) fn set_clock_source(clock_source: RtcClockSource) { | ||
| 212 | #[cfg(not(rtc_v2wb))] | ||
| 213 | use stm32_metapac::rcc::vals::Rtcsel; | ||
| 214 | 121 | ||
| 215 | #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | 122 | crate::pac::EXTI |
| 216 | let cr = crate::pac::RCC.bdcr(); | 123 | .pr(0) |
| 217 | #[cfg(any(rtc_v2l0, rtc_v2l1))] | 124 | .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); |
| 218 | let cr = crate::pac::RCC.csr(); | ||
| 219 | 125 | ||
| 220 | Self::unlock_registers(); | 126 | <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend(); |
| 221 | |||
| 222 | cr.modify(|w| { | ||
| 223 | // Select RTC source | ||
| 224 | #[cfg(not(rtc_v2wb))] | ||
| 225 | w.set_rtcsel(Rtcsel::from_bits(clock_source as u8)); | ||
| 226 | #[cfg(rtc_v2wb)] | ||
| 227 | w.set_rtcsel(clock_source as u8); | ||
| 228 | }); | 127 | }); |
| 229 | } | ||
| 230 | 128 | ||
| 231 | pub(super) fn enable() { | 129 | if let Some(stop_time) = self.stop_time.borrow(cs).take() { |
| 232 | #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | 130 | Some(self.instant() - stop_time) |
| 233 | let reg = crate::pac::RCC.bdcr().read(); | 131 | } else { |
| 234 | #[cfg(any(rtc_v2l0, rtc_v2l1))] | 132 | None |
| 235 | let reg = crate::pac::RCC.csr().read(); | 133 | } |
| 236 | 134 | } | |
| 237 | #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] | ||
| 238 | assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); | ||
| 239 | |||
| 240 | if !reg.rtcen() { | ||
| 241 | Self::unlock_registers(); | ||
| 242 | |||
| 243 | #[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))] | ||
| 244 | crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); | ||
| 245 | #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | ||
| 246 | let cr = crate::pac::RCC.bdcr(); | ||
| 247 | #[cfg(any(rtc_v2l0, rtc_v2l1))] | ||
| 248 | let cr = crate::pac::RCC.csr(); | ||
| 249 | |||
| 250 | cr.modify(|w| { | ||
| 251 | // Reset | ||
| 252 | #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | ||
| 253 | w.set_bdrst(false); | ||
| 254 | |||
| 255 | w.set_rtcen(true); | ||
| 256 | w.set_rtcsel(reg.rtcsel()); | ||
| 257 | 135 | ||
| 258 | // Restore bcdr | 136 | #[cfg(feature = "low-power")] |
| 259 | #[cfg(any(rtc_v2l4, rtc_v2wb))] | 137 | pub(crate) fn enable_wakeup_line(&self) { |
| 260 | w.set_lscosel(reg.lscosel()); | 138 | use crate::interrupt::typelevel::Interrupt; |
| 261 | #[cfg(any(rtc_v2l4, rtc_v2wb))] | 139 | use crate::pac::EXTI; |
| 262 | w.set_lscoen(reg.lscoen()); | ||
| 263 | 140 | ||
| 264 | w.set_lseon(reg.lseon()); | 141 | <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend(); |
| 142 | unsafe { <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::enable() }; | ||
| 265 | 143 | ||
| 266 | #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] | 144 | EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); |
| 267 | w.set_lsedrv(reg.lsedrv()); | 145 | EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); |
| 268 | w.set_lsebyp(reg.lsebyp()); | ||
| 269 | }); | ||
| 270 | } | ||
| 271 | } | 146 | } |
| 272 | 147 | ||
| 273 | /// Applies the RTC config | 148 | /// Applies the RTC config |
| 274 | /// It this changes the RTC clock source the time will be reset | 149 | /// It this changes the RTC clock source the time will be reset |
| 275 | pub(super) fn configure(&mut self, rtc_config: RtcConfig) { | 150 | pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { |
| 276 | self.write(true, |rtc| { | 151 | self.write(true, |rtc| { |
| 277 | rtc.cr().modify(|w| { | 152 | rtc.cr().modify(|w| { |
| 278 | #[cfg(rtc_v2f2)] | 153 | #[cfg(rtc_v2f2)] |
| @@ -284,8 +159,8 @@ impl super::Rtc { | |||
| 284 | }); | 159 | }); |
| 285 | 160 | ||
| 286 | rtc.prer().modify(|w| { | 161 | rtc.prer().modify(|w| { |
| 287 | w.set_prediv_s(rtc_config.sync_prescaler); | 162 | w.set_prediv_s(sync_psc); |
| 288 | w.set_prediv_a(rtc_config.async_prescaler); | 163 | w.set_prediv_a(async_psc); |
| 289 | }); | 164 | }); |
| 290 | }); | 165 | }); |
| 291 | } | 166 | } |
| @@ -390,21 +265,17 @@ impl super::Rtc { | |||
| 390 | impl sealed::Instance for crate::peripherals::RTC { | 265 | impl sealed::Instance for crate::peripherals::RTC { |
| 391 | const BACKUP_REGISTER_COUNT: usize = 20; | 266 | const BACKUP_REGISTER_COUNT: usize = 20; |
| 392 | 267 | ||
| 393 | fn enable_peripheral_clk() { | 268 | #[cfg(all(feature = "low-power", stm32f4))] |
| 394 | #[cfg(any(rtc_v2l4, rtc_v2wb))] | 269 | const EXTI_WAKEUP_LINE: usize = 22; |
| 395 | { | ||
| 396 | // enable peripheral clock for communication | ||
| 397 | crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true)); | ||
| 398 | 270 | ||
| 399 | // read to allow the pwr clock to enable | 271 | #[cfg(all(feature = "low-power", stm32l0))] |
| 400 | crate::pac::PWR.cr1().read(); | 272 | const EXTI_WAKEUP_LINE: usize = 20; |
| 401 | } | 273 | |
| 402 | #[cfg(any(rtc_v2f2))] | 274 | #[cfg(all(feature = "low-power", stm32f4))] |
| 403 | { | 275 | type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; |
| 404 | crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true)); | 276 | |
| 405 | crate::pac::PWR.cr().read(); | 277 | #[cfg(all(feature = "low-power", stm32l0))] |
| 406 | } | 278 | type WakeupInterrupt = crate::interrupt::typelevel::RTC; |
| 407 | } | ||
| 408 | 279 | ||
| 409 | fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> { | 280 | fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> { |
| 410 | if register < Self::BACKUP_REGISTER_COUNT { | 281 | if register < Self::BACKUP_REGISTER_COUNT { |
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 3297303ee..a6b2655d8 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs | |||
| @@ -1,77 +1,14 @@ | |||
| 1 | use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Init, Key, Osel, Pol, TampalrmPu, TampalrmType}; | 1 | use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Init, Key, Osel, Pol, TampalrmPu, TampalrmType}; |
| 2 | 2 | ||
| 3 | use super::{sealed, RtcCalibrationCyclePeriod, RtcClockSource, RtcConfig}; | 3 | use super::{sealed, RtcCalibrationCyclePeriod}; |
| 4 | use crate::pac::rtc::Rtc; | 4 | use crate::pac::rtc::Rtc; |
| 5 | use crate::peripherals::RTC; | 5 | use crate::peripherals::RTC; |
| 6 | use crate::rtc::sealed::Instance; | 6 | use crate::rtc::sealed::Instance; |
| 7 | 7 | ||
| 8 | impl super::Rtc { | 8 | impl super::Rtc { |
| 9 | fn unlock_registers() { | ||
| 10 | // Unlock the backup domain | ||
| 11 | #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] | ||
| 12 | { | ||
| 13 | if !crate::pac::PWR.cr1().read().dbp() { | ||
| 14 | crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); | ||
| 15 | while !crate::pac::PWR.cr1().read().dbp() {} | ||
| 16 | } | ||
| 17 | } | ||
| 18 | #[cfg(any(rcc_wl5, rcc_wle))] | ||
| 19 | { | ||
| 20 | use crate::pac::pwr::vals::Dbp; | ||
| 21 | |||
| 22 | if crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED { | ||
| 23 | crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); | ||
| 24 | while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {} | ||
| 25 | } | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | #[allow(dead_code)] | ||
| 30 | pub(crate) fn set_clock_source(clock_source: RtcClockSource) { | ||
| 31 | let clock_source = clock_source as u8; | ||
| 32 | #[cfg(not(any(rcc_wl5, rcc_wle)))] | ||
| 33 | let clock_source = crate::pac::rcc::vals::Rtcsel::from_bits(clock_source); | ||
| 34 | |||
| 35 | Self::unlock_registers(); | ||
| 36 | |||
| 37 | crate::pac::RCC.bdcr().modify(|w| { | ||
| 38 | // Select RTC source | ||
| 39 | w.set_rtcsel(clock_source); | ||
| 40 | }); | ||
| 41 | } | ||
| 42 | |||
| 43 | pub(super) fn enable() { | ||
| 44 | let bdcr = crate::pac::RCC.bdcr(); | ||
| 45 | |||
| 46 | let reg = bdcr.read(); | ||
| 47 | assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); | ||
| 48 | |||
| 49 | if !reg.rtcen() { | ||
| 50 | Self::unlock_registers(); | ||
| 51 | |||
| 52 | bdcr.modify(|w| w.set_bdrst(true)); | ||
| 53 | |||
| 54 | bdcr.modify(|w| { | ||
| 55 | // Reset | ||
| 56 | w.set_bdrst(false); | ||
| 57 | |||
| 58 | w.set_rtcen(true); | ||
| 59 | w.set_rtcsel(reg.rtcsel()); | ||
| 60 | |||
| 61 | // Restore bcdr | ||
| 62 | w.set_lscosel(reg.lscosel()); | ||
| 63 | w.set_lscoen(reg.lscoen()); | ||
| 64 | |||
| 65 | w.set_lseon(reg.lseon()); | ||
| 66 | w.set_lsedrv(reg.lsedrv()); | ||
| 67 | w.set_lsebyp(reg.lsebyp()); | ||
| 68 | }); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | /// Applies the RTC config | 9 | /// Applies the RTC config |
| 73 | /// It this changes the RTC clock source the time will be reset | 10 | /// It this changes the RTC clock source the time will be reset |
| 74 | pub(super) fn configure(&mut self, rtc_config: RtcConfig) { | 11 | pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { |
| 75 | self.write(true, |rtc| { | 12 | self.write(true, |rtc| { |
| 76 | rtc.cr().modify(|w| { | 13 | rtc.cr().modify(|w| { |
| 77 | w.set_fmt(Fmt::TWENTYFOURHOUR); | 14 | w.set_fmt(Fmt::TWENTYFOURHOUR); |
| @@ -80,8 +17,8 @@ impl super::Rtc { | |||
| 80 | }); | 17 | }); |
| 81 | 18 | ||
| 82 | rtc.prer().modify(|w| { | 19 | rtc.prer().modify(|w| { |
| 83 | w.set_prediv_s(rtc_config.sync_prescaler); | 20 | w.set_prediv_s(sync_psc); |
| 84 | w.set_prediv_a(rtc_config.async_prescaler); | 21 | w.set_prediv_a(async_psc); |
| 85 | }); | 22 | }); |
| 86 | 23 | ||
| 87 | // TODO: configuration for output pins | 24 | // TODO: configuration for output pins |
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 6b532363c..9fb380fd6 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -33,6 +33,8 @@ impl<T: Instance> InterruptHandler<T> { | |||
| 33 | w.set_dtimeoutie(enable); | 33 | w.set_dtimeoutie(enable); |
| 34 | w.set_dataendie(enable); | 34 | w.set_dataendie(enable); |
| 35 | 35 | ||
| 36 | #[cfg(sdmmc_v1)] | ||
| 37 | w.set_stbiterre(enable); | ||
| 36 | #[cfg(sdmmc_v2)] | 38 | #[cfg(sdmmc_v2)] |
| 37 | w.set_dabortie(enable); | 39 | w.set_dabortie(enable); |
| 38 | }); | 40 | }); |
| @@ -102,6 +104,8 @@ pub enum Error { | |||
| 102 | BadClock, | 104 | BadClock, |
| 103 | SignalingSwitchFailed, | 105 | SignalingSwitchFailed, |
| 104 | PeripheralBusy, | 106 | PeripheralBusy, |
| 107 | #[cfg(sdmmc_v1)] | ||
| 108 | StBitErr, | ||
| 105 | } | 109 | } |
| 106 | 110 | ||
| 107 | /// A SD command | 111 | /// A SD command |
| @@ -707,9 +711,15 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 707 | 711 | ||
| 708 | if status.dcrcfail() { | 712 | if status.dcrcfail() { |
| 709 | return Poll::Ready(Err(Error::Crc)); | 713 | return Poll::Ready(Err(Error::Crc)); |
| 710 | } else if status.dtimeout() { | 714 | } |
| 715 | if status.dtimeout() { | ||
| 711 | return Poll::Ready(Err(Error::Timeout)); | 716 | return Poll::Ready(Err(Error::Timeout)); |
| 712 | } else if status.dataend() { | 717 | } |
| 718 | #[cfg(sdmmc_v1)] | ||
| 719 | if status.stbiterr() { | ||
| 720 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 721 | } | ||
| 722 | if status.dataend() { | ||
| 713 | return Poll::Ready(Ok(())); | 723 | return Poll::Ready(Ok(())); |
| 714 | } | 724 | } |
| 715 | Poll::Pending | 725 | Poll::Pending |
| @@ -782,9 +792,15 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 782 | 792 | ||
| 783 | if status.dcrcfail() { | 793 | if status.dcrcfail() { |
| 784 | return Poll::Ready(Err(Error::Crc)); | 794 | return Poll::Ready(Err(Error::Crc)); |
| 785 | } else if status.dtimeout() { | 795 | } |
| 796 | if status.dtimeout() { | ||
| 786 | return Poll::Ready(Err(Error::Timeout)); | 797 | return Poll::Ready(Err(Error::Timeout)); |
| 787 | } else if status.dataend() { | 798 | } |
| 799 | #[cfg(sdmmc_v1)] | ||
| 800 | if status.stbiterr() { | ||
| 801 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 802 | } | ||
| 803 | if status.dataend() { | ||
| 788 | return Poll::Ready(Ok(())); | 804 | return Poll::Ready(Ok(())); |
| 789 | } | 805 | } |
| 790 | Poll::Pending | 806 | Poll::Pending |
| @@ -836,6 +852,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 836 | w.set_dataendc(true); | 852 | w.set_dataendc(true); |
| 837 | w.set_dbckendc(true); | 853 | w.set_dbckendc(true); |
| 838 | w.set_sdioitc(true); | 854 | w.set_sdioitc(true); |
| 855 | #[cfg(sdmmc_v1)] | ||
| 856 | w.set_stbiterrc(true); | ||
| 839 | 857 | ||
| 840 | #[cfg(sdmmc_v2)] | 858 | #[cfg(sdmmc_v2)] |
| 841 | { | 859 | { |
| @@ -873,9 +891,15 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 873 | 891 | ||
| 874 | if status.dcrcfail() { | 892 | if status.dcrcfail() { |
| 875 | return Poll::Ready(Err(Error::Crc)); | 893 | return Poll::Ready(Err(Error::Crc)); |
| 876 | } else if status.dtimeout() { | 894 | } |
| 895 | if status.dtimeout() { | ||
| 877 | return Poll::Ready(Err(Error::Timeout)); | 896 | return Poll::Ready(Err(Error::Timeout)); |
| 878 | } else if status.dataend() { | 897 | } |
| 898 | #[cfg(sdmmc_v1)] | ||
| 899 | if status.stbiterr() { | ||
| 900 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 901 | } | ||
| 902 | if status.dataend() { | ||
| 879 | return Poll::Ready(Ok(())); | 903 | return Poll::Ready(Ok(())); |
| 880 | } | 904 | } |
| 881 | Poll::Pending | 905 | Poll::Pending |
| @@ -1156,9 +1180,15 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1156 | 1180 | ||
| 1157 | if status.dcrcfail() { | 1181 | if status.dcrcfail() { |
| 1158 | return Poll::Ready(Err(Error::Crc)); | 1182 | return Poll::Ready(Err(Error::Crc)); |
| 1159 | } else if status.dtimeout() { | 1183 | } |
| 1184 | if status.dtimeout() { | ||
| 1160 | return Poll::Ready(Err(Error::Timeout)); | 1185 | return Poll::Ready(Err(Error::Timeout)); |
| 1161 | } else if status.dataend() { | 1186 | } |
| 1187 | #[cfg(sdmmc_v1)] | ||
| 1188 | if status.stbiterr() { | ||
| 1189 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 1190 | } | ||
| 1191 | if status.dataend() { | ||
| 1162 | return Poll::Ready(Ok(())); | 1192 | return Poll::Ready(Ok(())); |
| 1163 | } | 1193 | } |
| 1164 | Poll::Pending | 1194 | Poll::Pending |
| @@ -1207,9 +1237,15 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1207 | 1237 | ||
| 1208 | if status.dcrcfail() { | 1238 | if status.dcrcfail() { |
| 1209 | return Poll::Ready(Err(Error::Crc)); | 1239 | return Poll::Ready(Err(Error::Crc)); |
| 1210 | } else if status.dtimeout() { | 1240 | } |
| 1241 | if status.dtimeout() { | ||
| 1211 | return Poll::Ready(Err(Error::Timeout)); | 1242 | return Poll::Ready(Err(Error::Timeout)); |
| 1212 | } else if status.dataend() { | 1243 | } |
| 1244 | #[cfg(sdmmc_v1)] | ||
| 1245 | if status.stbiterr() { | ||
| 1246 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 1247 | } | ||
| 1248 | if status.dataend() { | ||
| 1213 | return Poll::Ready(Ok(())); | 1249 | return Poll::Ready(Ok(())); |
| 1214 | } | 1250 | } |
| 1215 | Poll::Pending | 1251 | Poll::Pending |
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index e2bc8d7f2..f40bce784 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs | |||
| @@ -323,7 +323,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 323 | } | 323 | } |
| 324 | 324 | ||
| 325 | /// Reconfigures it with the supplied config. | 325 | /// Reconfigures it with the supplied config. |
| 326 | pub fn reconfigure(&mut self, config: Config) { | 326 | pub fn set_config(&mut self, config: Config) { |
| 327 | let cpha = config.raw_phase(); | 327 | let cpha = config.raw_phase(); |
| 328 | let cpol = config.raw_polarity(); | 328 | let cpol = config.raw_polarity(); |
| 329 | 329 | ||
| @@ -646,6 +646,8 @@ impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { | |||
| 646 | self.sck.as_ref().map(|x| x.set_as_disconnected()); | 646 | self.sck.as_ref().map(|x| x.set_as_disconnected()); |
| 647 | self.mosi.as_ref().map(|x| x.set_as_disconnected()); | 647 | self.mosi.as_ref().map(|x| x.set_as_disconnected()); |
| 648 | self.miso.as_ref().map(|x| x.set_as_disconnected()); | 648 | self.miso.as_ref().map(|x| x.set_as_disconnected()); |
| 649 | |||
| 650 | T::disable(); | ||
| 649 | } | 651 | } |
| 650 | } | 652 | } |
| 651 | 653 | ||
| @@ -1060,6 +1062,6 @@ foreach_peripheral!( | |||
| 1060 | impl<'d, T: Instance, Tx, Rx> SetConfig for Spi<'d, T, Tx, Rx> { | 1062 | impl<'d, T: Instance, Tx, Rx> SetConfig for Spi<'d, T, Tx, Rx> { |
| 1061 | type Config = Config; | 1063 | type Config = Config; |
| 1062 | fn set_config(&mut self, config: &Self::Config) { | 1064 | fn set_config(&mut self, config: &Self::Config) { |
| 1063 | self.reconfigure(*config); | 1065 | self.set_config(*config); |
| 1064 | } | 1066 | } |
| 1065 | } | 1067 | } |
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 2622442f4..5b01937f5 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -14,6 +14,8 @@ use stm32_metapac::timer::regs; | |||
| 14 | use crate::interrupt::typelevel::Interrupt; | 14 | use crate::interrupt::typelevel::Interrupt; |
| 15 | use crate::pac::timer::vals; | 15 | use crate::pac::timer::vals; |
| 16 | use crate::rcc::sealed::RccPeripheral; | 16 | use crate::rcc::sealed::RccPeripheral; |
| 17 | #[cfg(feature = "low-power")] | ||
| 18 | use crate::rtc::Rtc; | ||
| 17 | use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; | 19 | use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; |
| 18 | use crate::{interrupt, peripherals}; | 20 | use crate::{interrupt, peripherals}; |
| 19 | 21 | ||
| @@ -130,12 +132,14 @@ impl AlarmState { | |||
| 130 | } | 132 | } |
| 131 | } | 133 | } |
| 132 | 134 | ||
| 133 | struct RtcDriver { | 135 | pub(crate) struct RtcDriver { |
| 134 | /// Number of 2^15 periods elapsed since boot. | 136 | /// Number of 2^15 periods elapsed since boot. |
| 135 | period: AtomicU32, | 137 | period: AtomicU32, |
| 136 | alarm_count: AtomicU8, | 138 | alarm_count: AtomicU8, |
| 137 | /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. | 139 | /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. |
| 138 | alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>, | 140 | alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>, |
| 141 | #[cfg(feature = "low-power")] | ||
| 142 | rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>, | ||
| 139 | } | 143 | } |
| 140 | 144 | ||
| 141 | const ALARM_STATE_NEW: AlarmState = AlarmState::new(); | 145 | const ALARM_STATE_NEW: AlarmState = AlarmState::new(); |
| @@ -144,6 +148,8 @@ embassy_time::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | |||
| 144 | period: AtomicU32::new(0), | 148 | period: AtomicU32::new(0), |
| 145 | alarm_count: AtomicU8::new(0), | 149 | alarm_count: AtomicU8::new(0), |
| 146 | alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]), | 150 | alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]), |
| 151 | #[cfg(feature = "low-power")] | ||
| 152 | rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), | ||
| 147 | }); | 153 | }); |
| 148 | 154 | ||
| 149 | impl RtcDriver { | 155 | impl RtcDriver { |
| @@ -259,6 +265,127 @@ impl RtcDriver { | |||
| 259 | let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) }; | 265 | let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) }; |
| 260 | f(alarm.ctx.get()); | 266 | f(alarm.ctx.get()); |
| 261 | } | 267 | } |
| 268 | |||
| 269 | /* | ||
| 270 | Low-power private functions: all operate within a critical seciton | ||
| 271 | */ | ||
| 272 | |||
| 273 | #[cfg(feature = "low-power")] | ||
| 274 | /// Compute the approximate amount of time until the next alarm | ||
| 275 | fn time_until_next_alarm(&self, cs: CriticalSection) -> embassy_time::Duration { | ||
| 276 | let now = self.now() + 32; | ||
| 277 | |||
| 278 | embassy_time::Duration::from_ticks( | ||
| 279 | self.alarms | ||
| 280 | .borrow(cs) | ||
| 281 | .iter() | ||
| 282 | .map(|alarm: &AlarmState| alarm.timestamp.get().saturating_sub(now)) | ||
| 283 | .min() | ||
| 284 | .unwrap_or(u64::MAX), | ||
| 285 | ) | ||
| 286 | } | ||
| 287 | |||
| 288 | #[cfg(feature = "low-power")] | ||
| 289 | /// Add the given offset to the current time | ||
| 290 | fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { | ||
| 291 | let offset = offset.as_ticks(); | ||
| 292 | let cnt = T::regs_gp16().cnt().read().cnt() as u32; | ||
| 293 | let period = self.period.load(Ordering::SeqCst); | ||
| 294 | |||
| 295 | // Correct the race, if it exists | ||
| 296 | let period = if period & 1 == 1 && cnt < u16::MAX as u32 / 2 { | ||
| 297 | period + 1 | ||
| 298 | } else { | ||
| 299 | period | ||
| 300 | }; | ||
| 301 | |||
| 302 | // Normalize to the full overflow | ||
| 303 | let period = (period / 2) * 2; | ||
| 304 | |||
| 305 | // Add the offset | ||
| 306 | let period = period + 2 * (offset / u16::MAX as u64) as u32; | ||
| 307 | let cnt = cnt + (offset % u16::MAX as u64) as u32; | ||
| 308 | |||
| 309 | let (cnt, period) = if cnt > u16::MAX as u32 { | ||
| 310 | (cnt - u16::MAX as u32, period + 2) | ||
| 311 | } else { | ||
| 312 | (cnt, period) | ||
| 313 | }; | ||
| 314 | |||
| 315 | let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period }; | ||
| 316 | |||
| 317 | self.period.store(period, Ordering::SeqCst); | ||
| 318 | T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); | ||
| 319 | |||
| 320 | // Now, recompute all alarms | ||
| 321 | for i in 0..ALARM_COUNT { | ||
| 322 | let alarm_handle = unsafe { AlarmHandle::new(i as u8) }; | ||
| 323 | let alarm = self.get_alarm(cs, alarm_handle); | ||
| 324 | |||
| 325 | self.set_alarm(alarm_handle, alarm.timestamp.get()); | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | #[cfg(feature = "low-power")] | ||
| 330 | /// Stop the wakeup alarm, if enabled, and add the appropriate offset | ||
| 331 | fn stop_wakeup_alarm(&self, cs: CriticalSection) { | ||
| 332 | if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(cs) { | ||
| 333 | self.add_time(offset, cs); | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | /* | ||
| 338 | Low-power public functions: all create a critical section | ||
| 339 | */ | ||
| 340 | #[cfg(feature = "low-power")] | ||
| 341 | /// Set the rtc but panic if it's already been set | ||
| 342 | pub(crate) fn set_rtc(&self, rtc: &'static Rtc) { | ||
| 343 | critical_section::with(|cs| assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none())); | ||
| 344 | } | ||
| 345 | |||
| 346 | #[cfg(feature = "low-power")] | ||
| 347 | /// Pause the timer if ready; return err if not | ||
| 348 | pub(crate) fn pause_time(&self) -> Result<(), ()> { | ||
| 349 | critical_section::with(|cs| { | ||
| 350 | /* | ||
| 351 | If the wakeup timer is currently running, then we need to stop it and | ||
| 352 | add the elapsed time to the current time, as this will impact the result | ||
| 353 | of `time_until_next_alarm`. | ||
| 354 | */ | ||
| 355 | self.stop_wakeup_alarm(cs); | ||
| 356 | |||
| 357 | let time_until_next_alarm = self.time_until_next_alarm(cs); | ||
| 358 | if time_until_next_alarm < embassy_time::Duration::from_millis(250) { | ||
| 359 | Err(()) | ||
| 360 | } else { | ||
| 361 | self.rtc | ||
| 362 | .borrow(cs) | ||
| 363 | .get() | ||
| 364 | .unwrap() | ||
| 365 | .start_wakeup_alarm(time_until_next_alarm, cs); | ||
| 366 | |||
| 367 | T::regs_gp16().cr1().modify(|w| w.set_cen(false)); | ||
| 368 | |||
| 369 | Ok(()) | ||
| 370 | } | ||
| 371 | }) | ||
| 372 | } | ||
| 373 | |||
| 374 | #[cfg(feature = "low-power")] | ||
| 375 | /// Resume the timer with the given offset | ||
| 376 | pub(crate) fn resume_time(&self) { | ||
| 377 | if T::regs_gp16().cr1().read().cen() { | ||
| 378 | // Time isn't currently stopped | ||
| 379 | |||
| 380 | return; | ||
| 381 | } | ||
| 382 | |||
| 383 | critical_section::with(|cs| { | ||
| 384 | self.stop_wakeup_alarm(cs); | ||
| 385 | |||
| 386 | T::regs_gp16().cr1().modify(|w| w.set_cen(true)); | ||
| 387 | }) | ||
| 388 | } | ||
| 262 | } | 389 | } |
| 263 | 390 | ||
| 264 | impl Driver for RtcDriver { | 391 | impl Driver for RtcDriver { |
| @@ -329,6 +456,11 @@ impl Driver for RtcDriver { | |||
| 329 | } | 456 | } |
| 330 | } | 457 | } |
| 331 | 458 | ||
| 459 | #[cfg(feature = "low-power")] | ||
| 460 | pub(crate) fn get_driver() -> &'static RtcDriver { | ||
| 461 | &DRIVER | ||
| 462 | } | ||
| 463 | |||
| 332 | pub(crate) fn init() { | 464 | pub(crate) fn init() { |
| 333 | DRIVER.init() | 465 | DRIVER.init() |
| 334 | } | 466 | } |
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 4ffb2a289..1d642ed37 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | pub mod complementary_pwm; | 1 | pub mod complementary_pwm; |
| 2 | pub mod qei; | ||
| 2 | pub mod simple_pwm; | 3 | pub mod simple_pwm; |
| 3 | 4 | ||
| 4 | use stm32_metapac::timer::vals; | 5 | use stm32_metapac::timer::vals; |
| @@ -14,6 +15,7 @@ pub mod low_level { | |||
| 14 | } | 15 | } |
| 15 | 16 | ||
| 16 | pub(crate) mod sealed { | 17 | pub(crate) mod sealed { |
| 18 | |||
| 17 | use super::*; | 19 | use super::*; |
| 18 | pub trait Basic16bitInstance: RccPeripheral { | 20 | pub trait Basic16bitInstance: RccPeripheral { |
| 19 | type Interrupt: interrupt::typelevel::Interrupt; | 21 | type Interrupt: interrupt::typelevel::Interrupt; |
| @@ -31,10 +33,16 @@ pub(crate) mod sealed { | |||
| 31 | fn clear_update_interrupt(&mut self) -> bool; | 33 | fn clear_update_interrupt(&mut self) -> bool; |
| 32 | 34 | ||
| 33 | fn enable_update_interrupt(&mut self, enable: bool); | 35 | fn enable_update_interrupt(&mut self, enable: bool); |
| 36 | |||
| 37 | fn set_autoreload_preload(&mut self, enable: vals::Arpe); | ||
| 34 | } | 38 | } |
| 35 | 39 | ||
| 36 | pub trait GeneralPurpose16bitInstance: Basic16bitInstance { | 40 | pub trait GeneralPurpose16bitInstance: Basic16bitInstance { |
| 37 | fn regs_gp16() -> crate::pac::timer::TimGp16; | 41 | fn regs_gp16() -> crate::pac::timer::TimGp16; |
| 42 | |||
| 43 | fn set_count_direction(&mut self, direction: vals::Dir); | ||
| 44 | |||
| 45 | fn set_clock_division(&mut self, ckd: vals::Ckd); | ||
| 38 | } | 46 | } |
| 39 | 47 | ||
| 40 | pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { | 48 | pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { |
| @@ -48,6 +56,18 @@ pub(crate) mod sealed { | |||
| 48 | } | 56 | } |
| 49 | 57 | ||
| 50 | pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { | 58 | pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { |
| 59 | fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf); | ||
| 60 | |||
| 61 | fn clear_input_interrupt(&mut self, channel: Channel); | ||
| 62 | |||
| 63 | fn enable_input_interrupt(&mut self, channel: Channel, enable: bool); | ||
| 64 | |||
| 65 | fn set_input_capture_prescaler(&mut self, channel: Channel, val: u8); | ||
| 66 | |||
| 67 | fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection); | ||
| 68 | |||
| 69 | fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode); | ||
| 70 | |||
| 51 | /// Global output enable. Does not do anything on non-advanced timers. | 71 | /// Global output enable. Does not do anything on non-advanced timers. |
| 52 | fn enable_outputs(&mut self, enable: bool); | 72 | fn enable_outputs(&mut self, enable: bool); |
| 53 | 73 | ||
| @@ -59,6 +79,8 @@ pub(crate) mod sealed { | |||
| 59 | 79 | ||
| 60 | fn set_compare_value(&mut self, channel: Channel, value: u16); | 80 | fn set_compare_value(&mut self, channel: Channel, value: u16); |
| 61 | 81 | ||
| 82 | fn get_capture_value(&mut self, channel: Channel) -> u16; | ||
| 83 | |||
| 62 | fn get_max_compare_value(&self) -> u16; | 84 | fn get_max_compare_value(&self) -> u16; |
| 63 | } | 85 | } |
| 64 | 86 | ||
| @@ -73,6 +95,18 @@ pub(crate) mod sealed { | |||
| 73 | } | 95 | } |
| 74 | 96 | ||
| 75 | pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance { | 97 | pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance { |
| 98 | fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf); | ||
| 99 | |||
| 100 | fn clear_input_interrupt(&mut self, channel: Channel); | ||
| 101 | |||
| 102 | fn enable_input_interrupt(&mut self, channel: Channel, enable: bool); | ||
| 103 | |||
| 104 | fn set_input_capture_prescaler(&mut self, channel: Channel, val: u8); | ||
| 105 | |||
| 106 | fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection); | ||
| 107 | |||
| 108 | fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode); | ||
| 109 | |||
| 76 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); | 110 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); |
| 77 | 111 | ||
| 78 | fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity); | 112 | fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity); |
| @@ -81,6 +115,8 @@ pub(crate) mod sealed { | |||
| 81 | 115 | ||
| 82 | fn set_compare_value(&mut self, channel: Channel, value: u32); | 116 | fn set_compare_value(&mut self, channel: Channel, value: u32); |
| 83 | 117 | ||
| 118 | fn get_capture_value(&mut self, channel: Channel) -> u32; | ||
| 119 | |||
| 84 | fn get_max_compare_value(&self) -> u32; | 120 | fn get_max_compare_value(&self) -> u32; |
| 85 | } | 121 | } |
| 86 | } | 122 | } |
| @@ -105,6 +141,30 @@ impl Channel { | |||
| 105 | } | 141 | } |
| 106 | 142 | ||
| 107 | #[derive(Clone, Copy)] | 143 | #[derive(Clone, Copy)] |
| 144 | pub enum InputCaptureMode { | ||
| 145 | Rising, | ||
| 146 | Falling, | ||
| 147 | BothEdges, | ||
| 148 | } | ||
| 149 | |||
| 150 | #[derive(Clone, Copy)] | ||
| 151 | pub enum InputTISelection { | ||
| 152 | Normal, | ||
| 153 | Alternate, | ||
| 154 | TRC, | ||
| 155 | } | ||
| 156 | |||
| 157 | impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs { | ||
| 158 | fn from(tisel: InputTISelection) -> Self { | ||
| 159 | match tisel { | ||
| 160 | InputTISelection::Normal => stm32_metapac::timer::vals::CcmrInputCcs::TI4, | ||
| 161 | InputTISelection::Alternate => stm32_metapac::timer::vals::CcmrInputCcs::TI3, | ||
| 162 | InputTISelection::TRC => stm32_metapac::timer::vals::CcmrInputCcs::TRC, | ||
| 163 | } | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | #[derive(Clone, Copy)] | ||
| 108 | pub enum OutputCompareMode { | 168 | pub enum OutputCompareMode { |
| 109 | Frozen, | 169 | Frozen, |
| 110 | ActiveOnMatch, | 170 | ActiveOnMatch, |
| @@ -211,6 +271,7 @@ macro_rules! impl_basic_16bit_timer { | |||
| 211 | use core::convert::TryInto; | 271 | use core::convert::TryInto; |
| 212 | let f = frequency.0; | 272 | let f = frequency.0; |
| 213 | let timer_f = Self::frequency().0; | 273 | let timer_f = Self::frequency().0; |
| 274 | assert!(f > 0); | ||
| 214 | let pclk_ticks_per_timer_period = timer_f / f; | 275 | let pclk_ticks_per_timer_period = timer_f / f; |
| 215 | let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into()); | 276 | let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into()); |
| 216 | let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into()); | 277 | let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into()); |
| @@ -240,6 +301,10 @@ macro_rules! impl_basic_16bit_timer { | |||
| 240 | fn enable_update_interrupt(&mut self, enable: bool) { | 301 | fn enable_update_interrupt(&mut self, enable: bool) { |
| 241 | Self::regs().dier().write(|r| r.set_uie(enable)); | 302 | Self::regs().dier().write(|r| r.set_uie(enable)); |
| 242 | } | 303 | } |
| 304 | |||
| 305 | fn set_autoreload_preload(&mut self, enable: vals::Arpe) { | ||
| 306 | Self::regs().cr1().modify(|r| r.set_arpe(enable)); | ||
| 307 | } | ||
| 243 | } | 308 | } |
| 244 | }; | 309 | }; |
| 245 | } | 310 | } |
| @@ -255,6 +320,7 @@ macro_rules! impl_32bit_timer { | |||
| 255 | fn set_frequency(&mut self, frequency: Hertz) { | 320 | fn set_frequency(&mut self, frequency: Hertz) { |
| 256 | use core::convert::TryInto; | 321 | use core::convert::TryInto; |
| 257 | let f = frequency.0; | 322 | let f = frequency.0; |
| 323 | assert!(f > 0); | ||
| 258 | let timer_f = Self::frequency().0; | 324 | let timer_f = Self::frequency().0; |
| 259 | let pclk_ticks_per_timer_period = (timer_f / f) as u64; | 325 | let pclk_ticks_per_timer_period = (timer_f / f) as u64; |
| 260 | let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into()); | 326 | let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into()); |
| @@ -276,6 +342,59 @@ macro_rules! impl_32bit_timer { | |||
| 276 | macro_rules! impl_compare_capable_16bit { | 342 | macro_rules! impl_compare_capable_16bit { |
| 277 | ($inst:ident) => { | 343 | ($inst:ident) => { |
| 278 | impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { | 344 | impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { |
| 345 | fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { | ||
| 346 | use sealed::GeneralPurpose16bitInstance; | ||
| 347 | let raw_channel = channel.raw(); | ||
| 348 | Self::regs_gp16() | ||
| 349 | .ccmr_input(raw_channel / 2) | ||
| 350 | .modify(|r| r.set_icf(raw_channel % 2, icf)); | ||
| 351 | } | ||
| 352 | |||
| 353 | fn clear_input_interrupt(&mut self, channel: Channel) { | ||
| 354 | use sealed::GeneralPurpose16bitInstance; | ||
| 355 | Self::regs_gp16() | ||
| 356 | .sr() | ||
| 357 | .modify(|r| r.set_ccif(channel.raw(), false)); | ||
| 358 | } | ||
| 359 | |||
| 360 | fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { | ||
| 361 | use sealed::GeneralPurpose16bitInstance; | ||
| 362 | Self::regs_gp16() | ||
| 363 | .dier() | ||
| 364 | .modify(|r| r.set_ccie(channel.raw(), enable)); | ||
| 365 | } | ||
| 366 | fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { | ||
| 367 | use sealed::GeneralPurpose16bitInstance; | ||
| 368 | let raw_channel = channel.raw(); | ||
| 369 | Self::regs_gp16() | ||
| 370 | .ccmr_input(raw_channel / 2) | ||
| 371 | .modify(|r| r.set_icpsc(raw_channel % 2, factor)); | ||
| 372 | } | ||
| 373 | |||
| 374 | fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { | ||
| 375 | use sealed::GeneralPurpose16bitInstance; | ||
| 376 | let raw_channel = channel.raw(); | ||
| 377 | Self::regs_gp16() | ||
| 378 | .ccmr_input(raw_channel / 2) | ||
| 379 | .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); | ||
| 380 | } | ||
| 381 | fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { | ||
| 382 | use sealed::GeneralPurpose16bitInstance; | ||
| 383 | Self::regs_gp16().ccer().modify(|r| match mode { | ||
| 384 | InputCaptureMode::Rising => { | ||
| 385 | r.set_ccnp(channel.raw(), false); | ||
| 386 | r.set_ccp(channel.raw(), false); | ||
| 387 | } | ||
| 388 | InputCaptureMode::Falling => { | ||
| 389 | r.set_ccnp(channel.raw(), false); | ||
| 390 | r.set_ccp(channel.raw(), true); | ||
| 391 | } | ||
| 392 | InputCaptureMode::BothEdges => { | ||
| 393 | r.set_ccnp(channel.raw(), true); | ||
| 394 | r.set_ccp(channel.raw(), true); | ||
| 395 | } | ||
| 396 | }); | ||
| 397 | } | ||
| 279 | fn enable_outputs(&mut self, _enable: bool) {} | 398 | fn enable_outputs(&mut self, _enable: bool) {} |
| 280 | 399 | ||
| 281 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { | 400 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { |
| @@ -305,6 +424,11 @@ macro_rules! impl_compare_capable_16bit { | |||
| 305 | Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); | 424 | Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); |
| 306 | } | 425 | } |
| 307 | 426 | ||
| 427 | fn get_capture_value(&mut self, channel: Channel) -> u16 { | ||
| 428 | use sealed::GeneralPurpose16bitInstance; | ||
| 429 | Self::regs_gp16().ccr(channel.raw()).read().ccr() | ||
| 430 | } | ||
| 431 | |||
| 308 | fn get_max_compare_value(&self) -> u16 { | 432 | fn get_max_compare_value(&self) -> u16 { |
| 309 | use sealed::GeneralPurpose16bitInstance; | 433 | use sealed::GeneralPurpose16bitInstance; |
| 310 | Self::regs_gp16().arr().read().arr() | 434 | Self::regs_gp16().arr().read().arr() |
| @@ -329,6 +453,14 @@ foreach_interrupt! { | |||
| 329 | fn regs_gp16() -> crate::pac::timer::TimGp16 { | 453 | fn regs_gp16() -> crate::pac::timer::TimGp16 { |
| 330 | crate::pac::$inst | 454 | crate::pac::$inst |
| 331 | } | 455 | } |
| 456 | |||
| 457 | fn set_count_direction(&mut self, direction: vals::Dir) { | ||
| 458 | Self::regs_gp16().cr1().modify(|r| r.set_dir(direction)); | ||
| 459 | } | ||
| 460 | |||
| 461 | fn set_clock_division(&mut self, ckd: vals::Ckd) { | ||
| 462 | Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); | ||
| 463 | } | ||
| 332 | } | 464 | } |
| 333 | }; | 465 | }; |
| 334 | 466 | ||
| @@ -343,6 +475,59 @@ foreach_interrupt! { | |||
| 343 | impl GeneralPurpose32bitInstance for crate::peripherals::$inst {} | 475 | impl GeneralPurpose32bitInstance for crate::peripherals::$inst {} |
| 344 | 476 | ||
| 345 | impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst { | 477 | impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst { |
| 478 | fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { | ||
| 479 | use sealed::GeneralPurpose32bitInstance; | ||
| 480 | let raw_channel = channel.raw(); | ||
| 481 | Self::regs_gp32() | ||
| 482 | .ccmr_input(raw_channel / 2) | ||
| 483 | .modify(|r| r.set_icf(raw_channel % 2, icf)); | ||
| 484 | } | ||
| 485 | |||
| 486 | fn clear_input_interrupt(&mut self, channel: Channel) { | ||
| 487 | use sealed::GeneralPurpose32bitInstance; | ||
| 488 | Self::regs_gp32() | ||
| 489 | .sr() | ||
| 490 | .modify(|r| r.set_ccif(channel.raw(), false)); | ||
| 491 | } | ||
| 492 | fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { | ||
| 493 | use sealed::GeneralPurpose32bitInstance; | ||
| 494 | Self::regs_gp32() | ||
| 495 | .dier() | ||
| 496 | .modify(|r| r.set_ccie(channel.raw(), enable)); | ||
| 497 | } | ||
| 498 | fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { | ||
| 499 | use crate::timer::sealed::GeneralPurpose32bitInstance; | ||
| 500 | let raw_channel = channel.raw(); | ||
| 501 | Self::regs_gp32() | ||
| 502 | .ccmr_input(raw_channel / 2) | ||
| 503 | .modify(|r| r.set_icpsc(raw_channel % 2, factor)); | ||
| 504 | } | ||
| 505 | |||
| 506 | fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { | ||
| 507 | use crate::timer::sealed::GeneralPurpose32bitInstance; | ||
| 508 | let raw_channel = channel.raw(); | ||
| 509 | Self::regs_gp32() | ||
| 510 | .ccmr_input(raw_channel / 2) | ||
| 511 | .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); | ||
| 512 | } | ||
| 513 | |||
| 514 | fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { | ||
| 515 | use crate::timer::sealed::GeneralPurpose32bitInstance; | ||
| 516 | Self::regs_gp32().ccer().modify(|r| match mode { | ||
| 517 | InputCaptureMode::Rising => { | ||
| 518 | r.set_ccnp(channel.raw(), false); | ||
| 519 | r.set_ccp(channel.raw(), false); | ||
| 520 | } | ||
| 521 | InputCaptureMode::Falling => { | ||
| 522 | r.set_ccnp(channel.raw(), false); | ||
| 523 | r.set_ccp(channel.raw(), true); | ||
| 524 | } | ||
| 525 | InputCaptureMode::BothEdges => { | ||
| 526 | r.set_ccnp(channel.raw(), true); | ||
| 527 | r.set_ccp(channel.raw(), true); | ||
| 528 | } | ||
| 529 | }); | ||
| 530 | } | ||
| 346 | fn set_output_compare_mode( | 531 | fn set_output_compare_mode( |
| 347 | &mut self, | 532 | &mut self, |
| 348 | channel: Channel, | 533 | channel: Channel, |
| @@ -370,6 +555,11 @@ foreach_interrupt! { | |||
| 370 | Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); | 555 | Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); |
| 371 | } | 556 | } |
| 372 | 557 | ||
| 558 | fn get_capture_value(&mut self, channel: Channel) -> u32 { | ||
| 559 | use crate::timer::sealed::GeneralPurpose32bitInstance; | ||
| 560 | Self::regs_gp32().ccr(channel.raw()).read().ccr() | ||
| 561 | } | ||
| 562 | |||
| 373 | fn get_max_compare_value(&self) -> u32 { | 563 | fn get_max_compare_value(&self) -> u32 { |
| 374 | use crate::timer::sealed::GeneralPurpose32bitInstance; | 564 | use crate::timer::sealed::GeneralPurpose32bitInstance; |
| 375 | Self::regs_gp32().arr().read().arr() as u32 | 565 | Self::regs_gp32().arr().read().arr() as u32 |
| @@ -380,6 +570,14 @@ foreach_interrupt! { | |||
| 380 | fn regs_gp16() -> crate::pac::timer::TimGp16 { | 570 | fn regs_gp16() -> crate::pac::timer::TimGp16 { |
| 381 | unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } | 571 | unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } |
| 382 | } | 572 | } |
| 573 | |||
| 574 | fn set_count_direction(&mut self, direction: vals::Dir) { | ||
| 575 | Self::regs_gp16().cr1().modify(|r| r.set_dir(direction)); | ||
| 576 | } | ||
| 577 | |||
| 578 | fn set_clock_division(&mut self, ckd: vals::Ckd) { | ||
| 579 | Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); | ||
| 580 | } | ||
| 383 | } | 581 | } |
| 384 | }; | 582 | }; |
| 385 | 583 | ||
| @@ -396,6 +594,14 @@ foreach_interrupt! { | |||
| 396 | fn regs_gp16() -> crate::pac::timer::TimGp16 { | 594 | fn regs_gp16() -> crate::pac::timer::TimGp16 { |
| 397 | unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } | 595 | unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } |
| 398 | } | 596 | } |
| 597 | |||
| 598 | fn set_count_direction(&mut self, direction: vals::Dir) { | ||
| 599 | Self::regs_gp16().cr1().modify(|r| r.set_dir(direction)); | ||
| 600 | } | ||
| 601 | |||
| 602 | fn set_clock_division(&mut self, ckd: vals::Ckd) { | ||
| 603 | Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); | ||
| 604 | } | ||
| 399 | } | 605 | } |
| 400 | 606 | ||
| 401 | impl sealed::AdvancedControlInstance for crate::peripherals::$inst { | 607 | impl sealed::AdvancedControlInstance for crate::peripherals::$inst { |
| @@ -405,6 +611,57 @@ foreach_interrupt! { | |||
| 405 | } | 611 | } |
| 406 | 612 | ||
| 407 | impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { | 613 | impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { |
| 614 | fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { | ||
| 615 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 616 | let raw_channel = channel.raw(); | ||
| 617 | Self::regs_advanced() | ||
| 618 | .ccmr_input(raw_channel / 2) | ||
| 619 | .modify(|r| r.set_icf(raw_channel % 2, icf)); | ||
| 620 | } | ||
| 621 | |||
| 622 | fn clear_input_interrupt(&mut self, channel: Channel) { | ||
| 623 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 624 | Self::regs_advanced() | ||
| 625 | .sr() | ||
| 626 | .modify(|r| r.set_ccif(channel.raw(), false)); | ||
| 627 | } | ||
| 628 | fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { | ||
| 629 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 630 | Self::regs_advanced() | ||
| 631 | .dier() | ||
| 632 | .modify(|r| r.set_ccie(channel.raw(), enable)); | ||
| 633 | } | ||
| 634 | fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { | ||
| 635 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 636 | let raw_channel = channel.raw(); | ||
| 637 | Self::regs_advanced() | ||
| 638 | .ccmr_input(raw_channel / 2) | ||
| 639 | .modify(|r| r.set_icpsc(raw_channel % 2, factor)); | ||
| 640 | } | ||
| 641 | fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { | ||
| 642 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 643 | let raw_channel = channel.raw(); | ||
| 644 | Self::regs_advanced() | ||
| 645 | .ccmr_input(raw_channel / 2) | ||
| 646 | .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); | ||
| 647 | } | ||
| 648 | fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { | ||
| 649 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 650 | Self::regs_advanced().ccer().modify(|r| match mode { | ||
| 651 | InputCaptureMode::Rising => { | ||
| 652 | r.set_ccnp(channel.raw(), false); | ||
| 653 | r.set_ccp(channel.raw(), false); | ||
| 654 | } | ||
| 655 | InputCaptureMode::Falling => { | ||
| 656 | r.set_ccnp(channel.raw(), false); | ||
| 657 | r.set_ccp(channel.raw(), true); | ||
| 658 | } | ||
| 659 | InputCaptureMode::BothEdges => { | ||
| 660 | r.set_ccnp(channel.raw(), true); | ||
| 661 | r.set_ccp(channel.raw(), true); | ||
| 662 | } | ||
| 663 | }); | ||
| 664 | } | ||
| 408 | fn enable_outputs(&mut self, enable: bool) { | 665 | fn enable_outputs(&mut self, enable: bool) { |
| 409 | use crate::timer::sealed::AdvancedControlInstance; | 666 | use crate::timer::sealed::AdvancedControlInstance; |
| 410 | let r = Self::regs_advanced(); | 667 | let r = Self::regs_advanced(); |
| @@ -437,6 +694,11 @@ foreach_interrupt! { | |||
| 437 | .modify(|w| w.set_cce(channel.raw(), enable)); | 694 | .modify(|w| w.set_cce(channel.raw(), enable)); |
| 438 | } | 695 | } |
| 439 | 696 | ||
| 697 | fn get_capture_value(&mut self, channel: Channel) -> u16 { | ||
| 698 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 699 | Self::regs_advanced().ccr(channel.raw()).read().ccr() | ||
| 700 | } | ||
| 701 | |||
| 440 | fn set_compare_value(&mut self, channel: Channel, value: u16) { | 702 | fn set_compare_value(&mut self, channel: Channel, value: u16) { |
| 441 | use crate::timer::sealed::AdvancedControlInstance; | 703 | use crate::timer::sealed::AdvancedControlInstance; |
| 442 | Self::regs_advanced() | 704 | Self::regs_advanced() |
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs new file mode 100644 index 000000000..15f2c3a79 --- /dev/null +++ b/embassy-stm32/src/timer/qei.rs | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||
| 4 | |||
| 5 | use super::*; | ||
| 6 | use crate::gpio::sealed::AFType; | ||
| 7 | use crate::gpio::AnyPin; | ||
| 8 | use crate::Peripheral; | ||
| 9 | |||
| 10 | pub enum Direction { | ||
| 11 | Upcounting, | ||
| 12 | Downcounting, | ||
| 13 | } | ||
| 14 | |||
| 15 | pub struct Ch1; | ||
| 16 | pub struct Ch2; | ||
| 17 | |||
| 18 | pub struct QeiPin<'d, Perip, Channel> { | ||
| 19 | _pin: PeripheralRef<'d, AnyPin>, | ||
| 20 | phantom: PhantomData<(Perip, Channel)>, | ||
| 21 | } | ||
| 22 | |||
| 23 | macro_rules! channel_impl { | ||
| 24 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | ||
| 25 | impl<'d, Perip: CaptureCompare16bitInstance> QeiPin<'d, Perip, $channel> { | ||
| 26 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { | ||
| 27 | into_ref!(pin); | ||
| 28 | critical_section::with(|_| { | ||
| 29 | pin.set_low(); | ||
| 30 | pin.set_as_af(pin.af_num(), AFType::Input); | ||
| 31 | #[cfg(gpio_v2)] | ||
| 32 | pin.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 33 | }); | ||
| 34 | QeiPin { | ||
| 35 | _pin: pin.map_into(), | ||
| 36 | phantom: PhantomData, | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | ||
| 40 | }; | ||
| 41 | } | ||
| 42 | |||
| 43 | channel_impl!(new_ch1, Ch1, Channel1Pin); | ||
| 44 | channel_impl!(new_ch2, Ch2, Channel2Pin); | ||
| 45 | |||
| 46 | pub struct Qei<'d, T> { | ||
| 47 | _inner: PeripheralRef<'d, T>, | ||
| 48 | } | ||
| 49 | |||
| 50 | impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | ||
| 51 | pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { | ||
| 52 | Self::new_inner(tim) | ||
| 53 | } | ||
| 54 | |||
| 55 | fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self { | ||
| 56 | into_ref!(tim); | ||
| 57 | |||
| 58 | T::enable(); | ||
| 59 | <T as crate::rcc::sealed::RccPeripheral>::reset(); | ||
| 60 | |||
| 61 | // Configure TxC1 and TxC2 as captures | ||
| 62 | T::regs_gp16().ccmr_input(0).modify(|w| { | ||
| 63 | w.set_ccs(0, vals::CcmrInputCcs::TI4); | ||
| 64 | w.set_ccs(1, vals::CcmrInputCcs::TI4); | ||
| 65 | }); | ||
| 66 | |||
| 67 | // enable and configure to capture on rising edge | ||
| 68 | T::regs_gp16().ccer().modify(|w| { | ||
| 69 | w.set_cce(0, true); | ||
| 70 | w.set_cce(1, true); | ||
| 71 | |||
| 72 | w.set_ccp(0, false); | ||
| 73 | w.set_ccp(1, false); | ||
| 74 | }); | ||
| 75 | |||
| 76 | T::regs_gp16().smcr().modify(|w| { | ||
| 77 | w.set_sms(vals::Sms::ENCODER_MODE_3); | ||
| 78 | }); | ||
| 79 | |||
| 80 | T::regs_gp16().arr().modify(|w| w.set_arr(u16::MAX)); | ||
| 81 | T::regs_gp16().cr1().modify(|w| w.set_cen(true)); | ||
| 82 | |||
| 83 | Self { _inner: tim } | ||
| 84 | } | ||
| 85 | |||
| 86 | pub fn read_direction(&self) -> Direction { | ||
| 87 | match T::regs_gp16().cr1().read().dir() { | ||
| 88 | vals::Dir::DOWN => Direction::Downcounting, | ||
| 89 | vals::Dir::UP => Direction::Upcounting, | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | pub fn count(&self) -> u16 { | ||
| 94 | T::regs_gp16().cnt().read().cnt() | ||
| 95 | } | ||
| 96 | } | ||
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 596d40bf9..e2d6e42af 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs | |||
| @@ -114,6 +114,30 @@ pub struct BufferedUartRx<'d, T: BasicInstance> { | |||
| 114 | phantom: PhantomData<&'d mut T>, | 114 | phantom: PhantomData<&'d mut T>, |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | impl<'d, T: BasicInstance> SetConfig for BufferedUart<'d, T> { | ||
| 118 | type Config = Config; | ||
| 119 | |||
| 120 | fn set_config(&mut self, config: &Self::Config) { | ||
| 121 | unwrap!(self.set_config(config)) | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | impl<'d, T: BasicInstance> SetConfig for BufferedUartRx<'d, T> { | ||
| 126 | type Config = Config; | ||
| 127 | |||
| 128 | fn set_config(&mut self, config: &Self::Config) { | ||
| 129 | unwrap!(self.set_config(config)) | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | impl<'d, T: BasicInstance> SetConfig for BufferedUartTx<'d, T> { | ||
| 134 | type Config = Config; | ||
| 135 | |||
| 136 | fn set_config(&mut self, config: &Self::Config) { | ||
| 137 | unwrap!(self.set_config(config)) | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 117 | impl<'d, T: BasicInstance> BufferedUart<'d, T> { | 141 | impl<'d, T: BasicInstance> BufferedUart<'d, T> { |
| 118 | pub fn new( | 142 | pub fn new( |
| 119 | peri: impl Peripheral<P = T> + 'd, | 143 | peri: impl Peripheral<P = T> + 'd, |
| @@ -123,7 +147,9 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 123 | tx_buffer: &'d mut [u8], | 147 | tx_buffer: &'d mut [u8], |
| 124 | rx_buffer: &'d mut [u8], | 148 | rx_buffer: &'d mut [u8], |
| 125 | config: Config, | 149 | config: Config, |
| 126 | ) -> BufferedUart<'d, T> { | 150 | ) -> Result<Self, ConfigError> { |
| 151 | // UartRx and UartTx have one refcount ea. | ||
| 152 | T::enable(); | ||
| 127 | T::enable(); | 153 | T::enable(); |
| 128 | T::reset(); | 154 | T::reset(); |
| 129 | 155 | ||
| @@ -140,9 +166,11 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 140 | tx_buffer: &'d mut [u8], | 166 | tx_buffer: &'d mut [u8], |
| 141 | rx_buffer: &'d mut [u8], | 167 | rx_buffer: &'d mut [u8], |
| 142 | config: Config, | 168 | config: Config, |
| 143 | ) -> BufferedUart<'d, T> { | 169 | ) -> Result<Self, ConfigError> { |
| 144 | into_ref!(cts, rts); | 170 | into_ref!(cts, rts); |
| 145 | 171 | ||
| 172 | // UartRx and UartTx have one refcount ea. | ||
| 173 | T::enable(); | ||
| 146 | T::enable(); | 174 | T::enable(); |
| 147 | T::reset(); | 175 | T::reset(); |
| 148 | 176 | ||
| @@ -166,9 +194,11 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 166 | tx_buffer: &'d mut [u8], | 194 | tx_buffer: &'d mut [u8], |
| 167 | rx_buffer: &'d mut [u8], | 195 | rx_buffer: &'d mut [u8], |
| 168 | config: Config, | 196 | config: Config, |
| 169 | ) -> BufferedUart<'d, T> { | 197 | ) -> Result<Self, ConfigError> { |
| 170 | into_ref!(de); | 198 | into_ref!(de); |
| 171 | 199 | ||
| 200 | // UartRx and UartTx have one refcount ea. | ||
| 201 | T::enable(); | ||
| 172 | T::enable(); | 202 | T::enable(); |
| 173 | T::reset(); | 203 | T::reset(); |
| 174 | 204 | ||
| @@ -187,7 +217,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 187 | tx_buffer: &'d mut [u8], | 217 | tx_buffer: &'d mut [u8], |
| 188 | rx_buffer: &'d mut [u8], | 218 | rx_buffer: &'d mut [u8], |
| 189 | config: Config, | 219 | config: Config, |
| 190 | ) -> BufferedUart<'d, T> { | 220 | ) -> Result<Self, ConfigError> { |
| 191 | into_ref!(_peri, rx, tx); | 221 | into_ref!(_peri, rx, tx); |
| 192 | 222 | ||
| 193 | let state = T::buffered_state(); | 223 | let state = T::buffered_state(); |
| @@ -200,7 +230,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 200 | rx.set_as_af(rx.af_num(), AFType::Input); | 230 | rx.set_as_af(rx.af_num(), AFType::Input); |
| 201 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | 231 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |
| 202 | 232 | ||
| 203 | configure(r, &config, T::frequency(), T::KIND, true, true); | 233 | configure(r, &config, T::frequency(), T::KIND, true, true)?; |
| 204 | 234 | ||
| 205 | r.cr1().modify(|w| { | 235 | r.cr1().modify(|w| { |
| 206 | #[cfg(lpuart_v2)] | 236 | #[cfg(lpuart_v2)] |
| @@ -213,15 +243,19 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 213 | T::Interrupt::unpend(); | 243 | T::Interrupt::unpend(); |
| 214 | unsafe { T::Interrupt::enable() }; | 244 | unsafe { T::Interrupt::enable() }; |
| 215 | 245 | ||
| 216 | Self { | 246 | Ok(Self { |
| 217 | rx: BufferedUartRx { phantom: PhantomData }, | 247 | rx: BufferedUartRx { phantom: PhantomData }, |
| 218 | tx: BufferedUartTx { phantom: PhantomData }, | 248 | tx: BufferedUartTx { phantom: PhantomData }, |
| 219 | } | 249 | }) |
| 220 | } | 250 | } |
| 221 | 251 | ||
| 222 | pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { | 252 | pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { |
| 223 | (self.tx, self.rx) | 253 | (self.tx, self.rx) |
| 224 | } | 254 | } |
| 255 | |||
| 256 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { | ||
| 257 | reconfigure::<T>(config) | ||
| 258 | } | ||
| 225 | } | 259 | } |
| 226 | 260 | ||
| 227 | impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { | 261 | impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { |
| @@ -298,6 +332,10 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { | |||
| 298 | T::Interrupt::pend(); | 332 | T::Interrupt::pend(); |
| 299 | } | 333 | } |
| 300 | } | 334 | } |
| 335 | |||
| 336 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { | ||
| 337 | reconfigure::<T>(config) | ||
| 338 | } | ||
| 301 | } | 339 | } |
| 302 | 340 | ||
| 303 | impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { | 341 | impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { |
| @@ -368,6 +406,10 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { | |||
| 368 | } | 406 | } |
| 369 | } | 407 | } |
| 370 | } | 408 | } |
| 409 | |||
| 410 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { | ||
| 411 | reconfigure::<T>(config) | ||
| 412 | } | ||
| 371 | } | 413 | } |
| 372 | 414 | ||
| 373 | impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> { | 415 | impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> { |
| @@ -382,6 +424,8 @@ impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> { | |||
| 382 | T::Interrupt::disable(); | 424 | T::Interrupt::disable(); |
| 383 | } | 425 | } |
| 384 | } | 426 | } |
| 427 | |||
| 428 | T::disable(); | ||
| 385 | } | 429 | } |
| 386 | } | 430 | } |
| 387 | 431 | ||
| @@ -397,12 +441,8 @@ impl<'d, T: BasicInstance> Drop for BufferedUartTx<'d, T> { | |||
| 397 | T::Interrupt::disable(); | 441 | T::Interrupt::disable(); |
| 398 | } | 442 | } |
| 399 | } | 443 | } |
| 400 | } | ||
| 401 | } | ||
| 402 | 444 | ||
| 403 | impl embedded_io_async::Error for Error { | 445 | T::disable(); |
| 404 | fn kind(&self) -> embedded_io_async::ErrorKind { | ||
| 405 | embedded_io_async::ErrorKind::Other | ||
| 406 | } | 446 | } |
| 407 | } | 447 | } |
| 408 | 448 | ||
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 255ddfd4b..9835f1ace 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -5,6 +5,7 @@ use core::marker::PhantomData; | |||
| 5 | use core::sync::atomic::{compiler_fence, Ordering}; | 5 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 6 | use core::task::Poll; | 6 | use core::task::Poll; |
| 7 | 7 | ||
| 8 | use embassy_embedded_hal::SetConfig; | ||
| 8 | use embassy_hal_internal::drop::OnDrop; | 9 | use embassy_hal_internal::drop::OnDrop; |
| 9 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 10 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 10 | use futures::future::{select, Either}; | 11 | use futures::future::{select, Either}; |
| @@ -12,11 +13,10 @@ use futures::future::{select, Either}; | |||
| 12 | use crate::dma::{NoDma, Transfer}; | 13 | use crate::dma::{NoDma, Transfer}; |
| 13 | use crate::gpio::sealed::AFType; | 14 | use crate::gpio::sealed::AFType; |
| 14 | use crate::interrupt::typelevel::Interrupt; | 15 | use crate::interrupt::typelevel::Interrupt; |
| 15 | #[cfg(not(any(usart_v1, usart_v2)))] | ||
| 16 | #[allow(unused_imports)] | 16 | #[allow(unused_imports)] |
| 17 | #[cfg(not(any(usart_v1, usart_v2)))] | ||
| 17 | use crate::pac::usart::regs::Isr as Sr; | 18 | use crate::pac::usart::regs::Isr as Sr; |
| 18 | #[cfg(any(usart_v1, usart_v2))] | 19 | #[cfg(any(usart_v1, usart_v2))] |
| 19 | #[allow(unused_imports)] | ||
| 20 | use crate::pac::usart::regs::Sr; | 20 | use crate::pac::usart::regs::Sr; |
| 21 | #[cfg(not(any(usart_v1, usart_v2)))] | 21 | #[cfg(not(any(usart_v1, usart_v2)))] |
| 22 | use crate::pac::usart::Lpuart as Regs; | 22 | use crate::pac::usart::Lpuart as Regs; |
| @@ -75,12 +75,14 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt | |||
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 77 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 78 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 78 | pub enum DataBits { | 79 | pub enum DataBits { |
| 79 | DataBits8, | 80 | DataBits8, |
| 80 | DataBits9, | 81 | DataBits9, |
| 81 | } | 82 | } |
| 82 | 83 | ||
| 83 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 84 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 85 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 84 | pub enum Parity { | 86 | pub enum Parity { |
| 85 | ParityNone, | 87 | ParityNone, |
| 86 | ParityEven, | 88 | ParityEven, |
| @@ -88,6 +90,7 @@ pub enum Parity { | |||
| 88 | } | 90 | } |
| 89 | 91 | ||
| 90 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 92 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 93 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 91 | pub enum StopBits { | 94 | pub enum StopBits { |
| 92 | #[doc = "1 stop bit"] | 95 | #[doc = "1 stop bit"] |
| 93 | STOP1, | 96 | STOP1, |
| @@ -101,6 +104,14 @@ pub enum StopBits { | |||
| 101 | 104 | ||
| 102 | #[non_exhaustive] | 105 | #[non_exhaustive] |
| 103 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 106 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 107 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 108 | pub enum ConfigError { | ||
| 109 | BaudrateTooLow, | ||
| 110 | BaudrateTooHigh, | ||
| 111 | } | ||
| 112 | |||
| 113 | #[non_exhaustive] | ||
| 114 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | ||
| 104 | pub struct Config { | 115 | pub struct Config { |
| 105 | pub baudrate: u32, | 116 | pub baudrate: u32, |
| 106 | pub data_bits: DataBits, | 117 | pub data_bits: DataBits, |
| @@ -168,11 +179,28 @@ pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { | |||
| 168 | rx: UartRx<'d, T, RxDma>, | 179 | rx: UartRx<'d, T, RxDma>, |
| 169 | } | 180 | } |
| 170 | 181 | ||
| 182 | impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> { | ||
| 183 | type Config = Config; | ||
| 184 | |||
| 185 | fn set_config(&mut self, config: &Self::Config) { | ||
| 186 | unwrap!(self.tx.set_config(config)); | ||
| 187 | unwrap!(self.rx.set_config(config)); | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 171 | pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { | 191 | pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { |
| 172 | phantom: PhantomData<&'d mut T>, | 192 | phantom: PhantomData<&'d mut T>, |
| 173 | tx_dma: PeripheralRef<'d, TxDma>, | 193 | tx_dma: PeripheralRef<'d, TxDma>, |
| 174 | } | 194 | } |
| 175 | 195 | ||
| 196 | impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> { | ||
| 197 | type Config = Config; | ||
| 198 | |||
| 199 | fn set_config(&mut self, config: &Self::Config) { | ||
| 200 | unwrap!(self.set_config(config)); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 176 | pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { | 204 | pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { |
| 177 | _peri: PeripheralRef<'d, T>, | 205 | _peri: PeripheralRef<'d, T>, |
| 178 | rx_dma: PeripheralRef<'d, RxDma>, | 206 | rx_dma: PeripheralRef<'d, RxDma>, |
| @@ -181,6 +209,14 @@ pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { | |||
| 181 | buffered_sr: stm32_metapac::usart::regs::Sr, | 209 | buffered_sr: stm32_metapac::usart::regs::Sr, |
| 182 | } | 210 | } |
| 183 | 211 | ||
| 212 | impl<'d, T: BasicInstance, RxDma> SetConfig for UartRx<'d, T, RxDma> { | ||
| 213 | type Config = Config; | ||
| 214 | |||
| 215 | fn set_config(&mut self, config: &Self::Config) { | ||
| 216 | unwrap!(self.set_config(config)); | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 184 | impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | 220 | impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { |
| 185 | /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power. | 221 | /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power. |
| 186 | pub fn new( | 222 | pub fn new( |
| @@ -188,7 +224,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||
| 188 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 224 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 189 | tx_dma: impl Peripheral<P = TxDma> + 'd, | 225 | tx_dma: impl Peripheral<P = TxDma> + 'd, |
| 190 | config: Config, | 226 | config: Config, |
| 191 | ) -> Self { | 227 | ) -> Result<Self, ConfigError> { |
| 192 | T::enable(); | 228 | T::enable(); |
| 193 | T::reset(); | 229 | T::reset(); |
| 194 | 230 | ||
| @@ -201,7 +237,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||
| 201 | cts: impl Peripheral<P = impl CtsPin<T>> + 'd, | 237 | cts: impl Peripheral<P = impl CtsPin<T>> + 'd, |
| 202 | tx_dma: impl Peripheral<P = TxDma> + 'd, | 238 | tx_dma: impl Peripheral<P = TxDma> + 'd, |
| 203 | config: Config, | 239 | config: Config, |
| 204 | ) -> Self { | 240 | ) -> Result<Self, ConfigError> { |
| 205 | into_ref!(cts); | 241 | into_ref!(cts); |
| 206 | 242 | ||
| 207 | T::enable(); | 243 | T::enable(); |
| @@ -219,22 +255,26 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||
| 219 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 255 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 220 | tx_dma: impl Peripheral<P = TxDma> + 'd, | 256 | tx_dma: impl Peripheral<P = TxDma> + 'd, |
| 221 | config: Config, | 257 | config: Config, |
| 222 | ) -> Self { | 258 | ) -> Result<Self, ConfigError> { |
| 223 | into_ref!(_peri, tx, tx_dma); | 259 | into_ref!(_peri, tx, tx_dma); |
| 224 | 260 | ||
| 225 | let r = T::regs(); | 261 | let r = T::regs(); |
| 226 | 262 | ||
| 227 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | 263 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |
| 228 | 264 | ||
| 229 | configure(r, &config, T::frequency(), T::KIND, false, true); | 265 | configure(r, &config, T::frequency(), T::KIND, false, true)?; |
| 230 | 266 | ||
| 231 | // create state once! | 267 | // create state once! |
| 232 | let _s = T::state(); | 268 | let _s = T::state(); |
| 233 | 269 | ||
| 234 | Self { | 270 | Ok(Self { |
| 235 | tx_dma, | 271 | tx_dma, |
| 236 | phantom: PhantomData, | 272 | phantom: PhantomData, |
| 237 | } | 273 | }) |
| 274 | } | ||
| 275 | |||
| 276 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { | ||
| 277 | reconfigure::<T>(config) | ||
| 238 | } | 278 | } |
| 239 | 279 | ||
| 240 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> | 280 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> |
| @@ -277,7 +317,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 277 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 317 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 278 | rx_dma: impl Peripheral<P = RxDma> + 'd, | 318 | rx_dma: impl Peripheral<P = RxDma> + 'd, |
| 279 | config: Config, | 319 | config: Config, |
| 280 | ) -> Self { | 320 | ) -> Result<Self, ConfigError> { |
| 281 | T::enable(); | 321 | T::enable(); |
| 282 | T::reset(); | 322 | T::reset(); |
| 283 | 323 | ||
| @@ -291,7 +331,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 291 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, | 331 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, |
| 292 | rx_dma: impl Peripheral<P = RxDma> + 'd, | 332 | rx_dma: impl Peripheral<P = RxDma> + 'd, |
| 293 | config: Config, | 333 | config: Config, |
| 294 | ) -> Self { | 334 | ) -> Result<Self, ConfigError> { |
| 295 | into_ref!(rts); | 335 | into_ref!(rts); |
| 296 | 336 | ||
| 297 | T::enable(); | 337 | T::enable(); |
| @@ -310,14 +350,14 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 310 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 350 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 311 | rx_dma: impl Peripheral<P = RxDma> + 'd, | 351 | rx_dma: impl Peripheral<P = RxDma> + 'd, |
| 312 | config: Config, | 352 | config: Config, |
| 313 | ) -> Self { | 353 | ) -> Result<Self, ConfigError> { |
| 314 | into_ref!(peri, rx, rx_dma); | 354 | into_ref!(peri, rx, rx_dma); |
| 315 | 355 | ||
| 316 | let r = T::regs(); | 356 | let r = T::regs(); |
| 317 | 357 | ||
| 318 | rx.set_as_af(rx.af_num(), AFType::Input); | 358 | rx.set_as_af(rx.af_num(), AFType::Input); |
| 319 | 359 | ||
| 320 | configure(r, &config, T::frequency(), T::KIND, true, false); | 360 | configure(r, &config, T::frequency(), T::KIND, true, false)?; |
| 321 | 361 | ||
| 322 | T::Interrupt::unpend(); | 362 | T::Interrupt::unpend(); |
| 323 | unsafe { T::Interrupt::enable() }; | 363 | unsafe { T::Interrupt::enable() }; |
| @@ -325,13 +365,17 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 325 | // create state once! | 365 | // create state once! |
| 326 | let _s = T::state(); | 366 | let _s = T::state(); |
| 327 | 367 | ||
| 328 | Self { | 368 | Ok(Self { |
| 329 | _peri: peri, | 369 | _peri: peri, |
| 330 | rx_dma, | 370 | rx_dma, |
| 331 | detect_previous_overrun: config.detect_previous_overrun, | 371 | detect_previous_overrun: config.detect_previous_overrun, |
| 332 | #[cfg(any(usart_v1, usart_v2))] | 372 | #[cfg(any(usart_v1, usart_v2))] |
| 333 | buffered_sr: stm32_metapac::usart::regs::Sr(0), | 373 | buffered_sr: stm32_metapac::usart::regs::Sr(0), |
| 334 | } | 374 | }) |
| 375 | } | ||
| 376 | |||
| 377 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { | ||
| 378 | reconfigure::<T>(config) | ||
| 335 | } | 379 | } |
| 336 | 380 | ||
| 337 | #[cfg(any(usart_v1, usart_v2))] | 381 | #[cfg(any(usart_v1, usart_v2))] |
| @@ -545,6 +589,13 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 545 | unsafe { rdr(r).read_volatile() }; | 589 | unsafe { rdr(r).read_volatile() }; |
| 546 | clear_interrupt_flags(r, sr); | 590 | clear_interrupt_flags(r, sr); |
| 547 | 591 | ||
| 592 | if enable_idle_line_detection { | ||
| 593 | // enable idle interrupt | ||
| 594 | r.cr1().modify(|w| { | ||
| 595 | w.set_idleie(true); | ||
| 596 | }); | ||
| 597 | } | ||
| 598 | |||
| 548 | compiler_fence(Ordering::SeqCst); | 599 | compiler_fence(Ordering::SeqCst); |
| 549 | 600 | ||
| 550 | let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore(); | 601 | let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore(); |
| @@ -618,6 +669,18 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 618 | } | 669 | } |
| 619 | } | 670 | } |
| 620 | 671 | ||
| 672 | impl<'d, T: BasicInstance, TxDma> Drop for UartTx<'d, T, TxDma> { | ||
| 673 | fn drop(&mut self) { | ||
| 674 | T::disable(); | ||
| 675 | } | ||
| 676 | } | ||
| 677 | |||
| 678 | impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> { | ||
| 679 | fn drop(&mut self) { | ||
| 680 | T::disable(); | ||
| 681 | } | ||
| 682 | } | ||
| 683 | |||
| 621 | impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | 684 | impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { |
| 622 | pub fn new( | 685 | pub fn new( |
| 623 | peri: impl Peripheral<P = T> + 'd, | 686 | peri: impl Peripheral<P = T> + 'd, |
| @@ -627,7 +690,9 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 627 | tx_dma: impl Peripheral<P = TxDma> + 'd, | 690 | tx_dma: impl Peripheral<P = TxDma> + 'd, |
| 628 | rx_dma: impl Peripheral<P = RxDma> + 'd, | 691 | rx_dma: impl Peripheral<P = RxDma> + 'd, |
| 629 | config: Config, | 692 | config: Config, |
| 630 | ) -> Self { | 693 | ) -> Result<Self, ConfigError> { |
| 694 | // UartRx and UartTx have one refcount ea. | ||
| 695 | T::enable(); | ||
| 631 | T::enable(); | 696 | T::enable(); |
| 632 | T::reset(); | 697 | T::reset(); |
| 633 | 698 | ||
| @@ -644,9 +709,11 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 644 | tx_dma: impl Peripheral<P = TxDma> + 'd, | 709 | tx_dma: impl Peripheral<P = TxDma> + 'd, |
| 645 | rx_dma: impl Peripheral<P = RxDma> + 'd, | 710 | rx_dma: impl Peripheral<P = RxDma> + 'd, |
| 646 | config: Config, | 711 | config: Config, |
| 647 | ) -> Self { | 712 | ) -> Result<Self, ConfigError> { |
| 648 | into_ref!(cts, rts); | 713 | into_ref!(cts, rts); |
| 649 | 714 | ||
| 715 | // UartRx and UartTx have one refcount ea. | ||
| 716 | T::enable(); | ||
| 650 | T::enable(); | 717 | T::enable(); |
| 651 | T::reset(); | 718 | T::reset(); |
| 652 | 719 | ||
| @@ -669,9 +736,11 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 669 | tx_dma: impl Peripheral<P = TxDma> + 'd, | 736 | tx_dma: impl Peripheral<P = TxDma> + 'd, |
| 670 | rx_dma: impl Peripheral<P = RxDma> + 'd, | 737 | rx_dma: impl Peripheral<P = RxDma> + 'd, |
| 671 | config: Config, | 738 | config: Config, |
| 672 | ) -> Self { | 739 | ) -> Result<Self, ConfigError> { |
| 673 | into_ref!(de); | 740 | into_ref!(de); |
| 674 | 741 | ||
| 742 | // UartRx and UartTx have one refcount ea. | ||
| 743 | T::enable(); | ||
| 675 | T::enable(); | 744 | T::enable(); |
| 676 | T::reset(); | 745 | T::reset(); |
| 677 | 746 | ||
| @@ -689,7 +758,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 689 | tx_dma: impl Peripheral<P = TxDma> + 'd, | 758 | tx_dma: impl Peripheral<P = TxDma> + 'd, |
| 690 | rx_dma: impl Peripheral<P = RxDma> + 'd, | 759 | rx_dma: impl Peripheral<P = RxDma> + 'd, |
| 691 | config: Config, | 760 | config: Config, |
| 692 | ) -> Self { | 761 | ) -> Result<Self, ConfigError> { |
| 693 | into_ref!(peri, rx, tx, tx_dma, rx_dma); | 762 | into_ref!(peri, rx, tx, tx_dma, rx_dma); |
| 694 | 763 | ||
| 695 | let r = T::regs(); | 764 | let r = T::regs(); |
| @@ -711,7 +780,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 711 | } | 780 | } |
| 712 | } | 781 | } |
| 713 | 782 | ||
| 714 | configure(r, &config, T::frequency(), T::KIND, true, true); | 783 | configure(r, &config, T::frequency(), T::KIND, true, true)?; |
| 715 | 784 | ||
| 716 | T::Interrupt::unpend(); | 785 | T::Interrupt::unpend(); |
| 717 | unsafe { T::Interrupt::enable() }; | 786 | unsafe { T::Interrupt::enable() }; |
| @@ -719,7 +788,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 719 | // create state once! | 788 | // create state once! |
| 720 | let _s = T::state(); | 789 | let _s = T::state(); |
| 721 | 790 | ||
| 722 | Self { | 791 | Ok(Self { |
| 723 | tx: UartTx { | 792 | tx: UartTx { |
| 724 | tx_dma, | 793 | tx_dma, |
| 725 | phantom: PhantomData, | 794 | phantom: PhantomData, |
| @@ -731,7 +800,11 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 731 | #[cfg(any(usart_v1, usart_v2))] | 800 | #[cfg(any(usart_v1, usart_v2))] |
| 732 | buffered_sr: stm32_metapac::usart::regs::Sr(0), | 801 | buffered_sr: stm32_metapac::usart::regs::Sr(0), |
| 733 | }, | 802 | }, |
| 734 | } | 803 | }) |
| 804 | } | ||
| 805 | |||
| 806 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { | ||
| 807 | reconfigure::<T>(config) | ||
| 735 | } | 808 | } |
| 736 | 809 | ||
| 737 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> | 810 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> |
| @@ -779,7 +852,27 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 779 | } | 852 | } |
| 780 | } | 853 | } |
| 781 | 854 | ||
| 782 | fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: bool, enable_tx: bool) { | 855 | fn reconfigure<T: BasicInstance>(config: &Config) -> Result<(), ConfigError> { |
| 856 | T::Interrupt::disable(); | ||
| 857 | let r = T::regs(); | ||
| 858 | |||
| 859 | let cr = r.cr1().read(); | ||
| 860 | configure(r, config, T::frequency(), T::KIND, cr.re(), cr.te())?; | ||
| 861 | |||
| 862 | T::Interrupt::unpend(); | ||
| 863 | unsafe { T::Interrupt::enable() }; | ||
| 864 | |||
| 865 | Ok(()) | ||
| 866 | } | ||
| 867 | |||
| 868 | fn configure( | ||
| 869 | r: Regs, | ||
| 870 | config: &Config, | ||
| 871 | pclk_freq: Hertz, | ||
| 872 | kind: Kind, | ||
| 873 | enable_rx: bool, | ||
| 874 | enable_tx: bool, | ||
| 875 | ) -> Result<(), ConfigError> { | ||
| 783 | if !enable_rx && !enable_tx { | 876 | if !enable_rx && !enable_tx { |
| 784 | panic!("USART: At least one of RX or TX should be enabled"); | 877 | panic!("USART: At least one of RX or TX should be enabled"); |
| 785 | } | 878 | } |
| @@ -847,7 +940,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: | |||
| 847 | found_brr = Some(brr); | 940 | found_brr = Some(brr); |
| 848 | break; | 941 | break; |
| 849 | } | 942 | } |
| 850 | panic!("USART: baudrate too high"); | 943 | return Err(ConfigError::BaudrateTooHigh); |
| 851 | } | 944 | } |
| 852 | 945 | ||
| 853 | if brr < brr_max { | 946 | if brr < brr_max { |
| @@ -859,7 +952,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: | |||
| 859 | } | 952 | } |
| 860 | } | 953 | } |
| 861 | 954 | ||
| 862 | let brr = found_brr.expect("USART: baudrate too low"); | 955 | let brr = found_brr.ok_or(ConfigError::BaudrateTooLow)?; |
| 863 | 956 | ||
| 864 | #[cfg(not(usart_v1))] | 957 | #[cfg(not(usart_v1))] |
| 865 | let oversampling = if over8 { "8 bit" } else { "16 bit" }; | 958 | let oversampling = if over8 { "8 bit" } else { "16 bit" }; |
| @@ -905,12 +998,16 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: | |||
| 905 | }); | 998 | }); |
| 906 | #[cfg(not(usart_v1))] | 999 | #[cfg(not(usart_v1))] |
| 907 | w.set_over8(vals::Over8::from_bits(over8 as _)); | 1000 | w.set_over8(vals::Over8::from_bits(over8 as _)); |
| 1001 | #[cfg(usart_v4)] | ||
| 1002 | w.set_fifoen(true); | ||
| 908 | }); | 1003 | }); |
| 909 | 1004 | ||
| 910 | #[cfg(not(usart_v1))] | 1005 | #[cfg(not(usart_v1))] |
| 911 | r.cr3().modify(|w| { | 1006 | r.cr3().modify(|w| { |
| 912 | w.set_onebit(config.assume_noise_free); | 1007 | w.set_onebit(config.assume_noise_free); |
| 913 | }); | 1008 | }); |
| 1009 | |||
| 1010 | Ok(()) | ||
| 914 | } | 1011 | } |
| 915 | 1012 | ||
| 916 | mod eh02 { | 1013 | mod eh02 { |
| @@ -1012,20 +1109,61 @@ mod eh1 { | |||
| 1012 | } | 1109 | } |
| 1013 | } | 1110 | } |
| 1014 | 1111 | ||
| 1015 | #[cfg(all(feature = "unstable-traits", feature = "nightly"))] | 1112 | impl embedded_io::Error for Error { |
| 1016 | mod eio { | 1113 | fn kind(&self) -> embedded_io::ErrorKind { |
| 1017 | use embedded_io_async::{ErrorType, Write}; | 1114 | embedded_io::ErrorKind::Other |
| 1115 | } | ||
| 1116 | } | ||
| 1018 | 1117 | ||
| 1019 | use super::*; | 1118 | impl<T, TxDma, RxDma> embedded_io::ErrorType for Uart<'_, T, TxDma, RxDma> |
| 1119 | where | ||
| 1120 | T: BasicInstance, | ||
| 1121 | { | ||
| 1122 | type Error = Error; | ||
| 1123 | } | ||
| 1020 | 1124 | ||
| 1021 | impl<T, TxDma, RxDma> ErrorType for Uart<'_, T, TxDma, RxDma> | 1125 | impl<T, TxDma> embedded_io::ErrorType for UartTx<'_, T, TxDma> |
| 1022 | where | 1126 | where |
| 1023 | T: BasicInstance, | 1127 | T: BasicInstance, |
| 1024 | { | 1128 | { |
| 1025 | type Error = Error; | 1129 | type Error = Error; |
| 1130 | } | ||
| 1131 | |||
| 1132 | impl<T, TxDma, RxDma> embedded_io::Write for Uart<'_, T, TxDma, RxDma> | ||
| 1133 | where | ||
| 1134 | T: BasicInstance, | ||
| 1135 | TxDma: crate::usart::TxDma<T>, | ||
| 1136 | { | ||
| 1137 | fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { | ||
| 1138 | self.blocking_write(buf)?; | ||
| 1139 | Ok(buf.len()) | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 1143 | self.blocking_flush() | ||
| 1144 | } | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | impl<T, TxDma> embedded_io::Write for UartTx<'_, T, TxDma> | ||
| 1148 | where | ||
| 1149 | T: BasicInstance, | ||
| 1150 | TxDma: crate::usart::TxDma<T>, | ||
| 1151 | { | ||
| 1152 | fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { | ||
| 1153 | self.blocking_write(buf)?; | ||
| 1154 | Ok(buf.len()) | ||
| 1026 | } | 1155 | } |
| 1027 | 1156 | ||
| 1028 | impl<T, TxDma, RxDma> Write for Uart<'_, T, TxDma, RxDma> | 1157 | fn flush(&mut self) -> Result<(), Self::Error> { |
| 1158 | self.blocking_flush() | ||
| 1159 | } | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | #[cfg(all(feature = "unstable-traits", feature = "nightly"))] | ||
| 1163 | mod eio { | ||
| 1164 | use super::*; | ||
| 1165 | |||
| 1166 | impl<T, TxDma, RxDma> embedded_io_async::Write for Uart<'_, T, TxDma, RxDma> | ||
| 1029 | where | 1167 | where |
| 1030 | T: BasicInstance, | 1168 | T: BasicInstance, |
| 1031 | TxDma: super::TxDma<T>, | 1169 | TxDma: super::TxDma<T>, |
| @@ -1040,14 +1178,7 @@ mod eio { | |||
| 1040 | } | 1178 | } |
| 1041 | } | 1179 | } |
| 1042 | 1180 | ||
| 1043 | impl<T, TxDma> ErrorType for UartTx<'_, T, TxDma> | 1181 | impl<T, TxDma> embedded_io_async::Write for UartTx<'_, T, TxDma> |
| 1044 | where | ||
| 1045 | T: BasicInstance, | ||
| 1046 | { | ||
| 1047 | type Error = Error; | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | impl<T, TxDma> Write for UartTx<'_, T, TxDma> | ||
| 1051 | where | 1182 | where |
| 1052 | T: BasicInstance, | 1183 | T: BasicInstance, |
| 1053 | TxDma: super::TxDma<T>, | 1184 | TxDma: super::TxDma<T>, |
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index b3f570624..347aae7c9 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs | |||
| @@ -1,11 +1,13 @@ | |||
| 1 | use core::future::poll_fn; | 1 | use core::future::poll_fn; |
| 2 | use core::mem; | ||
| 2 | use core::sync::atomic::{compiler_fence, Ordering}; | 3 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 3 | use core::task::Poll; | 4 | use core::task::Poll; |
| 4 | 5 | ||
| 6 | use embassy_embedded_hal::SetConfig; | ||
| 5 | use embassy_hal_internal::PeripheralRef; | 7 | use embassy_hal_internal::PeripheralRef; |
| 6 | use futures::future::{select, Either}; | 8 | use futures::future::{select, Either}; |
| 7 | 9 | ||
| 8 | use super::{clear_interrupt_flags, rdr, sr, BasicInstance, Error, UartRx}; | 10 | use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, UartRx}; |
| 9 | use crate::dma::ReadableRingBuffer; | 11 | use crate::dma::ReadableRingBuffer; |
| 10 | use crate::usart::{Regs, Sr}; | 12 | use crate::usart::{Regs, Sr}; |
| 11 | 13 | ||
| @@ -14,6 +16,14 @@ pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma<T>> { | |||
| 14 | ring_buf: ReadableRingBuffer<'d, RxDma, u8>, | 16 | ring_buf: ReadableRingBuffer<'d, RxDma, u8>, |
| 15 | } | 17 | } |
| 16 | 18 | ||
| 19 | impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> SetConfig for RingBufferedUartRx<'d, T, RxDma> { | ||
| 20 | type Config = Config; | ||
| 21 | |||
| 22 | fn set_config(&mut self, config: &Self::Config) { | ||
| 23 | unwrap!(self.set_config(config)); | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 17 | impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> { | 27 | impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> { |
| 18 | /// Turn the `UartRx` into a buffered uart which can continously receive in the background | 28 | /// Turn the `UartRx` into a buffered uart which can continously receive in the background |
| 19 | /// without the possibility of loosing bytes. The `dma_buf` is a buffer registered to the | 29 | /// without the possibility of loosing bytes. The `dma_buf` is a buffer registered to the |
| @@ -24,12 +34,16 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> { | |||
| 24 | let request = self.rx_dma.request(); | 34 | let request = self.rx_dma.request(); |
| 25 | let opts = Default::default(); | 35 | let opts = Default::default(); |
| 26 | 36 | ||
| 27 | let ring_buf = unsafe { ReadableRingBuffer::new_read(self.rx_dma, request, rdr(T::regs()), dma_buf, opts) }; | 37 | // Safety: we forget the struct before this function returns. |
| 38 | let rx_dma = unsafe { self.rx_dma.clone_unchecked() }; | ||
| 39 | let _peri = unsafe { self._peri.clone_unchecked() }; | ||
| 28 | 40 | ||
| 29 | RingBufferedUartRx { | 41 | let ring_buf = unsafe { ReadableRingBuffer::new_read(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; |
| 30 | _peri: self._peri, | 42 | |
| 31 | ring_buf, | 43 | // Don't disable the clock |
| 32 | } | 44 | mem::forget(self); |
| 45 | |||
| 46 | RingBufferedUartRx { _peri, ring_buf } | ||
| 33 | } | 47 | } |
| 34 | } | 48 | } |
| 35 | 49 | ||
| @@ -49,6 +63,11 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD | |||
| 49 | Err(err) | 63 | Err(err) |
| 50 | } | 64 | } |
| 51 | 65 | ||
| 66 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { | ||
| 67 | self.teardown_uart(); | ||
| 68 | reconfigure::<T>(config) | ||
| 69 | } | ||
| 70 | |||
| 52 | /// Start uart background receive | 71 | /// Start uart background receive |
| 53 | fn setup_uart(&mut self) { | 72 | fn setup_uart(&mut self) { |
| 54 | // fence before starting DMA. | 73 | // fence before starting DMA. |
| @@ -186,6 +205,8 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD | |||
| 186 | impl<T: BasicInstance, RxDma: super::RxDma<T>> Drop for RingBufferedUartRx<'_, T, RxDma> { | 205 | impl<T: BasicInstance, RxDma: super::RxDma<T>> Drop for RingBufferedUartRx<'_, T, RxDma> { |
| 187 | fn drop(&mut self) { | 206 | fn drop(&mut self) { |
| 188 | self.teardown_uart(); | 207 | self.teardown_uart(); |
| 208 | |||
| 209 | T::disable(); | ||
| 189 | } | 210 | } |
| 190 | } | 211 | } |
| 191 | /// Return an error result if the Sr register has errors | 212 | /// Return an error result if the Sr register has errors |
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index cef196355..b24fc74eb 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs | |||
| @@ -264,10 +264,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 264 | let regs = T::regs(); | 264 | let regs = T::regs(); |
| 265 | 265 | ||
| 266 | #[cfg(stm32l5)] | 266 | #[cfg(stm32l5)] |
| 267 | { | 267 | crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); |
| 268 | crate::peripherals::PWR::enable(); | ||
| 269 | crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); | ||
| 270 | } | ||
| 271 | 268 | ||
| 272 | #[cfg(pwr_h5)] | 269 | #[cfg(pwr_h5)] |
| 273 | crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)); | 270 | crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)); |
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index 348f0f79d..1fe010bbb 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs | |||
| @@ -540,10 +540,7 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 540 | impl<'d, T: Instance> Bus<'d, T> { | 540 | impl<'d, T: Instance> Bus<'d, T> { |
| 541 | fn init(&mut self) { | 541 | fn init(&mut self) { |
| 542 | #[cfg(stm32l4)] | 542 | #[cfg(stm32l4)] |
| 543 | { | 543 | critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); |
| 544 | crate::peripherals::PWR::enable(); | ||
| 545 | critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); | ||
| 546 | } | ||
| 547 | 544 | ||
| 548 | #[cfg(stm32f7)] | 545 | #[cfg(stm32f7)] |
| 549 | { | 546 | { |
| @@ -618,15 +615,10 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 618 | { | 615 | { |
| 619 | // Enable USB power | 616 | // Enable USB power |
| 620 | critical_section::with(|_| { | 617 | critical_section::with(|_| { |
| 621 | crate::pac::RCC.ahb3enr().modify(|w| { | ||
| 622 | w.set_pwren(true); | ||
| 623 | }); | ||
| 624 | cortex_m::asm::delay(2); | ||
| 625 | |||
| 626 | crate::pac::PWR.svmcr().modify(|w| { | 618 | crate::pac::PWR.svmcr().modify(|w| { |
| 627 | w.set_usv(true); | 619 | w.set_usv(true); |
| 628 | w.set_uvmen(true); | 620 | w.set_uvmen(true); |
| 629 | }); | 621 | }) |
| 630 | }); | 622 | }); |
| 631 | 623 | ||
| 632 | // Wait for USB power to stabilize | 624 | // Wait for USB power to stabilize |
