aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/modules/ROOT/pages/basic_application.adoc15
-rw-r--r--embassy-executor/Cargo.toml5
-rw-r--r--embassy-executor/src/arch/riscv32.rs2
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/build.rs299
-rw-r--r--embassy-stm32/src/can/fdcan.rs62
-rw-r--r--embassy-stm32/src/can/frame.rs4
-rw-r--r--embassy-stm32/src/cryp/mod.rs1356
-rw-r--r--embassy-stm32/src/ipcc.rs19
-rw-r--r--embassy-stm32/src/lib.rs2
-rw-r--r--embassy-stm32/src/rcc/c0.rs34
-rw-r--r--embassy-stm32/src/rcc/f013.rs6
-rw-r--r--embassy-stm32/src/rcc/f247.rs10
-rw-r--r--embassy-stm32/src/rcc/g0.rs63
-rw-r--r--embassy-stm32/src/rcc/g4.rs78
-rw-r--r--embassy-stm32/src/rcc/h.rs72
-rw-r--r--embassy-stm32/src/rcc/l.rs56
-rw-r--r--embassy-stm32/src/rcc/mod.rs4
-rw-r--r--embassy-stm32/src/rcc/u5.rs7
-rw-r--r--embassy-stm32/src/rcc/wba.rs13
-rw-r--r--embassy-stm32/src/usb_otg/usb.rs14
-rw-r--r--examples/stm32f334/src/bin/pwm.rs2
-rw-r--r--examples/stm32f7/Cargo.toml1
-rw-r--r--examples/stm32f7/src/bin/cryp.rs74
-rw-r--r--examples/stm32g0/src/bin/hf_timer.rs44
-rw-r--r--examples/stm32g0/src/bin/usb_serial.rs10
-rw-r--r--examples/stm32g4/src/bin/adc.rs29
-rw-r--r--examples/stm32g4/src/bin/can.rs27
-rw-r--r--examples/stm32g4/src/bin/pll.rs1
-rw-r--r--examples/stm32g4/src/bin/usb_serial.rs50
-rw-r--r--examples/stm32h5/src/bin/can.rs2
-rw-r--r--examples/stm32h5/src/bin/usb_serial.rs7
-rw-r--r--examples/stm32h7/src/bin/adc.rs2
-rw-r--r--examples/stm32h7/src/bin/can.rs2
-rw-r--r--examples/stm32h7/src/bin/dac.rs2
-rw-r--r--examples/stm32h7/src/bin/dac_dma.rs2
-rw-r--r--examples/stm32l4/src/bin/adc.rs14
-rw-r--r--tests/stm32/Cargo.toml11
-rw-r--r--tests/stm32/src/bin/cryp.rs69
-rw-r--r--tests/stm32/src/bin/fdcan.rs4
-rw-r--r--tests/stm32/src/common.rs47
41 files changed, 1988 insertions, 537 deletions
diff --git a/docs/modules/ROOT/pages/basic_application.adoc b/docs/modules/ROOT/pages/basic_application.adoc
index 95792d5a0..d5aad806d 100644
--- a/docs/modules/ROOT/pages/basic_application.adoc
+++ b/docs/modules/ROOT/pages/basic_application.adoc
@@ -17,22 +17,13 @@ The first thing you’ll notice are two attributes at the top of the file. These
17include::example$basic/src/main.rs[lines="1..2"] 17include::example$basic/src/main.rs[lines="1..2"]
18---- 18----
19 19
20=== Rust Nightly
21
22The next declaration is a Rust Unstable feature, which means that Embassy requires Rust Nightly:
23
24[source,rust]
25----
26include::example$basic/src/main.rs[lines="3"]
27----
28
29=== Dealing with errors 20=== Dealing with errors
30 21
31Then, what follows are some declarations on how to deal with panics and faults. During development, a good practice is to rely on `defmt-rtt` and `panic-probe` to print diagnostics to the terminal: 22Then, what follows are some declarations on how to deal with panics and faults. During development, a good practice is to rely on `defmt-rtt` and `panic-probe` to print diagnostics to the terminal:
32 23
33[source,rust] 24[source,rust]
34---- 25----
35include::example$basic/src/main.rs[lines="10"] 26include::example$basic/src/main.rs[lines="8"]
36---- 27----
37 28
38=== Task declaration 29=== Task declaration
@@ -41,7 +32,7 @@ After a bit of import declaration, the tasks run by the application should be de
41 32
42[source,rust] 33[source,rust]
43---- 34----
44include::example$basic/src/main.rs[lines="12..20"] 35include::example$basic/src/main.rs[lines="10..18"]
45---- 36----
46 37
47An embassy task must be declared `async`, and may NOT take generic arguments. In this case, we are handed the LED that should be blinked and the interval of the blinking. 38An embassy task must be declared `async`, and may NOT take generic arguments. In this case, we are handed the LED that should be blinked and the interval of the blinking.
@@ -56,7 +47,7 @@ We then initialize the HAL with a default config, which gives us a `Peripherals`
56 47
57[source,rust] 48[source,rust]
58---- 49----
59include::example$basic/src/main.rs[lines="22..-1"] 50include::example$basic/src/main.rs[lines="20..-1"]
60---- 51----
61 52
62What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy_executor::main]` macro. The macro does the following: 53What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy_executor::main]` macro. The macro does the following:
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index 409df0d75..431165cee 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -40,8 +40,7 @@ critical-section = "1.1"
40 40
41document-features = "0.2.7" 41document-features = "0.2.7"
42 42
43# needed for riscv and avr 43# needed for AVR
44# remove when https://github.com/rust-lang/rust/pull/114499 lands on stable (on 1.76)
45portable-atomic = { version = "1.5", optional = true } 44portable-atomic = { version = "1.5", optional = true }
46 45
47# arch-cortex-m dependencies 46# arch-cortex-m dependencies
@@ -78,7 +77,7 @@ arch-std = ["_arch", "critical-section/std"]
78## Cortex-M 77## Cortex-M
79arch-cortex-m = ["_arch", "dep:cortex-m"] 78arch-cortex-m = ["_arch", "dep:cortex-m"]
80## RISC-V 32 79## RISC-V 32
81arch-riscv32 = ["_arch", "dep:portable-atomic"] 80arch-riscv32 = ["_arch"]
82## WASM 81## WASM
83arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"] 82arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"]
84## AVR 83## AVR
diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs
index c56f502d3..01e63a9fd 100644
--- a/embassy-executor/src/arch/riscv32.rs
+++ b/embassy-executor/src/arch/riscv32.rs
@@ -6,9 +6,9 @@ pub use thread::*;
6#[cfg(feature = "executor-thread")] 6#[cfg(feature = "executor-thread")]
7mod thread { 7mod thread {
8 use core::marker::PhantomData; 8 use core::marker::PhantomData;
9 use core::sync::atomic::{AtomicBool, Ordering};
9 10
10 pub use embassy_executor_macros::main_riscv as main; 11 pub use embassy_executor_macros::main_riscv as main;
11 use portable_atomic::{AtomicBool, Ordering};
12 12
13 use crate::{raw, Spawner}; 13 use crate::{raw, Spawner};
14 14
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 08ccd35ae..4bbd43c47 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -70,7 +70,7 @@ rand_core = "0.6.3"
70sdio-host = "0.5.0" 70sdio-host = "0.5.0"
71critical-section = "1.1" 71critical-section = "1.1"
72#stm32-metapac = { version = "15" } 72#stm32-metapac = { version = "15" }
73stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a0bcec33362449fb733c066936d25cbabab396a" } 73stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d" }
74vcell = "0.1.3" 74vcell = "0.1.3"
75bxcan = "0.7.0" 75bxcan = "0.7.0"
76nb = "1.0.0" 76nb = "1.0.0"
@@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] }
94proc-macro2 = "1.0.36" 94proc-macro2 = "1.0.36"
95quote = "1.0.15" 95quote = "1.0.15"
96#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 96#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
97stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a0bcec33362449fb733c066936d25cbabab396a", default-features = false, features = ["metadata"]} 97stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d", default-features = false, features = ["metadata"]}
98 98
99 99
100[features] 100[features]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 08c051956..84e8be25d 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -5,7 +5,9 @@ use std::{env, fs};
5 5
6use proc_macro2::{Ident, TokenStream}; 6use proc_macro2::{Ident, TokenStream};
7use quote::{format_ident, quote}; 7use quote::{format_ident, quote};
8use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccKernelClock, StopMode, METADATA}; 8use stm32_metapac::metadata::{
9 MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, METADATA,
10};
9 11
10fn main() { 12fn main() {
11 let target = env::var("TARGET").unwrap(); 13 let target = env::var("TARGET").unwrap();
@@ -374,12 +376,130 @@ fn main() {
374 } 376 }
375 } 377 }
376 378
377 let force_refcount = HashSet::from(["usart"]); 379 struct ClockGen<'a> {
378 let mut refcount_statics = BTreeSet::new(); 380 rcc_registers: &'a PeripheralRegisters,
381 chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>,
382 force_refcount: HashSet<&'a str>,
379 383
380 let mut clock_names = BTreeSet::new(); 384 refcount_statics: BTreeSet<Ident>,
385 clock_names: BTreeSet<String>,
386 muxes: BTreeSet<(Ident, Ident, Ident)>,
387 }
388
389 let mut clock_gen = ClockGen {
390 rcc_registers,
391 chained_muxes: HashMap::new(),
392 force_refcount: HashSet::from(["usart"]),
381 393
382 let mut rcc_cfgr_regs = BTreeSet::new(); 394 refcount_statics: BTreeSet::new(),
395 clock_names: BTreeSet::new(),
396 muxes: BTreeSet::new(),
397 };
398 if chip_name.starts_with("stm32h5") {
399 clock_gen.chained_muxes.insert(
400 "PER",
401 &PeripheralRccRegister {
402 register: "CCIPR5",
403 field: "PERSEL",
404 },
405 );
406 }
407 if chip_name.starts_with("stm32h7") {
408 clock_gen.chained_muxes.insert(
409 "PER",
410 &PeripheralRccRegister {
411 register: "D1CCIPR",
412 field: "PERSEL",
413 },
414 );
415 }
416 if chip_name.starts_with("stm32u5") {
417 clock_gen.chained_muxes.insert(
418 "ICLK",
419 &PeripheralRccRegister {
420 register: "CCIPR1",
421 field: "ICLKSEL",
422 },
423 );
424 }
425 if chip_name.starts_with("stm32wb") && !chip_name.starts_with("stm32wba") {
426 clock_gen.chained_muxes.insert(
427 "CLK48",
428 &PeripheralRccRegister {
429 register: "CCIPR",
430 field: "CLK48SEL",
431 },
432 );
433 }
434 if chip_name.starts_with("stm32f7") {
435 clock_gen.chained_muxes.insert(
436 "CLK48",
437 &PeripheralRccRegister {
438 register: "DCKCFGR2",
439 field: "CLK48SEL",
440 },
441 );
442 }
443 if chip_name.starts_with("stm32f4") && !chip_name.starts_with("stm32f410") {
444 clock_gen.chained_muxes.insert(
445 "CLK48",
446 &PeripheralRccRegister {
447 register: "DCKCFGR",
448 field: "CLK48SEL",
449 },
450 );
451 }
452
453 impl<'a> ClockGen<'a> {
454 fn gen_clock(&mut self, name: &str) -> TokenStream {
455 let clock_name = format_ident!("{}", name.to_ascii_lowercase());
456 self.clock_names.insert(name.to_ascii_lowercase());
457 quote!( unsafe { crate::rcc::get_freqs().#clock_name.unwrap() } )
458 }
459
460 fn gen_mux(&mut self, mux: &PeripheralRccRegister) -> TokenStream {
461 let ir = &self.rcc_registers.ir;
462 let fieldset_name = mux.register.to_ascii_lowercase();
463 let fieldset = ir
464 .fieldsets
465 .iter()
466 .find(|i| i.name.eq_ignore_ascii_case(&fieldset_name))
467 .unwrap();
468 let field_name = mux.field.to_ascii_lowercase();
469 let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap();
470 let enum_name = field.enumm.unwrap();
471 let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap();
472
473 let fieldset_name = format_ident!("{}", fieldset_name);
474 let field_name = format_ident!("{}", field_name);
475 let enum_name = format_ident!("{}", enum_name);
476
477 self.muxes
478 .insert((fieldset_name.clone(), field_name.clone(), enum_name.clone()));
479
480 let mut match_arms = TokenStream::new();
481
482 for v in enumm.variants.iter().filter(|v| v.name != "DISABLE") {
483 let variant_name = format_ident!("{}", v.name);
484 let expr = if let Some(mux) = self.chained_muxes.get(&v.name) {
485 self.gen_mux(mux)
486 } else {
487 self.gen_clock(&v.name)
488 };
489 match_arms.extend(quote! {
490 crate::pac::rcc::vals::#enum_name::#variant_name => #expr,
491 });
492 }
493
494 quote! {
495 match crate::pac::RCC.#fieldset_name().read().#field_name() {
496 #match_arms
497 #[allow(unreachable_patterns)]
498 _ => unreachable!(),
499 }
500 }
501 }
502 }
383 503
384 for p in METADATA.peripherals { 504 for p in METADATA.peripherals {
385 if !singletons.contains(&p.name.to_string()) { 505 if !singletons.contains(&p.name.to_string()) {
@@ -416,12 +536,12 @@ fn main() {
416 let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); 536 let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
417 537
418 let refcount = 538 let refcount =
419 force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1; 539 clock_gen.force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
420 let (before_enable, before_disable) = if refcount { 540 let (before_enable, before_disable) = if refcount {
421 let refcount_static = 541 let refcount_static =
422 format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); 542 format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase());
423 543
424 refcount_statics.insert(refcount_static.clone()); 544 clock_gen.refcount_statics.insert(refcount_static.clone());
425 545
426 ( 546 (
427 quote! { 547 quote! {
@@ -442,63 +562,12 @@ fn main() {
442 }; 562 };
443 563
444 let clock_frequency = match &rcc.kernel_clock { 564 let clock_frequency = match &rcc.kernel_clock {
445 PeripheralRccKernelClock::Mux(mux) => { 565 PeripheralRccKernelClock::Mux(mux) => clock_gen.gen_mux(mux),
446 let ir = &rcc_registers.ir; 566 PeripheralRccKernelClock::Clock(clock) => clock_gen.gen_clock(clock),
447 let fieldset_name = mux.register.to_ascii_lowercase();
448 let fieldset = ir
449 .fieldsets
450 .iter()
451 .find(|i| i.name.eq_ignore_ascii_case(&fieldset_name))
452 .unwrap();
453 let field_name = mux.field.to_ascii_lowercase();
454 let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap();
455 let enum_name = field.enumm.unwrap();
456 let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap();
457
458 let fieldset_name = format_ident!("{}", fieldset_name);
459 let field_name = format_ident!("{}", field_name);
460 let enum_name = format_ident!("{}", enum_name);
461
462 rcc_cfgr_regs.insert((fieldset_name.clone(), field_name.clone(), enum_name.clone()));
463
464 let match_arms: TokenStream = enumm
465 .variants
466 .iter()
467 .filter(|v| v.name != "DISABLE")
468 .map(|v| {
469 let variant_name = format_ident!("{}", v.name);
470 let clock_name = format_ident!("{}", v.name.to_ascii_lowercase());
471 clock_names.insert(v.name.to_ascii_lowercase());
472 quote! {
473 #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() },
474 }
475 })
476 .collect();
477
478 quote! {
479 use crate::pac::rcc::vals::#enum_name;
480
481 #[allow(unreachable_patterns)]
482 match crate::pac::RCC.#fieldset_name().read().#field_name() {
483 #match_arms
484 _ => unreachable!(),
485 }
486 }
487 }
488 PeripheralRccKernelClock::Clock(clock) => {
489 let clock = clock.to_ascii_lowercase();
490 let clock_name = format_ident!("{}", clock);
491 clock_names.insert(clock.to_string());
492 quote! {
493 unsafe { crate::rcc::get_freqs().#clock_name.unwrap() }
494 }
495 }
496 }; 567 };
497 568
498 /* 569 // A refcount leak can result if the same field is shared by peripherals with different stop modes
499 A refcount leak can result if the same field is shared by peripherals with different stop modes 570 // This condition should be checked in stm32-data
500 This condition should be checked in stm32-data
501 */
502 let stop_refcount = match rcc.stop_mode { 571 let stop_refcount = match rcc.stop_mode {
503 StopMode::Standby => None, 572 StopMode::Standby => None,
504 StopMode::Stop2 => Some(quote! { REFCOUNT_STOP2 }), 573 StopMode::Stop2 => Some(quote! { REFCOUNT_STOP2 }),
@@ -543,74 +612,79 @@ fn main() {
543 } 612 }
544 } 613 }
545 614
546 if !rcc_cfgr_regs.is_empty() { 615 let struct_fields: Vec<_> = clock_gen
547 println!("cargo:rustc-cfg=clock_mux"); 616 .muxes
617 .iter()
618 .map(|(_fieldset, fieldname, enum_name)| {
619 quote! {
620 pub #fieldname: #enum_name
621 }
622 })
623 .collect();
548 624
549 let struct_fields: Vec<_> = rcc_cfgr_regs 625 let mut inits = TokenStream::new();
626 for fieldset in clock_gen
627 .muxes
628 .iter()
629 .map(|(f, _, _)| f)
630 .collect::<BTreeSet<_>>()
631 .into_iter()
632 {
633 let setters: Vec<_> = clock_gen
634 .muxes
550 .iter() 635 .iter()
551 .map(|(_fieldset, fieldname, enum_name)| { 636 .filter(|(f, _, _)| f == fieldset)
637 .map(|(_, fieldname, _)| {
638 let setter = format_ident!("set_{}", fieldname);
552 quote! { 639 quote! {
553 pub #fieldname: Option<#enum_name> 640 w.#setter(self.#fieldname);
554 } 641 }
555 }) 642 })
556 .collect(); 643 .collect();
557 644
558 let field_names: Vec<_> = rcc_cfgr_regs 645 inits.extend(quote! {
559 .iter() 646 crate::pac::RCC.#fieldset().modify(|w| {
560 .map(|(_fieldset, fieldname, _enum_name)| fieldname) 647 #(#setters)*
561 .collect(); 648 });
649 })
650 }
562 651
563 let inits: Vec<_> = rcc_cfgr_regs 652 let enum_names: BTreeSet<_> = clock_gen.muxes.iter().map(|(_, _, enum_name)| enum_name).collect();
564 .iter()
565 .map(|(fieldset, fieldname, _enum_name)| {
566 let setter = format_ident!("set_{}", fieldname);
567 quote! {
568 match self.#fieldname {
569 None => {}
570 Some(val) => {
571 crate::pac::RCC.#fieldset()
572 .modify(|w| w.#setter(val));
573 }
574 };
575 }
576 })
577 .collect();
578 653
579 let enum_names: BTreeSet<_> = rcc_cfgr_regs 654 g.extend(quote! {
580 .iter() 655 pub mod mux {
581 .map(|(_fieldset, _fieldname, enum_name)| enum_name) 656 #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )*
582 .collect();
583 657
584 g.extend(quote! { 658 #[derive(Clone, Copy)]
585 pub mod mux { 659 pub struct ClockMux {
586 #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )* 660 #( #struct_fields, )*
661 }
587 662
588 #[derive(Clone, Copy)] 663 impl ClockMux {
589 pub struct ClockMux { 664 pub(crate) const fn default() -> Self {
590 #( #struct_fields, )* 665 // safety: zero value is valid for all PAC enums.
666 unsafe { ::core::mem::zeroed() }
591 } 667 }
668 }
592 669
593 impl Default for ClockMux { 670 impl Default for ClockMux {
594 fn default() -> Self { 671 fn default() -> Self {
595 Self { 672 Self::default()
596 #( #field_names: None, )*
597 }
598 }
599 } 673 }
674 }
600 675
601 impl ClockMux { 676 impl ClockMux {
602 pub fn init(self) { 677 pub(crate) fn init(&self) {
603 #( #inits )* 678 #inits
604 }
605 } 679 }
606 } 680 }
607 }); 681 }
608 } 682 });
609 683
610 // Generate RCC 684 // Generate RCC
611 clock_names.insert("sys".to_string()); 685 clock_gen.clock_names.insert("sys".to_string());
612 clock_names.insert("rtc".to_string()); 686 clock_gen.clock_names.insert("rtc".to_string());
613 let clock_idents: Vec<_> = clock_names.iter().map(|n| format_ident!("{}", n)).collect(); 687 let clock_idents: Vec<_> = clock_gen.clock_names.iter().map(|n| format_ident!("{}", n)).collect();
614 g.extend(quote! { 688 g.extend(quote! {
615 #[derive(Clone, Copy, Debug)] 689 #[derive(Clone, Copy, Debug)]
616 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 690 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -640,7 +714,8 @@ fn main() {
640 } 714 }
641 ); 715 );
642 716
643 let refcount_mod: TokenStream = refcount_statics 717 let refcount_mod: TokenStream = clock_gen
718 .refcount_statics
644 .iter() 719 .iter()
645 .map(|refcount_static| { 720 .map(|refcount_static| {
646 quote! { 721 quote! {
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index 6a4a25cb7..77db774fc 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -436,7 +436,31 @@ pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_S
436} 436}
437 437
438/// Sender that can be used for sending CAN frames. 438/// Sender that can be used for sending CAN frames.
439pub type BufferedCanSender = embassy_sync::channel::DynamicSender<'static, ClassicFrame>; 439#[derive(Copy, Clone)]
440pub struct BufferedCanSender {
441 tx_buf: embassy_sync::channel::DynamicSender<'static, ClassicFrame>,
442 waker: fn(),
443}
444
445impl BufferedCanSender {
446 /// Async write frame to TX buffer.
447 pub fn try_write(&mut self, frame: ClassicFrame) -> Result<(), embassy_sync::channel::TrySendError<ClassicFrame>> {
448 self.tx_buf.try_send(frame)?;
449 (self.waker)();
450 Ok(())
451 }
452
453 /// Async write frame to TX buffer.
454 pub async fn write(&mut self, frame: ClassicFrame) {
455 self.tx_buf.send(frame).await;
456 (self.waker)();
457 }
458
459 /// Allows a poll_fn to poll until the channel is ready to write
460 pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> {
461 self.tx_buf.poll_ready_to_send(cx)
462 }
463}
440 464
441/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. 465/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
442pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, (ClassicFrame, Timestamp)>; 466pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, (ClassicFrame, Timestamp)>;
@@ -489,7 +513,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
489 513
490 /// Returns a sender that can be used for sending CAN frames. 514 /// Returns a sender that can be used for sending CAN frames.
491 pub fn writer(&self) -> BufferedCanSender { 515 pub fn writer(&self) -> BufferedCanSender {
492 self.tx_buf.sender().into() 516 BufferedCanSender {
517 tx_buf: self.tx_buf.sender().into(),
518 waker: T::IT0Interrupt::pend,
519 }
493 } 520 }
494 521
495 /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. 522 /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
@@ -525,7 +552,31 @@ pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF
525} 552}
526 553
527/// Sender that can be used for sending CAN frames. 554/// Sender that can be used for sending CAN frames.
528pub type BufferedFdCanSender = embassy_sync::channel::DynamicSender<'static, FdFrame>; 555#[derive(Copy, Clone)]
556pub struct BufferedFdCanSender {
557 tx_buf: embassy_sync::channel::DynamicSender<'static, FdFrame>,
558 waker: fn(),
559}
560
561impl BufferedFdCanSender {
562 /// Async write frame to TX buffer.
563 pub fn try_write(&mut self, frame: FdFrame) -> Result<(), embassy_sync::channel::TrySendError<FdFrame>> {
564 self.tx_buf.try_send(frame)?;
565 (self.waker)();
566 Ok(())
567 }
568
569 /// Async write frame to TX buffer.
570 pub async fn write(&mut self, frame: FdFrame) {
571 self.tx_buf.send(frame).await;
572 (self.waker)();
573 }
574
575 /// Allows a poll_fn to poll until the channel is ready to write
576 pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> {
577 self.tx_buf.poll_ready_to_send(cx)
578 }
579}
529 580
530/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. 581/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
531pub type BufferedFdCanReceiver = embassy_sync::channel::DynamicReceiver<'static, (FdFrame, Timestamp)>; 582pub type BufferedFdCanReceiver = embassy_sync::channel::DynamicReceiver<'static, (FdFrame, Timestamp)>;
@@ -578,7 +629,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
578 629
579 /// Returns a sender that can be used for sending CAN frames. 630 /// Returns a sender that can be used for sending CAN frames.
580 pub fn writer(&self) -> BufferedFdCanSender { 631 pub fn writer(&self) -> BufferedFdCanSender {
581 self.tx_buf.sender().into() 632 BufferedFdCanSender {
633 tx_buf: self.tx_buf.sender().into(),
634 waker: T::IT0Interrupt::pend,
635 }
582 } 636 }
583 637
584 /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. 638 /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs
index 00a441db6..9c293035d 100644
--- a/embassy-stm32/src/can/frame.rs
+++ b/embassy-stm32/src/can/frame.rs
@@ -206,7 +206,7 @@ impl embedded_can::Frame for ClassicFrame {
206 fn is_extended(&self) -> bool { 206 fn is_extended(&self) -> bool {
207 match self.can_header.id { 207 match self.can_header.id {
208 embedded_can::Id::Extended(_) => true, 208 embedded_can::Id::Extended(_) => true,
209 embedded_can::Id::Standard(_) => true, 209 embedded_can::Id::Standard(_) => false,
210 } 210 }
211 } 211 }
212 fn is_remote_frame(&self) -> bool { 212 fn is_remote_frame(&self) -> bool {
@@ -369,7 +369,7 @@ impl embedded_can::Frame for FdFrame {
369 fn is_extended(&self) -> bool { 369 fn is_extended(&self) -> bool {
370 match self.can_header.id { 370 match self.can_header.id {
371 embedded_can::Id::Extended(_) => true, 371 embedded_can::Id::Extended(_) => true,
372 embedded_can::Id::Standard(_) => true, 372 embedded_can::Id::Standard(_) => false,
373 } 373 }
374 } 374 }
375 fn is_remote_frame(&self) -> bool { 375 fn is_remote_frame(&self) -> bool {
diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
new file mode 100644
index 000000000..8f259520a
--- /dev/null
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -0,0 +1,1356 @@
1//! Crypto Accelerator (CRYP)
2#[cfg(any(cryp_v2, cryp_v3))]
3use core::cmp::min;
4use core::marker::PhantomData;
5
6use embassy_hal_internal::{into_ref, PeripheralRef};
7
8use crate::{interrupt, pac, peripherals, Peripheral};
9
10const DES_BLOCK_SIZE: usize = 8; // 64 bits
11const AES_BLOCK_SIZE: usize = 16; // 128 bits
12
13/// This trait encapsulates all cipher-specific behavior/
14pub trait Cipher<'c> {
15 /// Processing block size. Determined by the processor and the algorithm.
16 const BLOCK_SIZE: usize;
17
18 /// Indicates whether the cipher requires the application to provide padding.
19 /// If `true`, no partial blocks will be accepted (a panic will occur).
20 const REQUIRES_PADDING: bool = false;
21
22 /// Returns the symmetric key.
23 fn key(&self) -> &[u8];
24
25 /// Returns the initialization vector.
26 fn iv(&self) -> &[u8];
27
28 /// Sets the processor algorithm mode according to the associated cipher.
29 fn set_algomode(&self, p: &pac::cryp::Cryp);
30
31 /// Performs any key preparation within the processor, if necessary.
32 fn prepare_key(&self, _p: &pac::cryp::Cryp) {}
33
34 /// Performs any cipher-specific initialization.
35 fn init_phase(&self, _p: &pac::cryp::Cryp) {}
36
37 /// Called prior to processing the last data block for cipher-specific operations.
38 fn pre_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] {
39 return [0; 4];
40 }
41
42 /// Called after processing the last data block for cipher-specific operations.
43 fn post_final_block(
44 &self,
45 _p: &pac::cryp::Cryp,
46 _dir: Direction,
47 _int_data: &mut [u8; AES_BLOCK_SIZE],
48 _temp1: [u32; 4],
49 _padding_mask: [u8; 16],
50 ) {
51 }
52
53 /// Called prior to processing the first associated data block for cipher-specific operations.
54 fn get_header_block(&self) -> &[u8] {
55 return [0; 0].as_slice();
56 }
57}
58
59/// This trait enables restriction of ciphers to specific key sizes.
60pub trait CipherSized {}
61
62/// This trait enables restriction of initialization vectors to sizes compatibile with a cipher mode.
63pub trait IVSized {}
64
65/// This trait enables restriction of a header phase to authenticated ciphers only.
66pub trait CipherAuthenticated<const TAG_SIZE: usize> {
67 /// Defines the authentication tag size.
68 const TAG_SIZE: usize = TAG_SIZE;
69}
70
71/// TDES-ECB Cipher Mode
72pub struct TdesEcb<'c, const KEY_SIZE: usize> {
73 iv: &'c [u8; 0],
74 key: &'c [u8; KEY_SIZE],
75}
76
77impl<'c, const KEY_SIZE: usize> TdesEcb<'c, KEY_SIZE> {
78 /// Constructs a new AES-ECB cipher for a cryptographic operation.
79 pub fn new(key: &'c [u8; KEY_SIZE]) -> Self {
80 return Self { key: key, iv: &[0; 0] };
81 }
82}
83
84impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesEcb<'c, KEY_SIZE> {
85 const BLOCK_SIZE: usize = DES_BLOCK_SIZE;
86 const REQUIRES_PADDING: bool = true;
87
88 fn key(&self) -> &'c [u8] {
89 self.key
90 }
91
92 fn iv(&self) -> &'c [u8] {
93 self.iv
94 }
95
96 fn set_algomode(&self, p: &pac::cryp::Cryp) {
97 #[cfg(cryp_v1)]
98 {
99 p.cr().modify(|w| w.set_algomode(0));
100 }
101 #[cfg(any(cryp_v2, cryp_v3))]
102 {
103 p.cr().modify(|w| w.set_algomode0(0));
104 p.cr().modify(|w| w.set_algomode3(false));
105 }
106 }
107}
108
109impl<'c> CipherSized for TdesEcb<'c, { 112 / 8 }> {}
110impl<'c> CipherSized for TdesEcb<'c, { 168 / 8 }> {}
111impl<'c, const KEY_SIZE: usize> IVSized for TdesEcb<'c, KEY_SIZE> {}
112
113/// TDES-CBC Cipher Mode
114pub struct TdesCbc<'c, const KEY_SIZE: usize> {
115 iv: &'c [u8; 8],
116 key: &'c [u8; KEY_SIZE],
117}
118
119impl<'c, const KEY_SIZE: usize> TdesCbc<'c, KEY_SIZE> {
120 /// Constructs a new TDES-CBC cipher for a cryptographic operation.
121 pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 8]) -> Self {
122 return Self { key: key, iv: iv };
123 }
124}
125
126impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesCbc<'c, KEY_SIZE> {
127 const BLOCK_SIZE: usize = DES_BLOCK_SIZE;
128 const REQUIRES_PADDING: bool = true;
129
130 fn key(&self) -> &'c [u8] {
131 self.key
132 }
133
134 fn iv(&self) -> &'c [u8] {
135 self.iv
136 }
137
138 fn set_algomode(&self, p: &pac::cryp::Cryp) {
139 #[cfg(cryp_v1)]
140 {
141 p.cr().modify(|w| w.set_algomode(1));
142 }
143 #[cfg(any(cryp_v2, cryp_v3))]
144 {
145 p.cr().modify(|w| w.set_algomode0(1));
146 p.cr().modify(|w| w.set_algomode3(false));
147 }
148 }
149}
150
151impl<'c> CipherSized for TdesCbc<'c, { 112 / 8 }> {}
152impl<'c> CipherSized for TdesCbc<'c, { 168 / 8 }> {}
153impl<'c, const KEY_SIZE: usize> IVSized for TdesCbc<'c, KEY_SIZE> {}
154
155/// DES-ECB Cipher Mode
156pub struct DesEcb<'c, const KEY_SIZE: usize> {
157 iv: &'c [u8; 0],
158 key: &'c [u8; KEY_SIZE],
159}
160
161impl<'c, const KEY_SIZE: usize> DesEcb<'c, KEY_SIZE> {
162 /// Constructs a new AES-ECB cipher for a cryptographic operation.
163 pub fn new(key: &'c [u8; KEY_SIZE]) -> Self {
164 return Self { key: key, iv: &[0; 0] };
165 }
166}
167
168impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesEcb<'c, KEY_SIZE> {
169 const BLOCK_SIZE: usize = DES_BLOCK_SIZE;
170 const REQUIRES_PADDING: bool = true;
171
172 fn key(&self) -> &'c [u8] {
173 self.key
174 }
175
176 fn iv(&self) -> &'c [u8] {
177 self.iv
178 }
179
180 fn set_algomode(&self, p: &pac::cryp::Cryp) {
181 #[cfg(cryp_v1)]
182 {
183 p.cr().modify(|w| w.set_algomode(2));
184 }
185 #[cfg(any(cryp_v2, cryp_v3))]
186 {
187 p.cr().modify(|w| w.set_algomode0(2));
188 p.cr().modify(|w| w.set_algomode3(false));
189 }
190 }
191}
192
193impl<'c> CipherSized for DesEcb<'c, { 56 / 8 }> {}
194impl<'c, const KEY_SIZE: usize> IVSized for DesEcb<'c, KEY_SIZE> {}
195
196/// DES-CBC Cipher Mode
197pub struct DesCbc<'c, const KEY_SIZE: usize> {
198 iv: &'c [u8; 8],
199 key: &'c [u8; KEY_SIZE],
200}
201
202impl<'c, const KEY_SIZE: usize> DesCbc<'c, KEY_SIZE> {
203 /// Constructs a new AES-CBC cipher for a cryptographic operation.
204 pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 8]) -> Self {
205 return Self { key: key, iv: iv };
206 }
207}
208
209impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesCbc<'c, KEY_SIZE> {
210 const BLOCK_SIZE: usize = DES_BLOCK_SIZE;
211 const REQUIRES_PADDING: bool = true;
212
213 fn key(&self) -> &'c [u8] {
214 self.key
215 }
216
217 fn iv(&self) -> &'c [u8] {
218 self.iv
219 }
220
221 fn set_algomode(&self, p: &pac::cryp::Cryp) {
222 #[cfg(cryp_v1)]
223 {
224 p.cr().modify(|w| w.set_algomode(3));
225 }
226 #[cfg(any(cryp_v2, cryp_v3))]
227 {
228 p.cr().modify(|w| w.set_algomode0(3));
229 p.cr().modify(|w| w.set_algomode3(false));
230 }
231 }
232}
233
234impl<'c> CipherSized for DesCbc<'c, { 56 / 8 }> {}
235impl<'c, const KEY_SIZE: usize> IVSized for DesCbc<'c, KEY_SIZE> {}
236
237/// AES-ECB Cipher Mode
238pub struct AesEcb<'c, const KEY_SIZE: usize> {
239 iv: &'c [u8; 0],
240 key: &'c [u8; KEY_SIZE],
241}
242
243impl<'c, const KEY_SIZE: usize> AesEcb<'c, KEY_SIZE> {
244 /// Constructs a new AES-ECB cipher for a cryptographic operation.
245 pub fn new(key: &'c [u8; KEY_SIZE]) -> Self {
246 return Self { key: key, iv: &[0; 0] };
247 }
248}
249
250impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> {
251 const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
252 const REQUIRES_PADDING: bool = true;
253
254 fn key(&self) -> &'c [u8] {
255 self.key
256 }
257
258 fn iv(&self) -> &'c [u8] {
259 self.iv
260 }
261
262 fn prepare_key(&self, p: &pac::cryp::Cryp) {
263 #[cfg(cryp_v1)]
264 {
265 p.cr().modify(|w| w.set_algomode(7));
266 }
267 #[cfg(any(cryp_v2, cryp_v3))]
268 {
269 p.cr().modify(|w| w.set_algomode0(7));
270 p.cr().modify(|w| w.set_algomode3(false));
271 }
272 p.cr().modify(|w| w.set_crypen(true));
273 while p.sr().read().busy() {}
274 }
275
276 fn set_algomode(&self, p: &pac::cryp::Cryp) {
277 #[cfg(cryp_v1)]
278 {
279 p.cr().modify(|w| w.set_algomode(2));
280 }
281 #[cfg(any(cryp_v2, cryp_v3))]
282 {
283 p.cr().modify(|w| w.set_algomode0(2));
284 p.cr().modify(|w| w.set_algomode3(false));
285 }
286 }
287}
288
289impl<'c> CipherSized for AesEcb<'c, { 128 / 8 }> {}
290impl<'c> CipherSized for AesEcb<'c, { 192 / 8 }> {}
291impl<'c> CipherSized for AesEcb<'c, { 256 / 8 }> {}
292impl<'c, const KEY_SIZE: usize> IVSized for AesEcb<'c, KEY_SIZE> {}
293
294/// AES-CBC Cipher Mode
295pub struct AesCbc<'c, const KEY_SIZE: usize> {
296 iv: &'c [u8; 16],
297 key: &'c [u8; KEY_SIZE],
298}
299
300impl<'c, const KEY_SIZE: usize> AesCbc<'c, KEY_SIZE> {
301 /// Constructs a new AES-CBC cipher for a cryptographic operation.
302 pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 16]) -> Self {
303 return Self { key: key, iv: iv };
304 }
305}
306
307impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> {
308 const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
309 const REQUIRES_PADDING: bool = true;
310
311 fn key(&self) -> &'c [u8] {
312 self.key
313 }
314
315 fn iv(&self) -> &'c [u8] {
316 self.iv
317 }
318
319 fn prepare_key(&self, p: &pac::cryp::Cryp) {
320 #[cfg(cryp_v1)]
321 {
322 p.cr().modify(|w| w.set_algomode(7));
323 }
324 #[cfg(any(cryp_v2, cryp_v3))]
325 {
326 p.cr().modify(|w| w.set_algomode0(7));
327 p.cr().modify(|w| w.set_algomode3(false));
328 }
329 p.cr().modify(|w| w.set_crypen(true));
330 while p.sr().read().busy() {}
331 }
332
333 fn set_algomode(&self, p: &pac::cryp::Cryp) {
334 #[cfg(cryp_v1)]
335 {
336 p.cr().modify(|w| w.set_algomode(5));
337 }
338 #[cfg(any(cryp_v2, cryp_v3))]
339 {
340 p.cr().modify(|w| w.set_algomode0(5));
341 p.cr().modify(|w| w.set_algomode3(false));
342 }
343 }
344}
345
346impl<'c> CipherSized for AesCbc<'c, { 128 / 8 }> {}
347impl<'c> CipherSized for AesCbc<'c, { 192 / 8 }> {}
348impl<'c> CipherSized for AesCbc<'c, { 256 / 8 }> {}
349impl<'c, const KEY_SIZE: usize> IVSized for AesCbc<'c, KEY_SIZE> {}
350
351/// AES-CTR Cipher Mode
352pub struct AesCtr<'c, const KEY_SIZE: usize> {
353 iv: &'c [u8; 16],
354 key: &'c [u8; KEY_SIZE],
355}
356
357impl<'c, const KEY_SIZE: usize> AesCtr<'c, KEY_SIZE> {
358 /// Constructs a new AES-CTR cipher for a cryptographic operation.
359 pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 16]) -> Self {
360 return Self { key: key, iv: iv };
361 }
362}
363
364impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCtr<'c, KEY_SIZE> {
365 const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
366
367 fn key(&self) -> &'c [u8] {
368 self.key
369 }
370
371 fn iv(&self) -> &'c [u8] {
372 self.iv
373 }
374
375 fn set_algomode(&self, p: &pac::cryp::Cryp) {
376 #[cfg(cryp_v1)]
377 {
378 p.cr().modify(|w| w.set_algomode(6));
379 }
380 #[cfg(any(cryp_v2, cryp_v3))]
381 {
382 p.cr().modify(|w| w.set_algomode0(6));
383 p.cr().modify(|w| w.set_algomode3(false));
384 }
385 }
386}
387
388impl<'c> CipherSized for AesCtr<'c, { 128 / 8 }> {}
389impl<'c> CipherSized for AesCtr<'c, { 192 / 8 }> {}
390impl<'c> CipherSized for AesCtr<'c, { 256 / 8 }> {}
391impl<'c, const KEY_SIZE: usize> IVSized for AesCtr<'c, KEY_SIZE> {}
392
393#[cfg(any(cryp_v2, cryp_v3))]
394///AES-GCM Cipher Mode
395pub struct AesGcm<'c, const KEY_SIZE: usize> {
396 iv: [u8; 16],
397 key: &'c [u8; KEY_SIZE],
398}
399
400#[cfg(any(cryp_v2, cryp_v3))]
401impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> {
402 /// Constucts a new AES-GCM cipher for a cryptographic operation.
403 pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self {
404 let mut new_gcm = Self { key: key, iv: [0; 16] };
405 new_gcm.iv[..12].copy_from_slice(iv);
406 new_gcm.iv[15] = 2;
407 new_gcm
408 }
409}
410
411#[cfg(any(cryp_v2, cryp_v3))]
412impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
413 const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
414
415 fn key(&self) -> &'c [u8] {
416 self.key
417 }
418
419 fn iv(&self) -> &[u8] {
420 self.iv.as_slice()
421 }
422
423 fn set_algomode(&self, p: &pac::cryp::Cryp) {
424 p.cr().modify(|w| w.set_algomode0(0));
425 p.cr().modify(|w| w.set_algomode3(true));
426 }
427
428 fn init_phase(&self, p: &pac::cryp::Cryp) {
429 p.cr().modify(|w| w.set_gcm_ccmph(0));
430 p.cr().modify(|w| w.set_crypen(true));
431 while p.cr().read().crypen() {}
432 }
433
434 #[cfg(cryp_v2)]
435 fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
436 //Handle special GCM partial block process.
437 if dir == Direction::Encrypt {
438 p.cr().modify(|w| w.set_crypen(false));
439 p.cr().modify(|w| w.set_algomode3(false));
440 p.cr().modify(|w| w.set_algomode0(6));
441 let iv1r = p.csgcmccmr(7).read() - 1;
442 p.init(1).ivrr().write_value(iv1r);
443 p.cr().modify(|w| w.set_crypen(true));
444 }
445 [0; 4]
446 }
447
448 #[cfg(cryp_v3)]
449 fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
450 //Handle special GCM partial block process.
451 p.cr().modify(|w| w.set_npblb(padding_len as u8));
452 [0; 4]
453 }
454
455 #[cfg(cryp_v2)]
456 fn post_final_block(
457 &self,
458 p: &pac::cryp::Cryp,
459 dir: Direction,
460 int_data: &mut [u8; AES_BLOCK_SIZE],
461 _temp1: [u32; 4],
462 padding_mask: [u8; AES_BLOCK_SIZE],
463 ) {
464 if dir == Direction::Encrypt {
465 //Handle special GCM partial block process.
466 p.cr().modify(|w| w.set_crypen(false));
467 p.cr().modify(|w| w.set_algomode3(true));
468 p.cr().modify(|w| w.set_algomode0(0));
469 for i in 0..AES_BLOCK_SIZE {
470 int_data[i] = int_data[i] & padding_mask[i];
471 }
472 p.cr().modify(|w| w.set_crypen(true));
473 p.cr().modify(|w| w.set_gcm_ccmph(3));
474 let mut index = 0;
475 let end_index = Self::BLOCK_SIZE;
476 while index < end_index {
477 let mut in_word: [u8; 4] = [0; 4];
478 in_word.copy_from_slice(&int_data[index..index + 4]);
479 p.din().write_value(u32::from_ne_bytes(in_word));
480 index += 4;
481 }
482 for _ in 0..4 {
483 p.dout().read();
484 }
485 }
486 }
487}
488
489#[cfg(any(cryp_v2, cryp_v3))]
490impl<'c> CipherSized for AesGcm<'c, { 128 / 8 }> {}
491#[cfg(any(cryp_v2, cryp_v3))]
492impl<'c> CipherSized for AesGcm<'c, { 192 / 8 }> {}
493#[cfg(any(cryp_v2, cryp_v3))]
494impl<'c> CipherSized for AesGcm<'c, { 256 / 8 }> {}
495#[cfg(any(cryp_v2, cryp_v3))]
496impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGcm<'c, KEY_SIZE> {}
497#[cfg(any(cryp_v2, cryp_v3))]
498impl<'c, const KEY_SIZE: usize> IVSized for AesGcm<'c, KEY_SIZE> {}
499
500#[cfg(any(cryp_v2, cryp_v3))]
501/// AES-GMAC Cipher Mode
502pub struct AesGmac<'c, const KEY_SIZE: usize> {
503 iv: [u8; 16],
504 key: &'c [u8; KEY_SIZE],
505}
506
507#[cfg(any(cryp_v2, cryp_v3))]
508impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> {
509 /// Constructs a new AES-GMAC cipher for a cryptographic operation.
510 pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self {
511 let mut new_gmac = Self { key: key, iv: [0; 16] };
512 new_gmac.iv[..12].copy_from_slice(iv);
513 new_gmac.iv[15] = 2;
514 new_gmac
515 }
516}
517
518#[cfg(any(cryp_v2, cryp_v3))]
519impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
520 const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
521
522 fn key(&self) -> &'c [u8] {
523 self.key
524 }
525
526 fn iv(&self) -> &[u8] {
527 self.iv.as_slice()
528 }
529
530 fn set_algomode(&self, p: &pac::cryp::Cryp) {
531 p.cr().modify(|w| w.set_algomode0(0));
532 p.cr().modify(|w| w.set_algomode3(true));
533 }
534
535 fn init_phase(&self, p: &pac::cryp::Cryp) {
536 p.cr().modify(|w| w.set_gcm_ccmph(0));
537 p.cr().modify(|w| w.set_crypen(true));
538 while p.cr().read().crypen() {}
539 }
540
541 #[cfg(cryp_v2)]
542 fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
543 //Handle special GCM partial block process.
544 if dir == Direction::Encrypt {
545 p.cr().modify(|w| w.set_crypen(false));
546 p.cr().modify(|w| w.set_algomode3(false));
547 p.cr().modify(|w| w.set_algomode0(6));
548 let iv1r = p.csgcmccmr(7).read() - 1;
549 p.init(1).ivrr().write_value(iv1r);
550 p.cr().modify(|w| w.set_crypen(true));
551 }
552 [0; 4]
553 }
554
555 #[cfg(cryp_v3)]
556 fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
557 //Handle special GCM partial block process.
558 p.cr().modify(|w| w.set_npblb(padding_len as u8));
559 [0; 4]
560 }
561
562 #[cfg(cryp_v2)]
563 fn post_final_block(
564 &self,
565 p: &pac::cryp::Cryp,
566 dir: Direction,
567 int_data: &mut [u8; AES_BLOCK_SIZE],
568 _temp1: [u32; 4],
569 padding_mask: [u8; AES_BLOCK_SIZE],
570 ) {
571 if dir == Direction::Encrypt {
572 //Handle special GCM partial block process.
573 p.cr().modify(|w| w.set_crypen(false));
574 p.cr().modify(|w| w.set_algomode3(true));
575 p.cr().modify(|w| w.set_algomode0(0));
576 for i in 0..AES_BLOCK_SIZE {
577 int_data[i] = int_data[i] & padding_mask[i];
578 }
579 p.cr().modify(|w| w.set_crypen(true));
580 p.cr().modify(|w| w.set_gcm_ccmph(3));
581 let mut index = 0;
582 let end_index = Self::BLOCK_SIZE;
583 while index < end_index {
584 let mut in_word: [u8; 4] = [0; 4];
585 in_word.copy_from_slice(&int_data[index..index + 4]);
586 p.din().write_value(u32::from_ne_bytes(in_word));
587 index += 4;
588 }
589 for _ in 0..4 {
590 p.dout().read();
591 }
592 }
593 }
594}
595
596#[cfg(any(cryp_v2, cryp_v3))]
597impl<'c> CipherSized for AesGmac<'c, { 128 / 8 }> {}
598#[cfg(any(cryp_v2, cryp_v3))]
599impl<'c> CipherSized for AesGmac<'c, { 192 / 8 }> {}
600#[cfg(any(cryp_v2, cryp_v3))]
601impl<'c> CipherSized for AesGmac<'c, { 256 / 8 }> {}
602#[cfg(any(cryp_v2, cryp_v3))]
603impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGmac<'c, KEY_SIZE> {}
604#[cfg(any(cryp_v2, cryp_v3))]
605impl<'c, const KEY_SIZE: usize> IVSized for AesGmac<'c, KEY_SIZE> {}
606
607#[cfg(any(cryp_v2, cryp_v3))]
608/// AES-CCM Cipher Mode
609pub struct AesCcm<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> {
610 key: &'c [u8; KEY_SIZE],
611 aad_header: [u8; 6],
612 aad_header_len: usize,
613 block0: [u8; 16],
614 ctr: [u8; 16],
615}
616
617#[cfg(any(cryp_v2, cryp_v3))]
618impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE> {
619 /// Constructs a new AES-CCM cipher for a cryptographic operation.
620 pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; IV_SIZE], aad_len: usize, payload_len: usize) -> Self {
621 let mut aad_header: [u8; 6] = [0; 6];
622 let mut aad_header_len = 0;
623 let mut block0: [u8; 16] = [0; 16];
624 if aad_len != 0 {
625 if aad_len < 65280 {
626 aad_header[0] = (aad_len >> 8) as u8 & 0xFF;
627 aad_header[1] = aad_len as u8 & 0xFF;
628 aad_header_len = 2;
629 } else {
630 aad_header[0] = 0xFF;
631 aad_header[1] = 0xFE;
632 let aad_len_bytes: [u8; 4] = aad_len.to_be_bytes();
633 aad_header[2] = aad_len_bytes[0];
634 aad_header[3] = aad_len_bytes[1];
635 aad_header[4] = aad_len_bytes[2];
636 aad_header[5] = aad_len_bytes[3];
637 aad_header_len = 6;
638 }
639 }
640 let total_aad_len = aad_header_len + aad_len;
641 let mut aad_padding_len = 16 - (total_aad_len % 16);
642 if aad_padding_len == 16 {
643 aad_padding_len = 0;
644 }
645 aad_header_len += aad_padding_len;
646 let total_aad_len_padded = aad_header_len + aad_len;
647 if total_aad_len_padded > 0 {
648 block0[0] = 0x40;
649 }
650 block0[0] |= ((((TAG_SIZE as u8) - 2) >> 1) & 0x07) << 3;
651 block0[0] |= ((15 - (iv.len() as u8)) - 1) & 0x07;
652 block0[1..1 + iv.len()].copy_from_slice(iv);
653 let payload_len_bytes: [u8; 4] = payload_len.to_be_bytes();
654 if iv.len() <= 11 {
655 block0[12] = payload_len_bytes[0];
656 } else if payload_len_bytes[0] > 0 {
657 panic!("Message is too large for given IV size.");
658 }
659 if iv.len() <= 12 {
660 block0[13] = payload_len_bytes[1];
661 } else if payload_len_bytes[1] > 0 {
662 panic!("Message is too large for given IV size.");
663 }
664 block0[14] = payload_len_bytes[2];
665 block0[15] = payload_len_bytes[3];
666 let mut ctr: [u8; 16] = [0; 16];
667 ctr[0] = block0[0] & 0x07;
668 ctr[1..1 + iv.len()].copy_from_slice(&block0[1..1 + iv.len()]);
669 ctr[15] = 0x01;
670
671 return Self {
672 key: key,
673 aad_header: aad_header,
674 aad_header_len: aad_header_len,
675 block0: block0,
676 ctr: ctr,
677 };
678 }
679}
680
681#[cfg(any(cryp_v2, cryp_v3))]
682impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cipher<'c>
683 for AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE>
684{
685 const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
686
687 fn key(&self) -> &'c [u8] {
688 self.key
689 }
690
691 fn iv(&self) -> &[u8] {
692 self.ctr.as_slice()
693 }
694
695 fn set_algomode(&self, p: &pac::cryp::Cryp) {
696 p.cr().modify(|w| w.set_algomode0(1));
697 p.cr().modify(|w| w.set_algomode3(true));
698 }
699
700 fn init_phase(&self, p: &pac::cryp::Cryp) {
701 p.cr().modify(|w| w.set_gcm_ccmph(0));
702
703 let mut index = 0;
704 let end_index = index + Self::BLOCK_SIZE;
705 // Write block in
706 while index < end_index {
707 let mut in_word: [u8; 4] = [0; 4];
708 in_word.copy_from_slice(&self.block0[index..index + 4]);
709 p.din().write_value(u32::from_ne_bytes(in_word));
710 index += 4;
711 }
712 p.cr().modify(|w| w.set_crypen(true));
713 while p.cr().read().crypen() {}
714 }
715
716 fn get_header_block(&self) -> &[u8] {
717 return &self.aad_header[0..self.aad_header_len];
718 }
719
720 #[cfg(cryp_v2)]
721 fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
722 //Handle special CCM partial block process.
723 let mut temp1 = [0; 4];
724 if dir == Direction::Decrypt {
725 p.cr().modify(|w| w.set_crypen(false));
726 let iv1temp = p.init(1).ivrr().read();
727 temp1[0] = p.csgcmccmr(0).read().swap_bytes();
728 temp1[1] = p.csgcmccmr(1).read().swap_bytes();
729 temp1[2] = p.csgcmccmr(2).read().swap_bytes();
730 temp1[3] = p.csgcmccmr(3).read().swap_bytes();
731 p.init(1).ivrr().write_value(iv1temp);
732 p.cr().modify(|w| w.set_algomode3(false));
733 p.cr().modify(|w| w.set_algomode0(6));
734 p.cr().modify(|w| w.set_crypen(true));
735 }
736 return temp1;
737 }
738
739 #[cfg(cryp_v3)]
740 fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
741 //Handle special GCM partial block process.
742 p.cr().modify(|w| w.set_npblb(padding_len as u8));
743 [0; 4]
744 }
745
746 #[cfg(cryp_v2)]
747 fn post_final_block(
748 &self,
749 p: &pac::cryp::Cryp,
750 dir: Direction,
751 int_data: &mut [u8; AES_BLOCK_SIZE],
752 temp1: [u32; 4],
753 padding_mask: [u8; 16],
754 ) {
755 if dir == Direction::Decrypt {
756 //Handle special CCM partial block process.
757 let mut temp2 = [0; 4];
758 temp2[0] = p.csgcmccmr(0).read().swap_bytes();
759 temp2[1] = p.csgcmccmr(1).read().swap_bytes();
760 temp2[2] = p.csgcmccmr(2).read().swap_bytes();
761 temp2[3] = p.csgcmccmr(3).read().swap_bytes();
762 p.cr().modify(|w| w.set_algomode3(true));
763 p.cr().modify(|w| w.set_algomode0(1));
764 p.cr().modify(|w| w.set_gcm_ccmph(3));
765 // Header phase
766 p.cr().modify(|w| w.set_gcm_ccmph(1));
767 for i in 0..AES_BLOCK_SIZE {
768 int_data[i] = int_data[i] & padding_mask[i];
769 }
770 let mut in_data: [u32; 4] = [0; 4];
771 for i in 0..in_data.len() {
772 let mut int_bytes: [u8; 4] = [0; 4];
773 int_bytes.copy_from_slice(&int_data[(i * 4)..(i * 4) + 4]);
774 let int_word = u32::from_le_bytes(int_bytes);
775 in_data[i] = int_word;
776 in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i];
777 p.din().write_value(in_data[i]);
778 }
779 }
780 }
781}
782
783#[cfg(any(cryp_v2, cryp_v3))]
784impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 128 / 8 }, TAG_SIZE, IV_SIZE> {}
785#[cfg(any(cryp_v2, cryp_v3))]
786impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 192 / 8 }, TAG_SIZE, IV_SIZE> {}
787#[cfg(any(cryp_v2, cryp_v3))]
788impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 256 / 8 }, TAG_SIZE, IV_SIZE> {}
789#[cfg(any(cryp_v2, cryp_v3))]
790impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<4> for AesCcm<'c, KEY_SIZE, 4, IV_SIZE> {}
791#[cfg(any(cryp_v2, cryp_v3))]
792impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<6> for AesCcm<'c, KEY_SIZE, 6, IV_SIZE> {}
793#[cfg(any(cryp_v2, cryp_v3))]
794impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<8> for AesCcm<'c, KEY_SIZE, 8, IV_SIZE> {}
795#[cfg(any(cryp_v2, cryp_v3))]
796impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<10> for AesCcm<'c, KEY_SIZE, 10, IV_SIZE> {}
797#[cfg(any(cryp_v2, cryp_v3))]
798impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<12> for AesCcm<'c, KEY_SIZE, 12, IV_SIZE> {}
799#[cfg(any(cryp_v2, cryp_v3))]
800impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<14> for AesCcm<'c, KEY_SIZE, 14, IV_SIZE> {}
801#[cfg(any(cryp_v2, cryp_v3))]
802impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<16> for AesCcm<'c, KEY_SIZE, 16, IV_SIZE> {}
803#[cfg(any(cryp_v2, cryp_v3))]
804impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 7> {}
805#[cfg(any(cryp_v2, cryp_v3))]
806impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 8> {}
807#[cfg(any(cryp_v2, cryp_v3))]
808impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 9> {}
809#[cfg(any(cryp_v2, cryp_v3))]
810impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 10> {}
811#[cfg(any(cryp_v2, cryp_v3))]
812impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 11> {}
813#[cfg(any(cryp_v2, cryp_v3))]
814impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 12> {}
815#[cfg(any(cryp_v2, cryp_v3))]
816impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 13> {}
817
818#[allow(dead_code)]
819/// Holds the state information for a cipher operation.
820/// Allows suspending/resuming of cipher operations.
821pub struct Context<'c, C: Cipher<'c> + CipherSized> {
822 phantom_data: PhantomData<&'c C>,
823 cipher: &'c C,
824 dir: Direction,
825 last_block_processed: bool,
826 header_processed: bool,
827 aad_complete: bool,
828 cr: u32,
829 iv: [u32; 4],
830 csgcmccm: [u32; 8],
831 csgcm: [u32; 8],
832 header_len: u64,
833 payload_len: u64,
834 aad_buffer: [u8; 16],
835 aad_buffer_len: usize,
836}
837
838/// Selects whether the crypto processor operates in encryption or decryption mode.
839#[derive(PartialEq, Clone, Copy)]
840pub enum Direction {
841 /// Encryption mode
842 Encrypt,
843 /// Decryption mode
844 Decrypt,
845}
846
847/// Crypto Accelerator Driver
848pub struct Cryp<'d, T: Instance> {
849 _peripheral: PeripheralRef<'d, T>,
850}
851
852impl<'d, T: Instance> Cryp<'d, T> {
853 /// Create a new CRYP driver.
854 pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self {
855 T::enable_and_reset();
856 into_ref!(peri);
857 let instance = Self { _peripheral: peri };
858 instance
859 }
860
861 /// Start a new cipher operation.
862 /// Key size must be 128, 192, or 256 bits.
863 /// Initialization vector must only be supplied if necessary.
864 /// Panics if there is any mismatch in parameters, such as an incorrect IV length or invalid mode.
865 pub fn start<'c, C: Cipher<'c> + CipherSized + IVSized>(&self, cipher: &'c C, dir: Direction) -> Context<'c, C> {
866 let mut ctx: Context<'c, C> = Context {
867 dir,
868 last_block_processed: false,
869 cr: 0,
870 iv: [0; 4],
871 csgcmccm: [0; 8],
872 csgcm: [0; 8],
873 aad_complete: false,
874 header_len: 0,
875 payload_len: 0,
876 cipher: cipher,
877 phantom_data: PhantomData,
878 header_processed: false,
879 aad_buffer: [0; 16],
880 aad_buffer_len: 0,
881 };
882
883 T::regs().cr().modify(|w| w.set_crypen(false));
884
885 let key = ctx.cipher.key();
886
887 if key.len() == (128 / 8) {
888 T::regs().cr().modify(|w| w.set_keysize(0));
889 } else if key.len() == (192 / 8) {
890 T::regs().cr().modify(|w| w.set_keysize(1));
891 } else if key.len() == (256 / 8) {
892 T::regs().cr().modify(|w| w.set_keysize(2));
893 }
894
895 self.load_key(key);
896
897 // Set data type to 8-bit. This will match software implementations.
898 T::regs().cr().modify(|w| w.set_datatype(2));
899
900 ctx.cipher.prepare_key(&T::regs());
901
902 ctx.cipher.set_algomode(&T::regs());
903
904 // Set encrypt/decrypt
905 if dir == Direction::Encrypt {
906 T::regs().cr().modify(|w| w.set_algodir(false));
907 } else {
908 T::regs().cr().modify(|w| w.set_algodir(true));
909 }
910
911 // Load the IV into the registers.
912 let iv = ctx.cipher.iv();
913 let mut full_iv: [u8; 16] = [0; 16];
914 full_iv[0..iv.len()].copy_from_slice(iv);
915 let mut iv_idx = 0;
916 let mut iv_word: [u8; 4] = [0; 4];
917 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
918 iv_idx += 4;
919 T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word));
920 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
921 iv_idx += 4;
922 T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word));
923 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
924 iv_idx += 4;
925 T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word));
926 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
927 T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word));
928
929 // Flush in/out FIFOs
930 T::regs().cr().modify(|w| w.fflush());
931
932 ctx.cipher.init_phase(&T::regs());
933
934 self.store_context(&mut ctx);
935
936 ctx
937 }
938
939 #[cfg(any(cryp_v2, cryp_v3))]
940 /// Controls the header phase of cipher processing.
941 /// This function is only valid for GCM, CCM, and GMAC modes.
942 /// It only needs to be called if using one of these modes and there is associated data.
943 /// All AAD must be supplied to this function prior to starting the payload phase with `payload_blocking`.
944 /// The AAD must be supplied in multiples of the block size (128 bits), except when supplying the last block.
945 /// When supplying the last block of AAD, `last_aad_block` must be `true`.
946 pub fn aad_blocking<
947 'c,
948 const TAG_SIZE: usize,
949 C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated<TAG_SIZE>,
950 >(
951 &self,
952 ctx: &mut Context<'c, C>,
953 aad: &[u8],
954 last_aad_block: bool,
955 ) {
956 self.load_context(ctx);
957
958 // Perform checks for correctness.
959 if ctx.aad_complete {
960 panic!("Cannot update AAD after starting payload!")
961 }
962
963 ctx.header_len += aad.len() as u64;
964
965 // Header phase
966 T::regs().cr().modify(|w| w.set_crypen(false));
967 T::regs().cr().modify(|w| w.set_gcm_ccmph(1));
968 T::regs().cr().modify(|w| w.set_crypen(true));
969
970 // First write the header B1 block if not yet written.
971 if !ctx.header_processed {
972 ctx.header_processed = true;
973 let header = ctx.cipher.get_header_block();
974 ctx.aad_buffer[0..header.len()].copy_from_slice(header);
975 ctx.aad_buffer_len += header.len();
976 }
977
978 // Fill the header block to make a full block.
979 let len_to_copy = min(aad.len(), C::BLOCK_SIZE - ctx.aad_buffer_len);
980 ctx.aad_buffer[ctx.aad_buffer_len..ctx.aad_buffer_len + len_to_copy].copy_from_slice(&aad[..len_to_copy]);
981 ctx.aad_buffer_len += len_to_copy;
982 ctx.aad_buffer[ctx.aad_buffer_len..].fill(0);
983 let mut aad_len_remaining = aad.len() - len_to_copy;
984
985 if ctx.aad_buffer_len < C::BLOCK_SIZE {
986 // The buffer isn't full and this is the last buffer, so process it as is (already padded).
987 if last_aad_block {
988 let mut index = 0;
989 let end_index = C::BLOCK_SIZE;
990 // Write block in
991 while index < end_index {
992 let mut in_word: [u8; 4] = [0; 4];
993 in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]);
994 T::regs().din().write_value(u32::from_ne_bytes(in_word));
995 index += 4;
996 }
997 // Block until input FIFO is empty.
998 while !T::regs().sr().read().ifem() {}
999
1000 // Switch to payload phase.
1001 ctx.aad_complete = true;
1002 T::regs().cr().modify(|w| w.set_crypen(false));
1003 T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
1004 T::regs().cr().modify(|w| w.fflush());
1005 } else {
1006 // Just return because we don't yet have a full block to process.
1007 return;
1008 }
1009 } else {
1010 // Load the full block from the buffer.
1011 let mut index = 0;
1012 let end_index = C::BLOCK_SIZE;
1013 // Write block in
1014 while index < end_index {
1015 let mut in_word: [u8; 4] = [0; 4];
1016 in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]);
1017 T::regs().din().write_value(u32::from_ne_bytes(in_word));
1018 index += 4;
1019 }
1020 // Block until input FIFO is empty.
1021 while !T::regs().sr().read().ifem() {}
1022 }
1023
1024 // Handle a partial block that is passed in.
1025 ctx.aad_buffer_len = 0;
1026 let leftovers = aad_len_remaining % C::BLOCK_SIZE;
1027 ctx.aad_buffer[..leftovers].copy_from_slice(&aad[aad.len() - leftovers..aad.len()]);
1028 ctx.aad_buffer_len += leftovers;
1029 ctx.aad_buffer[ctx.aad_buffer_len..].fill(0);
1030 aad_len_remaining -= leftovers;
1031 assert_eq!(aad_len_remaining % C::BLOCK_SIZE, 0);
1032
1033 // Load full data blocks into core.
1034 let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE;
1035 for block in 0..num_full_blocks {
1036 let mut index = len_to_copy + (block * C::BLOCK_SIZE);
1037 let end_index = index + C::BLOCK_SIZE;
1038 // Write block in
1039 while index < end_index {
1040 let mut in_word: [u8; 4] = [0; 4];
1041 in_word.copy_from_slice(&aad[index..index + 4]);
1042 T::regs().din().write_value(u32::from_ne_bytes(in_word));
1043 index += 4;
1044 }
1045 // Block until input FIFO is empty.
1046 while !T::regs().sr().read().ifem() {}
1047 }
1048
1049 if last_aad_block {
1050 if leftovers > 0 {
1051 let mut index = 0;
1052 let end_index = C::BLOCK_SIZE;
1053 // Write block in
1054 while index < end_index {
1055 let mut in_word: [u8; 4] = [0; 4];
1056 in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]);
1057 T::regs().din().write_value(u32::from_ne_bytes(in_word));
1058 index += 4;
1059 }
1060 // Block until input FIFO is empty.
1061 while !T::regs().sr().read().ifem() {}
1062 }
1063 // Switch to payload phase.
1064 ctx.aad_complete = true;
1065 T::regs().cr().modify(|w| w.set_crypen(false));
1066 T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
1067 T::regs().cr().modify(|w| w.fflush());
1068 }
1069
1070 self.store_context(ctx);
1071 }
1072
1073 /// Performs encryption/decryption on the provided context.
1074 /// The context determines algorithm, mode, and state of the crypto accelerator.
1075 /// When the last piece of data is supplied, `last_block` should be `true`.
1076 /// This function panics under various mismatches of parameters.
1077 /// Input and output buffer lengths must match.
1078 /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes.
1079 /// Padding or ciphertext stealing must be managed by the application for these modes.
1080 /// Data must also be a multiple of block size unless `last_block` is `true`.
1081 pub fn payload_blocking<'c, C: Cipher<'c> + CipherSized + IVSized>(
1082 &self,
1083 ctx: &mut Context<'c, C>,
1084 input: &[u8],
1085 output: &mut [u8],
1086 last_block: bool,
1087 ) {
1088 self.load_context(ctx);
1089
1090 let last_block_remainder = input.len() % C::BLOCK_SIZE;
1091
1092 // Perform checks for correctness.
1093 if !ctx.aad_complete && ctx.header_len > 0 {
1094 panic!("Additional associated data must be processed first!");
1095 } else if !ctx.aad_complete {
1096 #[cfg(any(cryp_v2, cryp_v3))]
1097 {
1098 ctx.aad_complete = true;
1099 T::regs().cr().modify(|w| w.set_crypen(false));
1100 T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
1101 T::regs().cr().modify(|w| w.fflush());
1102 T::regs().cr().modify(|w| w.set_crypen(true));
1103 }
1104 }
1105 if ctx.last_block_processed {
1106 panic!("The last block has already been processed!");
1107 }
1108 if input.len() > output.len() {
1109 panic!("Output buffer length must match input length.");
1110 }
1111 if !last_block {
1112 if last_block_remainder != 0 {
1113 panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE);
1114 }
1115 }
1116 if C::REQUIRES_PADDING {
1117 if last_block_remainder != 0 {
1118 panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE);
1119 }
1120 }
1121 if last_block {
1122 ctx.last_block_processed = true;
1123 }
1124
1125 // Load data into core, block by block.
1126 let num_full_blocks = input.len() / C::BLOCK_SIZE;
1127 for block in 0..num_full_blocks {
1128 let mut index = block * C::BLOCK_SIZE;
1129 let end_index = index + C::BLOCK_SIZE;
1130 // Write block in
1131 while index < end_index {
1132 let mut in_word: [u8; 4] = [0; 4];
1133 in_word.copy_from_slice(&input[index..index + 4]);
1134 T::regs().din().write_value(u32::from_ne_bytes(in_word));
1135 index += 4;
1136 }
1137 let mut index = block * C::BLOCK_SIZE;
1138 let end_index = index + C::BLOCK_SIZE;
1139 // Block until there is output to read.
1140 while !T::regs().sr().read().ofne() {}
1141 // Read block out
1142 while index < end_index {
1143 let out_word: u32 = T::regs().dout().read();
1144 output[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice());
1145 index += 4;
1146 }
1147 }
1148
1149 // Handle the final block, which is incomplete.
1150 if last_block_remainder > 0 {
1151 let padding_len = C::BLOCK_SIZE - last_block_remainder;
1152 let temp1 = ctx.cipher.pre_final_block(&T::regs(), ctx.dir, padding_len);
1153
1154 let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
1155 let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
1156 last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]);
1157 let mut index = 0;
1158 let end_index = C::BLOCK_SIZE;
1159 // Write block in
1160 while index < end_index {
1161 let mut in_word: [u8; 4] = [0; 4];
1162 in_word.copy_from_slice(&last_block[index..index + 4]);
1163 T::regs().din().write_value(u32::from_ne_bytes(in_word));
1164 index += 4;
1165 }
1166 let mut index = 0;
1167 let end_index = C::BLOCK_SIZE;
1168 // Block until there is output to read.
1169 while !T::regs().sr().read().ofne() {}
1170 // Read block out
1171 while index < end_index {
1172 let out_word: u32 = T::regs().dout().read();
1173 intermediate_data[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice());
1174 index += 4;
1175 }
1176
1177 // Handle the last block depending on mode.
1178 let output_len = output.len();
1179 output[output_len - last_block_remainder..output_len]
1180 .copy_from_slice(&intermediate_data[0..last_block_remainder]);
1181
1182 let mut mask: [u8; 16] = [0; 16];
1183 mask[..last_block_remainder].fill(0xFF);
1184 ctx.cipher
1185 .post_final_block(&T::regs(), ctx.dir, &mut intermediate_data, temp1, mask);
1186 }
1187
1188 ctx.payload_len += input.len() as u64;
1189
1190 self.store_context(ctx);
1191 }
1192
1193 #[cfg(any(cryp_v2, cryp_v3))]
1194 /// This function only needs to be called for GCM, CCM, and GMAC modes to
1195 /// generate an authentication tag.
1196 pub fn finish_blocking<
1197 'c,
1198 const TAG_SIZE: usize,
1199 C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated<TAG_SIZE>,
1200 >(
1201 &self,
1202 mut ctx: Context<'c, C>,
1203 ) -> [u8; TAG_SIZE] {
1204 self.load_context(&mut ctx);
1205
1206 T::regs().cr().modify(|w| w.set_crypen(false));
1207 T::regs().cr().modify(|w| w.set_gcm_ccmph(3));
1208 T::regs().cr().modify(|w| w.set_crypen(true));
1209
1210 let headerlen1: u32 = ((ctx.header_len * 8) >> 32) as u32;
1211 let headerlen2: u32 = (ctx.header_len * 8) as u32;
1212 let payloadlen1: u32 = ((ctx.payload_len * 8) >> 32) as u32;
1213 let payloadlen2: u32 = (ctx.payload_len * 8) as u32;
1214
1215 #[cfg(cryp_v2)]
1216 {
1217 T::regs().din().write_value(headerlen1.swap_bytes());
1218 T::regs().din().write_value(headerlen2.swap_bytes());
1219 T::regs().din().write_value(payloadlen1.swap_bytes());
1220 T::regs().din().write_value(payloadlen2.swap_bytes());
1221 }
1222
1223 #[cfg(cryp_v3)]
1224 {
1225 T::regs().din().write_value(headerlen1);
1226 T::regs().din().write_value(headerlen2);
1227 T::regs().din().write_value(payloadlen1);
1228 T::regs().din().write_value(payloadlen2);
1229 }
1230
1231 while !T::regs().sr().read().ofne() {}
1232
1233 let mut full_tag: [u8; 16] = [0; 16];
1234 full_tag[0..4].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
1235 full_tag[4..8].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
1236 full_tag[8..12].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
1237 full_tag[12..16].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
1238 let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE];
1239 tag.copy_from_slice(&full_tag[0..TAG_SIZE]);
1240
1241 T::regs().cr().modify(|w| w.set_crypen(false));
1242
1243 tag
1244 }
1245
1246 fn load_key(&self, key: &[u8]) {
1247 // Load the key into the registers.
1248 let mut keyidx = 0;
1249 let mut keyword: [u8; 4] = [0; 4];
1250 let keylen = key.len() * 8;
1251 if keylen > 192 {
1252 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
1253 keyidx += 4;
1254 T::regs().key(0).klr().write_value(u32::from_be_bytes(keyword));
1255 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
1256 keyidx += 4;
1257 T::regs().key(0).krr().write_value(u32::from_be_bytes(keyword));
1258 }
1259 if keylen > 128 {
1260 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
1261 keyidx += 4;
1262 T::regs().key(1).klr().write_value(u32::from_be_bytes(keyword));
1263 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
1264 keyidx += 4;
1265 T::regs().key(1).krr().write_value(u32::from_be_bytes(keyword));
1266 }
1267 if keylen > 64 {
1268 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
1269 keyidx += 4;
1270 T::regs().key(2).klr().write_value(u32::from_be_bytes(keyword));
1271 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
1272 keyidx += 4;
1273 T::regs().key(2).krr().write_value(u32::from_be_bytes(keyword));
1274 }
1275 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
1276 keyidx += 4;
1277 T::regs().key(3).klr().write_value(u32::from_be_bytes(keyword));
1278 keyword = [0; 4];
1279 keyword[0..key.len() - keyidx].copy_from_slice(&key[keyidx..key.len()]);
1280 T::regs().key(3).krr().write_value(u32::from_be_bytes(keyword));
1281 }
1282
1283 fn store_context<'c, C: Cipher<'c> + CipherSized>(&self, ctx: &mut Context<'c, C>) {
1284 // Wait for data block processing to finish.
1285 while !T::regs().sr().read().ifem() {}
1286 while T::regs().sr().read().ofne() {}
1287 while T::regs().sr().read().busy() {}
1288
1289 // Disable crypto processor.
1290 T::regs().cr().modify(|w| w.set_crypen(false));
1291
1292 // Save the peripheral state.
1293 ctx.cr = T::regs().cr().read().0;
1294 ctx.iv[0] = T::regs().init(0).ivlr().read();
1295 ctx.iv[1] = T::regs().init(0).ivrr().read();
1296 ctx.iv[2] = T::regs().init(1).ivlr().read();
1297 ctx.iv[3] = T::regs().init(1).ivrr().read();
1298
1299 #[cfg(any(cryp_v2, cryp_v3))]
1300 for i in 0..8 {
1301 ctx.csgcmccm[i] = T::regs().csgcmccmr(i).read();
1302 ctx.csgcm[i] = T::regs().csgcmr(i).read();
1303 }
1304 }
1305
1306 fn load_context<'c, C: Cipher<'c> + CipherSized>(&self, ctx: &Context<'c, C>) {
1307 // Reload state registers.
1308 T::regs().cr().write(|w| w.0 = ctx.cr);
1309 T::regs().init(0).ivlr().write_value(ctx.iv[0]);
1310 T::regs().init(0).ivrr().write_value(ctx.iv[1]);
1311 T::regs().init(1).ivlr().write_value(ctx.iv[2]);
1312 T::regs().init(1).ivrr().write_value(ctx.iv[3]);
1313
1314 #[cfg(any(cryp_v2, cryp_v3))]
1315 for i in 0..8 {
1316 T::regs().csgcmccmr(i).write_value(ctx.csgcmccm[i]);
1317 T::regs().csgcmr(i).write_value(ctx.csgcm[i]);
1318 }
1319 self.load_key(ctx.cipher.key());
1320
1321 // Prepare key if applicable.
1322 ctx.cipher.prepare_key(&T::regs());
1323 T::regs().cr().write(|w| w.0 = ctx.cr);
1324
1325 // Enable crypto processor.
1326 T::regs().cr().modify(|w| w.set_crypen(true));
1327 }
1328}
1329
1330pub(crate) mod sealed {
1331 use super::*;
1332
1333 pub trait Instance {
1334 fn regs() -> pac::cryp::Cryp;
1335 }
1336}
1337
1338/// CRYP instance trait.
1339pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send {
1340 /// Interrupt for this CRYP instance.
1341 type Interrupt: interrupt::typelevel::Interrupt;
1342}
1343
1344foreach_interrupt!(
1345 ($inst:ident, cryp, CRYP, GLOBAL, $irq:ident) => {
1346 impl Instance for peripherals::$inst {
1347 type Interrupt = crate::interrupt::typelevel::$irq;
1348 }
1349
1350 impl sealed::Instance for peripherals::$inst {
1351 fn regs() -> crate::pac::cryp::Cryp {
1352 crate::pac::$inst
1353 }
1354 }
1355 };
1356);
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index 663a7f59d..523719bb9 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -7,7 +7,6 @@ use core::task::Poll;
7use self::sealed::Instance; 7use self::sealed::Instance;
8use crate::interrupt; 8use crate::interrupt;
9use crate::interrupt::typelevel::Interrupt; 9use crate::interrupt::typelevel::Interrupt;
10use crate::pac::rcc::vals::{Lptim1sel, Lptim2sel};
11use crate::peripherals::IPCC; 10use crate::peripherals::IPCC;
12use crate::rcc::sealed::RccPeripheral; 11use crate::rcc::sealed::RccPeripheral;
13 12
@@ -105,7 +104,8 @@ impl Ipcc {
105 IPCC::enable_and_reset(); 104 IPCC::enable_and_reset();
106 IPCC::set_cpu2(true); 105 IPCC::set_cpu2(true);
107 106
108 _configure_pwr(); 107 // set RF wake-up clock = LSE
108 crate::pac::RCC.csr().modify(|w| w.set_rfwkpsel(0b01));
109 109
110 let regs = IPCC::regs(); 110 let regs = IPCC::regs();
111 111
@@ -271,18 +271,3 @@ pub(crate) mod sealed {
271 fn state() -> &'static State; 271 fn state() -> &'static State;
272 } 272 }
273} 273}
274
275fn _configure_pwr() {
276 // TODO: move the rest of this to rcc
277 let rcc = crate::pac::RCC;
278
279 // TODO: required
280 // set RF wake-up clock = LSE
281 rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
282
283 // set LPTIM1 & LPTIM2 clock source
284 rcc.ccipr().modify(|w| {
285 w.set_lptim1sel(Lptim1sel::PCLK1);
286 w.set_lptim2sel(Lptim2sel::PCLK1);
287 });
288}
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 15798e115..ff77399b2 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -34,6 +34,8 @@ pub mod adc;
34pub mod can; 34pub mod can;
35#[cfg(crc)] 35#[cfg(crc)]
36pub mod crc; 36pub mod crc;
37#[cfg(cryp)]
38pub mod cryp;
37#[cfg(dac)] 39#[cfg(dac)]
38pub mod dac; 40pub mod dac;
39#[cfg(dcmi)] 41#[cfg(dcmi)]
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index ec6ec34e8..1946c5a15 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -21,6 +21,9 @@ pub struct Config {
21 pub ahb_pre: AHBPrescaler, 21 pub ahb_pre: AHBPrescaler,
22 pub apb_pre: APBPrescaler, 22 pub apb_pre: APBPrescaler,
23 pub ls: super::LsConfig, 23 pub ls: super::LsConfig,
24
25 /// Per-peripheral kernel clock selection muxes
26 pub mux: super::mux::ClockMux,
24} 27}
25 28
26impl Default for Config { 29impl Default for Config {
@@ -31,6 +34,7 @@ impl Default for Config {
31 ahb_pre: AHBPrescaler::DIV1, 34 ahb_pre: AHBPrescaler::DIV1,
32 apb_pre: APBPrescaler::DIV1, 35 apb_pre: APBPrescaler::DIV1,
33 ls: Default::default(), 36 ls: Default::default(),
37 mux: Default::default(),
34 } 38 }
35 } 39 }
36} 40}
@@ -97,28 +101,25 @@ pub(crate) unsafe fn init(config: Config) {
97 101
98 if !set_flash_latency_after { 102 if !set_flash_latency_after {
99 // Spin until the effective flash latency is compatible with the clock change 103 // Spin until the effective flash latency is compatible with the clock change
100 while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {} 104 while FLASH.acr().read().latency() < target_flash_latency {}
101 } 105 }
102 106
103 // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once 107 // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
104 let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre);
105 RCC.cfgr().modify(|w| { 108 RCC.cfgr().modify(|w| {
106 w.set_sw(sw); 109 w.set_sw(sw);
107 w.set_hpre(hpre); 110 w.set_hpre(config.ahb_pre);
108 w.set_ppre(ppre); 111 w.set_ppre(config.apb_pre);
109 }); 112 });
110 113 // Spin until the SYSCLK changes have taken effect
111 if set_flash_latency_after { 114 loop {
112 // We can make the flash require fewer wait states 115 let cfgr = RCC.cfgr().read();
113 // Spin until the SYSCLK changes have taken effect 116 if cfgr.sw() == sw && cfgr.hpre() == config.ahb_pre && cfgr.ppre() == config.apb_pre {
114 loop { 117 break;
115 let cfgr = RCC.cfgr().read();
116 if cfgr.sw() == sw && cfgr.hpre() == hpre && cfgr.ppre() == ppre {
117 break;
118 }
119 } 118 }
119 }
120 120
121 // Set the flash latency to require fewer wait states 121 // Set the flash latency to require fewer wait states
122 if set_flash_latency_after {
122 FLASH.acr().modify(|w| w.set_latency(target_flash_latency)); 123 FLASH.acr().modify(|w| w.set_latency(target_flash_latency));
123 } 124 }
124 125
@@ -132,6 +133,11 @@ pub(crate) unsafe fn init(config: Config) {
132 } 133 }
133 }; 134 };
134 135
136 config.mux.init();
137
138 // without this, the ringbuffered uart test fails.
139 cortex_m::asm::dsb();
140
135 set_clocks!( 141 set_clocks!(
136 hsi: None, 142 hsi: None,
137 lse: None, 143 lse: None,
diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs
index 5046f0a3a..215f8a3d2 100644
--- a/embassy-stm32/src/rcc/f013.rs
+++ b/embassy-stm32/src/rcc/f013.rs
@@ -98,8 +98,8 @@ pub struct Config {
98 #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] 98 #[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
99 pub adc34: AdcClockSource, 99 pub adc34: AdcClockSource,
100 100
101 #[cfg(clock_mux)] 101 /// Per-peripheral kernel clock selection muxes
102 pub mux: crate::rcc::mux::ClockMux, 102 pub mux: super::mux::ClockMux,
103 103
104 pub ls: super::LsConfig, 104 pub ls: super::LsConfig,
105} 105}
@@ -128,7 +128,6 @@ impl Default for Config {
128 #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] 128 #[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
129 adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), 129 adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1),
130 130
131 #[cfg(clock_mux)]
132 mux: Default::default(), 131 mux: Default::default(),
133 } 132 }
134 } 133 }
@@ -370,7 +369,6 @@ pub(crate) unsafe fn init(config: Config) {
370 }; 369 };
371 */ 370 */
372 371
373 #[cfg(clock_mux)]
374 config.mux.init(); 372 config.mux.init();
375 373
376 set_clocks!( 374 set_clocks!(
diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs
index 343d075cd..7b252870c 100644
--- a/embassy-stm32/src/rcc/f247.rs
+++ b/embassy-stm32/src/rcc/f247.rs
@@ -95,6 +95,9 @@ pub struct Config {
95 95
96 pub ls: super::LsConfig, 96 pub ls: super::LsConfig,
97 97
98 /// Per-peripheral kernel clock selection muxes
99 pub mux: super::mux::ClockMux,
100
98 #[cfg(stm32f2)] 101 #[cfg(stm32f2)]
99 pub voltage: VoltageScale, 102 pub voltage: VoltageScale,
100} 103}
@@ -120,6 +123,7 @@ impl Default for Config {
120 123
121 #[cfg(stm32f2)] 124 #[cfg(stm32f2)]
122 voltage: VoltageScale::Range3, 125 voltage: VoltageScale::Range3,
126 mux: Default::default(),
123 } 127 }
124 } 128 }
125} 129}
@@ -256,6 +260,8 @@ pub(crate) unsafe fn init(config: Config) {
256 }); 260 });
257 while RCC.cfgr().read().sws() != config.sys {} 261 while RCC.cfgr().read().sws() != config.sys {}
258 262
263 config.mux.init();
264
259 set_clocks!( 265 set_clocks!(
260 hsi: hsi, 266 hsi: hsi,
261 hse: hse, 267 hse: hse,
@@ -286,7 +292,9 @@ pub(crate) unsafe fn init(config: Config) {
286 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] 292 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
287 pllsai1_r: pllsai.r, 293 pllsai1_r: pllsai.r,
288 294
289 clk48: pll.q, 295 // TODO workaround until f4 rcc is fixed in stm32-data
296 #[cfg(not(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7)))]
297 pllsai1_q: None,
290 298
291 hsi_div488: hsi.map(|hsi| hsi/488u32), 299 hsi_div488: hsi.map(|hsi| hsi/488u32),
292 hsi_hse: None, 300 hsi_hse: None,
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index ae502dd9c..5cfe9953b 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -71,22 +71,6 @@ pub enum PllSource {
71 HSE(Hertz, HseMode), 71 HSE(Hertz, HseMode),
72} 72}
73 73
74/// Sets the source for the 48MHz clock to the USB peripheral.
75#[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))]
76pub enum UsbSrc {
77 /// Use the High Speed Internal Oscillator. The CRS must be used to calibrate the
78 /// oscillator to comply with the USB specification for oscillator tolerance.
79 #[cfg(any(stm32g0b1, stm32g0c1))]
80 Hsi48(super::Hsi48Config),
81 /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. The
82 /// PLL needs to be using the HSE source to comply with the USB specification for oscillator
83 /// tolerance.
84 PllQ,
85 /// Use the HSE source directly. The HSE must be a 48MHz source. The HSE source must comply
86 /// with the USB specification for oscillator tolerance.
87 HSE,
88}
89
90/// Clocks configutation 74/// Clocks configutation
91pub struct Config { 75pub struct Config {
92 pub sys: Sysclk, 76 pub sys: Sysclk,
@@ -94,8 +78,10 @@ pub struct Config {
94 pub apb_pre: APBPrescaler, 78 pub apb_pre: APBPrescaler,
95 pub low_power_run: bool, 79 pub low_power_run: bool,
96 pub ls: super::LsConfig, 80 pub ls: super::LsConfig,
97 #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] 81 #[cfg(crs)]
98 pub usb_src: Option<UsbSrc>, 82 pub hsi48: Option<super::Hsi48Config>,
83 /// Per-peripheral kernel clock selection muxes
84 pub mux: super::mux::ClockMux,
99} 85}
100 86
101impl Default for Config { 87impl Default for Config {
@@ -107,8 +93,9 @@ impl Default for Config {
107 apb_pre: APBPrescaler::DIV1, 93 apb_pre: APBPrescaler::DIV1,
108 low_power_run: false, 94 low_power_run: false,
109 ls: Default::default(), 95 ls: Default::default(),
110 #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] 96 #[cfg(crs)]
111 usb_src: None, 97 hsi48: Some(Default::default()),
98 mux: Default::default(),
112 } 99 }
113 } 100 }
114} 101}
@@ -322,34 +309,12 @@ pub(crate) unsafe fn init(config: Config) {
322 let lsi_freq = (sw == Sw::LSI).then_some(super::LSI_FREQ); 309 let lsi_freq = (sw == Sw::LSI).then_some(super::LSI_FREQ);
323 let hse_freq = (sw == Sw::HSE).then_some(sys_clk); 310 let hse_freq = (sw == Sw::HSE).then_some(sys_clk);
324 311
325 #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] 312 #[cfg(crs)]
326 let hsi48_freq = config.usb_src.and_then(|config| { 313 let hsi48 = config.hsi48.map(super::init_hsi48);
327 match config { 314 #[cfg(not(crs))]
328 UsbSrc::PllQ => { 315 let hsi48: Option<Hertz> = None;
329 // Make sure the PLLQ is enabled and running at 48Mhz 316
330 assert!(pll1_q_freq.is_some() && pll1_q_freq.unwrap().0 == 48_000_000); 317 config.mux.init();
331 RCC.ccipr2()
332 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::PLL1_Q));
333 None
334 }
335 UsbSrc::HSE => {
336 // Make sure the HSE is enabled and running at 48Mhz
337 assert!(hse_freq.is_some() && hse_freq.unwrap().0 == 48_000_000);
338 RCC.ccipr2()
339 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSE));
340 None
341 }
342 #[cfg(any(stm32g0b1, stm32g0c1))]
343 UsbSrc::Hsi48(config) => {
344 let freq = super::init_hsi48(config);
345 RCC.ccipr2()
346 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48));
347 Some(freq)
348 }
349 }
350 });
351 #[cfg(not(any(stm32g0b1, stm32g0c1, stm32g0b0)))]
352 let hsi48_freq: Option<Hertz> = None;
353 318
354 set_clocks!( 319 set_clocks!(
355 sys: Some(sys_clk), 320 sys: Some(sys_clk),
@@ -357,7 +322,7 @@ pub(crate) unsafe fn init(config: Config) {
357 pclk1: Some(apb_freq), 322 pclk1: Some(apb_freq),
358 pclk1_tim: Some(apb_tim_freq), 323 pclk1_tim: Some(apb_tim_freq),
359 hsi: hsi_freq, 324 hsi: hsi_freq,
360 hsi48: hsi48_freq, 325 hsi48: hsi48,
361 hsi_div_8: hsi_div_8_freq, 326 hsi_div_8: hsi_div_8_freq,
362 hse: hse_freq, 327 hse: hse_freq,
363 lse: lse_freq, 328 lse: lse_freq,
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index 6ed266284..79bdbeb77 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -1,11 +1,10 @@
1use stm32_metapac::flash::vals::Latency; 1use stm32_metapac::flash::vals::Latency;
2use stm32_metapac::rcc::vals::{Adcsel, Sw}; 2use stm32_metapac::rcc::vals::Sw;
3use stm32_metapac::FLASH; 3use stm32_metapac::FLASH;
4 4
5pub use crate::pac::rcc::vals::{ 5pub use crate::pac::rcc::vals::{
6 Adcsel as AdcClockSource, Clk48sel as Clk48Src, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler, 6 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc,
7 Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, Ppre as APBPrescaler, 7 Ppre as APBPrescaler, Sw as Sysclk,
8 Sw as Sysclk,
9}; 8};
10use crate::pac::{PWR, RCC}; 9use crate::pac::{PWR, RCC};
11use crate::time::Hertz; 10use crate::time::Hertz;
@@ -82,24 +81,15 @@ pub struct Config {
82 81
83 pub low_power_run: bool, 82 pub low_power_run: bool,
84 83
85 /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
86 pub clk48_src: Clk48Src,
87
88 /// Low-Speed Clock Configuration 84 /// Low-Speed Clock Configuration
89 pub ls: super::LsConfig, 85 pub ls: super::LsConfig,
90 86
91 /// Clock Source for ADCs 1 and 2
92 pub adc12_clock_source: AdcClockSource,
93
94 /// Clock Source for ADCs 3, 4 and 5
95 pub adc345_clock_source: AdcClockSource,
96
97 /// Clock Source for FDCAN
98 pub fdcan_clock_source: FdCanClockSource,
99
100 /// Enable range1 boost mode 87 /// Enable range1 boost mode
101 /// Recommended when the SYSCLK frequency is greater than 150MHz. 88 /// Recommended when the SYSCLK frequency is greater than 150MHz.
102 pub boost: bool, 89 pub boost: bool,
90
91 /// Per-peripheral kernel clock selection muxes
92 pub mux: super::mux::ClockMux,
103} 93}
104 94
105impl Default for Config { 95impl Default for Config {
@@ -115,12 +105,9 @@ impl Default for Config {
115 apb1_pre: APBPrescaler::DIV1, 105 apb1_pre: APBPrescaler::DIV1,
116 apb2_pre: APBPrescaler::DIV1, 106 apb2_pre: APBPrescaler::DIV1,
117 low_power_run: false, 107 low_power_run: false,
118 clk48_src: Clk48Src::HSI48,
119 ls: Default::default(), 108 ls: Default::default(),
120 adc12_clock_source: Adcsel::DISABLE,
121 adc345_clock_source: Adcsel::DISABLE,
122 fdcan_clock_source: FdCanClockSource::PCLK1,
123 boost: false, 109 boost: false,
110 mux: Default::default(),
124 } 111 }
125 } 112 }
126} 113}
@@ -165,9 +152,7 @@ pub(crate) unsafe fn init(config: Config) {
165 }; 152 };
166 153
167 // Configure HSI48 if required 154 // Configure HSI48 if required
168 if let Some(hsi48_config) = config.hsi48 { 155 let hsi48 = config.hsi48.map(super::init_hsi48);
169 super::init_hsi48(hsi48_config);
170 }
171 156
172 let pll_freq = config.pll.map(|pll_config| { 157 let pll_freq = config.pll.map(|pll_config| {
173 let src_freq = match pll_config.source { 158 let src_freq = match pll_config.source {
@@ -176,13 +161,13 @@ pub(crate) unsafe fn init(config: Config) {
176 _ => unreachable!(), 161 _ => unreachable!(),
177 }; 162 };
178 163
179 assert!(max::PLL_IN.contains(&src_freq));
180
181 // Disable PLL before configuration 164 // Disable PLL before configuration
182 RCC.cr().modify(|w| w.set_pllon(false)); 165 RCC.cr().modify(|w| w.set_pllon(false));
183 while RCC.cr().read().pllrdy() {} 166 while RCC.cr().read().pllrdy() {}
184 167
185 let internal_freq = src_freq / pll_config.prediv * pll_config.mul; 168 let in_freq = src_freq / pll_config.prediv;
169 assert!(max::PLL_IN.contains(&in_freq));
170 let internal_freq = in_freq * pll_config.mul;
186 171
187 assert!(max::PLL_VCO.contains(&internal_freq)); 172 assert!(max::PLL_VCO.contains(&internal_freq));
188 173
@@ -301,42 +286,6 @@ pub(crate) unsafe fn init(config: Config) {
301 let (apb1_freq, apb1_tim_freq) = super::util::calc_pclk(hclk, config.apb1_pre); 286 let (apb1_freq, apb1_tim_freq) = super::util::calc_pclk(hclk, config.apb1_pre);
302 let (apb2_freq, apb2_tim_freq) = super::util::calc_pclk(hclk, config.apb2_pre); 287 let (apb2_freq, apb2_tim_freq) = super::util::calc_pclk(hclk, config.apb2_pre);
303 288
304 // Configure the 48MHz clock source for USB and RNG peripherals.
305 RCC.ccipr().modify(|w| {
306 w.set_clk48sel(match config.clk48_src {
307 Clk48Src::PLL1_Q => {
308 // Not checking that PLL1_Q is 48MHz here so as not to require the user to have a 48MHz clock.
309 // Peripherals which require one (USB, RNG) should check that they‘re driven by a valid 48MHz
310 // clock at init.
311 crate::pac::rcc::vals::Clk48sel::PLL1_Q
312 }
313 Clk48Src::HSI48 => {
314 // Make sure HSI48 is enabled
315 assert!(config.hsi48.is_some());
316 crate::pac::rcc::vals::Clk48sel::HSI48
317 }
318 _ => unreachable!(),
319 })
320 });
321
322 RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source));
323 RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source));
324 RCC.ccipr().modify(|w| w.set_fdcansel(config.fdcan_clock_source));
325
326 let adc12_ck = match config.adc12_clock_source {
327 AdcClockSource::DISABLE => None,
328 AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
329 AdcClockSource::SYS => Some(sys_clk),
330 _ => unreachable!(),
331 };
332
333 let adc345_ck = match config.adc345_clock_source {
334 AdcClockSource::DISABLE => None,
335 AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
336 AdcClockSource::SYS => Some(sys_clk),
337 _ => unreachable!(),
338 };
339
340 if config.low_power_run { 289 if config.low_power_run {
341 assert!(sys_clk <= Hertz(2_000_000)); 290 assert!(sys_clk <= Hertz(2_000_000));
342 PWR.cr1().modify(|w| w.set_lpr(true)); 291 PWR.cr1().modify(|w| w.set_lpr(true));
@@ -344,6 +293,8 @@ pub(crate) unsafe fn init(config: Config) {
344 293
345 let rtc = config.ls.init(); 294 let rtc = config.ls.init();
346 295
296 config.mux.init();
297
347 set_clocks!( 298 set_clocks!(
348 sys: Some(sys_clk), 299 sys: Some(sys_clk),
349 hclk1: Some(hclk), 300 hclk1: Some(hclk),
@@ -353,12 +304,11 @@ pub(crate) unsafe fn init(config: Config) {
353 pclk1_tim: Some(apb1_tim_freq), 304 pclk1_tim: Some(apb1_tim_freq),
354 pclk2: Some(apb2_freq), 305 pclk2: Some(apb2_freq),
355 pclk2_tim: Some(apb2_tim_freq), 306 pclk2_tim: Some(apb2_tim_freq),
356 adc: adc12_ck,
357 adc34: adc345_ck,
358 pll1_p: pll_freq.as_ref().and_then(|pll| pll.pll_p), 307 pll1_p: pll_freq.as_ref().and_then(|pll| pll.pll_p),
359 pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_q), 308 pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_q),
360 pll1_r: pll_freq.as_ref().and_then(|pll| pll.pll_r), 309 pll1_r: pll_freq.as_ref().and_then(|pll| pll.pll_r),
361 hse: hse, 310 hse: hse,
311 hsi48: hsi48,
362 rtc: rtc, 312 rtc: rtc,
363 ); 313 );
364} 314}
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 7b2255cc6..bab8bb19e 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -2,15 +2,10 @@ use core::ops::RangeInclusive;
2 2
3use crate::pac; 3use crate::pac;
4use crate::pac::pwr::vals::Vos; 4use crate::pac::pwr::vals::Vos;
5#[cfg(stm32h5)]
6pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
7#[cfg(stm32h7)]
8pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
9pub use crate::pac::rcc::vals::{ 5pub use crate::pac::rcc::vals::{
10 Ckpersel as PerClockSource, Fdcansel as FdCanClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, 6 Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk,
11 Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk,
12}; 7};
13use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre}; 8use crate::pac::rcc::vals::{Pllrge, Pllvcosel, Timpre};
14use crate::pac::{FLASH, PWR, RCC}; 9use crate::pac::{FLASH, PWR, RCC};
15use crate::time::Hertz; 10use crate::time::Hertz;
16 11
@@ -194,16 +189,15 @@ pub struct Config {
194 #[cfg(stm32h7)] 189 #[cfg(stm32h7)]
195 pub apb4_pre: APBPrescaler, 190 pub apb4_pre: APBPrescaler,
196 191
197 pub per_clock_source: PerClockSource,
198 pub adc_clock_source: AdcClockSource,
199 pub fdcan_clock_source: FdCanClockSource,
200
201 pub timer_prescaler: TimerPrescaler, 192 pub timer_prescaler: TimerPrescaler,
202 pub voltage_scale: VoltageScale, 193 pub voltage_scale: VoltageScale,
203 pub ls: super::LsConfig, 194 pub ls: super::LsConfig,
204 195
205 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] 196 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
206 pub supply_config: SupplyConfig, 197 pub supply_config: SupplyConfig,
198
199 /// Per-peripheral kernel clock selection muxes
200 pub mux: super::mux::ClockMux,
207} 201}
208 202
209impl Default for Config { 203impl Default for Config {
@@ -227,21 +221,14 @@ impl Default for Config {
227 #[cfg(stm32h7)] 221 #[cfg(stm32h7)]
228 apb4_pre: APBPrescaler::DIV1, 222 apb4_pre: APBPrescaler::DIV1,
229 223
230 per_clock_source: PerClockSource::HSI,
231
232 #[cfg(stm32h5)]
233 adc_clock_source: AdcClockSource::HCLK1,
234 #[cfg(stm32h7)]
235 adc_clock_source: AdcClockSource::PER,
236
237 fdcan_clock_source: FdCanClockSource::from_bits(0), // HSE
238
239 timer_prescaler: TimerPrescaler::DefaultX2, 224 timer_prescaler: TimerPrescaler::DefaultX2,
240 voltage_scale: VoltageScale::Scale0, 225 voltage_scale: VoltageScale::Scale0,
241 ls: Default::default(), 226 ls: Default::default(),
242 227
243 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] 228 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
244 supply_config: SupplyConfig::Default, 229 supply_config: SupplyConfig::Default,
230
231 mux: Default::default(),
245 } 232 }
246 } 233 }
247} 234}
@@ -504,31 +491,6 @@ pub(crate) unsafe fn init(config: Config) {
504 #[cfg(stm32h7)] 491 #[cfg(stm32h7)]
505 assert!(apb4 <= pclk_max); 492 assert!(apb4 <= pclk_max);
506 493
507 let _per_ck = match config.per_clock_source {
508 Ckpersel::HSI => hsi,
509 Ckpersel::CSI => csi,
510 Ckpersel::HSE => hse,
511 _ => unreachable!(),
512 };
513
514 #[cfg(stm32h7)]
515 let adc = match config.adc_clock_source {
516 AdcClockSource::PLL2_P => pll2.p,
517 AdcClockSource::PLL3_R => pll3.r,
518 AdcClockSource::PER => _per_ck,
519 _ => unreachable!(),
520 };
521 #[cfg(stm32h5)]
522 let adc = match config.adc_clock_source {
523 AdcClockSource::HCLK1 => Some(hclk),
524 AdcClockSource::SYS => Some(sys),
525 AdcClockSource::PLL2_R => pll2.r,
526 AdcClockSource::HSE => hse,
527 AdcClockSource::HSI => hsi,
528 AdcClockSource::CSI => csi,
529 _ => unreachable!(),
530 };
531
532 flash_setup(hclk, config.voltage_scale); 494 flash_setup(hclk, config.voltage_scale);
533 495
534 let rtc = config.ls.init(); 496 let rtc = config.ls.init();
@@ -550,16 +512,6 @@ pub(crate) unsafe fn init(config: Config) {
550 RCC.d3cfgr().modify(|w| { 512 RCC.d3cfgr().modify(|w| {
551 w.set_d3ppre(config.apb4_pre); 513 w.set_d3ppre(config.apb4_pre);
552 }); 514 });
553
554 RCC.d1ccipr().modify(|w| {
555 w.set_ckpersel(config.per_clock_source);
556 });
557 RCC.d3ccipr().modify(|w| {
558 w.set_adcsel(config.adc_clock_source);
559 });
560 RCC.d2ccip1r().modify(|w| {
561 w.set_fdcansel(config.fdcan_clock_source);
562 });
563 } 515 }
564 #[cfg(stm32h5)] 516 #[cfg(stm32h5)]
565 { 517 {
@@ -573,12 +525,6 @@ pub(crate) unsafe fn init(config: Config) {
573 w.set_ppre2(config.apb2_pre); 525 w.set_ppre2(config.apb2_pre);
574 w.set_ppre3(config.apb3_pre); 526 w.set_ppre3(config.apb3_pre);
575 }); 527 });
576
577 RCC.ccipr5().modify(|w| {
578 w.set_ckpersel(config.per_clock_source);
579 w.set_adcdacsel(config.adc_clock_source);
580 w.set_fdcan12sel(config.fdcan_clock_source)
581 });
582 } 528 }
583 529
584 RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into())); 530 RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
@@ -601,6 +547,8 @@ pub(crate) unsafe fn init(config: Config) {
601 while !pac::SYSCFG.cccsr().read().ready() {} 547 while !pac::SYSCFG.cccsr().read().ready() {}
602 } 548 }
603 549
550 config.mux.init();
551
604 set_clocks!( 552 set_clocks!(
605 sys: Some(sys), 553 sys: Some(sys),
606 hclk1: Some(hclk), 554 hclk1: Some(hclk),
@@ -614,7 +562,6 @@ pub(crate) unsafe fn init(config: Config) {
614 pclk4: Some(apb4), 562 pclk4: Some(apb4),
615 pclk1_tim: Some(apb1_tim), 563 pclk1_tim: Some(apb1_tim),
616 pclk2_tim: Some(apb2_tim), 564 pclk2_tim: Some(apb2_tim),
617 adc: adc,
618 rtc: rtc, 565 rtc: rtc,
619 566
620 hsi: hsi, 567 hsi: hsi,
@@ -646,7 +593,6 @@ pub(crate) unsafe fn init(config: Config) {
646 593
647 #[cfg(stm32h5)] 594 #[cfg(stm32h5)]
648 audioclk: None, 595 audioclk: None,
649 per: None,
650 i2s_ckin: None, 596 i2s_ckin: None,
651 ); 597 );
652} 598}
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index aa4245d4e..9079ddd41 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -1,10 +1,6 @@
1#[cfg(any(stm32l0, stm32l1))] 1#[cfg(any(stm32l0, stm32l1))]
2pub use crate::pac::pwr::vals::Vos as VoltageScale; 2pub use crate::pac::pwr::vals::Vos as VoltageScale;
3use crate::pac::rcc::regs::Cfgr; 3use crate::pac::rcc::regs::Cfgr;
4#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
5pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
6#[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
7pub use crate::pac::rcc::vals::Clk48sel as Clk48Src;
8#[cfg(any(stm32wb, stm32wl))] 4#[cfg(any(stm32wb, stm32wl))]
9pub use crate::pac::rcc::vals::Hsepre as HsePrescaler; 5pub use crate::pac::rcc::vals::Hsepre as HsePrescaler;
10pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as Sysclk}; 6pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as Sysclk};
@@ -59,18 +55,14 @@ pub struct Config {
59 #[cfg(any(stm32wl, stm32wb))] 55 #[cfg(any(stm32wl, stm32wb))]
60 pub shared_ahb_pre: AHBPrescaler, 56 pub shared_ahb_pre: AHBPrescaler,
61 57
62 // muxes
63 #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
64 pub clk48_src: Clk48Src,
65
66 // low speed LSI/LSE/RTC 58 // low speed LSI/LSE/RTC
67 pub ls: super::LsConfig, 59 pub ls: super::LsConfig,
68 60
69 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
70 pub adc_clock_source: AdcClockSource,
71
72 #[cfg(any(stm32l0, stm32l1))] 61 #[cfg(any(stm32l0, stm32l1))]
73 pub voltage_scale: VoltageScale, 62 pub voltage_scale: VoltageScale,
63
64 /// Per-peripheral kernel clock selection muxes
65 pub mux: super::mux::ClockMux,
74} 66}
75 67
76impl Default for Config { 68impl Default for Config {
@@ -95,13 +87,10 @@ impl Default for Config {
95 pllsai2: None, 87 pllsai2: None,
96 #[cfg(crs)] 88 #[cfg(crs)]
97 hsi48: Some(Default::default()), 89 hsi48: Some(Default::default()),
98 #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
99 clk48_src: Clk48Src::HSI48,
100 ls: Default::default(), 90 ls: Default::default(),
101 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
102 adc_clock_source: AdcClockSource::SYS,
103 #[cfg(any(stm32l0, stm32l1))] 91 #[cfg(any(stm32l0, stm32l1))]
104 voltage_scale: VoltageScale::RANGE1, 92 voltage_scale: VoltageScale::RANGE1,
93 mux: Default::default(),
105 } 94 }
106 } 95 }
107} 96}
@@ -118,7 +107,6 @@ pub const WPAN_DEFAULT: Config = Config {
118 hsi48: Some(super::Hsi48Config { sync_from_usb: false }), 107 hsi48: Some(super::Hsi48Config { sync_from_usb: false }),
119 msi: None, 108 msi: None,
120 hsi: false, 109 hsi: false,
121 clk48_src: Clk48Src::PLL1_Q,
122 110
123 ls: super::LsConfig::default_lse(), 111 ls: super::LsConfig::default_lse(),
124 112
@@ -137,7 +125,8 @@ pub const WPAN_DEFAULT: Config = Config {
137 shared_ahb_pre: AHBPrescaler::DIV1, 125 shared_ahb_pre: AHBPrescaler::DIV1,
138 apb1_pre: APBPrescaler::DIV1, 126 apb1_pre: APBPrescaler::DIV1,
139 apb2_pre: APBPrescaler::DIV1, 127 apb2_pre: APBPrescaler::DIV1,
140 adc_clock_source: AdcClockSource::SYS, 128
129 mux: super::mux::ClockMux::default(),
141}; 130};
142 131
143fn msi_enable(range: MSIRange) { 132fn msi_enable(range: MSIRange) {
@@ -267,21 +256,6 @@ pub(crate) unsafe fn init(config: Config) {
267 Sysclk::PLL1_R => pll.r.unwrap(), 256 Sysclk::PLL1_R => pll.r.unwrap(),
268 }; 257 };
269 258
270 #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
271 RCC.ccipr().modify(|w| w.set_clk48sel(config.clk48_src));
272 #[cfg(any(rcc_l0_v2))]
273 let clk48 = match config.clk48_src {
274 Clk48Src::HSI48 => hsi48,
275 Clk48Src::PLL1_VCO_DIV_2 => pll.clk48,
276 };
277 #[cfg(any(stm32l4, stm32l5, stm32wb))]
278 let clk48 = match config.clk48_src {
279 Clk48Src::HSI48 => hsi48,
280 Clk48Src::MSI => msi,
281 Clk48Src::PLLSAI1_Q => pllsai1.q,
282 Clk48Src::PLL1_Q => pll.q,
283 };
284
285 #[cfg(rcc_l4plus)] 259 #[cfg(rcc_l4plus)]
286 assert!(sys_clk.0 <= 120_000_000); 260 assert!(sys_clk.0 <= 120_000_000);
287 #[cfg(all(stm32l4, not(rcc_l4plus)))] 261 #[cfg(all(stm32l4, not(rcc_l4plus)))]
@@ -357,9 +331,6 @@ pub(crate) unsafe fn init(config: Config) {
357 }); 331 });
358 while RCC.cfgr().read().sws() != config.sys {} 332 while RCC.cfgr().read().sws() != config.sys {}
359 333
360 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
361 RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source));
362
363 #[cfg(any(stm32wl, stm32wb))] 334 #[cfg(any(stm32wl, stm32wb))]
364 { 335 {
365 RCC.extcfgr().modify(|w| { 336 RCC.extcfgr().modify(|w| {
@@ -372,6 +343,8 @@ pub(crate) unsafe fn init(config: Config) {
372 while !RCC.extcfgr().read().c2hpref() {} 343 while !RCC.extcfgr().read().c2hpref() {}
373 } 344 }
374 345
346 config.mux.init();
347
375 set_clocks!( 348 set_clocks!(
376 sys: Some(sys_clk), 349 sys: Some(sys_clk),
377 hclk1: Some(hclk1), 350 hclk1: Some(hclk1),
@@ -388,10 +361,11 @@ pub(crate) unsafe fn init(config: Config) {
388 hsi: hsi, 361 hsi: hsi,
389 hse: hse, 362 hse: hse,
390 msi: msi, 363 msi: msi,
391 #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
392 clk48: clk48,
393 hsi48: hsi48, 364 hsi48: hsi48,
394 365
366 #[cfg(any(stm32l0, stm32l1))]
367 pll1_vco_div_2: pll.vco.map(|c| c/2u32),
368
395 #[cfg(not(any(stm32l0, stm32l1)))] 369 #[cfg(not(any(stm32l0, stm32l1)))]
396 pll1_p: pll.p, 370 pll1_p: pll.p,
397 #[cfg(not(any(stm32l0, stm32l1)))] 371 #[cfg(not(any(stm32l0, stm32l1)))]
@@ -511,7 +485,7 @@ mod pll {
511 #[derive(Default)] 485 #[derive(Default)]
512 pub(super) struct PllOutput { 486 pub(super) struct PllOutput {
513 pub r: Option<Hertz>, 487 pub r: Option<Hertz>,
514 pub clk48: Option<Hertz>, 488 pub vco: Option<Hertz>,
515 } 489 }
516 490
517 pub(super) fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> PllOutput { 491 pub(super) fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> PllOutput {
@@ -528,7 +502,6 @@ mod pll {
528 let vco_freq = pll_src * pll.mul; 502 let vco_freq = pll_src * pll.mul;
529 503
530 let r = vco_freq / pll.div; 504 let r = vco_freq / pll.div;
531 let clk48 = (vco_freq == Hertz(96_000_000)).then_some(Hertz(48_000_000));
532 505
533 assert!(r <= Hertz(32_000_000)); 506 assert!(r <= Hertz(32_000_000));
534 507
@@ -541,7 +514,10 @@ mod pll {
541 // Enable PLL 514 // Enable PLL
542 pll_enable(instance, true); 515 pll_enable(instance, true);
543 516
544 PllOutput { r: Some(r), clk48 } 517 PllOutput {
518 r: Some(r),
519 vco: Some(vco_freq),
520 }
545 } 521 }
546} 522}
547 523
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index c8ca713de..910ebe205 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -31,9 +31,7 @@ mod _version;
31 31
32pub use _version::*; 32pub use _version::*;
33 33
34#[cfg(clock_mux)] 34pub use crate::_generated::{mux, Clocks};
35pub use crate::_generated::mux;
36pub use crate::_generated::Clocks;
37 35
38#[cfg(feature = "low-power")] 36#[cfg(feature = "low-power")]
39/// Must be written within a critical section 37/// Must be written within a critical section
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index c8814ed69..9533e16c4 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -85,6 +85,9 @@ pub struct Config {
85 /// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits. 85 /// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits.
86 pub voltage_range: VoltageScale, 86 pub voltage_range: VoltageScale,
87 pub ls: super::LsConfig, 87 pub ls: super::LsConfig,
88
89 /// Per-peripheral kernel clock selection muxes
90 pub mux: super::mux::ClockMux,
88} 91}
89 92
90impl Default for Config { 93impl Default for Config {
@@ -104,6 +107,7 @@ impl Default for Config {
104 apb3_pre: APBPrescaler::DIV1, 107 apb3_pre: APBPrescaler::DIV1,
105 voltage_range: VoltageScale::RANGE1, 108 voltage_range: VoltageScale::RANGE1,
106 ls: Default::default(), 109 ls: Default::default(),
110 mux: Default::default(),
107 } 111 }
108 } 112 }
109} 113}
@@ -259,6 +263,8 @@ pub(crate) unsafe fn init(config: Config) {
259 263
260 let rtc = config.ls.init(); 264 let rtc = config.ls.init();
261 265
266 config.mux.init();
267
262 set_clocks!( 268 set_clocks!(
263 sys: Some(sys_clk), 269 sys: Some(sys_clk),
264 hclk1: Some(hclk), 270 hclk1: Some(hclk),
@@ -289,7 +295,6 @@ pub(crate) unsafe fn init(config: Config) {
289 lse: None, 295 lse: None,
290 lsi: None, 296 lsi: None,
291 msik: None, 297 msik: None,
292 iclk: None,
293 shsi: None, 298 shsi: None,
294 shsi_div_2: None, 299 shsi_div_2: None,
295 ); 300 );
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs
index 9d5dcfc4b..8e1779d7c 100644
--- a/embassy-stm32/src/rcc/wba.rs
+++ b/embassy-stm32/src/rcc/wba.rs
@@ -1,8 +1,6 @@
1pub use crate::pac::pwr::vals::Vos as VoltageScale; 1pub use crate::pac::pwr::vals::Vos as VoltageScale;
2use crate::pac::rcc::regs::Cfgr1; 2use crate::pac::rcc::regs::Cfgr1;
3pub use crate::pac::rcc::vals::{ 3pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk};
4 Adcsel as AdcClockSource, Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk,
5};
6use crate::pac::{FLASH, RCC}; 4use crate::pac::{FLASH, RCC};
7use crate::time::Hertz; 5use crate::time::Hertz;
8 6
@@ -32,9 +30,10 @@ pub struct Config {
32 // low speed LSI/LSE/RTC 30 // low speed LSI/LSE/RTC
33 pub ls: super::LsConfig, 31 pub ls: super::LsConfig,
34 32
35 pub adc_clock_source: AdcClockSource,
36
37 pub voltage_scale: VoltageScale, 33 pub voltage_scale: VoltageScale,
34
35 /// Per-peripheral kernel clock selection muxes
36 pub mux: super::mux::ClockMux,
38} 37}
39 38
40impl Default for Config { 39impl Default for Config {
@@ -49,8 +48,8 @@ impl Default for Config {
49 apb2_pre: APBPrescaler::DIV1, 48 apb2_pre: APBPrescaler::DIV1,
50 apb7_pre: APBPrescaler::DIV1, 49 apb7_pre: APBPrescaler::DIV1,
51 ls: Default::default(), 50 ls: Default::default(),
52 adc_clock_source: AdcClockSource::HCLK4,
53 voltage_scale: VoltageScale::RANGE2, 51 voltage_scale: VoltageScale::RANGE2,
52 mux: Default::default(),
54 } 53 }
55 } 54 }
56} 55}
@@ -152,7 +151,7 @@ pub(crate) unsafe fn init(config: Config) {
152 w.set_ppre2(config.apb2_pre); 151 w.set_ppre2(config.apb2_pre);
153 }); 152 });
154 153
155 RCC.ccipr3().modify(|w| w.set_adcsel(config.adc_clock_source)); 154 config.mux.init();
156 155
157 set_clocks!( 156 set_clocks!(
158 sys: Some(sys_clk), 157 sys: Some(sys_clk),
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index 190fb274f..373697ec8 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -606,13 +606,6 @@ impl<'d, T: Instance> Bus<'d, T> {
606 // Wait for USB power to stabilize 606 // Wait for USB power to stabilize
607 while !crate::pac::PWR.cr3().read().usb33rdy() {} 607 while !crate::pac::PWR.cr3().read().usb33rdy() {}
608 608
609 // Use internal 48MHz HSI clock. Should be enabled in RCC by default.
610 critical_section::with(|_| {
611 crate::pac::RCC
612 .d2ccip2r()
613 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
614 });
615
616 // Enable ULPI clock if external PHY is used 609 // Enable ULPI clock if external PHY is used
617 let ulpien = !self.phy_type.internal(); 610 let ulpien = !self.phy_type.internal();
618 critical_section::with(|_| { 611 critical_section::with(|_| {
@@ -645,13 +638,6 @@ impl<'d, T: Instance> Bus<'d, T> {
645 638
646 // Wait for USB power to stabilize 639 // Wait for USB power to stabilize
647 while !crate::pac::PWR.svmsr().read().vddusbrdy() {} 640 while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
648
649 // Select HSI48 as USB clock source.
650 critical_section::with(|_| {
651 crate::pac::RCC.ccipr1().modify(|w| {
652 w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
653 })
654 });
655 } 641 }
656 642
657 <T as RccPeripheral>::enable_and_reset(); 643 <T as RccPeripheral>::enable_and_reset();
diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs
index 7c6d6cd71..e6d1a6c02 100644
--- a/examples/stm32f334/src/bin/pwm.rs
+++ b/examples/stm32f334/src/bin/pwm.rs
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
28 config.rcc.apb1_pre = APBPrescaler::DIV2; 28 config.rcc.apb1_pre = APBPrescaler::DIV2;
29 config.rcc.apb2_pre = APBPrescaler::DIV1; 29 config.rcc.apb2_pre = APBPrescaler::DIV1;
30 30
31 config.rcc.mux.hrtim1sw = Some(embassy_stm32::rcc::mux::Timsw::PLL1_P); 31 config.rcc.mux.hrtim1sw = embassy_stm32::rcc::mux::Timsw::PLL1_P;
32 } 32 }
33 let p = embassy_stm32::init(config); 33 let p = embassy_stm32::init(config);
34 34
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index 736e81723..305816a2b 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -30,6 +30,7 @@ embedded-storage = "0.3.1"
30static_cell = "2" 30static_cell = "2"
31sha2 = { version = "0.10.8", default-features = false } 31sha2 = { version = "0.10.8", default-features = false }
32hmac = "0.12.1" 32hmac = "0.12.1"
33aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] }
33 34
34[profile.release] 35[profile.release]
35debug = 2 36debug = 2
diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs
new file mode 100644
index 000000000..04927841a
--- /dev/null
+++ b/examples/stm32f7/src/bin/cryp.rs
@@ -0,0 +1,74 @@
1#![no_std]
2#![no_main]
3
4use aes_gcm::aead::heapless::Vec;
5use aes_gcm::aead::{AeadInPlace, KeyInit};
6use aes_gcm::Aes128Gcm;
7use defmt::info;
8use embassy_executor::Spawner;
9use embassy_stm32::cryp::*;
10use embassy_stm32::Config;
11use embassy_time::Instant;
12use {defmt_rtt as _, panic_probe as _};
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) -> ! {
16 let config = Config::default();
17 let p = embassy_stm32::init(config);
18
19 let payload: &[u8] = b"hello world";
20 let aad: &[u8] = b"additional data";
21
22 let hw_cryp = Cryp::new(p.CRYP);
23 let key: [u8; 16] = [0; 16];
24 let mut ciphertext: [u8; 11] = [0; 11];
25 let mut plaintext: [u8; 11] = [0; 11];
26 let iv: [u8; 12] = [0; 12];
27
28 let hw_start_time = Instant::now();
29
30 // Encrypt in hardware using AES-GCM 128-bit
31 let aes_gcm = AesGcm::new(&key, &iv);
32 let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt);
33 hw_cryp.aad_blocking(&mut gcm_encrypt, aad, true);
34 hw_cryp.payload_blocking(&mut gcm_encrypt, payload, &mut ciphertext, true);
35 let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt);
36
37 // Decrypt in hardware using AES-GCM 128-bit
38 let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt);
39 hw_cryp.aad_blocking(&mut gcm_decrypt, aad, true);
40 hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true);
41 let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt);
42
43 let hw_end_time = Instant::now();
44 let hw_execution_time = hw_end_time - hw_start_time;
45
46 info!("AES-GCM Ciphertext: {:?}", ciphertext);
47 info!("AES-GCM Plaintext: {:?}", plaintext);
48 assert_eq!(payload, plaintext);
49 assert_eq!(encrypt_tag, decrypt_tag);
50
51 let sw_start_time = Instant::now();
52
53 // Encrypt in software using AES-GCM 128-bit
54 let mut payload_vec: Vec<u8, 32> = Vec::from_slice(&payload).unwrap();
55 let cipher = Aes128Gcm::new(&key.into());
56 let _ = cipher.encrypt_in_place(&iv.into(), aad.into(), &mut payload_vec);
57
58 assert_eq!(ciphertext, payload_vec[0..ciphertext.len()]);
59 assert_eq!(
60 encrypt_tag,
61 payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]
62 );
63
64 // Decrypt in software using AES-GCM 128-bit
65 let _ = cipher.decrypt_in_place(&iv.into(), aad.into(), &mut payload_vec);
66
67 let sw_end_time = Instant::now();
68 let sw_execution_time = sw_end_time - sw_start_time;
69
70 info!("Hardware Execution Time: {:?}", hw_execution_time);
71 info!("Software Execution Time: {:?}", sw_execution_time);
72
73 loop {}
74}
diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs
index 3f63d0dfd..647ff0419 100644
--- a/examples/stm32g0/src/bin/hf_timer.rs
+++ b/examples/stm32g0/src/bin/hf_timer.rs
@@ -4,37 +4,35 @@
4use defmt::info; 4use defmt::info;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::gpio::OutputType; 6use embassy_stm32::gpio::OutputType;
7use embassy_stm32::pac::rcc::vals::Tim1sel;
8use embassy_stm32::rcc::{Config as RccConfig, PllConfig, PllSource, Pllm, Plln, Pllq, Pllr, Sysclk};
9use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
10use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; 8use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin};
11use embassy_stm32::timer::simple_pwm::PwmPin; 9use embassy_stm32::timer::simple_pwm::PwmPin;
12use embassy_stm32::timer::Channel; 10use embassy_stm32::timer::Channel;
13use embassy_stm32::{pac, Config as PeripheralConfig}; 11use embassy_stm32::Config as PeripheralConfig;
14use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
15 13
16#[embassy_executor::main] 14#[embassy_executor::main]
17async fn main(_spawner: Spawner) { 15async fn main(_spawner: Spawner) {
18 let mut rcc_config = RccConfig::default(); 16 let mut config = PeripheralConfig::default();
19 rcc_config.sys = Sysclk::PLL(PllConfig { 17 {
20 source: PllSource::HSI, 18 use embassy_stm32::rcc::*;
21 m: Pllm::DIV1, 19
22 n: Plln::MUL16, 20 config.rcc.sys = Sysclk::PLL(PllConfig {
23 r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz) 21 source: PllSource::HSI,
24 q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz) 22 m: Pllm::DIV1,
25 p: None, 23 n: Plln::MUL16,
26 }); 24 r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz)
27 25 q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz)
28 let mut peripheral_config = PeripheralConfig::default(); 26 p: None,
29 peripheral_config.rcc = rcc_config; 27 });
30 28
31 let p = embassy_stm32::init(peripheral_config); 29 // configure TIM1 mux to select PLLQ as clock source
32 30 // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
33 // configure TIM1 mux to select PLLQ as clock source 31 // RM0444 page 210
34 // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf 32 // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1
35 // RM0444 page 210 33 config.rcc.mux.tim1sel = embassy_stm32::rcc::mux::Tim1sel::PLL1_Q;
36 // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1 34 }
37 pac::RCC.ccipr().modify(|w| w.set_tim1sel(Tim1sel::PLL1_Q)); 35 let p = embassy_stm32::init(config);
38 36
39 let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); 37 let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull);
40 let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull); 38 let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull);
diff --git a/examples/stm32g0/src/bin/usb_serial.rs b/examples/stm32g0/src/bin/usb_serial.rs
index f5aaa5624..8b9915626 100644
--- a/examples/stm32g0/src/bin/usb_serial.rs
+++ b/examples/stm32g0/src/bin/usb_serial.rs
@@ -4,7 +4,6 @@
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_futures::join::join; 6use embassy_futures::join::join;
7use embassy_stm32::rcc::{Hsi48Config, UsbSrc};
8use embassy_stm32::usb::{Driver, Instance}; 7use embassy_stm32::usb::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@@ -19,10 +18,11 @@ bind_interrupts!(struct Irqs {
19#[embassy_executor::main] 18#[embassy_executor::main]
20async fn main(_spawner: Spawner) { 19async fn main(_spawner: Spawner) {
21 let mut config = Config::default(); 20 let mut config = Config::default();
22 config.rcc.usb_src = Some(UsbSrc::Hsi48(Hsi48Config { 21 {
23 sync_from_usb: true, 22 use embassy_stm32::rcc::*;
24 ..Default::default() 23 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true });
25 })); 24 config.rcc.mux.usbsel = mux::Usbsel::HSI48;
25 }
26 let p = embassy_stm32::init(config); 26 let p = embassy_stm32::init(config);
27 27
28 info!("Hello World!"); 28 info!("Hello World!");
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
index 6c6de1ffe..f81335f93 100644
--- a/examples/stm32g4/src/bin/adc.rs
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -4,7 +4,6 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime}; 6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::rcc::{AdcClockSource, Pll, PllMul, PllPreDiv, PllRDiv, Pllsrc, Sysclk};
8use embassy_stm32::Config; 7use embassy_stm32::Config;
9use embassy_time::{Delay, Timer}; 8use embassy_time::{Delay, Timer};
10use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
@@ -12,20 +11,20 @@ use {defmt_rtt as _, panic_probe as _};
12#[embassy_executor::main] 11#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 12async fn main(_spawner: Spawner) {
14 let mut config = Config::default(); 13 let mut config = Config::default();
15 14 {
16 config.rcc.pll = Some(Pll { 15 use embassy_stm32::rcc::*;
17 source: Pllsrc::HSI, 16 config.rcc.pll = Some(Pll {
18 prediv: PllPreDiv::DIV4, 17 source: Pllsrc::HSI,
19 mul: PllMul::MUL85, 18 prediv: PllPreDiv::DIV4,
20 divp: None, 19 mul: PllMul::MUL85,
21 divq: None, 20 divp: None,
22 // Main system clock at 170 MHz 21 divq: None,
23 divr: Some(PllRDiv::DIV2), 22 // Main system clock at 170 MHz
24 }); 23 divr: Some(PllRDiv::DIV2),
25 24 });
26 config.rcc.adc12_clock_source = AdcClockSource::SYS; 25 config.rcc.mux.adc12sel = mux::Adcsel::SYS;
27 config.rcc.sys = Sysclk::PLL1_R; 26 config.rcc.sys = Sysclk::PLL1_R;
28 27 }
29 let mut p = embassy_stm32::init(config); 28 let mut p = embassy_stm32::init(config);
30 info!("Hello World!"); 29 info!("Hello World!");
31 30
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs
index a41f765c1..93b206de8 100644
--- a/examples/stm32g4/src/bin/can.rs
+++ b/examples/stm32g4/src/bin/can.rs
@@ -3,6 +3,7 @@
3use defmt::*; 3use defmt::*;
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_stm32::peripherals::*; 5use embassy_stm32::peripherals::*;
6use embassy_stm32::time::Hertz;
6use embassy_stm32::{bind_interrupts, can, Config}; 7use embassy_stm32::{bind_interrupts, can, Config};
7use embassy_time::Timer; 8use embassy_time::Timer;
8use static_cell::StaticCell; 9use static_cell::StaticCell;
@@ -15,8 +16,24 @@ bind_interrupts!(struct Irqs {
15 16
16#[embassy_executor::main] 17#[embassy_executor::main]
17async fn main(_spawner: Spawner) { 18async fn main(_spawner: Spawner) {
18 let config = Config::default(); 19 let mut config = Config::default();
19 20 {
21 use embassy_stm32::rcc::*;
22 config.rcc.hse = Some(Hse {
23 freq: Hertz(24_000_000),
24 mode: HseMode::Oscillator,
25 });
26 config.rcc.pll = Some(Pll {
27 source: Pllsrc::HSE,
28 prediv: PllPreDiv::DIV6,
29 mul: PllMul::MUL85,
30 divp: None,
31 divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan.
32 divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz
33 });
34 config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q;
35 config.rcc.sys = Sysclk::PLL1_R;
36 }
20 let peripherals = embassy_stm32::init(config); 37 let peripherals = embassy_stm32::init(config);
21 38
22 let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); 39 let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
@@ -184,7 +201,11 @@ async fn main(_spawner: Spawner) {
184 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); 201 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
185 info!("Writing frame"); 202 info!("Writing frame");
186 203
187 _ = can.write(frame).await; 204 // You can use any of these approaches to send. The writer makes it
205 // easy to share sending from multiple tasks.
206 //_ = can.write(frame).await;
207 //can.writer().try_write(frame).unwrap();
208 can.writer().write(frame).await;
188 209
189 match can.read().await { 210 match can.read().await {
190 Ok((rx_frame, ts)) => { 211 Ok((rx_frame, ts)) => {
diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs
index 5274de79d..2609abfa2 100644
--- a/examples/stm32g4/src/bin/pll.rs
+++ b/examples/stm32g4/src/bin/pll.rs
@@ -12,6 +12,7 @@ use {defmt_rtt as _, panic_probe as _};
12async fn main(_spawner: Spawner) { 12async fn main(_spawner: Spawner) {
13 let mut config = Config::default(); 13 let mut config = Config::default();
14 14
15 config.rcc.hsi = true;
15 config.rcc.pll = Some(Pll { 16 config.rcc.pll = Some(Pll {
16 source: Pllsrc::HSI, 17 source: Pllsrc::HSI,
17 prediv: PllPreDiv::DIV4, 18 prediv: PllPreDiv::DIV4,
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index 989fef5b0..90caaae14 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -3,9 +3,6 @@
3 3
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::rcc::{
7 Clk48Src, Hse, HseMode, Hsi48Config, Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, Pllsrc, Sysclk,
8};
9use embassy_stm32::time::Hertz; 6use embassy_stm32::time::Hertz;
10use embassy_stm32::usb::{self, Driver, Instance}; 7use embassy_stm32::usb::{self, Driver, Instance};
11use embassy_stm32::{bind_interrupts, peripherals, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, Config};
@@ -22,38 +19,27 @@ bind_interrupts!(struct Irqs {
22#[embassy_executor::main] 19#[embassy_executor::main]
23async fn main(_spawner: Spawner) { 20async fn main(_spawner: Spawner) {
24 let mut config = Config::default(); 21 let mut config = Config::default();
25 22 {
26 // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE. 23 use embassy_stm32::rcc::*;
27 const USE_HSI48: bool = true;
28
29 let plldivq = if USE_HSI48 { None } else { Some(PllQDiv::DIV6) };
30
31 config.rcc.hse = Some(Hse {
32 freq: Hertz(8_000_000),
33 mode: HseMode::Oscillator,
34 });
35
36 config.rcc.pll = Some(Pll {
37 source: Pllsrc::HSE,
38 prediv: PllPreDiv::DIV2,
39 mul: PllMul::MUL72,
40 divp: None,
41 divq: plldivq,
42 // Main system clock at 144 MHz
43 divr: Some(PllRDiv::DIV2),
44 });
45
46 config.rcc.sys = Sysclk::PLL1_R;
47 config.rcc.boost = true; // BOOST!
48
49 if USE_HSI48 {
50 // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator. 24 // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator.
51 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); 25 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true });
52 config.rcc.clk48_src = Clk48Src::HSI48; 26 config.rcc.hse = Some(Hse {
53 } else { 27 freq: Hertz(8_000_000),
54 config.rcc.clk48_src = Clk48Src::PLL1_Q; 28 mode: HseMode::Oscillator,
29 });
30 config.rcc.pll = Some(Pll {
31 source: Pllsrc::HSE,
32 prediv: PllPreDiv::DIV2,
33 mul: PllMul::MUL72,
34 divp: None,
35 divq: Some(PllQDiv::DIV6), // 48mhz
36 divr: Some(PllRDiv::DIV2), // Main system clock at 144 MHz
37 });
38 config.rcc.sys = Sysclk::PLL1_R;
39 config.rcc.boost = true; // BOOST!
40 config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
41 //config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; // uncomment to use PLL1_Q instead.
55 } 42 }
56
57 let p = embassy_stm32::init(config); 43 let p = embassy_stm32::init(config);
58 44
59 info!("Hello World!"); 45 info!("Hello World!");
diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs
index e5ccfe4f7..643df27f9 100644
--- a/examples/stm32h5/src/bin/can.rs
+++ b/examples/stm32h5/src/bin/can.rs
@@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) {
20 freq: embassy_stm32::time::Hertz(25_000_000), 20 freq: embassy_stm32::time::Hertz(25_000_000),
21 mode: rcc::HseMode::Oscillator, 21 mode: rcc::HseMode::Oscillator,
22 }); 22 });
23 config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; 23 config.rcc.mux.fdcan12sel = rcc::mux::Fdcansel::HSE;
24 24
25 let peripherals = embassy_stm32::init(config); 25 let peripherals = embassy_stm32::init(config);
26 26
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
index 208493d8c..83477c8fa 100644
--- a/examples/stm32h5/src/bin/usb_serial.rs
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -5,7 +5,7 @@ use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::time::Hertz; 6use embassy_stm32::time::Hertz;
7use embassy_stm32::usb::{Driver, Instance}; 7use embassy_stm32::usb::{Driver, Instance};
8use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
9use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
10use embassy_usb::driver::EndpointError; 10use embassy_usb::driver::EndpointError;
11use embassy_usb::Builder; 11use embassy_usb::Builder;
@@ -41,15 +41,12 @@ async fn main(_spawner: Spawner) {
41 config.rcc.apb3_pre = APBPrescaler::DIV4; 41 config.rcc.apb3_pre = APBPrescaler::DIV4;
42 config.rcc.sys = Sysclk::PLL1_P; 42 config.rcc.sys = Sysclk::PLL1_P;
43 config.rcc.voltage_scale = VoltageScale::Scale0; 43 config.rcc.voltage_scale = VoltageScale::Scale0;
44 config.rcc.mux.usbsel = mux::Usbsel::HSI48;
44 } 45 }
45 let p = embassy_stm32::init(config); 46 let p = embassy_stm32::init(config);
46 47
47 info!("Hello World!"); 48 info!("Hello World!");
48 49
49 pac::RCC.ccipr4().write(|w| {
50 w.set_usbsel(pac::rcc::vals::Usbsel::HSI48);
51 });
52
53 // Create the driver, from the HAL. 50 // Create the driver, from the HAL.
54 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); 51 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
55 52
diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs
index f0278239f..a5594d10c 100644
--- a/examples/stm32h7/src/bin/adc.rs
+++ b/examples/stm32h7/src/bin/adc.rs
@@ -38,7 +38,7 @@ async fn main(_spawner: Spawner) {
38 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz 38 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
39 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz 39 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
40 config.rcc.voltage_scale = VoltageScale::Scale1; 40 config.rcc.voltage_scale = VoltageScale::Scale1;
41 config.rcc.adc_clock_source = AdcClockSource::PLL2_P; 41 config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
42 } 42 }
43 let mut p = embassy_stm32::init(config); 43 let mut p = embassy_stm32::init(config);
44 44
diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs
index e5ccfe4f7..13a6a5051 100644
--- a/examples/stm32h7/src/bin/can.rs
+++ b/examples/stm32h7/src/bin/can.rs
@@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) {
20 freq: embassy_stm32::time::Hertz(25_000_000), 20 freq: embassy_stm32::time::Hertz(25_000_000),
21 mode: rcc::HseMode::Oscillator, 21 mode: rcc::HseMode::Oscillator,
22 }); 22 });
23 config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; 23 config.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
24 24
25 let peripherals = embassy_stm32::init(config); 25 let peripherals = embassy_stm32::init(config);
26 26
diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs
index a9bf46de0..a6f969aba 100644
--- a/examples/stm32h7/src/bin/dac.rs
+++ b/examples/stm32h7/src/bin/dac.rs
@@ -40,7 +40,7 @@ fn main() -> ! {
40 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz 40 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
41 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz 41 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
42 config.rcc.voltage_scale = VoltageScale::Scale1; 42 config.rcc.voltage_scale = VoltageScale::Scale1;
43 config.rcc.adc_clock_source = AdcClockSource::PLL2_P; 43 config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
44 } 44 }
45 let p = embassy_stm32::init(config); 45 let p = embassy_stm32::init(config);
46 46
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs
index d88bd838f..feec28993 100644
--- a/examples/stm32h7/src/bin/dac_dma.rs
+++ b/examples/stm32h7/src/bin/dac_dma.rs
@@ -42,7 +42,7 @@ async fn main(spawner: Spawner) {
42 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz 42 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
43 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz 43 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
44 config.rcc.voltage_scale = VoltageScale::Scale1; 44 config.rcc.voltage_scale = VoltageScale::Scale1;
45 config.rcc.adc_clock_source = AdcClockSource::PLL2_P; 45 config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
46 } 46 }
47 47
48 // Initialize the board and obtain a Peripherals instance 48 // Initialize the board and obtain a Peripherals instance
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs
index 910944673..a9f4604aa 100644
--- a/examples/stm32l4/src/bin/adc.rs
+++ b/examples/stm32l4/src/bin/adc.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::adc::{Adc, Resolution}; 5use embassy_stm32::adc::{Adc, Resolution};
6use embassy_stm32::pac; 6use embassy_stm32::Config;
7use embassy_time::Delay; 7use embassy_time::Delay;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
@@ -11,12 +11,12 @@ use {defmt_rtt as _, panic_probe as _};
11fn main() -> ! { 11fn main() -> ! {
12 info!("Hello World!"); 12 info!("Hello World!");
13 13
14 pac::RCC.ccipr().modify(|w| { 14 let mut config = Config::default();
15 w.set_adcsel(pac::rcc::vals::Adcsel::SYS); 15 {
16 }); 16 use embassy_stm32::rcc::*;
17 pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); 17 config.rcc.mux.adcsel = mux::Adcsel::SYS;
18 18 }
19 let p = embassy_stm32::init(Default::default()); 19 let p = embassy_stm32::init(config);
20 20
21 let mut adc = Adc::new(p.ADC1, &mut Delay); 21 let mut adc = Adc::new(p.ADC1, &mut Delay);
22 //adc.enable_vref(); 22 //adc.enable_vref();
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 828a28e2c..bfe003a11 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -16,8 +16,8 @@ stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] 16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"]
17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] 17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"]
18stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"] 18stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"]
19stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash"] 19stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"]
20stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash"] 20stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"]
21stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] 21stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"]
22stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] 22stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"]
23stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] 23stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"]
@@ -33,6 +33,7 @@ stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"]
33stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"] 33stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"]
34stm32h503rb = ["embassy-stm32/stm32h503rb", "rng"] 34stm32h503rb = ["embassy-stm32/stm32h503rb", "rng"]
35 35
36cryp = []
36hash = [] 37hash = []
37eth = ["embassy-executor/task-arena-size-16384"] 38eth = ["embassy-executor/task-arena-size-16384"]
38rng = [] 39rng = []
@@ -80,6 +81,7 @@ portable-atomic = { version = "1.5", features = [] }
80chrono = { version = "^0.4", default-features = false, optional = true} 81chrono = { version = "^0.4", default-features = false, optional = true}
81sha2 = { version = "0.10.8", default-features = false } 82sha2 = { version = "0.10.8", default-features = false }
82hmac = "0.12.1" 83hmac = "0.12.1"
84aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] }
83 85
84# BEGIN TESTS 86# BEGIN TESTS
85# Generated by gen_test.py. DO NOT EDIT. 87# Generated by gen_test.py. DO NOT EDIT.
@@ -89,6 +91,11 @@ path = "src/bin/can.rs"
89required-features = [ "can",] 91required-features = [ "can",]
90 92
91[[bin]] 93[[bin]]
94name = "cryp"
95path = "src/bin/cryp.rs"
96required-features = [ "cryp",]
97
98[[bin]]
92name = "dac" 99name = "dac"
93path = "src/bin/dac.rs" 100path = "src/bin/dac.rs"
94required-features = [ "dac",] 101required-features = [ "dac",]
diff --git a/tests/stm32/src/bin/cryp.rs b/tests/stm32/src/bin/cryp.rs
new file mode 100644
index 000000000..f105abf26
--- /dev/null
+++ b/tests/stm32/src/bin/cryp.rs
@@ -0,0 +1,69 @@
1// required-features: cryp
2#![no_std]
3#![no_main]
4
5#[path = "../common.rs"]
6mod common;
7
8use aes_gcm::aead::heapless::Vec;
9use aes_gcm::aead::{AeadInPlace, KeyInit};
10use aes_gcm::Aes128Gcm;
11use common::*;
12use embassy_executor::Spawner;
13use embassy_stm32::cryp::*;
14use {defmt_rtt as _, panic_probe as _};
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let p: embassy_stm32::Peripherals = embassy_stm32::init(config());
19
20 const PAYLOAD1: &[u8] = b"payload data 1 ;zdfhzdfhS;GKJASBDG;ASKDJBAL,zdfhzdfhzdfhzdfhvljhb,jhbjhb,sdhsdghsdhsfhsghzdfhzdfhzdfhzdfdhsdthsthsdhsgaadfhhgkdgfuoyguoft6783567";
21 const PAYLOAD2: &[u8] = b"payload data 2 ;SKEzdfhzdfhzbhgvljhb,jhbjhb,sdhsdghsdhsfhsghshsfhshstsdthadfhsdfjhsfgjsfgjxfgjzdhgDFghSDGHjtfjtjszftjzsdtjhstdsdhsdhsdhsdhsdthsthsdhsgfh";
22 const AAD1: &[u8] = b"additional data 1 stdargadrhaethaethjatjatjaetjartjstrjsfkk;'jopofyuisrteytweTASTUIKFUKIXTRDTEREharhaeryhaterjartjarthaethjrtjarthaetrhartjatejatrjsrtjartjyt1";
23 const AAD2: &[u8] = b"additional data 2 stdhthsthsthsrthsrthsrtjdykjdukdyuldadfhsdghsdghsdghsadghjk'hioethjrtjarthaetrhartjatecfgjhzdfhgzdfhzdfghzdfhzdfhzfhjatrjsrtjartjytjfytjfyg";
24
25 let hw_cryp = Cryp::new(p.CRYP);
26 let key: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
27 let mut ciphertext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()];
28 let mut plaintext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()];
29 let iv: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
30
31 // Encrypt in hardware using AES-GCM 128-bit
32 let aes_gcm = AesGcm::new(&key, &iv);
33 let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt);
34 hw_cryp.aad_blocking(&mut gcm_encrypt, AAD1, false);
35 hw_cryp.aad_blocking(&mut gcm_encrypt, AAD2, true);
36 hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD1, &mut ciphertext[..PAYLOAD1.len()], false);
37 hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD2, &mut ciphertext[PAYLOAD1.len()..], true);
38 let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt);
39
40 // Decrypt in hardware using AES-GCM 128-bit
41 let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt);
42 hw_cryp.aad_blocking(&mut gcm_decrypt, AAD1, false);
43 hw_cryp.aad_blocking(&mut gcm_decrypt, AAD2, true);
44 hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true);
45 let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt);
46
47 info!("AES-GCM Ciphertext: {:?}", ciphertext);
48 info!("AES-GCM Plaintext: {:?}", plaintext);
49 defmt::assert!(PAYLOAD1 == &plaintext[..PAYLOAD1.len()]);
50 defmt::assert!(PAYLOAD2 == &plaintext[PAYLOAD1.len()..]);
51 defmt::assert!(encrypt_tag == decrypt_tag);
52
53 // Encrypt in software using AES-GCM 128-bit
54 let mut payload_vec: Vec<u8, { PAYLOAD1.len() + PAYLOAD2.len() + 16 }> = Vec::from_slice(&PAYLOAD1).unwrap();
55 payload_vec.extend_from_slice(&PAYLOAD2).unwrap();
56 let cipher = Aes128Gcm::new(&key.into());
57 let mut aad: Vec<u8, { AAD1.len() + AAD2.len() }> = Vec::from_slice(&AAD1).unwrap();
58 aad.extend_from_slice(&AAD2).unwrap();
59 let _ = cipher.encrypt_in_place(&iv.into(), &aad, &mut payload_vec);
60
61 defmt::assert!(ciphertext == payload_vec[0..ciphertext.len()]);
62 defmt::assert!(encrypt_tag == payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]);
63
64 // Decrypt in software using AES-GCM 128-bit
65 let _ = cipher.decrypt_in_place(&iv.into(), &aad, &mut payload_vec);
66
67 info!("Test OK");
68 cortex_m::asm::bkpt();
69}
diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs
index f21aa797c..dd78d7fb3 100644
--- a/tests/stm32/src/bin/fdcan.rs
+++ b/tests/stm32/src/bin/fdcan.rs
@@ -33,7 +33,7 @@ fn options() -> TestOptions {
33 freq: embassy_stm32::time::Hertz(25_000_000), 33 freq: embassy_stm32::time::Hertz(25_000_000),
34 mode: rcc::HseMode::Oscillator, 34 mode: rcc::HseMode::Oscillator,
35 }); 35 });
36 c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; 36 c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
37 TestOptions { 37 TestOptions {
38 config: c, 38 config: c,
39 max_latency: Duration::from_micros(1200), 39 max_latency: Duration::from_micros(1200),
@@ -50,7 +50,7 @@ fn options() -> TestOptions {
50 freq: embassy_stm32::time::Hertz(25_000_000), 50 freq: embassy_stm32::time::Hertz(25_000_000),
51 mode: rcc::HseMode::Oscillator, 51 mode: rcc::HseMode::Oscillator,
52 }); 52 });
53 c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; 53 c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
54 TestOptions { 54 TestOptions {
55 config: c, 55 config: c,
56 max_latency: Duration::from_micros(1200), 56 max_latency: Duration::from_micros(1200),
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index 7b9585afd..cf3e04a4b 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -2,6 +2,8 @@
2 2
3pub use defmt::*; 3pub use defmt::*;
4#[allow(unused)] 4#[allow(unused)]
5use embassy_stm32::rcc::*;
6#[allow(unused)]
5use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
6use embassy_stm32::Config; 8use embassy_stm32::Config;
7use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
@@ -265,7 +267,6 @@ pub fn config() -> Config {
265 267
266 #[cfg(feature = "stm32f091rc")] 268 #[cfg(feature = "stm32f091rc")]
267 { 269 {
268 use embassy_stm32::rcc::*;
269 config.rcc.hse = Some(Hse { 270 config.rcc.hse = Some(Hse {
270 freq: Hertz(8_000_000), 271 freq: Hertz(8_000_000),
271 mode: HseMode::Bypass, 272 mode: HseMode::Bypass,
@@ -281,7 +282,6 @@ pub fn config() -> Config {
281 } 282 }
282 #[cfg(feature = "stm32f103c8")] 283 #[cfg(feature = "stm32f103c8")]
283 { 284 {
284 use embassy_stm32::rcc::*;
285 config.rcc.hse = Some(Hse { 285 config.rcc.hse = Some(Hse {
286 freq: Hertz(8_000_000), 286 freq: Hertz(8_000_000),
287 mode: HseMode::Oscillator, 287 mode: HseMode::Oscillator,
@@ -298,7 +298,6 @@ pub fn config() -> Config {
298 } 298 }
299 #[cfg(feature = "stm32f207zg")] 299 #[cfg(feature = "stm32f207zg")]
300 { 300 {
301 use embassy_stm32::rcc::*;
302 // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal) 301 // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal)
303 config.rcc.hse = Some(Hse { 302 config.rcc.hse = Some(Hse {
304 freq: Hertz(8_000_000), 303 freq: Hertz(8_000_000),
@@ -327,7 +326,6 @@ pub fn config() -> Config {
327 326
328 #[cfg(feature = "stm32f303ze")] 327 #[cfg(feature = "stm32f303ze")]
329 { 328 {
330 use embassy_stm32::rcc::*;
331 config.rcc.hse = Some(Hse { 329 config.rcc.hse = Some(Hse {
332 freq: Hertz(8_000_000), 330 freq: Hertz(8_000_000),
333 mode: HseMode::Bypass, 331 mode: HseMode::Bypass,
@@ -345,7 +343,6 @@ pub fn config() -> Config {
345 343
346 #[cfg(feature = "stm32f429zi")] 344 #[cfg(feature = "stm32f429zi")]
347 { 345 {
348 use embassy_stm32::rcc::*;
349 config.rcc.hse = Some(Hse { 346 config.rcc.hse = Some(Hse {
350 freq: Hertz(8_000_000), 347 freq: Hertz(8_000_000),
351 mode: HseMode::Bypass, 348 mode: HseMode::Bypass,
@@ -366,7 +363,6 @@ pub fn config() -> Config {
366 363
367 #[cfg(feature = "stm32f446re")] 364 #[cfg(feature = "stm32f446re")]
368 { 365 {
369 use embassy_stm32::rcc::*;
370 config.rcc.hse = Some(Hse { 366 config.rcc.hse = Some(Hse {
371 freq: Hertz(8_000_000), 367 freq: Hertz(8_000_000),
372 mode: HseMode::Oscillator, 368 mode: HseMode::Oscillator,
@@ -387,7 +383,6 @@ pub fn config() -> Config {
387 383
388 #[cfg(feature = "stm32f767zi")] 384 #[cfg(feature = "stm32f767zi")]
389 { 385 {
390 use embassy_stm32::rcc::*;
391 config.rcc.hse = Some(Hse { 386 config.rcc.hse = Some(Hse {
392 freq: Hertz(8_000_000), 387 freq: Hertz(8_000_000),
393 mode: HseMode::Bypass, 388 mode: HseMode::Bypass,
@@ -408,7 +403,6 @@ pub fn config() -> Config {
408 403
409 #[cfg(feature = "stm32h563zi")] 404 #[cfg(feature = "stm32h563zi")]
410 { 405 {
411 use embassy_stm32::rcc::*;
412 config.rcc.hsi = None; 406 config.rcc.hsi = None;
413 config.rcc.hsi48 = Some(Default::default()); // needed for RNG 407 config.rcc.hsi48 = Some(Default::default()); // needed for RNG
414 config.rcc.hse = Some(Hse { 408 config.rcc.hse = Some(Hse {
@@ -433,7 +427,6 @@ pub fn config() -> Config {
433 427
434 #[cfg(feature = "stm32h503rb")] 428 #[cfg(feature = "stm32h503rb")]
435 { 429 {
436 use embassy_stm32::rcc::*;
437 config.rcc.hsi = None; 430 config.rcc.hsi = None;
438 config.rcc.hsi48 = Some(Default::default()); // needed for RNG 431 config.rcc.hsi48 = Some(Default::default()); // needed for RNG
439 config.rcc.hse = Some(Hse { 432 config.rcc.hse = Some(Hse {
@@ -456,9 +449,26 @@ pub fn config() -> Config {
456 config.rcc.voltage_scale = VoltageScale::Scale0; 449 config.rcc.voltage_scale = VoltageScale::Scale0;
457 } 450 }
458 451
452 #[cfg(feature = "stm32g491re")]
453 {
454 config.rcc.hse = Some(Hse {
455 freq: Hertz(24_000_000),
456 mode: HseMode::Oscillator,
457 });
458 config.rcc.pll = Some(Pll {
459 source: Pllsrc::HSE,
460 prediv: PllPreDiv::DIV6,
461 mul: PllMul::MUL85,
462 divp: None,
463 divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan.
464 divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz
465 });
466 config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q;
467 config.rcc.sys = Sysclk::PLL1_R;
468 }
469
459 #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))] 470 #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))]
460 { 471 {
461 use embassy_stm32::rcc::*;
462 config.rcc.hsi = Some(HSIPrescaler::DIV1); 472 config.rcc.hsi = Some(HSIPrescaler::DIV1);
463 config.rcc.csi = true; 473 config.rcc.csi = true;
464 config.rcc.hsi48 = Some(Default::default()); // needed for RNG 474 config.rcc.hsi48 = Some(Default::default()); // needed for RNG
@@ -485,7 +495,7 @@ pub fn config() -> Config {
485 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz 495 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
486 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz 496 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
487 config.rcc.voltage_scale = VoltageScale::Scale1; 497 config.rcc.voltage_scale = VoltageScale::Scale1;
488 config.rcc.adc_clock_source = AdcClockSource::PLL2_P; 498 config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
489 #[cfg(any(feature = "stm32h755zi"))] 499 #[cfg(any(feature = "stm32h755zi"))]
490 { 500 {
491 config.rcc.supply_config = SupplyConfig::DirectSMPS; 501 config.rcc.supply_config = SupplyConfig::DirectSMPS;
@@ -494,7 +504,6 @@ pub fn config() -> Config {
494 504
495 #[cfg(any(feature = "stm32h7a3zi"))] 505 #[cfg(any(feature = "stm32h7a3zi"))]
496 { 506 {
497 use embassy_stm32::rcc::*;
498 config.rcc.hsi = Some(HSIPrescaler::DIV1); 507 config.rcc.hsi = Some(HSIPrescaler::DIV1);
499 config.rcc.csi = true; 508 config.rcc.csi = true;
500 config.rcc.hsi48 = Some(Default::default()); // needed for RNG 509 config.rcc.hsi48 = Some(Default::default()); // needed for RNG
@@ -521,12 +530,11 @@ pub fn config() -> Config {
521 config.rcc.apb3_pre = APBPrescaler::DIV2; // 140 Mhz 530 config.rcc.apb3_pre = APBPrescaler::DIV2; // 140 Mhz
522 config.rcc.apb4_pre = APBPrescaler::DIV2; // 140 Mhz 531 config.rcc.apb4_pre = APBPrescaler::DIV2; // 140 Mhz
523 config.rcc.voltage_scale = VoltageScale::Scale0; 532 config.rcc.voltage_scale = VoltageScale::Scale0;
524 config.rcc.adc_clock_source = AdcClockSource::PLL2_P; 533 config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
525 } 534 }
526 535
527 #[cfg(any(feature = "stm32l496zg", feature = "stm32l4a6zg", feature = "stm32l4r5zi"))] 536 #[cfg(any(feature = "stm32l496zg", feature = "stm32l4a6zg", feature = "stm32l4r5zi"))]
528 { 537 {
529 use embassy_stm32::rcc::*;
530 config.rcc.sys = Sysclk::PLL1_R; 538 config.rcc.sys = Sysclk::PLL1_R;
531 config.rcc.hsi = true; 539 config.rcc.hsi = true;
532 config.rcc.pll = Some(Pll { 540 config.rcc.pll = Some(Pll {
@@ -541,7 +549,6 @@ pub fn config() -> Config {
541 549
542 #[cfg(feature = "stm32wl55jc")] 550 #[cfg(feature = "stm32wl55jc")]
543 { 551 {
544 use embassy_stm32::rcc::*;
545 config.rcc.hse = Some(Hse { 552 config.rcc.hse = Some(Hse {
546 freq: Hertz(32_000_000), 553 freq: Hertz(32_000_000),
547 mode: HseMode::Bypass, 554 mode: HseMode::Bypass,
@@ -560,7 +567,6 @@ pub fn config() -> Config {
560 567
561 #[cfg(any(feature = "stm32l552ze"))] 568 #[cfg(any(feature = "stm32l552ze"))]
562 { 569 {
563 use embassy_stm32::rcc::*;
564 config.rcc.hsi = true; 570 config.rcc.hsi = true;
565 config.rcc.sys = Sysclk::PLL1_R; 571 config.rcc.sys = Sysclk::PLL1_R;
566 config.rcc.pll = Some(Pll { 572 config.rcc.pll = Some(Pll {
@@ -576,7 +582,6 @@ pub fn config() -> Config {
576 582
577 #[cfg(any(feature = "stm32u585ai", feature = "stm32u5a5zj"))] 583 #[cfg(any(feature = "stm32u585ai", feature = "stm32u5a5zj"))]
578 { 584 {
579 use embassy_stm32::rcc::*;
580 config.rcc.hsi = true; 585 config.rcc.hsi = true;
581 config.rcc.pll1 = Some(Pll { 586 config.rcc.pll1 = Some(Pll {
582 source: PllSource::HSI, // 16 MHz 587 source: PllSource::HSI, // 16 MHz
@@ -593,17 +598,12 @@ pub fn config() -> Config {
593 598
594 #[cfg(feature = "stm32wba52cg")] 599 #[cfg(feature = "stm32wba52cg")]
595 { 600 {
596 use embassy_stm32::rcc::*;
597 config.rcc.sys = Sysclk::HSI; 601 config.rcc.sys = Sysclk::HSI;
598 602 config.rcc.mux.rngsel = mux::Rngsel::HSI;
599 embassy_stm32::pac::RCC.ccipr2().write(|w| {
600 w.set_rngsel(embassy_stm32::pac::rcc::vals::Rngsel::HSI);
601 });
602 } 603 }
603 604
604 #[cfg(feature = "stm32l073rz")] 605 #[cfg(feature = "stm32l073rz")]
605 { 606 {
606 use embassy_stm32::rcc::*;
607 config.rcc.hsi = true; 607 config.rcc.hsi = true;
608 config.rcc.pll = Some(Pll { 608 config.rcc.pll = Some(Pll {
609 source: PllSource::HSI, 609 source: PllSource::HSI,
@@ -615,7 +615,6 @@ pub fn config() -> Config {
615 615
616 #[cfg(any(feature = "stm32l152re"))] 616 #[cfg(any(feature = "stm32l152re"))]
617 { 617 {
618 use embassy_stm32::rcc::*;
619 config.rcc.hsi = true; 618 config.rcc.hsi = true;
620 config.rcc.pll = Some(Pll { 619 config.rcc.pll = Some(Pll {
621 source: PllSource::HSI, 620 source: PllSource::HSI,