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 include::example$basic/src/main.rs[lines="1..2"] ---- -=== Rust Nightly - -The next declaration is a Rust Unstable feature, which means that Embassy requires Rust Nightly: - -[source,rust] ----- -include::example$basic/src/main.rs[lines="3"] ----- - === Dealing with errors Then, 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: [source,rust] ---- -include::example$basic/src/main.rs[lines="10"] +include::example$basic/src/main.rs[lines="8"] ---- === Task declaration @@ -41,7 +32,7 @@ After a bit of import declaration, the tasks run by the application should be de [source,rust] ---- -include::example$basic/src/main.rs[lines="12..20"] +include::example$basic/src/main.rs[lines="10..18"] ---- An 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` [source,rust] ---- -include::example$basic/src/main.rs[lines="22..-1"] +include::example$basic/src/main.rs[lines="20..-1"] ---- What 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" document-features = "0.2.7" -# needed for riscv and avr -# remove when https://github.com/rust-lang/rust/pull/114499 lands on stable (on 1.76) +# needed for AVR portable-atomic = { version = "1.5", optional = true } # arch-cortex-m dependencies @@ -78,7 +77,7 @@ arch-std = ["_arch", "critical-section/std"] ## Cortex-M arch-cortex-m = ["_arch", "dep:cortex-m"] ## RISC-V 32 -arch-riscv32 = ["_arch", "dep:portable-atomic"] +arch-riscv32 = ["_arch"] ## WASM arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"] ## 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::*; #[cfg(feature = "executor-thread")] mod thread { use core::marker::PhantomData; + use core::sync::atomic::{AtomicBool, Ordering}; pub use embassy_executor_macros::main_riscv as main; - use portable_atomic::{AtomicBool, Ordering}; use crate::{raw, Spawner}; 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" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a0bcec33362449fb733c066936d25cbabab396a" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] } proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a0bcec33362449fb733c066936d25cbabab396a", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d", default-features = false, features = ["metadata"]} [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}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; -use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccKernelClock, StopMode, METADATA}; +use stm32_metapac::metadata::{ + MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, METADATA, +}; fn main() { let target = env::var("TARGET").unwrap(); @@ -374,12 +376,130 @@ fn main() { } } - let force_refcount = HashSet::from(["usart"]); - let mut refcount_statics = BTreeSet::new(); + struct ClockGen<'a> { + rcc_registers: &'a PeripheralRegisters, + chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>, + force_refcount: HashSet<&'a str>, - let mut clock_names = BTreeSet::new(); + refcount_statics: BTreeSet, + clock_names: BTreeSet, + muxes: BTreeSet<(Ident, Ident, Ident)>, + } - let mut rcc_cfgr_regs = BTreeSet::new(); + let mut clock_gen = ClockGen { + rcc_registers, + chained_muxes: HashMap::new(), + force_refcount: HashSet::from(["usart"]), + + refcount_statics: BTreeSet::new(), + clock_names: BTreeSet::new(), + muxes: BTreeSet::new(), + }; + if chip_name.starts_with("stm32h5") { + clock_gen.chained_muxes.insert( + "PER", + &PeripheralRccRegister { + register: "CCIPR5", + field: "PERSEL", + }, + ); + } + if chip_name.starts_with("stm32h7") { + clock_gen.chained_muxes.insert( + "PER", + &PeripheralRccRegister { + register: "D1CCIPR", + field: "PERSEL", + }, + ); + } + if chip_name.starts_with("stm32u5") { + clock_gen.chained_muxes.insert( + "ICLK", + &PeripheralRccRegister { + register: "CCIPR1", + field: "ICLKSEL", + }, + ); + } + if chip_name.starts_with("stm32wb") && !chip_name.starts_with("stm32wba") { + clock_gen.chained_muxes.insert( + "CLK48", + &PeripheralRccRegister { + register: "CCIPR", + field: "CLK48SEL", + }, + ); + } + if chip_name.starts_with("stm32f7") { + clock_gen.chained_muxes.insert( + "CLK48", + &PeripheralRccRegister { + register: "DCKCFGR2", + field: "CLK48SEL", + }, + ); + } + if chip_name.starts_with("stm32f4") && !chip_name.starts_with("stm32f410") { + clock_gen.chained_muxes.insert( + "CLK48", + &PeripheralRccRegister { + register: "DCKCFGR", + field: "CLK48SEL", + }, + ); + } + + impl<'a> ClockGen<'a> { + fn gen_clock(&mut self, name: &str) -> TokenStream { + let clock_name = format_ident!("{}", name.to_ascii_lowercase()); + self.clock_names.insert(name.to_ascii_lowercase()); + quote!( unsafe { crate::rcc::get_freqs().#clock_name.unwrap() } ) + } + + fn gen_mux(&mut self, mux: &PeripheralRccRegister) -> TokenStream { + let ir = &self.rcc_registers.ir; + let fieldset_name = mux.register.to_ascii_lowercase(); + let fieldset = ir + .fieldsets + .iter() + .find(|i| i.name.eq_ignore_ascii_case(&fieldset_name)) + .unwrap(); + let field_name = mux.field.to_ascii_lowercase(); + let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap(); + let enum_name = field.enumm.unwrap(); + let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap(); + + let fieldset_name = format_ident!("{}", fieldset_name); + let field_name = format_ident!("{}", field_name); + let enum_name = format_ident!("{}", enum_name); + + self.muxes + .insert((fieldset_name.clone(), field_name.clone(), enum_name.clone())); + + let mut match_arms = TokenStream::new(); + + for v in enumm.variants.iter().filter(|v| v.name != "DISABLE") { + let variant_name = format_ident!("{}", v.name); + let expr = if let Some(mux) = self.chained_muxes.get(&v.name) { + self.gen_mux(mux) + } else { + self.gen_clock(&v.name) + }; + match_arms.extend(quote! { + crate::pac::rcc::vals::#enum_name::#variant_name => #expr, + }); + } + + quote! { + match crate::pac::RCC.#fieldset_name().read().#field_name() { + #match_arms + #[allow(unreachable_patterns)] + _ => unreachable!(), + } + } + } + } for p in METADATA.peripherals { if !singletons.contains(&p.name.to_string()) { @@ -416,12 +536,12 @@ fn main() { let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); let refcount = - force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1; + clock_gen.force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1; let (before_enable, before_disable) = if refcount { let refcount_static = format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); - refcount_statics.insert(refcount_static.clone()); + clock_gen.refcount_statics.insert(refcount_static.clone()); ( quote! { @@ -442,63 +562,12 @@ fn main() { }; let clock_frequency = match &rcc.kernel_clock { - PeripheralRccKernelClock::Mux(mux) => { - let ir = &rcc_registers.ir; - let fieldset_name = mux.register.to_ascii_lowercase(); - let fieldset = ir - .fieldsets - .iter() - .find(|i| i.name.eq_ignore_ascii_case(&fieldset_name)) - .unwrap(); - let field_name = mux.field.to_ascii_lowercase(); - let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap(); - let enum_name = field.enumm.unwrap(); - let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap(); - - let fieldset_name = format_ident!("{}", fieldset_name); - let field_name = format_ident!("{}", field_name); - let enum_name = format_ident!("{}", enum_name); - - rcc_cfgr_regs.insert((fieldset_name.clone(), field_name.clone(), enum_name.clone())); - - let match_arms: TokenStream = enumm - .variants - .iter() - .filter(|v| v.name != "DISABLE") - .map(|v| { - let variant_name = format_ident!("{}", v.name); - let clock_name = format_ident!("{}", v.name.to_ascii_lowercase()); - clock_names.insert(v.name.to_ascii_lowercase()); - quote! { - #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() }, - } - }) - .collect(); - - quote! { - use crate::pac::rcc::vals::#enum_name; - - #[allow(unreachable_patterns)] - match crate::pac::RCC.#fieldset_name().read().#field_name() { - #match_arms - _ => unreachable!(), - } - } - } - PeripheralRccKernelClock::Clock(clock) => { - let clock = clock.to_ascii_lowercase(); - let clock_name = format_ident!("{}", clock); - clock_names.insert(clock.to_string()); - quote! { - unsafe { crate::rcc::get_freqs().#clock_name.unwrap() } - } - } + PeripheralRccKernelClock::Mux(mux) => clock_gen.gen_mux(mux), + PeripheralRccKernelClock::Clock(clock) => clock_gen.gen_clock(clock), }; - /* - A refcount leak can result if the same field is shared by peripherals with different stop modes - This condition should be checked in stm32-data - */ + // A refcount leak can result if the same field is shared by peripherals with different stop modes + // This condition should be checked in stm32-data let stop_refcount = match rcc.stop_mode { StopMode::Standby => None, StopMode::Stop2 => Some(quote! { REFCOUNT_STOP2 }), @@ -543,74 +612,79 @@ fn main() { } } - if !rcc_cfgr_regs.is_empty() { - println!("cargo:rustc-cfg=clock_mux"); + let struct_fields: Vec<_> = clock_gen + .muxes + .iter() + .map(|(_fieldset, fieldname, enum_name)| { + quote! { + pub #fieldname: #enum_name + } + }) + .collect(); - let struct_fields: Vec<_> = rcc_cfgr_regs + let mut inits = TokenStream::new(); + for fieldset in clock_gen + .muxes + .iter() + .map(|(f, _, _)| f) + .collect::>() + .into_iter() + { + let setters: Vec<_> = clock_gen + .muxes .iter() - .map(|(_fieldset, fieldname, enum_name)| { - quote! { - pub #fieldname: Option<#enum_name> - } - }) - .collect(); - - let field_names: Vec<_> = rcc_cfgr_regs - .iter() - .map(|(_fieldset, fieldname, _enum_name)| fieldname) - .collect(); - - let inits: Vec<_> = rcc_cfgr_regs - .iter() - .map(|(fieldset, fieldname, _enum_name)| { + .filter(|(f, _, _)| f == fieldset) + .map(|(_, fieldname, _)| { let setter = format_ident!("set_{}", fieldname); quote! { - match self.#fieldname { - None => {} - Some(val) => { - crate::pac::RCC.#fieldset() - .modify(|w| w.#setter(val)); - } - }; + w.#setter(self.#fieldname); } }) .collect(); - let enum_names: BTreeSet<_> = rcc_cfgr_regs - .iter() - .map(|(_fieldset, _fieldname, enum_name)| enum_name) - .collect(); - - g.extend(quote! { - pub mod mux { - #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )* - - #[derive(Clone, Copy)] - pub struct ClockMux { - #( #struct_fields, )* - } - - impl Default for ClockMux { - fn default() -> Self { - Self { - #( #field_names: None, )* - } - } - } - - impl ClockMux { - pub fn init(self) { - #( #inits )* - } - } - } - }); + inits.extend(quote! { + crate::pac::RCC.#fieldset().modify(|w| { + #(#setters)* + }); + }) } + let enum_names: BTreeSet<_> = clock_gen.muxes.iter().map(|(_, _, enum_name)| enum_name).collect(); + + g.extend(quote! { + pub mod mux { + #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )* + + #[derive(Clone, Copy)] + pub struct ClockMux { + #( #struct_fields, )* + } + + impl ClockMux { + pub(crate) const fn default() -> Self { + // safety: zero value is valid for all PAC enums. + unsafe { ::core::mem::zeroed() } + } + } + + impl Default for ClockMux { + fn default() -> Self { + Self::default() + } + } + + impl ClockMux { + pub(crate) fn init(&self) { + #inits + } + } + } + }); + // Generate RCC - clock_names.insert("sys".to_string()); - clock_names.insert("rtc".to_string()); - let clock_idents: Vec<_> = clock_names.iter().map(|n| format_ident!("{}", n)).collect(); + clock_gen.clock_names.insert("sys".to_string()); + clock_gen.clock_names.insert("rtc".to_string()); + let clock_idents: Vec<_> = clock_gen.clock_names.iter().map(|n| format_ident!("{}", n)).collect(); g.extend(quote! { #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -640,7 +714,8 @@ fn main() { } ); - let refcount_mod: TokenStream = refcount_statics + let refcount_mod: TokenStream = clock_gen + .refcount_statics .iter() .map(|refcount_static| { 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 } /// Sender that can be used for sending CAN frames. -pub type BufferedCanSender = embassy_sync::channel::DynamicSender<'static, ClassicFrame>; +#[derive(Copy, Clone)] +pub struct BufferedCanSender { + tx_buf: embassy_sync::channel::DynamicSender<'static, ClassicFrame>, + waker: fn(), +} + +impl BufferedCanSender { + /// Async write frame to TX buffer. + pub fn try_write(&mut self, frame: ClassicFrame) -> Result<(), embassy_sync::channel::TrySendError> { + self.tx_buf.try_send(frame)?; + (self.waker)(); + Ok(()) + } + + /// Async write frame to TX buffer. + pub async fn write(&mut self, frame: ClassicFrame) { + self.tx_buf.send(frame).await; + (self.waker)(); + } + + /// Allows a poll_fn to poll until the channel is ready to write + pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> { + self.tx_buf.poll_ready_to_send(cx) + } +} /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. pub 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> /// Returns a sender that can be used for sending CAN frames. pub fn writer(&self) -> BufferedCanSender { - self.tx_buf.sender().into() + BufferedCanSender { + tx_buf: self.tx_buf.sender().into(), + waker: T::IT0Interrupt::pend, + } } /// 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 } /// Sender that can be used for sending CAN frames. -pub type BufferedFdCanSender = embassy_sync::channel::DynamicSender<'static, FdFrame>; +#[derive(Copy, Clone)] +pub struct BufferedFdCanSender { + tx_buf: embassy_sync::channel::DynamicSender<'static, FdFrame>, + waker: fn(), +} + +impl BufferedFdCanSender { + /// Async write frame to TX buffer. + pub fn try_write(&mut self, frame: FdFrame) -> Result<(), embassy_sync::channel::TrySendError> { + self.tx_buf.try_send(frame)?; + (self.waker)(); + Ok(()) + } + + /// Async write frame to TX buffer. + pub async fn write(&mut self, frame: FdFrame) { + self.tx_buf.send(frame).await; + (self.waker)(); + } + + /// Allows a poll_fn to poll until the channel is ready to write + pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> { + self.tx_buf.poll_ready_to_send(cx) + } +} /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. pub 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> /// Returns a sender that can be used for sending CAN frames. pub fn writer(&self) -> BufferedFdCanSender { - self.tx_buf.sender().into() + BufferedFdCanSender { + tx_buf: self.tx_buf.sender().into(), + waker: T::IT0Interrupt::pend, + } } /// 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 { fn is_extended(&self) -> bool { match self.can_header.id { embedded_can::Id::Extended(_) => true, - embedded_can::Id::Standard(_) => true, + embedded_can::Id::Standard(_) => false, } } fn is_remote_frame(&self) -> bool { @@ -369,7 +369,7 @@ impl embedded_can::Frame for FdFrame { fn is_extended(&self) -> bool { match self.can_header.id { embedded_can::Id::Extended(_) => true, - embedded_can::Id::Standard(_) => true, + embedded_can::Id::Standard(_) => false, } } 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 @@ +//! Crypto Accelerator (CRYP) +#[cfg(any(cryp_v2, cryp_v3))] +use core::cmp::min; +use core::marker::PhantomData; + +use embassy_hal_internal::{into_ref, PeripheralRef}; + +use crate::{interrupt, pac, peripherals, Peripheral}; + +const DES_BLOCK_SIZE: usize = 8; // 64 bits +const AES_BLOCK_SIZE: usize = 16; // 128 bits + +/// This trait encapsulates all cipher-specific behavior/ +pub trait Cipher<'c> { + /// Processing block size. Determined by the processor and the algorithm. + const BLOCK_SIZE: usize; + + /// Indicates whether the cipher requires the application to provide padding. + /// If `true`, no partial blocks will be accepted (a panic will occur). + const REQUIRES_PADDING: bool = false; + + /// Returns the symmetric key. + fn key(&self) -> &[u8]; + + /// Returns the initialization vector. + fn iv(&self) -> &[u8]; + + /// Sets the processor algorithm mode according to the associated cipher. + fn set_algomode(&self, p: &pac::cryp::Cryp); + + /// Performs any key preparation within the processor, if necessary. + fn prepare_key(&self, _p: &pac::cryp::Cryp) {} + + /// Performs any cipher-specific initialization. + fn init_phase(&self, _p: &pac::cryp::Cryp) {} + + /// Called prior to processing the last data block for cipher-specific operations. + fn pre_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] { + return [0; 4]; + } + + /// Called after processing the last data block for cipher-specific operations. + fn post_final_block( + &self, + _p: &pac::cryp::Cryp, + _dir: Direction, + _int_data: &mut [u8; AES_BLOCK_SIZE], + _temp1: [u32; 4], + _padding_mask: [u8; 16], + ) { + } + + /// Called prior to processing the first associated data block for cipher-specific operations. + fn get_header_block(&self) -> &[u8] { + return [0; 0].as_slice(); + } +} + +/// This trait enables restriction of ciphers to specific key sizes. +pub trait CipherSized {} + +/// This trait enables restriction of initialization vectors to sizes compatibile with a cipher mode. +pub trait IVSized {} + +/// This trait enables restriction of a header phase to authenticated ciphers only. +pub trait CipherAuthenticated { + /// Defines the authentication tag size. + const TAG_SIZE: usize = TAG_SIZE; +} + +/// TDES-ECB Cipher Mode +pub struct TdesEcb<'c, const KEY_SIZE: usize> { + iv: &'c [u8; 0], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> TdesEcb<'c, KEY_SIZE> { + /// Constructs a new AES-ECB cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE]) -> Self { + return Self { key: key, iv: &[0; 0] }; + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesEcb<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = DES_BLOCK_SIZE; + const REQUIRES_PADDING: bool = true; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &'c [u8] { + self.iv + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(0)); + } + #[cfg(any(cryp_v2, cryp_v3))] + { + p.cr().modify(|w| w.set_algomode0(0)); + p.cr().modify(|w| w.set_algomode3(false)); + } + } +} + +impl<'c> CipherSized for TdesEcb<'c, { 112 / 8 }> {} +impl<'c> CipherSized for TdesEcb<'c, { 168 / 8 }> {} +impl<'c, const KEY_SIZE: usize> IVSized for TdesEcb<'c, KEY_SIZE> {} + +/// TDES-CBC Cipher Mode +pub struct TdesCbc<'c, const KEY_SIZE: usize> { + iv: &'c [u8; 8], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> TdesCbc<'c, KEY_SIZE> { + /// Constructs a new TDES-CBC cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 8]) -> Self { + return Self { key: key, iv: iv }; + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesCbc<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = DES_BLOCK_SIZE; + const REQUIRES_PADDING: bool = true; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &'c [u8] { + self.iv + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(1)); + } + #[cfg(any(cryp_v2, cryp_v3))] + { + p.cr().modify(|w| w.set_algomode0(1)); + p.cr().modify(|w| w.set_algomode3(false)); + } + } +} + +impl<'c> CipherSized for TdesCbc<'c, { 112 / 8 }> {} +impl<'c> CipherSized for TdesCbc<'c, { 168 / 8 }> {} +impl<'c, const KEY_SIZE: usize> IVSized for TdesCbc<'c, KEY_SIZE> {} + +/// DES-ECB Cipher Mode +pub struct DesEcb<'c, const KEY_SIZE: usize> { + iv: &'c [u8; 0], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> DesEcb<'c, KEY_SIZE> { + /// Constructs a new AES-ECB cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE]) -> Self { + return Self { key: key, iv: &[0; 0] }; + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesEcb<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = DES_BLOCK_SIZE; + const REQUIRES_PADDING: bool = true; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &'c [u8] { + self.iv + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(2)); + } + #[cfg(any(cryp_v2, cryp_v3))] + { + p.cr().modify(|w| w.set_algomode0(2)); + p.cr().modify(|w| w.set_algomode3(false)); + } + } +} + +impl<'c> CipherSized for DesEcb<'c, { 56 / 8 }> {} +impl<'c, const KEY_SIZE: usize> IVSized for DesEcb<'c, KEY_SIZE> {} + +/// DES-CBC Cipher Mode +pub struct DesCbc<'c, const KEY_SIZE: usize> { + iv: &'c [u8; 8], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> DesCbc<'c, KEY_SIZE> { + /// Constructs a new AES-CBC cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 8]) -> Self { + return Self { key: key, iv: iv }; + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesCbc<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = DES_BLOCK_SIZE; + const REQUIRES_PADDING: bool = true; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &'c [u8] { + self.iv + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(3)); + } + #[cfg(any(cryp_v2, cryp_v3))] + { + p.cr().modify(|w| w.set_algomode0(3)); + p.cr().modify(|w| w.set_algomode3(false)); + } + } +} + +impl<'c> CipherSized for DesCbc<'c, { 56 / 8 }> {} +impl<'c, const KEY_SIZE: usize> IVSized for DesCbc<'c, KEY_SIZE> {} + +/// AES-ECB Cipher Mode +pub struct AesEcb<'c, const KEY_SIZE: usize> { + iv: &'c [u8; 0], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> AesEcb<'c, KEY_SIZE> { + /// Constructs a new AES-ECB cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE]) -> Self { + return Self { key: key, iv: &[0; 0] }; + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = AES_BLOCK_SIZE; + const REQUIRES_PADDING: bool = true; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &'c [u8] { + self.iv + } + + fn prepare_key(&self, p: &pac::cryp::Cryp) { + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(7)); + } + #[cfg(any(cryp_v2, cryp_v3))] + { + p.cr().modify(|w| w.set_algomode0(7)); + p.cr().modify(|w| w.set_algomode3(false)); + } + p.cr().modify(|w| w.set_crypen(true)); + while p.sr().read().busy() {} + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(2)); + } + #[cfg(any(cryp_v2, cryp_v3))] + { + p.cr().modify(|w| w.set_algomode0(2)); + p.cr().modify(|w| w.set_algomode3(false)); + } + } +} + +impl<'c> CipherSized for AesEcb<'c, { 128 / 8 }> {} +impl<'c> CipherSized for AesEcb<'c, { 192 / 8 }> {} +impl<'c> CipherSized for AesEcb<'c, { 256 / 8 }> {} +impl<'c, const KEY_SIZE: usize> IVSized for AesEcb<'c, KEY_SIZE> {} + +/// AES-CBC Cipher Mode +pub struct AesCbc<'c, const KEY_SIZE: usize> { + iv: &'c [u8; 16], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> AesCbc<'c, KEY_SIZE> { + /// Constructs a new AES-CBC cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 16]) -> Self { + return Self { key: key, iv: iv }; + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = AES_BLOCK_SIZE; + const REQUIRES_PADDING: bool = true; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &'c [u8] { + self.iv + } + + fn prepare_key(&self, p: &pac::cryp::Cryp) { + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(7)); + } + #[cfg(any(cryp_v2, cryp_v3))] + { + p.cr().modify(|w| w.set_algomode0(7)); + p.cr().modify(|w| w.set_algomode3(false)); + } + p.cr().modify(|w| w.set_crypen(true)); + while p.sr().read().busy() {} + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(5)); + } + #[cfg(any(cryp_v2, cryp_v3))] + { + p.cr().modify(|w| w.set_algomode0(5)); + p.cr().modify(|w| w.set_algomode3(false)); + } + } +} + +impl<'c> CipherSized for AesCbc<'c, { 128 / 8 }> {} +impl<'c> CipherSized for AesCbc<'c, { 192 / 8 }> {} +impl<'c> CipherSized for AesCbc<'c, { 256 / 8 }> {} +impl<'c, const KEY_SIZE: usize> IVSized for AesCbc<'c, KEY_SIZE> {} + +/// AES-CTR Cipher Mode +pub struct AesCtr<'c, const KEY_SIZE: usize> { + iv: &'c [u8; 16], + key: &'c [u8; KEY_SIZE], +} + +impl<'c, const KEY_SIZE: usize> AesCtr<'c, KEY_SIZE> { + /// Constructs a new AES-CTR cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 16]) -> Self { + return Self { key: key, iv: iv }; + } +} + +impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCtr<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = AES_BLOCK_SIZE; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &'c [u8] { + self.iv + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + #[cfg(cryp_v1)] + { + p.cr().modify(|w| w.set_algomode(6)); + } + #[cfg(any(cryp_v2, cryp_v3))] + { + p.cr().modify(|w| w.set_algomode0(6)); + p.cr().modify(|w| w.set_algomode3(false)); + } + } +} + +impl<'c> CipherSized for AesCtr<'c, { 128 / 8 }> {} +impl<'c> CipherSized for AesCtr<'c, { 192 / 8 }> {} +impl<'c> CipherSized for AesCtr<'c, { 256 / 8 }> {} +impl<'c, const KEY_SIZE: usize> IVSized for AesCtr<'c, KEY_SIZE> {} + +#[cfg(any(cryp_v2, cryp_v3))] +///AES-GCM Cipher Mode +pub struct AesGcm<'c, const KEY_SIZE: usize> { + iv: [u8; 16], + key: &'c [u8; KEY_SIZE], +} + +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> { + /// Constucts a new AES-GCM cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self { + let mut new_gcm = Self { key: key, iv: [0; 16] }; + new_gcm.iv[..12].copy_from_slice(iv); + new_gcm.iv[15] = 2; + new_gcm + } +} + +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = AES_BLOCK_SIZE; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &[u8] { + self.iv.as_slice() + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_algomode0(0)); + p.cr().modify(|w| w.set_algomode3(true)); + } + + fn init_phase(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_gcm_ccmph(0)); + p.cr().modify(|w| w.set_crypen(true)); + while p.cr().read().crypen() {} + } + + #[cfg(cryp_v2)] + fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { + //Handle special GCM partial block process. + if dir == Direction::Encrypt { + p.cr().modify(|w| w.set_crypen(false)); + p.cr().modify(|w| w.set_algomode3(false)); + p.cr().modify(|w| w.set_algomode0(6)); + let iv1r = p.csgcmccmr(7).read() - 1; + p.init(1).ivrr().write_value(iv1r); + p.cr().modify(|w| w.set_crypen(true)); + } + [0; 4] + } + + #[cfg(cryp_v3)] + fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { + //Handle special GCM partial block process. + p.cr().modify(|w| w.set_npblb(padding_len as u8)); + [0; 4] + } + + #[cfg(cryp_v2)] + fn post_final_block( + &self, + p: &pac::cryp::Cryp, + dir: Direction, + int_data: &mut [u8; AES_BLOCK_SIZE], + _temp1: [u32; 4], + padding_mask: [u8; AES_BLOCK_SIZE], + ) { + if dir == Direction::Encrypt { + //Handle special GCM partial block process. + p.cr().modify(|w| w.set_crypen(false)); + p.cr().modify(|w| w.set_algomode3(true)); + p.cr().modify(|w| w.set_algomode0(0)); + for i in 0..AES_BLOCK_SIZE { + int_data[i] = int_data[i] & padding_mask[i]; + } + p.cr().modify(|w| w.set_crypen(true)); + p.cr().modify(|w| w.set_gcm_ccmph(3)); + let mut index = 0; + let end_index = Self::BLOCK_SIZE; + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&int_data[index..index + 4]); + p.din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + for _ in 0..4 { + p.dout().read(); + } + } + } +} + +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c> CipherSized for AesGcm<'c, { 128 / 8 }> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c> CipherSized for AesGcm<'c, { 192 / 8 }> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c> CipherSized for AesGcm<'c, { 256 / 8 }> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGcm<'c, KEY_SIZE> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize> IVSized for AesGcm<'c, KEY_SIZE> {} + +#[cfg(any(cryp_v2, cryp_v3))] +/// AES-GMAC Cipher Mode +pub struct AesGmac<'c, const KEY_SIZE: usize> { + iv: [u8; 16], + key: &'c [u8; KEY_SIZE], +} + +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> { + /// Constructs a new AES-GMAC cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self { + let mut new_gmac = Self { key: key, iv: [0; 16] }; + new_gmac.iv[..12].copy_from_slice(iv); + new_gmac.iv[15] = 2; + new_gmac + } +} + +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { + const BLOCK_SIZE: usize = AES_BLOCK_SIZE; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &[u8] { + self.iv.as_slice() + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_algomode0(0)); + p.cr().modify(|w| w.set_algomode3(true)); + } + + fn init_phase(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_gcm_ccmph(0)); + p.cr().modify(|w| w.set_crypen(true)); + while p.cr().read().crypen() {} + } + + #[cfg(cryp_v2)] + fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { + //Handle special GCM partial block process. + if dir == Direction::Encrypt { + p.cr().modify(|w| w.set_crypen(false)); + p.cr().modify(|w| w.set_algomode3(false)); + p.cr().modify(|w| w.set_algomode0(6)); + let iv1r = p.csgcmccmr(7).read() - 1; + p.init(1).ivrr().write_value(iv1r); + p.cr().modify(|w| w.set_crypen(true)); + } + [0; 4] + } + + #[cfg(cryp_v3)] + fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { + //Handle special GCM partial block process. + p.cr().modify(|w| w.set_npblb(padding_len as u8)); + [0; 4] + } + + #[cfg(cryp_v2)] + fn post_final_block( + &self, + p: &pac::cryp::Cryp, + dir: Direction, + int_data: &mut [u8; AES_BLOCK_SIZE], + _temp1: [u32; 4], + padding_mask: [u8; AES_BLOCK_SIZE], + ) { + if dir == Direction::Encrypt { + //Handle special GCM partial block process. + p.cr().modify(|w| w.set_crypen(false)); + p.cr().modify(|w| w.set_algomode3(true)); + p.cr().modify(|w| w.set_algomode0(0)); + for i in 0..AES_BLOCK_SIZE { + int_data[i] = int_data[i] & padding_mask[i]; + } + p.cr().modify(|w| w.set_crypen(true)); + p.cr().modify(|w| w.set_gcm_ccmph(3)); + let mut index = 0; + let end_index = Self::BLOCK_SIZE; + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&int_data[index..index + 4]); + p.din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + for _ in 0..4 { + p.dout().read(); + } + } + } +} + +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c> CipherSized for AesGmac<'c, { 128 / 8 }> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c> CipherSized for AesGmac<'c, { 192 / 8 }> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c> CipherSized for AesGmac<'c, { 256 / 8 }> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGmac<'c, KEY_SIZE> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize> IVSized for AesGmac<'c, KEY_SIZE> {} + +#[cfg(any(cryp_v2, cryp_v3))] +/// AES-CCM Cipher Mode +pub struct AesCcm<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> { + key: &'c [u8; KEY_SIZE], + aad_header: [u8; 6], + aad_header_len: usize, + block0: [u8; 16], + ctr: [u8; 16], +} + +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE> { + /// Constructs a new AES-CCM cipher for a cryptographic operation. + pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; IV_SIZE], aad_len: usize, payload_len: usize) -> Self { + let mut aad_header: [u8; 6] = [0; 6]; + let mut aad_header_len = 0; + let mut block0: [u8; 16] = [0; 16]; + if aad_len != 0 { + if aad_len < 65280 { + aad_header[0] = (aad_len >> 8) as u8 & 0xFF; + aad_header[1] = aad_len as u8 & 0xFF; + aad_header_len = 2; + } else { + aad_header[0] = 0xFF; + aad_header[1] = 0xFE; + let aad_len_bytes: [u8; 4] = aad_len.to_be_bytes(); + aad_header[2] = aad_len_bytes[0]; + aad_header[3] = aad_len_bytes[1]; + aad_header[4] = aad_len_bytes[2]; + aad_header[5] = aad_len_bytes[3]; + aad_header_len = 6; + } + } + let total_aad_len = aad_header_len + aad_len; + let mut aad_padding_len = 16 - (total_aad_len % 16); + if aad_padding_len == 16 { + aad_padding_len = 0; + } + aad_header_len += aad_padding_len; + let total_aad_len_padded = aad_header_len + aad_len; + if total_aad_len_padded > 0 { + block0[0] = 0x40; + } + block0[0] |= ((((TAG_SIZE as u8) - 2) >> 1) & 0x07) << 3; + block0[0] |= ((15 - (iv.len() as u8)) - 1) & 0x07; + block0[1..1 + iv.len()].copy_from_slice(iv); + let payload_len_bytes: [u8; 4] = payload_len.to_be_bytes(); + if iv.len() <= 11 { + block0[12] = payload_len_bytes[0]; + } else if payload_len_bytes[0] > 0 { + panic!("Message is too large for given IV size."); + } + if iv.len() <= 12 { + block0[13] = payload_len_bytes[1]; + } else if payload_len_bytes[1] > 0 { + panic!("Message is too large for given IV size."); + } + block0[14] = payload_len_bytes[2]; + block0[15] = payload_len_bytes[3]; + let mut ctr: [u8; 16] = [0; 16]; + ctr[0] = block0[0] & 0x07; + ctr[1..1 + iv.len()].copy_from_slice(&block0[1..1 + iv.len()]); + ctr[15] = 0x01; + + return Self { + key: key, + aad_header: aad_header, + aad_header_len: aad_header_len, + block0: block0, + ctr: ctr, + }; + } +} + +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cipher<'c> + for AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE> +{ + const BLOCK_SIZE: usize = AES_BLOCK_SIZE; + + fn key(&self) -> &'c [u8] { + self.key + } + + fn iv(&self) -> &[u8] { + self.ctr.as_slice() + } + + fn set_algomode(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_algomode0(1)); + p.cr().modify(|w| w.set_algomode3(true)); + } + + fn init_phase(&self, p: &pac::cryp::Cryp) { + p.cr().modify(|w| w.set_gcm_ccmph(0)); + + let mut index = 0; + let end_index = index + Self::BLOCK_SIZE; + // Write block in + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&self.block0[index..index + 4]); + p.din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + p.cr().modify(|w| w.set_crypen(true)); + while p.cr().read().crypen() {} + } + + fn get_header_block(&self) -> &[u8] { + return &self.aad_header[0..self.aad_header_len]; + } + + #[cfg(cryp_v2)] + fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { + //Handle special CCM partial block process. + let mut temp1 = [0; 4]; + if dir == Direction::Decrypt { + p.cr().modify(|w| w.set_crypen(false)); + let iv1temp = p.init(1).ivrr().read(); + temp1[0] = p.csgcmccmr(0).read().swap_bytes(); + temp1[1] = p.csgcmccmr(1).read().swap_bytes(); + temp1[2] = p.csgcmccmr(2).read().swap_bytes(); + temp1[3] = p.csgcmccmr(3).read().swap_bytes(); + p.init(1).ivrr().write_value(iv1temp); + p.cr().modify(|w| w.set_algomode3(false)); + p.cr().modify(|w| w.set_algomode0(6)); + p.cr().modify(|w| w.set_crypen(true)); + } + return temp1; + } + + #[cfg(cryp_v3)] + fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { + //Handle special GCM partial block process. + p.cr().modify(|w| w.set_npblb(padding_len as u8)); + [0; 4] + } + + #[cfg(cryp_v2)] + fn post_final_block( + &self, + p: &pac::cryp::Cryp, + dir: Direction, + int_data: &mut [u8; AES_BLOCK_SIZE], + temp1: [u32; 4], + padding_mask: [u8; 16], + ) { + if dir == Direction::Decrypt { + //Handle special CCM partial block process. + let mut temp2 = [0; 4]; + temp2[0] = p.csgcmccmr(0).read().swap_bytes(); + temp2[1] = p.csgcmccmr(1).read().swap_bytes(); + temp2[2] = p.csgcmccmr(2).read().swap_bytes(); + temp2[3] = p.csgcmccmr(3).read().swap_bytes(); + p.cr().modify(|w| w.set_algomode3(true)); + p.cr().modify(|w| w.set_algomode0(1)); + p.cr().modify(|w| w.set_gcm_ccmph(3)); + // Header phase + p.cr().modify(|w| w.set_gcm_ccmph(1)); + for i in 0..AES_BLOCK_SIZE { + int_data[i] = int_data[i] & padding_mask[i]; + } + let mut in_data: [u32; 4] = [0; 4]; + for i in 0..in_data.len() { + let mut int_bytes: [u8; 4] = [0; 4]; + int_bytes.copy_from_slice(&int_data[(i * 4)..(i * 4) + 4]); + let int_word = u32::from_le_bytes(int_bytes); + in_data[i] = int_word; + in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i]; + p.din().write_value(in_data[i]); + } + } + } +} + +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 128 / 8 }, TAG_SIZE, IV_SIZE> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 192 / 8 }, TAG_SIZE, IV_SIZE> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 256 / 8 }, TAG_SIZE, IV_SIZE> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<4> for AesCcm<'c, KEY_SIZE, 4, IV_SIZE> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<6> for AesCcm<'c, KEY_SIZE, 6, IV_SIZE> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<8> for AesCcm<'c, KEY_SIZE, 8, IV_SIZE> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<10> for AesCcm<'c, KEY_SIZE, 10, IV_SIZE> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<12> for AesCcm<'c, KEY_SIZE, 12, IV_SIZE> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<14> for AesCcm<'c, KEY_SIZE, 14, IV_SIZE> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<16> for AesCcm<'c, KEY_SIZE, 16, IV_SIZE> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 7> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 8> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 9> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 10> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 11> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 12> {} +#[cfg(any(cryp_v2, cryp_v3))] +impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 13> {} + +#[allow(dead_code)] +/// Holds the state information for a cipher operation. +/// Allows suspending/resuming of cipher operations. +pub struct Context<'c, C: Cipher<'c> + CipherSized> { + phantom_data: PhantomData<&'c C>, + cipher: &'c C, + dir: Direction, + last_block_processed: bool, + header_processed: bool, + aad_complete: bool, + cr: u32, + iv: [u32; 4], + csgcmccm: [u32; 8], + csgcm: [u32; 8], + header_len: u64, + payload_len: u64, + aad_buffer: [u8; 16], + aad_buffer_len: usize, +} + +/// Selects whether the crypto processor operates in encryption or decryption mode. +#[derive(PartialEq, Clone, Copy)] +pub enum Direction { + /// Encryption mode + Encrypt, + /// Decryption mode + Decrypt, +} + +/// Crypto Accelerator Driver +pub struct Cryp<'d, T: Instance> { + _peripheral: PeripheralRef<'d, T>, +} + +impl<'d, T: Instance> Cryp<'d, T> { + /// Create a new CRYP driver. + pub fn new(peri: impl Peripheral

+ 'd) -> Self { + T::enable_and_reset(); + into_ref!(peri); + let instance = Self { _peripheral: peri }; + instance + } + + /// Start a new cipher operation. + /// Key size must be 128, 192, or 256 bits. + /// Initialization vector must only be supplied if necessary. + /// Panics if there is any mismatch in parameters, such as an incorrect IV length or invalid mode. + pub fn start<'c, C: Cipher<'c> + CipherSized + IVSized>(&self, cipher: &'c C, dir: Direction) -> Context<'c, C> { + let mut ctx: Context<'c, C> = Context { + dir, + last_block_processed: false, + cr: 0, + iv: [0; 4], + csgcmccm: [0; 8], + csgcm: [0; 8], + aad_complete: false, + header_len: 0, + payload_len: 0, + cipher: cipher, + phantom_data: PhantomData, + header_processed: false, + aad_buffer: [0; 16], + aad_buffer_len: 0, + }; + + T::regs().cr().modify(|w| w.set_crypen(false)); + + let key = ctx.cipher.key(); + + if key.len() == (128 / 8) { + T::regs().cr().modify(|w| w.set_keysize(0)); + } else if key.len() == (192 / 8) { + T::regs().cr().modify(|w| w.set_keysize(1)); + } else if key.len() == (256 / 8) { + T::regs().cr().modify(|w| w.set_keysize(2)); + } + + self.load_key(key); + + // Set data type to 8-bit. This will match software implementations. + T::regs().cr().modify(|w| w.set_datatype(2)); + + ctx.cipher.prepare_key(&T::regs()); + + ctx.cipher.set_algomode(&T::regs()); + + // Set encrypt/decrypt + if dir == Direction::Encrypt { + T::regs().cr().modify(|w| w.set_algodir(false)); + } else { + T::regs().cr().modify(|w| w.set_algodir(true)); + } + + // Load the IV into the registers. + let iv = ctx.cipher.iv(); + let mut full_iv: [u8; 16] = [0; 16]; + full_iv[0..iv.len()].copy_from_slice(iv); + let mut iv_idx = 0; + let mut iv_word: [u8; 4] = [0; 4]; + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word)); + + // Flush in/out FIFOs + T::regs().cr().modify(|w| w.fflush()); + + ctx.cipher.init_phase(&T::regs()); + + self.store_context(&mut ctx); + + ctx + } + + #[cfg(any(cryp_v2, cryp_v3))] + /// Controls the header phase of cipher processing. + /// This function is only valid for GCM, CCM, and GMAC modes. + /// It only needs to be called if using one of these modes and there is associated data. + /// All AAD must be supplied to this function prior to starting the payload phase with `payload_blocking`. + /// The AAD must be supplied in multiples of the block size (128 bits), except when supplying the last block. + /// When supplying the last block of AAD, `last_aad_block` must be `true`. + pub fn aad_blocking< + 'c, + const TAG_SIZE: usize, + C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated, + >( + &self, + ctx: &mut Context<'c, C>, + aad: &[u8], + last_aad_block: bool, + ) { + self.load_context(ctx); + + // Perform checks for correctness. + if ctx.aad_complete { + panic!("Cannot update AAD after starting payload!") + } + + ctx.header_len += aad.len() as u64; + + // Header phase + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(1)); + T::regs().cr().modify(|w| w.set_crypen(true)); + + // First write the header B1 block if not yet written. + if !ctx.header_processed { + ctx.header_processed = true; + let header = ctx.cipher.get_header_block(); + ctx.aad_buffer[0..header.len()].copy_from_slice(header); + ctx.aad_buffer_len += header.len(); + } + + // Fill the header block to make a full block. + let len_to_copy = min(aad.len(), C::BLOCK_SIZE - ctx.aad_buffer_len); + ctx.aad_buffer[ctx.aad_buffer_len..ctx.aad_buffer_len + len_to_copy].copy_from_slice(&aad[..len_to_copy]); + ctx.aad_buffer_len += len_to_copy; + ctx.aad_buffer[ctx.aad_buffer_len..].fill(0); + let mut aad_len_remaining = aad.len() - len_to_copy; + + if ctx.aad_buffer_len < C::BLOCK_SIZE { + // The buffer isn't full and this is the last buffer, so process it as is (already padded). + if last_aad_block { + let mut index = 0; + let end_index = C::BLOCK_SIZE; + // Write block in + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]); + T::regs().din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + // Block until input FIFO is empty. + while !T::regs().sr().read().ifem() {} + + // Switch to payload phase. + ctx.aad_complete = true; + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); + T::regs().cr().modify(|w| w.fflush()); + } else { + // Just return because we don't yet have a full block to process. + return; + } + } else { + // Load the full block from the buffer. + let mut index = 0; + let end_index = C::BLOCK_SIZE; + // Write block in + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]); + T::regs().din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + // Block until input FIFO is empty. + while !T::regs().sr().read().ifem() {} + } + + // Handle a partial block that is passed in. + ctx.aad_buffer_len = 0; + let leftovers = aad_len_remaining % C::BLOCK_SIZE; + ctx.aad_buffer[..leftovers].copy_from_slice(&aad[aad.len() - leftovers..aad.len()]); + ctx.aad_buffer_len += leftovers; + ctx.aad_buffer[ctx.aad_buffer_len..].fill(0); + aad_len_remaining -= leftovers; + assert_eq!(aad_len_remaining % C::BLOCK_SIZE, 0); + + // Load full data blocks into core. + let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE; + for block in 0..num_full_blocks { + let mut index = len_to_copy + (block * C::BLOCK_SIZE); + let end_index = index + C::BLOCK_SIZE; + // Write block in + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&aad[index..index + 4]); + T::regs().din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + // Block until input FIFO is empty. + while !T::regs().sr().read().ifem() {} + } + + if last_aad_block { + if leftovers > 0 { + let mut index = 0; + let end_index = C::BLOCK_SIZE; + // Write block in + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]); + T::regs().din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + // Block until input FIFO is empty. + while !T::regs().sr().read().ifem() {} + } + // Switch to payload phase. + ctx.aad_complete = true; + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); + T::regs().cr().modify(|w| w.fflush()); + } + + self.store_context(ctx); + } + + /// Performs encryption/decryption on the provided context. + /// The context determines algorithm, mode, and state of the crypto accelerator. + /// When the last piece of data is supplied, `last_block` should be `true`. + /// This function panics under various mismatches of parameters. + /// Input and output buffer lengths must match. + /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes. + /// Padding or ciphertext stealing must be managed by the application for these modes. + /// Data must also be a multiple of block size unless `last_block` is `true`. + pub fn payload_blocking<'c, C: Cipher<'c> + CipherSized + IVSized>( + &self, + ctx: &mut Context<'c, C>, + input: &[u8], + output: &mut [u8], + last_block: bool, + ) { + self.load_context(ctx); + + let last_block_remainder = input.len() % C::BLOCK_SIZE; + + // Perform checks for correctness. + if !ctx.aad_complete && ctx.header_len > 0 { + panic!("Additional associated data must be processed first!"); + } else if !ctx.aad_complete { + #[cfg(any(cryp_v2, cryp_v3))] + { + ctx.aad_complete = true; + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); + T::regs().cr().modify(|w| w.fflush()); + T::regs().cr().modify(|w| w.set_crypen(true)); + } + } + if ctx.last_block_processed { + panic!("The last block has already been processed!"); + } + if input.len() > output.len() { + panic!("Output buffer length must match input length."); + } + if !last_block { + if last_block_remainder != 0 { + panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE); + } + } + if C::REQUIRES_PADDING { + if last_block_remainder != 0 { + panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); + } + } + if last_block { + ctx.last_block_processed = true; + } + + // Load data into core, block by block. + let num_full_blocks = input.len() / C::BLOCK_SIZE; + for block in 0..num_full_blocks { + let mut index = block * C::BLOCK_SIZE; + let end_index = index + C::BLOCK_SIZE; + // Write block in + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&input[index..index + 4]); + T::regs().din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + let mut index = block * C::BLOCK_SIZE; + let end_index = index + C::BLOCK_SIZE; + // Block until there is output to read. + while !T::regs().sr().read().ofne() {} + // Read block out + while index < end_index { + let out_word: u32 = T::regs().dout().read(); + output[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice()); + index += 4; + } + } + + // Handle the final block, which is incomplete. + if last_block_remainder > 0 { + let padding_len = C::BLOCK_SIZE - last_block_remainder; + let temp1 = ctx.cipher.pre_final_block(&T::regs(), ctx.dir, padding_len); + + let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; + let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; + last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]); + let mut index = 0; + let end_index = C::BLOCK_SIZE; + // Write block in + while index < end_index { + let mut in_word: [u8; 4] = [0; 4]; + in_word.copy_from_slice(&last_block[index..index + 4]); + T::regs().din().write_value(u32::from_ne_bytes(in_word)); + index += 4; + } + let mut index = 0; + let end_index = C::BLOCK_SIZE; + // Block until there is output to read. + while !T::regs().sr().read().ofne() {} + // Read block out + while index < end_index { + let out_word: u32 = T::regs().dout().read(); + intermediate_data[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice()); + index += 4; + } + + // Handle the last block depending on mode. + let output_len = output.len(); + output[output_len - last_block_remainder..output_len] + .copy_from_slice(&intermediate_data[0..last_block_remainder]); + + let mut mask: [u8; 16] = [0; 16]; + mask[..last_block_remainder].fill(0xFF); + ctx.cipher + .post_final_block(&T::regs(), ctx.dir, &mut intermediate_data, temp1, mask); + } + + ctx.payload_len += input.len() as u64; + + self.store_context(ctx); + } + + #[cfg(any(cryp_v2, cryp_v3))] + /// This function only needs to be called for GCM, CCM, and GMAC modes to + /// generate an authentication tag. + pub fn finish_blocking< + 'c, + const TAG_SIZE: usize, + C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated, + >( + &self, + mut ctx: Context<'c, C>, + ) -> [u8; TAG_SIZE] { + self.load_context(&mut ctx); + + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(3)); + T::regs().cr().modify(|w| w.set_crypen(true)); + + let headerlen1: u32 = ((ctx.header_len * 8) >> 32) as u32; + let headerlen2: u32 = (ctx.header_len * 8) as u32; + let payloadlen1: u32 = ((ctx.payload_len * 8) >> 32) as u32; + let payloadlen2: u32 = (ctx.payload_len * 8) as u32; + + #[cfg(cryp_v2)] + { + T::regs().din().write_value(headerlen1.swap_bytes()); + T::regs().din().write_value(headerlen2.swap_bytes()); + T::regs().din().write_value(payloadlen1.swap_bytes()); + T::regs().din().write_value(payloadlen2.swap_bytes()); + } + + #[cfg(cryp_v3)] + { + T::regs().din().write_value(headerlen1); + T::regs().din().write_value(headerlen2); + T::regs().din().write_value(payloadlen1); + T::regs().din().write_value(payloadlen2); + } + + while !T::regs().sr().read().ofne() {} + + let mut full_tag: [u8; 16] = [0; 16]; + full_tag[0..4].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); + full_tag[4..8].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); + full_tag[8..12].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); + full_tag[12..16].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); + let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE]; + tag.copy_from_slice(&full_tag[0..TAG_SIZE]); + + T::regs().cr().modify(|w| w.set_crypen(false)); + + tag + } + + fn load_key(&self, key: &[u8]) { + // Load the key into the registers. + let mut keyidx = 0; + let mut keyword: [u8; 4] = [0; 4]; + let keylen = key.len() * 8; + if keylen > 192 { + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(0).klr().write_value(u32::from_be_bytes(keyword)); + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(0).krr().write_value(u32::from_be_bytes(keyword)); + } + if keylen > 128 { + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(1).klr().write_value(u32::from_be_bytes(keyword)); + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(1).krr().write_value(u32::from_be_bytes(keyword)); + } + if keylen > 64 { + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(2).klr().write_value(u32::from_be_bytes(keyword)); + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(2).krr().write_value(u32::from_be_bytes(keyword)); + } + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(3).klr().write_value(u32::from_be_bytes(keyword)); + keyword = [0; 4]; + keyword[0..key.len() - keyidx].copy_from_slice(&key[keyidx..key.len()]); + T::regs().key(3).krr().write_value(u32::from_be_bytes(keyword)); + } + + fn store_context<'c, C: Cipher<'c> + CipherSized>(&self, ctx: &mut Context<'c, C>) { + // Wait for data block processing to finish. + while !T::regs().sr().read().ifem() {} + while T::regs().sr().read().ofne() {} + while T::regs().sr().read().busy() {} + + // Disable crypto processor. + T::regs().cr().modify(|w| w.set_crypen(false)); + + // Save the peripheral state. + ctx.cr = T::regs().cr().read().0; + ctx.iv[0] = T::regs().init(0).ivlr().read(); + ctx.iv[1] = T::regs().init(0).ivrr().read(); + ctx.iv[2] = T::regs().init(1).ivlr().read(); + ctx.iv[3] = T::regs().init(1).ivrr().read(); + + #[cfg(any(cryp_v2, cryp_v3))] + for i in 0..8 { + ctx.csgcmccm[i] = T::regs().csgcmccmr(i).read(); + ctx.csgcm[i] = T::regs().csgcmr(i).read(); + } + } + + fn load_context<'c, C: Cipher<'c> + CipherSized>(&self, ctx: &Context<'c, C>) { + // Reload state registers. + T::regs().cr().write(|w| w.0 = ctx.cr); + T::regs().init(0).ivlr().write_value(ctx.iv[0]); + T::regs().init(0).ivrr().write_value(ctx.iv[1]); + T::regs().init(1).ivlr().write_value(ctx.iv[2]); + T::regs().init(1).ivrr().write_value(ctx.iv[3]); + + #[cfg(any(cryp_v2, cryp_v3))] + for i in 0..8 { + T::regs().csgcmccmr(i).write_value(ctx.csgcmccm[i]); + T::regs().csgcmr(i).write_value(ctx.csgcm[i]); + } + self.load_key(ctx.cipher.key()); + + // Prepare key if applicable. + ctx.cipher.prepare_key(&T::regs()); + T::regs().cr().write(|w| w.0 = ctx.cr); + + // Enable crypto processor. + T::regs().cr().modify(|w| w.set_crypen(true)); + } +} + +pub(crate) mod sealed { + use super::*; + + pub trait Instance { + fn regs() -> pac::cryp::Cryp; + } +} + +/// CRYP instance trait. +pub trait Instance: sealed::Instance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { + /// Interrupt for this CRYP instance. + type Interrupt: interrupt::typelevel::Interrupt; +} + +foreach_interrupt!( + ($inst:ident, cryp, CRYP, GLOBAL, $irq:ident) => { + impl Instance for peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$irq; + } + + impl sealed::Instance for peripherals::$inst { + fn regs() -> crate::pac::cryp::Cryp { + crate::pac::$inst + } + } + }; +); 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; use self::sealed::Instance; use crate::interrupt; use crate::interrupt::typelevel::Interrupt; -use crate::pac::rcc::vals::{Lptim1sel, Lptim2sel}; use crate::peripherals::IPCC; use crate::rcc::sealed::RccPeripheral; @@ -105,7 +104,8 @@ impl Ipcc { IPCC::enable_and_reset(); IPCC::set_cpu2(true); - _configure_pwr(); + // set RF wake-up clock = LSE + crate::pac::RCC.csr().modify(|w| w.set_rfwkpsel(0b01)); let regs = IPCC::regs(); @@ -271,18 +271,3 @@ pub(crate) mod sealed { fn state() -> &'static State; } } - -fn _configure_pwr() { - // TODO: move the rest of this to rcc - let rcc = crate::pac::RCC; - - // TODO: required - // set RF wake-up clock = LSE - rcc.csr().modify(|w| w.set_rfwkpsel(0b01)); - - // set LPTIM1 & LPTIM2 clock source - rcc.ccipr().modify(|w| { - w.set_lptim1sel(Lptim1sel::PCLK1); - w.set_lptim2sel(Lptim2sel::PCLK1); - }); -} 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; pub mod can; #[cfg(crc)] pub mod crc; +#[cfg(cryp)] +pub mod cryp; #[cfg(dac)] pub mod dac; #[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 { pub ahb_pre: AHBPrescaler, pub apb_pre: APBPrescaler, pub ls: super::LsConfig, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -31,6 +34,7 @@ impl Default for Config { ahb_pre: AHBPrescaler::DIV1, apb_pre: APBPrescaler::DIV1, ls: Default::default(), + mux: Default::default(), } } } @@ -97,28 +101,25 @@ pub(crate) unsafe fn init(config: Config) { if !set_flash_latency_after { // Spin until the effective flash latency is compatible with the clock change - while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {} + while FLASH.acr().read().latency() < target_flash_latency {} } // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once - let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre); RCC.cfgr().modify(|w| { w.set_sw(sw); - w.set_hpre(hpre); - w.set_ppre(ppre); + w.set_hpre(config.ahb_pre); + w.set_ppre(config.apb_pre); }); - - if set_flash_latency_after { - // We can make the flash require fewer wait states - // Spin until the SYSCLK changes have taken effect - loop { - let cfgr = RCC.cfgr().read(); - if cfgr.sw() == sw && cfgr.hpre() == hpre && cfgr.ppre() == ppre { - break; - } + // Spin until the SYSCLK changes have taken effect + loop { + let cfgr = RCC.cfgr().read(); + if cfgr.sw() == sw && cfgr.hpre() == config.ahb_pre && cfgr.ppre() == config.apb_pre { + break; } + } - // Set the flash latency to require fewer wait states + // Set the flash latency to require fewer wait states + if set_flash_latency_after { FLASH.acr().modify(|w| w.set_latency(target_flash_latency)); } @@ -132,6 +133,11 @@ pub(crate) unsafe fn init(config: Config) { } }; + config.mux.init(); + + // without this, the ringbuffered uart test fails. + cortex_m::asm::dsb(); + set_clocks!( hsi: None, 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 { #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] pub adc34: AdcClockSource, - #[cfg(clock_mux)] - pub mux: crate::rcc::mux::ClockMux, + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, pub ls: super::LsConfig, } @@ -128,7 +128,6 @@ impl Default for Config { #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), - #[cfg(clock_mux)] mux: Default::default(), } } @@ -370,7 +369,6 @@ pub(crate) unsafe fn init(config: Config) { }; */ - #[cfg(clock_mux)] config.mux.init(); 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 { pub ls: super::LsConfig, + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, + #[cfg(stm32f2)] pub voltage: VoltageScale, } @@ -120,6 +123,7 @@ impl Default for Config { #[cfg(stm32f2)] voltage: VoltageScale::Range3, + mux: Default::default(), } } } @@ -256,6 +260,8 @@ pub(crate) unsafe fn init(config: Config) { }); while RCC.cfgr().read().sws() != config.sys {} + config.mux.init(); + set_clocks!( hsi: hsi, hse: hse, @@ -286,7 +292,9 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] pllsai1_r: pllsai.r, - clk48: pll.q, + // TODO workaround until f4 rcc is fixed in stm32-data + #[cfg(not(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7)))] + pllsai1_q: None, hsi_div488: hsi.map(|hsi| hsi/488u32), 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 { HSE(Hertz, HseMode), } -/// Sets the source for the 48MHz clock to the USB peripheral. -#[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] -pub enum UsbSrc { - /// Use the High Speed Internal Oscillator. The CRS must be used to calibrate the - /// oscillator to comply with the USB specification for oscillator tolerance. - #[cfg(any(stm32g0b1, stm32g0c1))] - Hsi48(super::Hsi48Config), - /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. The - /// PLL needs to be using the HSE source to comply with the USB specification for oscillator - /// tolerance. - PllQ, - /// Use the HSE source directly. The HSE must be a 48MHz source. The HSE source must comply - /// with the USB specification for oscillator tolerance. - HSE, -} - /// Clocks configutation pub struct Config { pub sys: Sysclk, @@ -94,8 +78,10 @@ pub struct Config { pub apb_pre: APBPrescaler, pub low_power_run: bool, pub ls: super::LsConfig, - #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] - pub usb_src: Option, + #[cfg(crs)] + pub hsi48: Option, + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -107,8 +93,9 @@ impl Default for Config { apb_pre: APBPrescaler::DIV1, low_power_run: false, ls: Default::default(), - #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] - usb_src: None, + #[cfg(crs)] + hsi48: Some(Default::default()), + mux: Default::default(), } } } @@ -322,34 +309,12 @@ pub(crate) unsafe fn init(config: Config) { let lsi_freq = (sw == Sw::LSI).then_some(super::LSI_FREQ); let hse_freq = (sw == Sw::HSE).then_some(sys_clk); - #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] - let hsi48_freq = config.usb_src.and_then(|config| { - match config { - UsbSrc::PllQ => { - // Make sure the PLLQ is enabled and running at 48Mhz - assert!(pll1_q_freq.is_some() && pll1_q_freq.unwrap().0 == 48_000_000); - RCC.ccipr2() - .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::PLL1_Q)); - None - } - UsbSrc::HSE => { - // Make sure the HSE is enabled and running at 48Mhz - assert!(hse_freq.is_some() && hse_freq.unwrap().0 == 48_000_000); - RCC.ccipr2() - .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSE)); - None - } - #[cfg(any(stm32g0b1, stm32g0c1))] - UsbSrc::Hsi48(config) => { - let freq = super::init_hsi48(config); - RCC.ccipr2() - .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)); - Some(freq) - } - } - }); - #[cfg(not(any(stm32g0b1, stm32g0c1, stm32g0b0)))] - let hsi48_freq: Option = None; + #[cfg(crs)] + let hsi48 = config.hsi48.map(super::init_hsi48); + #[cfg(not(crs))] + let hsi48: Option = None; + + config.mux.init(); set_clocks!( sys: Some(sys_clk), @@ -357,7 +322,7 @@ pub(crate) unsafe fn init(config: Config) { pclk1: Some(apb_freq), pclk1_tim: Some(apb_tim_freq), hsi: hsi_freq, - hsi48: hsi48_freq, + hsi48: hsi48, hsi_div_8: hsi_div_8_freq, hse: hse_freq, 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 @@ use stm32_metapac::flash::vals::Latency; -use stm32_metapac::rcc::vals::{Adcsel, Sw}; +use stm32_metapac::rcc::vals::Sw; use stm32_metapac::FLASH; pub use crate::pac::rcc::vals::{ - Adcsel as AdcClockSource, Clk48sel as Clk48Src, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler, - Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, Ppre as APBPrescaler, - Sw as Sysclk, + Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, + Ppre as APBPrescaler, Sw as Sysclk, }; use crate::pac::{PWR, RCC}; use crate::time::Hertz; @@ -82,24 +81,15 @@ pub struct Config { pub low_power_run: bool, - /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals. - pub clk48_src: Clk48Src, - /// Low-Speed Clock Configuration pub ls: super::LsConfig, - /// Clock Source for ADCs 1 and 2 - pub adc12_clock_source: AdcClockSource, - - /// Clock Source for ADCs 3, 4 and 5 - pub adc345_clock_source: AdcClockSource, - - /// Clock Source for FDCAN - pub fdcan_clock_source: FdCanClockSource, - /// Enable range1 boost mode /// Recommended when the SYSCLK frequency is greater than 150MHz. pub boost: bool, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -115,12 +105,9 @@ impl Default for Config { apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, low_power_run: false, - clk48_src: Clk48Src::HSI48, ls: Default::default(), - adc12_clock_source: Adcsel::DISABLE, - adc345_clock_source: Adcsel::DISABLE, - fdcan_clock_source: FdCanClockSource::PCLK1, boost: false, + mux: Default::default(), } } } @@ -165,9 +152,7 @@ pub(crate) unsafe fn init(config: Config) { }; // Configure HSI48 if required - if let Some(hsi48_config) = config.hsi48 { - super::init_hsi48(hsi48_config); - } + let hsi48 = config.hsi48.map(super::init_hsi48); let pll_freq = config.pll.map(|pll_config| { let src_freq = match pll_config.source { @@ -176,13 +161,13 @@ pub(crate) unsafe fn init(config: Config) { _ => unreachable!(), }; - assert!(max::PLL_IN.contains(&src_freq)); - // Disable PLL before configuration RCC.cr().modify(|w| w.set_pllon(false)); while RCC.cr().read().pllrdy() {} - let internal_freq = src_freq / pll_config.prediv * pll_config.mul; + let in_freq = src_freq / pll_config.prediv; + assert!(max::PLL_IN.contains(&in_freq)); + let internal_freq = in_freq * pll_config.mul; assert!(max::PLL_VCO.contains(&internal_freq)); @@ -301,42 +286,6 @@ pub(crate) unsafe fn init(config: Config) { let (apb1_freq, apb1_tim_freq) = super::util::calc_pclk(hclk, config.apb1_pre); let (apb2_freq, apb2_tim_freq) = super::util::calc_pclk(hclk, config.apb2_pre); - // Configure the 48MHz clock source for USB and RNG peripherals. - RCC.ccipr().modify(|w| { - w.set_clk48sel(match config.clk48_src { - Clk48Src::PLL1_Q => { - // Not checking that PLL1_Q is 48MHz here so as not to require the user to have a 48MHz clock. - // Peripherals which require one (USB, RNG) should check that they‘re driven by a valid 48MHz - // clock at init. - crate::pac::rcc::vals::Clk48sel::PLL1_Q - } - Clk48Src::HSI48 => { - // Make sure HSI48 is enabled - assert!(config.hsi48.is_some()); - crate::pac::rcc::vals::Clk48sel::HSI48 - } - _ => unreachable!(), - }) - }); - - RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source)); - RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source)); - RCC.ccipr().modify(|w| w.set_fdcansel(config.fdcan_clock_source)); - - let adc12_ck = match config.adc12_clock_source { - AdcClockSource::DISABLE => None, - AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p, - AdcClockSource::SYS => Some(sys_clk), - _ => unreachable!(), - }; - - let adc345_ck = match config.adc345_clock_source { - AdcClockSource::DISABLE => None, - AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p, - AdcClockSource::SYS => Some(sys_clk), - _ => unreachable!(), - }; - if config.low_power_run { assert!(sys_clk <= Hertz(2_000_000)); PWR.cr1().modify(|w| w.set_lpr(true)); @@ -344,6 +293,8 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); + config.mux.init(); + set_clocks!( sys: Some(sys_clk), hclk1: Some(hclk), @@ -353,12 +304,11 @@ pub(crate) unsafe fn init(config: Config) { pclk1_tim: Some(apb1_tim_freq), pclk2: Some(apb2_freq), pclk2_tim: Some(apb2_tim_freq), - adc: adc12_ck, - adc34: adc345_ck, pll1_p: pll_freq.as_ref().and_then(|pll| pll.pll_p), pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_q), pll1_r: pll_freq.as_ref().and_then(|pll| pll.pll_r), hse: hse, + hsi48: hsi48, rtc: rtc, ); } 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; use crate::pac; use crate::pac::pwr::vals::Vos; -#[cfg(stm32h5)] -pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource; -#[cfg(stm32h7)] -pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; pub use crate::pac::rcc::vals::{ - Ckpersel as PerClockSource, Fdcansel as FdCanClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, - Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk, + Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk, }; -use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre}; +use crate::pac::rcc::vals::{Pllrge, Pllvcosel, Timpre}; use crate::pac::{FLASH, PWR, RCC}; use crate::time::Hertz; @@ -194,16 +189,15 @@ pub struct Config { #[cfg(stm32h7)] pub apb4_pre: APBPrescaler, - pub per_clock_source: PerClockSource, - pub adc_clock_source: AdcClockSource, - pub fdcan_clock_source: FdCanClockSource, - pub timer_prescaler: TimerPrescaler, pub voltage_scale: VoltageScale, pub ls: super::LsConfig, #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] pub supply_config: SupplyConfig, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -227,21 +221,14 @@ impl Default for Config { #[cfg(stm32h7)] apb4_pre: APBPrescaler::DIV1, - per_clock_source: PerClockSource::HSI, - - #[cfg(stm32h5)] - adc_clock_source: AdcClockSource::HCLK1, - #[cfg(stm32h7)] - adc_clock_source: AdcClockSource::PER, - - fdcan_clock_source: FdCanClockSource::from_bits(0), // HSE - timer_prescaler: TimerPrescaler::DefaultX2, voltage_scale: VoltageScale::Scale0, ls: Default::default(), #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] supply_config: SupplyConfig::Default, + + mux: Default::default(), } } } @@ -504,31 +491,6 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(stm32h7)] assert!(apb4 <= pclk_max); - let _per_ck = match config.per_clock_source { - Ckpersel::HSI => hsi, - Ckpersel::CSI => csi, - Ckpersel::HSE => hse, - _ => unreachable!(), - }; - - #[cfg(stm32h7)] - let adc = match config.adc_clock_source { - AdcClockSource::PLL2_P => pll2.p, - AdcClockSource::PLL3_R => pll3.r, - AdcClockSource::PER => _per_ck, - _ => unreachable!(), - }; - #[cfg(stm32h5)] - let adc = match config.adc_clock_source { - AdcClockSource::HCLK1 => Some(hclk), - AdcClockSource::SYS => Some(sys), - AdcClockSource::PLL2_R => pll2.r, - AdcClockSource::HSE => hse, - AdcClockSource::HSI => hsi, - AdcClockSource::CSI => csi, - _ => unreachable!(), - }; - flash_setup(hclk, config.voltage_scale); let rtc = config.ls.init(); @@ -550,16 +512,6 @@ pub(crate) unsafe fn init(config: Config) { RCC.d3cfgr().modify(|w| { w.set_d3ppre(config.apb4_pre); }); - - RCC.d1ccipr().modify(|w| { - w.set_ckpersel(config.per_clock_source); - }); - RCC.d3ccipr().modify(|w| { - w.set_adcsel(config.adc_clock_source); - }); - RCC.d2ccip1r().modify(|w| { - w.set_fdcansel(config.fdcan_clock_source); - }); } #[cfg(stm32h5)] { @@ -573,12 +525,6 @@ pub(crate) unsafe fn init(config: Config) { w.set_ppre2(config.apb2_pre); w.set_ppre3(config.apb3_pre); }); - - RCC.ccipr5().modify(|w| { - w.set_ckpersel(config.per_clock_source); - w.set_adcdacsel(config.adc_clock_source); - w.set_fdcan12sel(config.fdcan_clock_source) - }); } RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into())); @@ -601,6 +547,8 @@ pub(crate) unsafe fn init(config: Config) { while !pac::SYSCFG.cccsr().read().ready() {} } + config.mux.init(); + set_clocks!( sys: Some(sys), hclk1: Some(hclk), @@ -614,7 +562,6 @@ pub(crate) unsafe fn init(config: Config) { pclk4: Some(apb4), pclk1_tim: Some(apb1_tim), pclk2_tim: Some(apb2_tim), - adc: adc, rtc: rtc, hsi: hsi, @@ -646,7 +593,6 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(stm32h5)] audioclk: None, - per: None, i2s_ckin: None, ); } 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 @@ #[cfg(any(stm32l0, stm32l1))] pub use crate::pac::pwr::vals::Vos as VoltageScale; use crate::pac::rcc::regs::Cfgr; -#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] -pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; -#[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] -pub use crate::pac::rcc::vals::Clk48sel as Clk48Src; #[cfg(any(stm32wb, stm32wl))] pub use crate::pac::rcc::vals::Hsepre as HsePrescaler; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as Sysclk}; @@ -59,18 +55,14 @@ pub struct Config { #[cfg(any(stm32wl, stm32wb))] pub shared_ahb_pre: AHBPrescaler, - // muxes - #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] - pub clk48_src: Clk48Src, - // low speed LSI/LSE/RTC pub ls: super::LsConfig, - #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] - pub adc_clock_source: AdcClockSource, - #[cfg(any(stm32l0, stm32l1))] pub voltage_scale: VoltageScale, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -95,13 +87,10 @@ impl Default for Config { pllsai2: None, #[cfg(crs)] hsi48: Some(Default::default()), - #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] - clk48_src: Clk48Src::HSI48, ls: Default::default(), - #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] - adc_clock_source: AdcClockSource::SYS, #[cfg(any(stm32l0, stm32l1))] voltage_scale: VoltageScale::RANGE1, + mux: Default::default(), } } } @@ -118,7 +107,6 @@ pub const WPAN_DEFAULT: Config = Config { hsi48: Some(super::Hsi48Config { sync_from_usb: false }), msi: None, hsi: false, - clk48_src: Clk48Src::PLL1_Q, ls: super::LsConfig::default_lse(), @@ -137,7 +125,8 @@ pub const WPAN_DEFAULT: Config = Config { shared_ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, - adc_clock_source: AdcClockSource::SYS, + + mux: super::mux::ClockMux::default(), }; fn msi_enable(range: MSIRange) { @@ -267,21 +256,6 @@ pub(crate) unsafe fn init(config: Config) { Sysclk::PLL1_R => pll.r.unwrap(), }; - #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] - RCC.ccipr().modify(|w| w.set_clk48sel(config.clk48_src)); - #[cfg(any(rcc_l0_v2))] - let clk48 = match config.clk48_src { - Clk48Src::HSI48 => hsi48, - Clk48Src::PLL1_VCO_DIV_2 => pll.clk48, - }; - #[cfg(any(stm32l4, stm32l5, stm32wb))] - let clk48 = match config.clk48_src { - Clk48Src::HSI48 => hsi48, - Clk48Src::MSI => msi, - Clk48Src::PLLSAI1_Q => pllsai1.q, - Clk48Src::PLL1_Q => pll.q, - }; - #[cfg(rcc_l4plus)] assert!(sys_clk.0 <= 120_000_000); #[cfg(all(stm32l4, not(rcc_l4plus)))] @@ -357,9 +331,6 @@ pub(crate) unsafe fn init(config: Config) { }); while RCC.cfgr().read().sws() != config.sys {} - #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] - RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source)); - #[cfg(any(stm32wl, stm32wb))] { RCC.extcfgr().modify(|w| { @@ -372,6 +343,8 @@ pub(crate) unsafe fn init(config: Config) { while !RCC.extcfgr().read().c2hpref() {} } + config.mux.init(); + set_clocks!( sys: Some(sys_clk), hclk1: Some(hclk1), @@ -388,10 +361,11 @@ pub(crate) unsafe fn init(config: Config) { hsi: hsi, hse: hse, msi: msi, - #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] - clk48: clk48, hsi48: hsi48, + #[cfg(any(stm32l0, stm32l1))] + pll1_vco_div_2: pll.vco.map(|c| c/2u32), + #[cfg(not(any(stm32l0, stm32l1)))] pll1_p: pll.p, #[cfg(not(any(stm32l0, stm32l1)))] @@ -511,7 +485,7 @@ mod pll { #[derive(Default)] pub(super) struct PllOutput { pub r: Option, - pub clk48: Option, + pub vco: Option, } pub(super) fn init_pll(instance: PllInstance, config: Option, input: &PllInput) -> PllOutput { @@ -528,7 +502,6 @@ mod pll { let vco_freq = pll_src * pll.mul; let r = vco_freq / pll.div; - let clk48 = (vco_freq == Hertz(96_000_000)).then_some(Hertz(48_000_000)); assert!(r <= Hertz(32_000_000)); @@ -541,7 +514,10 @@ mod pll { // Enable PLL pll_enable(instance, true); - PllOutput { r: Some(r), clk48 } + PllOutput { + r: Some(r), + vco: Some(vco_freq), + } } } 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; pub use _version::*; -#[cfg(clock_mux)] -pub use crate::_generated::mux; -pub use crate::_generated::Clocks; +pub use crate::_generated::{mux, Clocks}; #[cfg(feature = "low-power")] /// 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 { /// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits. pub voltage_range: VoltageScale, pub ls: super::LsConfig, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -104,6 +107,7 @@ impl Default for Config { apb3_pre: APBPrescaler::DIV1, voltage_range: VoltageScale::RANGE1, ls: Default::default(), + mux: Default::default(), } } } @@ -259,6 +263,8 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); + config.mux.init(); + set_clocks!( sys: Some(sys_clk), hclk1: Some(hclk), @@ -289,7 +295,6 @@ pub(crate) unsafe fn init(config: Config) { lse: None, lsi: None, msik: None, - iclk: None, shsi: None, shsi_div_2: None, ); 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 @@ pub use crate::pac::pwr::vals::Vos as VoltageScale; use crate::pac::rcc::regs::Cfgr1; -pub use crate::pac::rcc::vals::{ - Adcsel as AdcClockSource, Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk, -}; +pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk}; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; @@ -32,9 +30,10 @@ pub struct Config { // low speed LSI/LSE/RTC pub ls: super::LsConfig, - pub adc_clock_source: AdcClockSource, - pub voltage_scale: VoltageScale, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -49,8 +48,8 @@ impl Default for Config { apb2_pre: APBPrescaler::DIV1, apb7_pre: APBPrescaler::DIV1, ls: Default::default(), - adc_clock_source: AdcClockSource::HCLK4, voltage_scale: VoltageScale::RANGE2, + mux: Default::default(), } } } @@ -152,7 +151,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_ppre2(config.apb2_pre); }); - RCC.ccipr3().modify(|w| w.set_adcsel(config.adc_clock_source)); + config.mux.init(); set_clocks!( 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> { // Wait for USB power to stabilize while !crate::pac::PWR.cr3().read().usb33rdy() {} - // Use internal 48MHz HSI clock. Should be enabled in RCC by default. - critical_section::with(|_| { - crate::pac::RCC - .d2ccip2r() - .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)) - }); - // Enable ULPI clock if external PHY is used let ulpien = !self.phy_type.internal(); critical_section::with(|_| { @@ -645,13 +638,6 @@ impl<'d, T: Instance> Bus<'d, T> { // Wait for USB power to stabilize while !crate::pac::PWR.svmsr().read().vddusbrdy() {} - - // Select HSI48 as USB clock source. - critical_section::with(|_| { - crate::pac::RCC.ccipr1().modify(|w| { - w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48); - }) - }); } ::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) { config.rcc.apb1_pre = APBPrescaler::DIV2; config.rcc.apb2_pre = APBPrescaler::DIV1; - config.rcc.mux.hrtim1sw = Some(embassy_stm32::rcc::mux::Timsw::PLL1_P); + config.rcc.mux.hrtim1sw = embassy_stm32::rcc::mux::Timsw::PLL1_P; } let p = embassy_stm32::init(config); 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" static_cell = "2" sha2 = { version = "0.10.8", default-features = false } hmac = "0.12.1" +aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] } [profile.release] debug = 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 @@ +#![no_std] +#![no_main] + +use aes_gcm::aead::heapless::Vec; +use aes_gcm::aead::{AeadInPlace, KeyInit}; +use aes_gcm::Aes128Gcm; +use defmt::info; +use embassy_executor::Spawner; +use embassy_stm32::cryp::*; +use embassy_stm32::Config; +use embassy_time::Instant; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let config = Config::default(); + let p = embassy_stm32::init(config); + + let payload: &[u8] = b"hello world"; + let aad: &[u8] = b"additional data"; + + let hw_cryp = Cryp::new(p.CRYP); + let key: [u8; 16] = [0; 16]; + let mut ciphertext: [u8; 11] = [0; 11]; + let mut plaintext: [u8; 11] = [0; 11]; + let iv: [u8; 12] = [0; 12]; + + let hw_start_time = Instant::now(); + + // Encrypt in hardware using AES-GCM 128-bit + let aes_gcm = AesGcm::new(&key, &iv); + let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt); + hw_cryp.aad_blocking(&mut gcm_encrypt, aad, true); + hw_cryp.payload_blocking(&mut gcm_encrypt, payload, &mut ciphertext, true); + let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt); + + // Decrypt in hardware using AES-GCM 128-bit + let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt); + hw_cryp.aad_blocking(&mut gcm_decrypt, aad, true); + hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true); + let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt); + + let hw_end_time = Instant::now(); + let hw_execution_time = hw_end_time - hw_start_time; + + info!("AES-GCM Ciphertext: {:?}", ciphertext); + info!("AES-GCM Plaintext: {:?}", plaintext); + assert_eq!(payload, plaintext); + assert_eq!(encrypt_tag, decrypt_tag); + + let sw_start_time = Instant::now(); + + // Encrypt in software using AES-GCM 128-bit + let mut payload_vec: Vec = Vec::from_slice(&payload).unwrap(); + let cipher = Aes128Gcm::new(&key.into()); + let _ = cipher.encrypt_in_place(&iv.into(), aad.into(), &mut payload_vec); + + assert_eq!(ciphertext, payload_vec[0..ciphertext.len()]); + assert_eq!( + encrypt_tag, + payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()] + ); + + // Decrypt in software using AES-GCM 128-bit + let _ = cipher.decrypt_in_place(&iv.into(), aad.into(), &mut payload_vec); + + let sw_end_time = Instant::now(); + let sw_execution_time = sw_end_time - sw_start_time; + + info!("Hardware Execution Time: {:?}", hw_execution_time); + info!("Software Execution Time: {:?}", sw_execution_time); + + loop {} +} 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 @@ use defmt::info; use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; -use embassy_stm32::pac::rcc::vals::Tim1sel; -use embassy_stm32::rcc::{Config as RccConfig, PllConfig, PllSource, Pllm, Plln, Pllq, Pllr, Sysclk}; use embassy_stm32::time::khz; use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; use embassy_stm32::timer::simple_pwm::PwmPin; use embassy_stm32::timer::Channel; -use embassy_stm32::{pac, Config as PeripheralConfig}; +use embassy_stm32::Config as PeripheralConfig; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let mut rcc_config = RccConfig::default(); - rcc_config.sys = Sysclk::PLL(PllConfig { - source: PllSource::HSI, - m: Pllm::DIV1, - n: Plln::MUL16, - r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz) - q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz) - p: None, - }); + let mut config = PeripheralConfig::default(); + { + use embassy_stm32::rcc::*; - let mut peripheral_config = PeripheralConfig::default(); - peripheral_config.rcc = rcc_config; + config.rcc.sys = Sysclk::PLL(PllConfig { + source: PllSource::HSI, + m: Pllm::DIV1, + n: Plln::MUL16, + r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz) + q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz) + p: None, + }); - let p = embassy_stm32::init(peripheral_config); - - // configure TIM1 mux to select PLLQ as clock source - // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf - // RM0444 page 210 - // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1 - pac::RCC.ccipr().modify(|w| w.set_tim1sel(Tim1sel::PLL1_Q)); + // configure TIM1 mux to select PLLQ as clock source + // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + // RM0444 page 210 + // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1 + config.rcc.mux.tim1sel = embassy_stm32::rcc::mux::Tim1sel::PLL1_Q; + } + let p = embassy_stm32::init(config); let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); 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 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_stm32::rcc::{Hsi48Config, UsbSrc}; use embassy_stm32::usb::{Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; @@ -19,10 +18,11 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.usb_src = Some(UsbSrc::Hsi48(Hsi48Config { - sync_from_usb: true, - ..Default::default() - })); + { + use embassy_stm32::rcc::*; + config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); + config.rcc.mux.usbsel = mux::Usbsel::HSI48; + } let p = embassy_stm32::init(config); 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 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; -use embassy_stm32::rcc::{AdcClockSource, Pll, PllMul, PllPreDiv, PllRDiv, Pllsrc, Sysclk}; use embassy_stm32::Config; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -12,20 +11,20 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - - config.rcc.pll = Some(Pll { - source: Pllsrc::HSI, - prediv: PllPreDiv::DIV4, - mul: PllMul::MUL85, - divp: None, - divq: None, - // Main system clock at 170 MHz - divr: Some(PllRDiv::DIV2), - }); - - config.rcc.adc12_clock_source = AdcClockSource::SYS; - config.rcc.sys = Sysclk::PLL1_R; - + { + use embassy_stm32::rcc::*; + config.rcc.pll = Some(Pll { + source: Pllsrc::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL85, + divp: None, + divq: None, + // Main system clock at 170 MHz + divr: Some(PllRDiv::DIV2), + }); + config.rcc.mux.adc12sel = mux::Adcsel::SYS; + config.rcc.sys = Sysclk::PLL1_R; + } let mut p = embassy_stm32::init(config); info!("Hello World!"); 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 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::peripherals::*; +use embassy_stm32::time::Hertz; use embassy_stm32::{bind_interrupts, can, Config}; use embassy_time::Timer; use static_cell::StaticCell; @@ -15,8 +16,24 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { - let config = Config::default(); - + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(24_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll = Some(Pll { + source: Pllsrc::HSE, + prediv: PllPreDiv::DIV6, + mul: PllMul::MUL85, + divp: None, + divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan. + divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz + }); + config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q; + config.rcc.sys = Sysclk::PLL1_R; + } let peripherals = embassy_stm32::init(config); let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); @@ -184,7 +201,11 @@ async fn main(_spawner: Spawner) { let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); info!("Writing frame"); - _ = can.write(frame).await; + // You can use any of these approaches to send. The writer makes it + // easy to share sending from multiple tasks. + //_ = can.write(frame).await; + //can.writer().try_write(frame).unwrap(); + can.writer().write(frame).await; match can.read().await { 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 _}; async fn main(_spawner: Spawner) { let mut config = Config::default(); + config.rcc.hsi = true; config.rcc.pll = Some(Pll { source: Pllsrc::HSI, 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 @@ use defmt::{panic, *}; use embassy_executor::Spawner; -use embassy_stm32::rcc::{ - Clk48Src, Hse, HseMode, Hsi48Config, Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, Pllsrc, Sysclk, -}; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{self, Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, Config}; @@ -22,38 +19,27 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - - // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE. - const USE_HSI48: bool = true; - - let plldivq = if USE_HSI48 { None } else { Some(PllQDiv::DIV6) }; - - config.rcc.hse = Some(Hse { - freq: Hertz(8_000_000), - mode: HseMode::Oscillator, - }); - - config.rcc.pll = Some(Pll { - source: Pllsrc::HSE, - prediv: PllPreDiv::DIV2, - mul: PllMul::MUL72, - divp: None, - divq: plldivq, - // Main system clock at 144 MHz - divr: Some(PllRDiv::DIV2), - }); - - config.rcc.sys = Sysclk::PLL1_R; - config.rcc.boost = true; // BOOST! - - if USE_HSI48 { + { + use embassy_stm32::rcc::*; // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator. config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); - config.rcc.clk48_src = Clk48Src::HSI48; - } else { - config.rcc.clk48_src = Clk48Src::PLL1_Q; + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll = Some(Pll { + source: Pllsrc::HSE, + prediv: PllPreDiv::DIV2, + mul: PllMul::MUL72, + divp: None, + divq: Some(PllQDiv::DIV6), // 48mhz + divr: Some(PllRDiv::DIV2), // Main system clock at 144 MHz + }); + config.rcc.sys = Sysclk::PLL1_R; + config.rcc.boost = true; // BOOST! + config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; + //config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; // uncomment to use PLL1_Q instead. } - let p = embassy_stm32::init(config); 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) { freq: embassy_stm32::time::Hertz(25_000_000), mode: rcc::HseMode::Oscillator, }); - config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; + config.rcc.mux.fdcan12sel = rcc::mux::Fdcansel::HSE; let peripherals = embassy_stm32::init(config); 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, *}; use embassy_executor::Spawner; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; @@ -41,15 +41,12 @@ async fn main(_spawner: Spawner) { config.rcc.apb3_pre = APBPrescaler::DIV4; config.rcc.sys = Sysclk::PLL1_P; config.rcc.voltage_scale = VoltageScale::Scale0; + config.rcc.mux.usbsel = mux::Usbsel::HSI48; } let p = embassy_stm32::init(config); info!("Hello World!"); - pac::RCC.ccipr4().write(|w| { - w.set_usbsel(pac::rcc::vals::Usbsel::HSI48); - }); - // Create the driver, from the HAL. let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); 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) { config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.voltage_scale = VoltageScale::Scale1; - config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; } let mut p = embassy_stm32::init(config); 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) { freq: embassy_stm32::time::Hertz(25_000_000), mode: rcc::HseMode::Oscillator, }); - config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; + config.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; let peripherals = embassy_stm32::init(config); 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() -> ! { config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.voltage_scale = VoltageScale::Scale1; - config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; } let p = embassy_stm32::init(config); 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) { config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.voltage_scale = VoltageScale::Scale1; - config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; } // 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 @@ use defmt::*; use embassy_stm32::adc::{Adc, Resolution}; -use embassy_stm32::pac; +use embassy_stm32::Config; use embassy_time::Delay; use {defmt_rtt as _, panic_probe as _}; @@ -11,12 +11,12 @@ use {defmt_rtt as _, panic_probe as _}; fn main() -> ! { info!("Hello World!"); - pac::RCC.ccipr().modify(|w| { - w.set_adcsel(pac::rcc::vals::Adcsel::SYS); - }); - pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); - - let p = embassy_stm32::init(Default::default()); + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.mux.adcsel = mux::Adcsel::SYS; + } + let p = embassy_stm32::init(config); let mut adc = Adc::new(p.ADC1, &mut Delay); //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"] stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"] -stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash"] -stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash"] +stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] +stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"] stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] @@ -33,6 +33,7 @@ stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"] stm32h503rb = ["embassy-stm32/stm32h503rb", "rng"] +cryp = [] hash = [] eth = ["embassy-executor/task-arena-size-16384"] rng = [] @@ -80,6 +81,7 @@ portable-atomic = { version = "1.5", features = [] } chrono = { version = "^0.4", default-features = false, optional = true} sha2 = { version = "0.10.8", default-features = false } hmac = "0.12.1" +aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] } # BEGIN TESTS # Generated by gen_test.py. DO NOT EDIT. @@ -88,6 +90,11 @@ name = "can" path = "src/bin/can.rs" required-features = [ "can",] +[[bin]] +name = "cryp" +path = "src/bin/cryp.rs" +required-features = [ "cryp",] + [[bin]] name = "dac" path = "src/bin/dac.rs" 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 @@ +// required-features: cryp +#![no_std] +#![no_main] + +#[path = "../common.rs"] +mod common; + +use aes_gcm::aead::heapless::Vec; +use aes_gcm::aead::{AeadInPlace, KeyInit}; +use aes_gcm::Aes128Gcm; +use common::*; +use embassy_executor::Spawner; +use embassy_stm32::cryp::*; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); + + const PAYLOAD1: &[u8] = b"payload data 1 ;zdfhzdfhS;GKJASBDG;ASKDJBAL,zdfhzdfhzdfhzdfhvljhb,jhbjhb,sdhsdghsdhsfhsghzdfhzdfhzdfhzdfdhsdthsthsdhsgaadfhhgkdgfuoyguoft6783567"; + const PAYLOAD2: &[u8] = b"payload data 2 ;SKEzdfhzdfhzbhgvljhb,jhbjhb,sdhsdghsdhsfhsghshsfhshstsdthadfhsdfjhsfgjsfgjxfgjzdhgDFghSDGHjtfjtjszftjzsdtjhstdsdhsdhsdhsdhsdthsthsdhsgfh"; + const AAD1: &[u8] = b"additional data 1 stdargadrhaethaethjatjatjaetjartjstrjsfkk;'jopofyuisrteytweTASTUIKFUKIXTRDTEREharhaeryhaterjartjarthaethjrtjarthaetrhartjatejatrjsrtjartjyt1"; + const AAD2: &[u8] = b"additional data 2 stdhthsthsthsrthsrthsrtjdykjdukdyuldadfhsdghsdghsdghsadghjk'hioethjrtjarthaetrhartjatecfgjhzdfhgzdfhzdfghzdfhzdfhzfhjatrjsrtjartjytjfytjfyg"; + + let hw_cryp = Cryp::new(p.CRYP); + let key: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut ciphertext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()]; + let mut plaintext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()]; + let iv: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + + // Encrypt in hardware using AES-GCM 128-bit + let aes_gcm = AesGcm::new(&key, &iv); + let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt); + hw_cryp.aad_blocking(&mut gcm_encrypt, AAD1, false); + hw_cryp.aad_blocking(&mut gcm_encrypt, AAD2, true); + hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD1, &mut ciphertext[..PAYLOAD1.len()], false); + hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD2, &mut ciphertext[PAYLOAD1.len()..], true); + let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt); + + // Decrypt in hardware using AES-GCM 128-bit + let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt); + hw_cryp.aad_blocking(&mut gcm_decrypt, AAD1, false); + hw_cryp.aad_blocking(&mut gcm_decrypt, AAD2, true); + hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true); + let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt); + + info!("AES-GCM Ciphertext: {:?}", ciphertext); + info!("AES-GCM Plaintext: {:?}", plaintext); + defmt::assert!(PAYLOAD1 == &plaintext[..PAYLOAD1.len()]); + defmt::assert!(PAYLOAD2 == &plaintext[PAYLOAD1.len()..]); + defmt::assert!(encrypt_tag == decrypt_tag); + + // Encrypt in software using AES-GCM 128-bit + let mut payload_vec: Vec = Vec::from_slice(&PAYLOAD1).unwrap(); + payload_vec.extend_from_slice(&PAYLOAD2).unwrap(); + let cipher = Aes128Gcm::new(&key.into()); + let mut aad: Vec = Vec::from_slice(&AAD1).unwrap(); + aad.extend_from_slice(&AAD2).unwrap(); + let _ = cipher.encrypt_in_place(&iv.into(), &aad, &mut payload_vec); + + defmt::assert!(ciphertext == payload_vec[0..ciphertext.len()]); + defmt::assert!(encrypt_tag == payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]); + + // Decrypt in software using AES-GCM 128-bit + let _ = cipher.decrypt_in_place(&iv.into(), &aad, &mut payload_vec); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} 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 { freq: embassy_stm32::time::Hertz(25_000_000), mode: rcc::HseMode::Oscillator, }); - c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; + c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; TestOptions { config: c, max_latency: Duration::from_micros(1200), @@ -50,7 +50,7 @@ fn options() -> TestOptions { freq: embassy_stm32::time::Hertz(25_000_000), mode: rcc::HseMode::Oscillator, }); - c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; + c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; TestOptions { config: c, 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 @@ pub use defmt::*; #[allow(unused)] +use embassy_stm32::rcc::*; +#[allow(unused)] use embassy_stm32::time::Hertz; use embassy_stm32::Config; use {defmt_rtt as _, panic_probe as _}; @@ -265,7 +267,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32f091rc")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Bypass, @@ -281,7 +282,6 @@ pub fn config() -> Config { } #[cfg(feature = "stm32f103c8")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Oscillator, @@ -298,7 +298,6 @@ pub fn config() -> Config { } #[cfg(feature = "stm32f207zg")] { - use embassy_stm32::rcc::*; // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal) config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), @@ -327,7 +326,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32f303ze")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Bypass, @@ -345,7 +343,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32f429zi")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Bypass, @@ -366,7 +363,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32f446re")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Oscillator, @@ -387,7 +383,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32f767zi")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Bypass, @@ -408,7 +403,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32h563zi")] { - use embassy_stm32::rcc::*; config.rcc.hsi = None; config.rcc.hsi48 = Some(Default::default()); // needed for RNG config.rcc.hse = Some(Hse { @@ -433,7 +427,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32h503rb")] { - use embassy_stm32::rcc::*; config.rcc.hsi = None; config.rcc.hsi48 = Some(Default::default()); // needed for RNG config.rcc.hse = Some(Hse { @@ -456,9 +449,26 @@ pub fn config() -> Config { config.rcc.voltage_scale = VoltageScale::Scale0; } + #[cfg(feature = "stm32g491re")] + { + config.rcc.hse = Some(Hse { + freq: Hertz(24_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll = Some(Pll { + source: Pllsrc::HSE, + prediv: PllPreDiv::DIV6, + mul: PllMul::MUL85, + divp: None, + divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan. + divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz + }); + config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q; + config.rcc.sys = Sysclk::PLL1_R; + } + #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))] { - use embassy_stm32::rcc::*; config.rcc.hsi = Some(HSIPrescaler::DIV1); config.rcc.csi = true; config.rcc.hsi48 = Some(Default::default()); // needed for RNG @@ -485,7 +495,7 @@ pub fn config() -> Config { config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.voltage_scale = VoltageScale::Scale1; - config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; #[cfg(any(feature = "stm32h755zi"))] { config.rcc.supply_config = SupplyConfig::DirectSMPS; @@ -494,7 +504,6 @@ pub fn config() -> Config { #[cfg(any(feature = "stm32h7a3zi"))] { - use embassy_stm32::rcc::*; config.rcc.hsi = Some(HSIPrescaler::DIV1); config.rcc.csi = true; config.rcc.hsi48 = Some(Default::default()); // needed for RNG @@ -521,12 +530,11 @@ pub fn config() -> Config { config.rcc.apb3_pre = APBPrescaler::DIV2; // 140 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 140 Mhz config.rcc.voltage_scale = VoltageScale::Scale0; - config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; } #[cfg(any(feature = "stm32l496zg", feature = "stm32l4a6zg", feature = "stm32l4r5zi"))] { - use embassy_stm32::rcc::*; config.rcc.sys = Sysclk::PLL1_R; config.rcc.hsi = true; config.rcc.pll = Some(Pll { @@ -541,7 +549,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32wl55jc")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(32_000_000), mode: HseMode::Bypass, @@ -560,7 +567,6 @@ pub fn config() -> Config { #[cfg(any(feature = "stm32l552ze"))] { - use embassy_stm32::rcc::*; config.rcc.hsi = true; config.rcc.sys = Sysclk::PLL1_R; config.rcc.pll = Some(Pll { @@ -576,7 +582,6 @@ pub fn config() -> Config { #[cfg(any(feature = "stm32u585ai", feature = "stm32u5a5zj"))] { - use embassy_stm32::rcc::*; config.rcc.hsi = true; config.rcc.pll1 = Some(Pll { source: PllSource::HSI, // 16 MHz @@ -593,17 +598,12 @@ pub fn config() -> Config { #[cfg(feature = "stm32wba52cg")] { - use embassy_stm32::rcc::*; config.rcc.sys = Sysclk::HSI; - - embassy_stm32::pac::RCC.ccipr2().write(|w| { - w.set_rngsel(embassy_stm32::pac::rcc::vals::Rngsel::HSI); - }); + config.rcc.mux.rngsel = mux::Rngsel::HSI; } #[cfg(feature = "stm32l073rz")] { - use embassy_stm32::rcc::*; config.rcc.hsi = true; config.rcc.pll = Some(Pll { source: PllSource::HSI, @@ -615,7 +615,6 @@ pub fn config() -> Config { #[cfg(any(feature = "stm32l152re"))] { - use embassy_stm32::rcc::*; config.rcc.hsi = true; config.rcc.pll = Some(Pll { source: PllSource::HSI,