diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index eb0437bc2..8ca79eadf 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1151,6 +1151,8 @@ fn main() { (("tsc", "G8_IO2"), quote!(crate::tsc::G8IO2Pin)), (("tsc", "G8_IO3"), quote!(crate::tsc::G8IO3Pin)), (("tsc", "G8_IO4"), quote!(crate::tsc::G8IO4Pin)), + (("dac", "OUT1"), quote!(crate::dac::DacPin)), + (("dac", "OUT2"), quote!(crate::dac::DacPin)), ].into(); for p in METADATA.peripherals { @@ -1250,17 +1252,6 @@ fn main() { } } - // DAC is special - if regs.kind == "dac" { - let peri = format_ident!("{}", p.name); - let pin_name = format_ident!("{}", pin.pin); - let ch: u8 = pin.signal.strip_prefix("OUT").unwrap().parse().unwrap(); - - g.extend(quote! { - impl_dac_pin!( #peri, #pin_name, #ch); - }) - } - if regs.kind == "spdifrx" { let peri = format_ident!("{}", p.name); let pin_name = format_ident!("{}", pin.pin); @@ -1304,8 +1295,8 @@ fn main() { (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)), (("octospi", "OCTOSPI1"), quote!(crate::ospi::OctoDma)), (("hspi", "HSPI1"), quote!(crate::hspi::HspiDma)), - (("dac", "CH1"), quote!(crate::dac::DacDma1)), - (("dac", "CH2"), quote!(crate::dac::DacDma2)), + (("dac", "CH1"), quote!(crate::dac::Dma)), + (("dac", "CH2"), quote!(crate::dac::Dma)), (("timer", "UP"), quote!(crate::timer::UpDma)), (("hash", "IN"), quote!(crate::hash::Dma)), (("cryp", "IN"), quote!(crate::cryp::DmaIn)), diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 6afe68a39..54d2c30e5 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -7,8 +7,9 @@ use core::ptr; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; -use crate::dma::{NoDma, Transfer, TransferOptions}; +use crate::dma::{ChannelAndRequest, TransferOptions}; use crate::interrupt::typelevel::Interrupt; +use crate::mode::{Async, Blocking, Mode}; use crate::{interrupt, pac, peripherals, rcc, Peripheral}; const DES_BLOCK_SIZE: usize = 8; // 64 bits @@ -57,15 +58,10 @@ pub trait Cipher<'c> { fn prepare_key(&self, _p: pac::cryp::Cryp) {} /// Performs any cipher-specific initialization. - fn init_phase_blocking(&self, _p: pac::cryp::Cryp, _cryp: &Cryp) {} + fn init_phase_blocking(&self, _p: pac::cryp::Cryp, _cryp: &Cryp) {} /// Performs any cipher-specific initialization. - async fn init_phase(&self, _p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) - where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { - } + async fn init_phase(&self, _p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, Async>) {} /// Called prior to processing the last data block for cipher-specific operations. fn pre_final(&self, _p: pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] { @@ -73,10 +69,10 @@ pub trait Cipher<'c> { } /// Called after processing the last data block for cipher-specific operations. - fn post_final_blocking( + fn post_final_blocking( &self, _p: pac::cryp::Cryp, - _cryp: &Cryp, + _cryp: &Cryp, _dir: Direction, _int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], @@ -85,18 +81,15 @@ pub trait Cipher<'c> { } /// Called after processing the last data block for cipher-specific operations. - async fn post_final( + async fn post_final( &self, _p: pac::cryp::Cryp, - _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, + _cryp: &mut Cryp<'_, T, Async>, _dir: Direction, _int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], _padding_mask: [u8; 16], - ) where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { + ) { } /// Returns the AAD header block as required by the cipher. @@ -474,13 +467,13 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { p.cr().modify(|w| w.set_algomode3(true)); } - fn init_phase_blocking(&self, p: pac::cryp::Cryp, _cryp: &Cryp) { + fn init_phase_blocking(&self, p: pac::cryp::Cryp, _cryp: &Cryp) { p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} } - async fn init_phase(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) { + async fn init_phase(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, Async>) { p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} @@ -508,10 +501,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { } #[cfg(cryp_v2)] - fn post_final_blocking( + fn post_final_blocking( &self, p: pac::cryp::Cryp, - cryp: &Cryp, + cryp: &Cryp, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], @@ -534,18 +527,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { } #[cfg(cryp_v2)] - async fn post_final( + async fn post_final( &self, p: pac::cryp::Cryp, - cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, + cryp: &mut Cryp<'_, T, Async>, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], padding_mask: [u8; AES_BLOCK_SIZE], - ) where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { + ) { if dir == Direction::Encrypt { // Handle special GCM partial block process. p.cr().modify(|w| w.set_crypen(false)); @@ -559,8 +549,8 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { let mut out_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; - let read = Cryp::::read_bytes(&mut cryp.outdma, Self::BLOCK_SIZE, &mut out_data); - let write = Cryp::::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, int_data); + let read = Cryp::::read_bytes(cryp.outdma.as_mut().unwrap(), Self::BLOCK_SIZE, &mut out_data); + let write = Cryp::::write_bytes(cryp.indma.as_mut().unwrap(), Self::BLOCK_SIZE, int_data); embassy_futures::join::join(read, write).await; @@ -615,13 +605,13 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { p.cr().modify(|w| w.set_algomode3(true)); } - fn init_phase_blocking(&self, p: pac::cryp::Cryp, _cryp: &Cryp) { + fn init_phase_blocking(&self, p: pac::cryp::Cryp, _cryp: &Cryp) { p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} } - async fn init_phase(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) { + async fn init_phase(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, Async>) { p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} @@ -649,10 +639,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { } #[cfg(cryp_v2)] - fn post_final_blocking( + fn post_final_blocking( &self, p: pac::cryp::Cryp, - cryp: &Cryp, + cryp: &Cryp, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], @@ -675,18 +665,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { } #[cfg(cryp_v2)] - async fn post_final( + async fn post_final( &self, p: pac::cryp::Cryp, - cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, + cryp: &mut Cryp<'_, T, Async>, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], padding_mask: [u8; AES_BLOCK_SIZE], - ) where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { + ) { if dir == Direction::Encrypt { // Handle special GCM partial block process. p.cr().modify(|w| w.set_crypen(false)); @@ -700,8 +687,8 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { let mut out_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; - let read = Cryp::::read_bytes(&mut cryp.outdma, Self::BLOCK_SIZE, &mut out_data); - let write = Cryp::::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, int_data); + let read = Cryp::::read_bytes(cryp.outdma.as_mut().unwrap(), Self::BLOCK_SIZE, &mut out_data); + let write = Cryp::::write_bytes(cryp.indma.as_mut().unwrap(), Self::BLOCK_SIZE, int_data); embassy_futures::join::join(read, write).await; } @@ -812,7 +799,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip p.cr().modify(|w| w.set_algomode3(true)); } - fn init_phase_blocking(&self, p: pac::cryp::Cryp, cryp: &Cryp) { + fn init_phase_blocking(&self, p: pac::cryp::Cryp, cryp: &Cryp) { p.cr().modify(|w| w.set_gcm_ccmph(0)); cryp.write_bytes_blocking(Self::BLOCK_SIZE, &self.block0); @@ -821,14 +808,10 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip while p.cr().read().crypen() {} } - async fn init_phase(&self, p: pac::cryp::Cryp, cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) - where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { + async fn init_phase(&self, p: pac::cryp::Cryp, cryp: &mut Cryp<'_, T, Async>) { p.cr().modify(|w| w.set_gcm_ccmph(0)); - Cryp::::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, &self.block0).await; + Cryp::::write_bytes(cryp.indma.as_mut().unwrap(), Self::BLOCK_SIZE, &self.block0).await; p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} @@ -865,10 +848,10 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip } #[cfg(cryp_v2)] - fn post_final_blocking( + fn post_final_blocking( &self, p: pac::cryp::Cryp, - cryp: &Cryp, + cryp: &Cryp, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], temp1: [u32; 4], @@ -902,18 +885,15 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip } #[cfg(cryp_v2)] - async fn post_final( + async fn post_final( &self, p: pac::cryp::Cryp, - cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, + cryp: &mut Cryp<'_, T, Async>, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], temp1: [u32; 4], padding_mask: [u8; 16], - ) where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { + ) { if dir == Direction::Decrypt { //Handle special CCM partial block process. let mut temp2 = [0; 4]; @@ -937,7 +917,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip in_data[i] = int_word; in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i]; } - Cryp::::write_words(&mut cryp.indma, Self::BLOCK_SIZE, &in_data).await; + Cryp::::write_words(cryp.indma.as_mut().unwrap(), Self::BLOCK_SIZE, &in_data).await; } } } @@ -1007,26 +987,26 @@ pub enum Direction { } /// Crypto Accelerator Driver -pub struct Cryp<'d, T: Instance, DmaIn = NoDma, DmaOut = NoDma> { +pub struct Cryp<'d, T: Instance, M: Mode> { _peripheral: PeripheralRef<'d, T>, - indma: PeripheralRef<'d, DmaIn>, - outdma: PeripheralRef<'d, DmaOut>, + _phantom: PhantomData, + indma: Option>, + outdma: Option>, } -impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { - /// Create a new CRYP driver. - pub fn new( +impl<'d, T: Instance> Cryp<'d, T, Blocking> { + /// Create a new CRYP driver in blocking mode. + pub fn new_blocking( peri: impl Peripheral

+ 'd, - indma: impl Peripheral

+ 'd, - outdma: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { rcc::enable_and_reset::(); - into_ref!(peri, indma, outdma); + into_ref!(peri); let instance = Self { _peripheral: peri, - indma: indma, - outdma: outdma, + _phantom: PhantomData, + indma: None, + outdma: None, }; T::Interrupt::unpend(); @@ -1034,7 +1014,9 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { instance } +} +impl<'d, T: Instance, M: Mode> Cryp<'d, T, M> { /// Start a new encrypt or decrypt operation for the given cipher. pub fn start_blocking<'c, C: Cipher<'c> + CipherSized + IVSized>( &self, @@ -1114,89 +1096,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { ctx } - /// Start a new encrypt or decrypt operation for the given cipher. - pub async fn start<'c, C: Cipher<'c> + CipherSized + IVSized>( - &mut self, - cipher: &'c C, - dir: Direction, - ) -> Context<'c, C> - where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { - 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).await; - - self.store_context(&mut ctx); - - ctx - } - #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] /// Controls the header phase of cipher processing. /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC. @@ -1294,101 +1193,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { self.store_context(ctx); } - #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] - /// Controls the header phase of cipher processing. - /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC. - /// All additional associated data (AAD) must be supplied to this function prior to starting the payload phase with `payload`. - /// The AAD must be supplied in multiples of the block size (128-bits for AES, 64-bits for DES), except when supplying the last block. - /// When supplying the last block of AAD, `last_aad_block` must be `true`. - pub async fn aad<'c, const TAG_SIZE: usize, C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated>( - &mut self, - ctx: &mut Context<'c, C>, - aad: &[u8], - last_aad_block: bool, - ) where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { - 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 { - Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await; - assert_eq!(T::regs().sr().read().ifem(), true); - - // 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. - Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await; - assert_eq!(T::regs().sr().read().ifem(), true); - } - - // 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; - let start_index = len_to_copy; - let end_index = start_index + (C::BLOCK_SIZE * num_full_blocks); - Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &aad[start_index..end_index]).await; - - if last_aad_block { - if leftovers > 0 { - Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await; - assert_eq!(T::regs().sr().read().ifem(), true); - } - // 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`. @@ -1478,105 +1282,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { 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. - /// Output buffer must be at least as long as the input buffer. - /// 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 async fn payload<'c, C: Cipher<'c> + CipherSized + IVSized>( - &mut self, - ctx: &mut Context<'c, C>, - input: &[u8], - output: &mut [u8], - last_block: bool, - ) where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { - 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, cryp_v4))] - { - 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 index = block * C::BLOCK_SIZE; - // Read block out - let read = Self::read_bytes( - &mut self.outdma, - C::BLOCK_SIZE, - &mut output[index..index + C::BLOCK_SIZE], - ); - // Write block in - let write = Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &input[index..index + C::BLOCK_SIZE]); - embassy_futures::join::join(read, write).await; - } - - // 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(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 read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut intermediate_data); - let write = Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &last_block); - embassy_futures::join::join(read, write).await; - - // 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(T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask) - .await; - } - - ctx.payload_len += input.len() as u64; - - self.store_context(ctx); - } - #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] /// Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC. /// Called after the all data has been encrypted/decrypted by `payload`. @@ -1623,57 +1328,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { tag } - #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] - // Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC. - /// Called after the all data has been encrypted/decrypted by `payload`. - pub async fn finish< - 'c, - const TAG_SIZE: usize, - C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated, - >( - &mut self, - mut ctx: Context<'c, C>, - ) -> [u8; TAG_SIZE] - where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { - 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)] - let footer: [u32; 4] = [ - headerlen1.swap_bytes(), - headerlen2.swap_bytes(), - payloadlen1.swap_bytes(), - payloadlen2.swap_bytes(), - ]; - #[cfg(any(cryp_v3, cryp_v4))] - let footer: [u32; 4] = [headerlen1, headerlen2, payloadlen1, payloadlen2]; - - let write = Self::write_words(&mut self.indma, C::BLOCK_SIZE, &footer); - - let mut full_tag: [u8; 16] = [0; 16]; - let read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut full_tag); - - embassy_futures::join::join(read, write).await; - - 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; @@ -1774,31 +1428,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { } } - async fn write_bytes(dma: &mut PeripheralRef<'_, DmaIn>, block_size: usize, blocks: &[u8]) - where - DmaIn: crate::cryp::DmaIn, - { - if blocks.len() == 0 { - return; - } - // Ensure input is a multiple of block size. - assert_eq!(blocks.len() % block_size, 0); - // Configure DMA to transfer input to crypto core. - let dma_request = dma.request(); - let dst_ptr: *mut u32 = T::regs().din().as_ptr(); - let num_words = blocks.len() / 4; - let src_ptr: *const [u8] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); - let options = TransferOptions { - #[cfg(not(gpdma))] - priority: crate::dma::Priority::High, - ..Default::default() - }; - let dma_transfer = unsafe { Transfer::new_write_raw(dma, dma_request, src_ptr, dst_ptr, options) }; - T::regs().dmacr().modify(|w| w.set_dien(true)); - // Wait for the transfer to complete. - dma_transfer.await; - } - #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] fn write_words_blocking(&self, block_size: usize, blocks: &[u32]) { assert_eq!((blocks.len() * 4) % block_size, 0); @@ -1813,32 +1442,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { } } - #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] - async fn write_words(dma: &mut PeripheralRef<'_, DmaIn>, block_size: usize, blocks: &[u32]) - where - DmaIn: crate::cryp::DmaIn, - { - if blocks.len() == 0 { - return; - } - // Ensure input is a multiple of block size. - assert_eq!((blocks.len() * 4) % block_size, 0); - // Configure DMA to transfer input to crypto core. - let dma_request = dma.request(); - let dst_ptr: *mut u32 = T::regs().din().as_ptr(); - let num_words = blocks.len(); - let src_ptr: *const [u32] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); - let options = TransferOptions { - #[cfg(not(gpdma))] - priority: crate::dma::Priority::High, - ..Default::default() - }; - let dma_transfer = unsafe { Transfer::new_write_raw(dma, dma_request, src_ptr, dst_ptr, options) }; - T::regs().dmacr().modify(|w| w.set_dien(true)); - // Wait for the transfer to complete. - dma_transfer.await; - } - fn read_bytes_blocking(&self, block_size: usize, blocks: &mut [u8]) { // Block until there is output to read. while !T::regs().sr().read().ofne() {} @@ -1853,18 +1456,408 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { index += 4; } } +} - async fn read_bytes(dma: &mut PeripheralRef<'_, DmaOut>, block_size: usize, blocks: &mut [u8]) - where - DmaOut: crate::cryp::DmaOut, - { +impl<'d, T: Instance> Cryp<'d, T, Async> { + /// Create a new CRYP driver. + pub fn new( + peri: impl Peripheral

+ 'd, + indma: impl Peripheral

> + 'd, + outdma: impl Peripheral

> + 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + ) -> Self { + rcc::enable_and_reset::(); + into_ref!(peri, indma, outdma); + let instance = Self { + _peripheral: peri, + _phantom: PhantomData, + indma: new_dma!(indma), + outdma: new_dma!(outdma), + }; + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + instance + } + + /// Start a new encrypt or decrypt operation for the given cipher. + pub async fn start<'c, C: Cipher<'c> + CipherSized + IVSized>( + &mut 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).await; + + self.store_context(&mut ctx); + + ctx + } + + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] + /// Controls the header phase of cipher processing. + /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC. + /// All additional associated data (AAD) must be supplied to this function prior to starting the payload phase with `payload`. + /// The AAD must be supplied in multiples of the block size (128-bits for AES, 64-bits for DES), except when supplying the last block. + /// When supplying the last block of AAD, `last_aad_block` must be `true`. + pub async fn aad< + 'c, + const TAG_SIZE: usize, + C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated, + >( + &mut 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 { + Self::write_bytes(self.indma.as_mut().unwrap(), C::BLOCK_SIZE, &ctx.aad_buffer).await; + assert_eq!(T::regs().sr().read().ifem(), true); + + // 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. + Self::write_bytes(self.indma.as_mut().unwrap(), C::BLOCK_SIZE, &ctx.aad_buffer).await; + assert_eq!(T::regs().sr().read().ifem(), true); + } + + // 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; + let start_index = len_to_copy; + let end_index = start_index + (C::BLOCK_SIZE * num_full_blocks); + Self::write_bytes( + self.indma.as_mut().unwrap(), + C::BLOCK_SIZE, + &aad[start_index..end_index], + ) + .await; + + if last_aad_block { + if leftovers > 0 { + Self::write_bytes(self.indma.as_mut().unwrap(), C::BLOCK_SIZE, &ctx.aad_buffer).await; + assert_eq!(T::regs().sr().read().ifem(), true); + } + // 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. + /// Output buffer must be at least as long as the input buffer. + /// 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 async fn payload<'c, C: Cipher<'c> + CipherSized + IVSized>( + &mut 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, cryp_v4))] + { + 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 index = block * C::BLOCK_SIZE; + // Read block out + let read = Self::read_bytes( + self.outdma.as_mut().unwrap(), + C::BLOCK_SIZE, + &mut output[index..index + C::BLOCK_SIZE], + ); + // Write block in + let write = Self::write_bytes( + self.indma.as_mut().unwrap(), + C::BLOCK_SIZE, + &input[index..index + C::BLOCK_SIZE], + ); + embassy_futures::join::join(read, write).await; + } + + // 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(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 read = Self::read_bytes(self.outdma.as_mut().unwrap(), C::BLOCK_SIZE, &mut intermediate_data); + let write = Self::write_bytes(self.indma.as_mut().unwrap(), C::BLOCK_SIZE, &last_block); + embassy_futures::join::join(read, write).await; + + // 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(T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask) + .await; + } + + ctx.payload_len += input.len() as u64; + + self.store_context(ctx); + } + + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] + // Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC. + /// Called after the all data has been encrypted/decrypted by `payload`. + pub async fn finish< + 'c, + const TAG_SIZE: usize, + C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated, + >( + &mut 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)] + let footer: [u32; 4] = [ + headerlen1.swap_bytes(), + headerlen2.swap_bytes(), + payloadlen1.swap_bytes(), + payloadlen2.swap_bytes(), + ]; + #[cfg(any(cryp_v3, cryp_v4))] + let footer: [u32; 4] = [headerlen1, headerlen2, payloadlen1, payloadlen2]; + + let write = Self::write_words(self.indma.as_mut().unwrap(), C::BLOCK_SIZE, &footer); + + let mut full_tag: [u8; 16] = [0; 16]; + let read = Self::read_bytes(self.outdma.as_mut().unwrap(), C::BLOCK_SIZE, &mut full_tag); + + embassy_futures::join::join(read, write).await; + + 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 + } + + async fn write_bytes(dma: &mut ChannelAndRequest<'d>, block_size: usize, blocks: &[u8]) { + if blocks.len() == 0 { + return; + } + // Ensure input is a multiple of block size. + assert_eq!(blocks.len() % block_size, 0); + // Configure DMA to transfer input to crypto core. + let dst_ptr: *mut u32 = T::regs().din().as_ptr(); + let num_words = blocks.len() / 4; + let src_ptr: *const [u8] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); + let options = TransferOptions { + #[cfg(not(gpdma))] + priority: crate::dma::Priority::High, + ..Default::default() + }; + let dma_transfer = unsafe { dma.write_raw(src_ptr, dst_ptr, options) }; + T::regs().dmacr().modify(|w| w.set_dien(true)); + // Wait for the transfer to complete. + dma_transfer.await; + } + + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] + async fn write_words(dma: &mut ChannelAndRequest<'d>, block_size: usize, blocks: &[u32]) { + if blocks.len() == 0 { + return; + } + // Ensure input is a multiple of block size. + assert_eq!((blocks.len() * 4) % block_size, 0); + // Configure DMA to transfer input to crypto core. + let dst_ptr: *mut u32 = T::regs().din().as_ptr(); + let num_words = blocks.len(); + let src_ptr: *const [u32] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); + let options = TransferOptions { + #[cfg(not(gpdma))] + priority: crate::dma::Priority::High, + ..Default::default() + }; + let dma_transfer = unsafe { dma.write_raw(src_ptr, dst_ptr, options) }; + T::regs().dmacr().modify(|w| w.set_dien(true)); + // Wait for the transfer to complete. + dma_transfer.await; + } + + async fn read_bytes(dma: &mut ChannelAndRequest<'d>, block_size: usize, blocks: &mut [u8]) { if blocks.len() == 0 { return; } // Ensure input is a multiple of block size. assert_eq!(blocks.len() % block_size, 0); // Configure DMA to get output from crypto core. - let dma_request = dma.request(); let src_ptr = T::regs().dout().as_ptr(); let num_words = blocks.len() / 4; let dst_ptr = ptr::slice_from_raw_parts_mut(blocks.as_mut_ptr().cast(), num_words); @@ -1873,7 +1866,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { priority: crate::dma::Priority::VeryHigh, ..Default::default() }; - let dma_transfer = unsafe { Transfer::new_read_raw(dma, dma_request, src_ptr, dst_ptr, options) }; + let dma_transfer = unsafe { dma.read_raw(src_ptr, dst_ptr, options) }; T::regs().dmacr().modify(|w| w.set_doen(true)); // Wait for the transfer to complete. dma_transfer.await; diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 8bba5ded0..7a63dc5fc 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -3,9 +3,10 @@ use core::marker::PhantomData; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::into_ref; -use crate::dma::NoDma; +use crate::dma::ChannelAndRequest; +use crate::mode::{Async, Blocking, Mode as PeriMode}; #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] use crate::pac::dac; use crate::rcc::{self, RccPeripheral}; @@ -100,24 +101,20 @@ pub enum ValueArray<'a> { /// /// If you want to use both channels, either together or independently, /// create a [`Dac`] first and use it to access each channel. -pub struct DacChannel<'d, T: Instance, const N: u8, DMA = NoDma> { - phantom: PhantomData<&'d mut T>, +pub struct DacChannel<'d, T: Instance, C: Channel, M: PeriMode> { + phantom: PhantomData<&'d mut (T, C, M)>, #[allow(unused)] - dma: PeripheralRef<'d, DMA>, + dma: Option>, } /// DAC channel 1 type alias. -pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>; +pub type DacCh1<'d, T, M> = DacChannel<'d, T, Ch1, M>; /// DAC channel 2 type alias. -pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>; - -impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { - const IDX: usize = (N - 1) as usize; +pub type DacCh2<'d, T, M> = DacChannel<'d, T, Ch2, M>; +impl<'d, T: Instance, C: Channel> DacChannel<'d, T, C, Async> { /// Create a new `DacChannel` instance, consuming the underlying DAC peripheral. /// - /// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument. - /// /// The channel is enabled on creation and begin to drive the output pin. /// Note that some methods, such as `set_trigger()` and `set_mode()`, will /// disable the channel; you must re-enable it with `enable()`. @@ -125,21 +122,18 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { /// By default, triggering is disabled, but it can be enabled using /// [`DacChannel::set_trigger()`]. pub fn new( - _peri: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, - pin: impl Peripheral

+ crate::gpio::Pin> + 'd, + peri: impl Peripheral

+ 'd, + dma: impl Peripheral

> + 'd, + pin: impl Peripheral

> + 'd, ) -> Self { into_ref!(dma, pin); pin.set_as_analog(); - rcc::enable_and_reset::(); - let mut dac = Self { - phantom: PhantomData, - dma, - }; - #[cfg(any(dac_v5, dac_v6, dac_v7))] - dac.set_hfsel(); - dac.enable(); - dac + Self::new_inner( + peri, + new_dma!(dma), + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] + Mode::NormalExternalBuffered, + ) } /// Create a new `DacChannel` instance where the external output pin is not used, @@ -150,13 +144,99 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the /// channel; you must re-enable it with `enable()`. /// - /// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument. + /// By default, triggering is disabled, but it can be enabled using + /// [`DacChannel::set_trigger()`]. + #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] + pub fn new_internal(peri: impl Peripheral

+ 'd, dma: impl Peripheral

> + 'd) -> Self { + into_ref!(dma); + Self::new_inner(peri, new_dma!(dma), Mode::NormalInternalUnbuffered) + } + + /// Write `data` to this channel via DMA. + /// + /// To prevent delays or glitches when outputing a periodic waveform, the `circular` + /// flag can be set. This configures a circular DMA transfer that continually outputs + /// `data`. Note that for performance reasons in circular mode the transfer-complete + /// interrupt is disabled. + #[cfg(not(gpdma))] + pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) { + // Enable DAC and DMA + T::regs().cr().modify(|w| { + w.set_en(C::IDX, true); + w.set_dmaen(C::IDX, true); + }); + + let dma = self.dma.as_mut().unwrap(); + + let tx_options = crate::dma::TransferOptions { + circular, + half_transfer_ir: false, + complete_transfer_ir: !circular, + ..Default::default() + }; + + // Initiate the correct type of DMA transfer depending on what data is passed + let tx_f = match data { + ValueArray::Bit8(buf) => unsafe { dma.write(buf, T::regs().dhr8r(C::IDX).as_ptr() as *mut u8, tx_options) }, + ValueArray::Bit12Left(buf) => unsafe { + dma.write(buf, T::regs().dhr12l(C::IDX).as_ptr() as *mut u16, tx_options) + }, + ValueArray::Bit12Right(buf) => unsafe { + dma.write(buf, T::regs().dhr12r(C::IDX).as_ptr() as *mut u16, tx_options) + }, + }; + + tx_f.await; + + T::regs().cr().modify(|w| { + w.set_en(C::IDX, false); + w.set_dmaen(C::IDX, false); + }); + } +} + +impl<'d, T: Instance, C: Channel> DacChannel<'d, T, C, Blocking> { + /// Create a new `DacChannel` instance, consuming the underlying DAC peripheral. + /// + /// The channel is enabled on creation and begin to drive the output pin. + /// Note that some methods, such as `set_trigger()` and `set_mode()`, will + /// disable the channel; you must re-enable it with `enable()`. + /// + /// By default, triggering is disabled, but it can be enabled using + /// [`DacChannel::set_trigger()`]. + pub fn new_blocking(peri: impl Peripheral

+ 'd, pin: impl Peripheral

> + 'd) -> Self { + into_ref!(pin); + pin.set_as_analog(); + Self::new_inner( + peri, + None, + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] + Mode::NormalExternalBuffered, + ) + } + + /// Create a new `DacChannel` instance where the external output pin is not used, + /// so the DAC can only be used to generate internal signals. + /// The GPIO pin is therefore available to be used for other functions. + /// + /// The channel is set to [`Mode::NormalInternalUnbuffered`] and enabled on creation. + /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the + /// channel; you must re-enable it with `enable()`. /// /// By default, triggering is disabled, but it can be enabled using /// [`DacChannel::set_trigger()`]. #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] - pub fn new_internal(_peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd) -> Self { - into_ref!(dma); + pub fn new_internal_blocking(peri: impl Peripheral

+ 'd) -> Self { + Self::new_inner(peri, None, Mode::NormalInternalUnbuffered) + } +} + +impl<'d, T: Instance, C: Channel, M: PeriMode> DacChannel<'d, T, C, M> { + fn new_inner( + _peri: impl Peripheral

+ 'd, + dma: Option>, + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] mode: Mode, + ) -> Self { rcc::enable_and_reset::(); let mut dac = Self { phantom: PhantomData, @@ -164,7 +244,8 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { }; #[cfg(any(dac_v5, dac_v6, dac_v7))] dac.set_hfsel(); - dac.set_mode(Mode::NormalInternalUnbuffered); + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] + dac.set_mode(mode); dac.enable(); dac } @@ -173,7 +254,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { pub fn set_enable(&mut self, on: bool) { critical_section::with(|_| { T::regs().cr().modify(|reg| { - reg.set_en(Self::IDX, on); + reg.set_en(C::IDX, on); }); }); } @@ -194,8 +275,8 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { pub fn set_trigger(&mut self, source: TriggerSel) { critical_section::with(|_| { T::regs().cr().modify(|reg| { - reg.set_en(Self::IDX, false); - reg.set_tsel(Self::IDX, source as u8); + reg.set_en(C::IDX, false); + reg.set_tsel(C::IDX, source as u8); }); }); } @@ -204,7 +285,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { pub fn set_triggering(&mut self, on: bool) { critical_section::with(|_| { T::regs().cr().modify(|reg| { - reg.set_ten(Self::IDX, on); + reg.set_ten(C::IDX, on); }); }); } @@ -212,7 +293,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { /// Software trigger this channel. pub fn trigger(&mut self) { T::regs().swtrigr().write(|reg| { - reg.set_swtrig(Self::IDX, true); + reg.set_swtrig(C::IDX, true); }); } @@ -223,10 +304,10 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { pub fn set_mode(&mut self, mode: Mode) { critical_section::with(|_| { T::regs().cr().modify(|reg| { - reg.set_en(Self::IDX, false); + reg.set_en(C::IDX, false); }); T::regs().mcr().modify(|reg| { - reg.set_mode(Self::IDX, mode.mode()); + reg.set_mode(C::IDX, mode.mode()); }); }); } @@ -237,15 +318,15 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { /// it will be output after the next trigger. pub fn set(&mut self, value: Value) { match value { - Value::Bit8(v) => T::regs().dhr8r(Self::IDX).write(|reg| reg.set_dhr(v)), - Value::Bit12Left(v) => T::regs().dhr12l(Self::IDX).write(|reg| reg.set_dhr(v)), - Value::Bit12Right(v) => T::regs().dhr12r(Self::IDX).write(|reg| reg.set_dhr(v)), + Value::Bit8(v) => T::regs().dhr8r(C::IDX).write(|reg| reg.set_dhr(v)), + Value::Bit12Left(v) => T::regs().dhr12l(C::IDX).write(|reg| reg.set_dhr(v)), + Value::Bit12Right(v) => T::regs().dhr12r(C::IDX).write(|reg| reg.set_dhr(v)), } } /// Read the current output value of the DAC. pub fn read(&self) -> u16 { - T::regs().dor(Self::IDX).read().dor() + T::regs().dor(C::IDX).read().dor() } /// Set HFSEL as appropriate for the current peripheral clock frequency. @@ -279,82 +360,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { } } -macro_rules! impl_dma_methods { - ($n:literal, $trait:ident) => { - impl<'d, T: Instance, DMA> DacChannel<'d, T, $n, DMA> - where - DMA: $trait, - { - /// Write `data` to this channel via DMA. - /// - /// To prevent delays or glitches when outputing a periodic waveform, the `circular` - /// flag can be set. This configures a circular DMA transfer that continually outputs - /// `data`. Note that for performance reasons in circular mode the transfer-complete - /// interrupt is disabled. - #[cfg(not(gpdma))] - pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) { - // Enable DAC and DMA - T::regs().cr().modify(|w| { - w.set_en(Self::IDX, true); - w.set_dmaen(Self::IDX, true); - }); - - let tx_request = self.dma.request(); - let dma_channel = &mut self.dma; - - let tx_options = crate::dma::TransferOptions { - circular, - half_transfer_ir: false, - complete_transfer_ir: !circular, - ..Default::default() - }; - - // Initiate the correct type of DMA transfer depending on what data is passed - let tx_f = match data { - ValueArray::Bit8(buf) => unsafe { - crate::dma::Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr8r(Self::IDX).as_ptr() as *mut u8, - tx_options, - ) - }, - ValueArray::Bit12Left(buf) => unsafe { - crate::dma::Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr12l(Self::IDX).as_ptr() as *mut u16, - tx_options, - ) - }, - ValueArray::Bit12Right(buf) => unsafe { - crate::dma::Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr12r(Self::IDX).as_ptr() as *mut u16, - tx_options, - ) - }, - }; - - tx_f.await; - - T::regs().cr().modify(|w| { - w.set_en(Self::IDX, false); - w.set_dmaen(Self::IDX, false); - }); - } - } - }; -} - -impl_dma_methods!(1, DacDma1); -impl_dma_methods!(2, DacDma2); - -impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> { +impl<'d, T: Instance, C: Channel, M: PeriMode> Drop for DacChannel<'d, T, C, M> { fn drop(&mut self) { rcc::disable::(); } @@ -368,14 +374,14 @@ impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> { /// /// ```ignore /// // Pins may need to be changed for your specific device. -/// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, NoDma, NoDma, p.PA4, p.PA5).split(); +/// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new_blocking(p.DAC1, p.PA4, p.PA5).split(); /// ``` -pub struct Dac<'d, T: Instance, DMACh1 = NoDma, DMACh2 = NoDma> { - ch1: DacChannel<'d, T, 1, DMACh1>, - ch2: DacChannel<'d, T, 2, DMACh2>, +pub struct Dac<'d, T: Instance, M: PeriMode> { + ch1: DacChannel<'d, T, Ch1, M>, + ch2: DacChannel<'d, T, Ch2, M>, } -impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { +impl<'d, T: Instance> Dac<'d, T, Async> { /// Create a new `Dac` instance, consuming the underlying DAC peripheral. /// /// This struct allows you to access both channels of the DAC, where available. You can either @@ -389,37 +395,22 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { /// By default, triggering is disabled, but it can be enabled using the `set_trigger()` /// method on the underlying channels. pub fn new( - _peri: impl Peripheral

+ 'd, - dma_ch1: impl Peripheral

+ 'd, - dma_ch2: impl Peripheral

+ 'd, - pin_ch1: impl Peripheral

+ crate::gpio::Pin> + 'd, - pin_ch2: impl Peripheral

+ crate::gpio::Pin> + 'd, + peri: impl Peripheral

+ 'd, + dma_ch1: impl Peripheral

> + 'd, + dma_ch2: impl Peripheral

> + 'd, + pin_ch1: impl Peripheral

+ crate::gpio::Pin> + 'd, + pin_ch2: impl Peripheral

+ crate::gpio::Pin> + 'd, ) -> Self { into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2); pin_ch1.set_as_analog(); pin_ch2.set_as_analog(); - - // Enable twice to increment the DAC refcount for each channel. - rcc::enable_and_reset::(); - rcc::enable_and_reset::(); - - let mut ch1 = DacCh1 { - phantom: PhantomData, - dma: dma_ch1, - }; - #[cfg(any(dac_v5, dac_v6, dac_v7))] - ch1.set_hfsel(); - ch1.enable(); - - let mut ch2 = DacCh2 { - phantom: PhantomData, - dma: dma_ch2, - }; - #[cfg(any(dac_v5, dac_v6, dac_v7))] - ch2.set_hfsel(); - ch2.enable(); - - Self { ch1, ch2 } + Self::new_inner( + peri, + new_dma!(dma_ch1), + new_dma!(dma_ch2), + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] + Mode::NormalExternalBuffered, + ) } /// Create a new `Dac` instance where the external output pins are not used, @@ -438,11 +429,77 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { /// method on the underlying channels. #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] pub fn new_internal( - _peri: impl Peripheral

+ 'd, - dma_ch1: impl Peripheral

+ 'd, - dma_ch2: impl Peripheral

+ 'd, + peri: impl Peripheral

+ 'd, + dma_ch1: impl Peripheral

> + 'd, + dma_ch2: impl Peripheral

> + 'd, ) -> Self { into_ref!(dma_ch1, dma_ch2); + Self::new_inner( + peri, + new_dma!(dma_ch1), + new_dma!(dma_ch2), + Mode::NormalInternalUnbuffered, + ) + } +} + +impl<'d, T: Instance> Dac<'d, T, Blocking> { + /// Create a new `Dac` instance, consuming the underlying DAC peripheral. + /// + /// This struct allows you to access both channels of the DAC, where available. You can either + /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use + /// the two channels together. + /// + /// The channels are enabled on creation and begin to drive their output pins. + /// Note that some methods, such as `set_trigger()` and `set_mode()`, will + /// disable the channel; you must re-enable them with `enable()`. + /// + /// By default, triggering is disabled, but it can be enabled using the `set_trigger()` + /// method on the underlying channels. + pub fn new_blocking( + peri: impl Peripheral

+ 'd, + pin_ch1: impl Peripheral

+ crate::gpio::Pin> + 'd, + pin_ch2: impl Peripheral

+ crate::gpio::Pin> + 'd, + ) -> Self { + into_ref!(pin_ch1, pin_ch2); + pin_ch1.set_as_analog(); + pin_ch2.set_as_analog(); + Self::new_inner( + peri, + None, + None, + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] + Mode::NormalExternalBuffered, + ) + } + + /// Create a new `Dac` instance where the external output pins are not used, + /// so the DAC can only be used to generate internal signals but the GPIO + /// pins remain available for other functions. + /// + /// This struct allows you to access both channels of the DAC, where available. You can either + /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use the two + /// channels together. + /// + /// The channels are set to [`Mode::NormalInternalUnbuffered`] and enabled on creation. + /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the + /// channel; you must re-enable them with `enable()`. + /// + /// By default, triggering is disabled, but it can be enabled using the `set_trigger()` + /// method on the underlying channels. + #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] + pub fn new_internal(peri: impl Peripheral

+ 'd) -> Self { + Self::new_inner(peri, None, None, Mode::NormalInternalUnbuffered) + } +} + +impl<'d, T: Instance, M: PeriMode> Dac<'d, T, M> { + fn new_inner( + _peri: impl Peripheral

+ 'd, + dma_ch1: Option>, + dma_ch2: Option>, + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] mode: Mode, + ) -> Self { // Enable twice to increment the DAC refcount for each channel. rcc::enable_and_reset::(); rcc::enable_and_reset::(); @@ -453,7 +510,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { }; #[cfg(any(dac_v5, dac_v6, dac_v7))] ch1.set_hfsel(); - ch1.set_mode(Mode::NormalInternalUnbuffered); + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] + ch1.set_mode(mode); ch1.enable(); let mut ch2 = DacCh2 { @@ -462,7 +520,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { }; #[cfg(any(dac_v5, dac_v6, dac_v7))] ch2.set_hfsel(); - ch2.set_mode(Mode::NormalInternalUnbuffered); + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] + ch2.set_mode(mode); ch2.enable(); Self { ch1, ch2 } @@ -471,17 +530,17 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { /// Split this `Dac` into separate channels. /// /// You can access and move the channels around separately after splitting. - pub fn split(self) -> (DacCh1<'d, T, DMACh1>, DacCh2<'d, T, DMACh2>) { + pub fn split(self) -> (DacCh1<'d, T, M>, DacCh2<'d, T, M>) { (self.ch1, self.ch2) } /// Temporarily access channel 1. - pub fn ch1(&mut self) -> &mut DacCh1<'d, T, DMACh1> { + pub fn ch1(&mut self) -> &mut DacCh1<'d, T, M> { &mut self.ch1 } /// Temporarily access channel 2. - pub fn ch2(&mut self) -> &mut DacCh2<'d, T, DMACh2> { + pub fn ch2(&mut self) -> &mut DacCh2<'d, T, M> { &mut self.ch2 } @@ -514,11 +573,30 @@ trait SealedInstance { /// DAC instance. #[allow(private_bounds)] pub trait Instance: SealedInstance + RccPeripheral + 'static {} -dma_trait!(DacDma1, Instance); -dma_trait!(DacDma2, Instance); -/// Marks a pin that can be used with the DAC -pub trait DacPin: crate::gpio::Pin + 'static {} +/// Channel 1 marker type. +pub enum Ch1 {} +/// Channel 2 marker type. +pub enum Ch2 {} + +trait SealedChannel { + const IDX: usize; +} +/// DAC channel trait. +#[allow(private_bounds)] +pub trait Channel: SealedChannel {} + +impl SealedChannel for Ch1 { + const IDX: usize = 0; +} +impl SealedChannel for Ch2 { + const IDX: usize = 1; +} +impl Channel for Ch1 {} +impl Channel for Ch2 {} + +dma_trait!(Dma, Instance, Channel); +pin_trait!(DacPin, Instance, Channel); foreach_peripheral!( (dac, $inst:ident) => { @@ -531,9 +609,3 @@ foreach_peripheral!( impl crate::dac::Instance for peripherals::$inst {} }; ); - -macro_rules! impl_dac_pin { - ($inst:ident, $pin:ident, $ch:expr) => { - impl crate::dac::DacPin for crate::peripherals::$pin {} - }; -} diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 66c4aa53c..ac4a0f98e 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -108,17 +108,6 @@ impl Channel for AnyChannel {} const CHANNEL_COUNT: usize = crate::_generated::DMA_CHANNELS.len(); static STATE: [ChannelState; CHANNEL_COUNT] = [ChannelState::NEW; CHANNEL_COUNT]; -/// "No DMA" placeholder. -/// -/// You may pass this in place of a real DMA channel when creating a driver -/// to indicate it should not use DMA. -/// -/// This often causes async functionality to not be available on the instance, -/// leaving only blocking functionality. -pub struct NoDma; - -impl_peripheral!(NoDma); - // safety: must be called only once at startup pub(crate) unsafe fn init( cs: critical_section::CriticalSection, diff --git a/embassy-stm32/src/dma/util.rs b/embassy-stm32/src/dma/util.rs index 5aaca57c9..5e1158182 100644 --- a/embassy-stm32/src/dma/util.rs +++ b/embassy-stm32/src/dma/util.rs @@ -39,10 +39,10 @@ impl<'d> ChannelAndRequest<'d> { Transfer::new_write(&mut self.channel, self.request, buf, peri_addr, options) } - pub unsafe fn write_raw<'a, W: Word>( + pub unsafe fn write_raw<'a, MW: Word, PW: Word>( &'a mut self, - buf: *const [W], - peri_addr: *mut W, + buf: *const [MW], + peri_addr: *mut PW, options: TransferOptions, ) -> Transfer<'a> { Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options) diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index 3c2125498..3951e9d63 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -12,10 +12,12 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use stm32_metapac::hash::regs::*; -use crate::dma::NoDma; #[cfg(hash_v2)] -use crate::dma::Transfer; +use crate::dma::ChannelAndRequest; use crate::interrupt::typelevel::Interrupt; +#[cfg(hash_v2)] +use crate::mode::Async; +use crate::mode::{Blocking, Mode}; use crate::peripherals::HASH; use crate::{interrupt, pac, peripherals, rcc, Peripheral}; @@ -116,24 +118,26 @@ pub struct Context<'c> { type HmacKey<'k> = Option<&'k [u8]>; /// HASH driver. -pub struct Hash<'d, T: Instance, D = NoDma> { +pub struct Hash<'d, T: Instance, M: Mode> { _peripheral: PeripheralRef<'d, T>, - #[allow(dead_code)] - dma: PeripheralRef<'d, D>, + _phantom: PhantomData, + #[cfg(hash_v2)] + dma: Option>, } -impl<'d, T: Instance, D> Hash<'d, T, D> { +impl<'d, T: Instance> Hash<'d, T, Blocking> { /// Instantiates, resets, and enables the HASH peripheral. - pub fn new( + pub fn new_blocking( peripheral: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { rcc::enable_and_reset::(); - into_ref!(peripheral, dma); + into_ref!(peripheral); let instance = Self { _peripheral: peripheral, - dma: dma, + _phantom: PhantomData, + #[cfg(hash_v2)] + dma: None, }; T::Interrupt::unpend(); @@ -141,7 +145,9 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { instance } +} +impl<'d, T: Instance, M: Mode> Hash<'d, T, M> { /// Starts computation of a new hash and returns the saved peripheral state. pub fn start<'c>(&mut self, algorithm: Algorithm, format: DataType, key: HmacKey<'c>) -> Context<'c> { // Define a context for this new computation. @@ -282,14 +288,136 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { self.store_context(ctx); } + /// Computes a digest for the given context. + /// The digest buffer must be large enough to accomodate a digest for the selected algorithm. + /// The largest returned digest size is 128 bytes for SHA-512. + /// Panics if the supplied digest buffer is too short. + pub fn finish_blocking<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize { + // Restore the peripheral state. + self.load_context(&ctx); + + // Hash the leftover bytes, if any. + self.accumulate_blocking(&ctx.buffer[0..ctx.buflen]); + ctx.buflen = 0; + + //Start the digest calculation. + T::regs().str().write(|w| w.set_dcal(true)); + + // Load the HMAC key if provided. + if let Some(key) = ctx.key { + while !T::regs().sr().read().dinis() {} + self.accumulate_blocking(key); + T::regs().str().write(|w| w.set_dcal(true)); + } + + // Block until digest computation is complete. + while !T::regs().sr().read().dcis() {} + + // Return the digest. + let digest_words = match ctx.algo { + Algorithm::SHA1 => 5, + #[cfg(any(hash_v1, hash_v2, hash_v4))] + Algorithm::MD5 => 4, + Algorithm::SHA224 => 7, + Algorithm::SHA256 => 8, + #[cfg(hash_v3)] + Algorithm::SHA384 => 12, + #[cfg(hash_v3)] + Algorithm::SHA512_224 => 7, + #[cfg(hash_v3)] + Algorithm::SHA512_256 => 8, + #[cfg(hash_v3)] + Algorithm::SHA512 => 16, + }; + + let digest_len_bytes = digest_words * 4; + // Panics if the supplied digest buffer is too short. + if digest.len() < digest_len_bytes { + panic!("Digest buffer must be at least {} bytes long.", digest_words * 4); + } + + let mut i = 0; + while i < digest_words { + let word = T::regs().hr(i).read(); + digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); + i += 1; + } + digest_len_bytes + } + + /// Push data into the hash core. + fn accumulate_blocking(&mut self, input: &[u8]) { + // Set the number of valid bits. + let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; + T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); + + let mut i = 0; + while i < input.len() { + let mut word: [u8; 4] = [0; 4]; + let copy_idx = min(i + 4, input.len()); + word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]); + T::regs().din().write_value(u32::from_ne_bytes(word)); + i += 4; + } + } + + /// Save the peripheral state to a context. + fn store_context<'c>(&mut self, ctx: &mut Context<'c>) { + // Block waiting for data in ready. + while !T::regs().sr().read().dinis() {} + + // Store peripheral context. + ctx.imr = T::regs().imr().read().0; + ctx.str = T::regs().str().read().0; + ctx.cr = T::regs().cr().read().0; + let mut i = 0; + while i < NUM_CONTEXT_REGS { + ctx.csr[i] = T::regs().csr(i).read(); + i += 1; + } + } + + /// Restore the peripheral state from a context. + fn load_context(&mut self, ctx: &Context) { + // Restore the peripheral state from the context. + T::regs().imr().write_value(Imr { 0: ctx.imr }); + T::regs().str().write_value(Str { 0: ctx.str }); + T::regs().cr().write_value(Cr { 0: ctx.cr }); + T::regs().cr().modify(|w| w.set_init(true)); + let mut i = 0; + while i < NUM_CONTEXT_REGS { + T::regs().csr(i).write_value(ctx.csr[i]); + i += 1; + } + } +} + +#[cfg(hash_v2)] +impl<'d, T: Instance> Hash<'d, T, Async> { + /// Instantiates, resets, and enables the HASH peripheral. + pub fn new( + peripheral: impl Peripheral

+ 'd, + dma: impl Peripheral

> + 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + ) -> Self { + rcc::enable_and_reset::(); + into_ref!(peripheral, dma); + let instance = Self { + _peripheral: peripheral, + _phantom: PhantomData, + dma: new_dma!(dma), + }; + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + instance + } + /// Restores the peripheral state using the given context, /// then updates the state with the provided data. /// Peripheral state is saved upon return. - #[cfg(hash_v2)] - pub async fn update<'c>(&mut self, ctx: &mut Context<'c>, input: &[u8]) - where - D: crate::hash::Dma, - { + pub async fn update(&mut self, ctx: &mut Context<'_>, input: &[u8]) { // Restore the peripheral state. self.load_context(&ctx); @@ -353,68 +481,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { /// The digest buffer must be large enough to accomodate a digest for the selected algorithm. /// The largest returned digest size is 128 bytes for SHA-512. /// Panics if the supplied digest buffer is too short. - pub fn finish_blocking<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize { - // Restore the peripheral state. - self.load_context(&ctx); - - // Hash the leftover bytes, if any. - self.accumulate_blocking(&ctx.buffer[0..ctx.buflen]); - ctx.buflen = 0; - - //Start the digest calculation. - T::regs().str().write(|w| w.set_dcal(true)); - - // Load the HMAC key if provided. - if let Some(key) = ctx.key { - while !T::regs().sr().read().dinis() {} - self.accumulate_blocking(key); - T::regs().str().write(|w| w.set_dcal(true)); - } - - // Block until digest computation is complete. - while !T::regs().sr().read().dcis() {} - - // Return the digest. - let digest_words = match ctx.algo { - Algorithm::SHA1 => 5, - #[cfg(any(hash_v1, hash_v2, hash_v4))] - Algorithm::MD5 => 4, - Algorithm::SHA224 => 7, - Algorithm::SHA256 => 8, - #[cfg(hash_v3)] - Algorithm::SHA384 => 12, - #[cfg(hash_v3)] - Algorithm::SHA512_224 => 7, - #[cfg(hash_v3)] - Algorithm::SHA512_256 => 8, - #[cfg(hash_v3)] - Algorithm::SHA512 => 16, - }; - - let digest_len_bytes = digest_words * 4; - // Panics if the supplied digest buffer is too short. - if digest.len() < digest_len_bytes { - panic!("Digest buffer must be at least {} bytes long.", digest_words * 4); - } - - let mut i = 0; - while i < digest_words { - let word = T::regs().hr(i).read(); - digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); - i += 1; - } - digest_len_bytes - } - - /// Computes a digest for the given context. - /// The digest buffer must be large enough to accomodate a digest for the selected algorithm. - /// The largest returned digest size is 128 bytes for SHA-512. - /// Panics if the supplied digest buffer is too short. - #[cfg(hash_v2)] - pub async fn finish<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize - where - D: crate::hash::Dma, - { + pub async fn finish<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize { // Restore the peripheral state. self.load_context(&ctx); @@ -483,27 +550,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { } /// Push data into the hash core. - fn accumulate_blocking(&mut self, input: &[u8]) { - // Set the number of valid bits. - let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; - T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); - - let mut i = 0; - while i < input.len() { - let mut word: [u8; 4] = [0; 4]; - let copy_idx = min(i + 4, input.len()); - word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]); - T::regs().din().write_value(u32::from_ne_bytes(word)); - i += 4; - } - } - - /// Push data into the hash core. - #[cfg(hash_v2)] - async fn accumulate(&mut self, input: &[u8]) - where - D: crate::hash::Dma, - { + async fn accumulate(&mut self, input: &[u8]) { // Ignore an input length of 0. if input.len() == 0 { return; @@ -514,57 +561,20 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); // Configure DMA to transfer input to hash core. - let dma_request = self.dma.request(); let dst_ptr: *mut u32 = T::regs().din().as_ptr(); let mut num_words = input.len() / 4; if input.len() % 4 > 0 { num_words += 1; } let src_ptr: *const [u8] = ptr::slice_from_raw_parts(input.as_ptr().cast(), num_words); - let dma_transfer = unsafe { - Transfer::new_write_raw( - &mut self.dma, - dma_request, - src_ptr, - dst_ptr as *mut u32, - Default::default(), - ) - }; + + let dma = self.dma.as_mut().unwrap(); + let dma_transfer = unsafe { dma.write_raw(src_ptr, dst_ptr as *mut u32, Default::default()) }; T::regs().cr().modify(|w| w.set_dmae(true)); // Wait for the transfer to complete. dma_transfer.await; } - - /// Save the peripheral state to a context. - fn store_context<'c>(&mut self, ctx: &mut Context<'c>) { - // Block waiting for data in ready. - while !T::regs().sr().read().dinis() {} - - // Store peripheral context. - ctx.imr = T::regs().imr().read().0; - ctx.str = T::regs().str().read().0; - ctx.cr = T::regs().cr().read().0; - let mut i = 0; - while i < NUM_CONTEXT_REGS { - ctx.csr[i] = T::regs().csr(i).read(); - i += 1; - } - } - - /// Restore the peripheral state from a context. - fn load_context(&mut self, ctx: &Context) { - // Restore the peripheral state from the context. - T::regs().imr().write_value(Imr { 0: ctx.imr }); - T::regs().str().write_value(Str { 0: ctx.str }); - T::regs().cr().write_value(Cr { 0: ctx.cr }); - T::regs().cr().modify(|w| w.set_init(true)); - let mut i = 0; - while i < NUM_CONTEXT_REGS { - T::regs().csr(i).write_value(ctx.csr[i]); - i += 1; - } - } } trait SealedInstance { diff --git a/embassy-stm32/src/macros.rs b/embassy-stm32/src/macros.rs index ae53deb08..000773e2d 100644 --- a/embassy-stm32/src/macros.rs +++ b/embassy-stm32/src/macros.rs @@ -85,6 +85,18 @@ macro_rules! dma_trait_impl { }; } +#[allow(unused)] +macro_rules! new_dma_nonopt { + ($name:ident) => {{ + let dma = $name.into_ref(); + let request = dma.request(); + crate::dma::ChannelAndRequest { + channel: dma.map_into(), + request, + } + }}; +} + macro_rules! new_dma { ($name:ident) => {{ let dma = $name.into_ref(); diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 8af2f8381..d8671caf7 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -12,7 +12,8 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; -use crate::dma::NoDma; +#[cfg(sdmmc_v1)] +use crate::dma::ChannelAndRequest; #[cfg(gpio_v2)] use crate::gpio::Pull; use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; @@ -301,10 +302,10 @@ impl Default for Config { } /// Sdmmc device -pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma = NoDma> { +pub struct Sdmmc<'d, T: Instance> { _peri: PeripheralRef<'d, T>, - #[allow(unused)] - dma: PeripheralRef<'d, Dma>, + #[cfg(sdmmc_v1)] + dma: ChannelAndRequest<'d>, clk: PeripheralRef<'d, AnyPin>, cmd: PeripheralRef<'d, AnyPin>, @@ -334,18 +335,18 @@ const CMD_AF: AfType = AfType::output_pull(OutputType::PushPull, Speed::VeryHigh const DATA_AF: AfType = CMD_AF; #[cfg(sdmmc_v1)] -impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { +impl<'d, T: Instance> Sdmmc<'d, T> { /// Create a new SDMMC driver, with 1 data lane. pub fn new_1bit( sdmmc: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, - dma: impl Peripheral

+ 'd, + dma: impl Peripheral

> + 'd, clk: impl Peripheral

> + 'd, cmd: impl Peripheral

> + 'd, d0: impl Peripheral

> + 'd, config: Config, ) -> Self { - into_ref!(clk, cmd, d0); + into_ref!(dma, clk, cmd, d0); critical_section::with(|_| { clk.set_as_af(clk.af_num(), CLK_AF); @@ -355,7 +356,7 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { Self::new_inner( sdmmc, - dma, + new_dma_nonopt!(dma), clk.map_into(), cmd.map_into(), d0.map_into(), @@ -370,7 +371,7 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { pub fn new_4bit( sdmmc: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, - dma: impl Peripheral

+ 'd, + dma: impl Peripheral

> + 'd, clk: impl Peripheral

> + 'd, cmd: impl Peripheral

> + 'd, d0: impl Peripheral

> + 'd, @@ -392,7 +393,7 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { Self::new_inner( sdmmc, - dma, + new_dma_nonopt!(dma), clk.map_into(), cmd.map_into(), d0.map_into(), @@ -405,7 +406,7 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { } #[cfg(sdmmc_v2)] -impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { +impl<'d, T: Instance> Sdmmc<'d, T> { /// Create a new SDMMC driver, with 1 data lane. pub fn new_1bit( sdmmc: impl Peripheral

+ 'd, @@ -425,7 +426,6 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { Self::new_inner( sdmmc, - NoDma.into_ref(), clk.map_into(), cmd.map_into(), d0.map_into(), @@ -461,7 +461,6 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { Self::new_inner( sdmmc, - NoDma.into_ref(), clk.map_into(), cmd.map_into(), d0.map_into(), @@ -473,10 +472,10 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { } } -impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { +impl<'d, T: Instance> Sdmmc<'d, T> { fn new_inner( sdmmc: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, + #[cfg(sdmmc_v1)] dma: ChannelAndRequest<'d>, clk: PeripheralRef<'d, AnyPin>, cmd: PeripheralRef<'d, AnyPin>, d0: PeripheralRef<'d, AnyPin>, @@ -485,7 +484,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { d3: Option>, config: Config, ) -> Self { - into_ref!(sdmmc, dma); + into_ref!(sdmmc); rcc::enable_and_reset::(); @@ -514,6 +513,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { Self { _peri: sdmmc, + #[cfg(sdmmc_v1)] dma, clk, @@ -567,7 +567,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { #[allow(unused_variables)] fn prepare_datapath_read<'a>( config: &Config, - dma: &'a mut PeripheralRef<'d, Dma>, + #[cfg(sdmmc_v1)] dma: &'a mut ChannelAndRequest<'d>, buffer: &'a mut [u32], length_bytes: u32, block_size: u8, @@ -583,16 +583,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { regs.dlenr().write(|w| w.set_datalength(length_bytes)); #[cfg(sdmmc_v1)] - let transfer = unsafe { - let request = dma.request(); - Transfer::new_read( - dma, - request, - regs.fifor().as_ptr() as *mut u32, - buffer, - DMA_TRANSFER_OPTIONS, - ) - }; + let transfer = unsafe { dma.read(regs.fifor().as_ptr() as *mut u32, buffer, DMA_TRANSFER_OPTIONS) }; #[cfg(sdmmc_v2)] let transfer = { regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); @@ -632,14 +623,8 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { #[cfg(sdmmc_v1)] let transfer = unsafe { - let request = self.dma.request(); - Transfer::new_write( - &mut self.dma, - request, - buffer, - regs.fifor().as_ptr() as *mut u32, - DMA_TRANSFER_OPTIONS, - ) + self.dma + .write(buffer, regs.fifor().as_ptr() as *mut u32, DMA_TRANSFER_OPTIONS) }; #[cfg(sdmmc_v2)] let transfer = { @@ -735,7 +720,14 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6); + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + status.as_mut(), + 64, + 6, + ); InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6 @@ -821,7 +813,14 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6); + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + status.as_mut(), + 64, + 6, + ); InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::card_status(0), true)?; @@ -924,7 +923,14 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, scr, 8, 3); + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + scr, + 8, + 3, + ); InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::cmd51(), true)?; @@ -1214,7 +1220,14 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, buffer, 512, 9); + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + buffer, + 512, + 9, + ); InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::read_single_block(address), true)?; @@ -1347,7 +1360,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } } -impl<'d, T: Instance, Dma: SdmmcDma + 'd> Drop for Sdmmc<'d, T, Dma> { +impl<'d, T: Instance> Drop for Sdmmc<'d, T> { fn drop(&mut self) { T::Interrupt::disable(); Self::on_drop(); @@ -1484,15 +1497,6 @@ pin_trait!(D7Pin, Instance); #[cfg(sdmmc_v1)] dma_trait!(SdmmcDma, Instance); -/// DMA instance trait. -/// -/// This is only implemented for `NoDma`, since SDMMCv2 has DMA built-in, instead of -/// using ST's system-wide DMA peripheral. -#[cfg(sdmmc_v2)] -pub trait SdmmcDma {} -#[cfg(sdmmc_v2)] -impl SdmmcDma for NoDma {} - foreach_peripheral!( (sdmmc, $inst:ident) => { impl SealedInstance for peripherals::$inst { @@ -1512,7 +1516,7 @@ foreach_peripheral!( }; ); -impl<'d, T: Instance, Dma: SdmmcDma + 'd> block_device_driver::BlockDevice<512> for Sdmmc<'d, T, Dma> { +impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> { type Error = Error; type Align = aligned::A4; diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 44dda6a9e..a43da1b5a 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -839,7 +839,7 @@ impl<'d> Spi<'d, Async> { let rx_src = self.info.regs.rx_ptr(); let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) }; - let tx_dst = self.info.regs.tx_ptr(); + let tx_dst: *mut W = self.info.regs.tx_ptr(); let tx_f = unsafe { self.tx_dma .as_mut() diff --git a/examples/stm32f4/src/bin/dac.rs b/examples/stm32f4/src/bin/dac.rs index dd2a45718..68fe6cabd 100644 --- a/examples/stm32f4/src/bin/dac.rs +++ b/examples/stm32f4/src/bin/dac.rs @@ -4,7 +4,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dac::{DacCh1, Value}; -use embassy_stm32::dma::NoDma; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,7 +11,7 @@ async fn main(_spawner: Spawner) -> ! { let p = embassy_stm32::init(Default::default()); info!("Hello World, dude!"); - let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); + let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4); loop { for v in 0..=255 { diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs index a6f969aba..27df80336 100644 --- a/examples/stm32h7/src/bin/dac.rs +++ b/examples/stm32h7/src/bin/dac.rs @@ -4,7 +4,6 @@ use cortex_m_rt::entry; use defmt::*; use embassy_stm32::dac::{DacCh1, Value}; -use embassy_stm32::dma::NoDma; use embassy_stm32::Config; use {defmt_rtt as _, panic_probe as _}; @@ -44,7 +43,7 @@ fn main() -> ! { } let p = embassy_stm32::init(config); - let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); + let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4); loop { for v in 0..=255 { diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index 3a9887e3c..98c9f1e90 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs @@ -4,8 +4,9 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; +use embassy_stm32::mode::Async; use embassy_stm32::pac::timer::vals::Mms; -use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; +use embassy_stm32::peripherals::{DAC1, TIM6, TIM7}; use embassy_stm32::rcc::frequency; use embassy_stm32::time::Hertz; use embassy_stm32::timer::low_level::Timer; @@ -56,7 +57,7 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { +async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, Async>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM6 frequency is {}", frequency::()); @@ -99,7 +100,7 @@ async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { } #[embassy_executor::task] -async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { +async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, Async>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM7 frequency is {}", frequency::()); diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs index fdbf1d374..50db0e082 100644 --- a/examples/stm32l4/src/bin/dac.rs +++ b/examples/stm32l4/src/bin/dac.rs @@ -3,7 +3,6 @@ use defmt::*; use embassy_stm32::dac::{DacCh1, Value}; -use embassy_stm32::dma::NoDma; use {defmt_rtt as _, panic_probe as _}; #[cortex_m_rt::entry] @@ -11,7 +10,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); + let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4); loop { for v in 0..=255 { diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index d01b016c0..6c9219080 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs @@ -4,8 +4,9 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; +use embassy_stm32::mode::Async; use embassy_stm32::pac::timer::vals::Mms; -use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; +use embassy_stm32::peripherals::{DAC1, TIM6, TIM7}; use embassy_stm32::rcc::frequency; use embassy_stm32::time::Hertz; use embassy_stm32::timer::low_level::Timer; @@ -27,7 +28,7 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { +async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, Async>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM6 frequency is {}", frequency::()); @@ -70,7 +71,7 @@ async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { } #[embassy_executor::task] -async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { +async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, Async>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM7 frequency is {}", frequency::()); diff --git a/examples/stm32u0/src/bin/dac.rs b/examples/stm32u0/src/bin/dac.rs index fdbf1d374..50db0e082 100644 --- a/examples/stm32u0/src/bin/dac.rs +++ b/examples/stm32u0/src/bin/dac.rs @@ -3,7 +3,6 @@ use defmt::*; use embassy_stm32::dac::{DacCh1, Value}; -use embassy_stm32::dma::NoDma; use {defmt_rtt as _, panic_probe as _}; #[cortex_m_rt::entry] @@ -11,7 +10,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); + let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4); loop { for v in 0..=255 { diff --git a/tests/stm32/src/bin/dac.rs b/tests/stm32/src/bin/dac.rs index 88e661525..d34bbb255 100644 --- a/tests/stm32/src/bin/dac.rs +++ b/tests/stm32/src/bin/dac.rs @@ -12,7 +12,6 @@ use defmt::assert; use embassy_executor::Spawner; use embassy_stm32::adc::Adc; use embassy_stm32::dac::{DacCh1, Value}; -use embassy_stm32::dma::NoDma; use embassy_time::Timer; use micromath::F32Ext; use {defmt_rtt as _, panic_probe as _}; @@ -27,7 +26,7 @@ async fn main(_spawner: Spawner) { let dac_pin = peri!(p, DAC_PIN); let mut adc_pin = unsafe { core::ptr::read(&dac_pin) }; - let mut dac = DacCh1::new(dac, NoDma, dac_pin); + let mut dac = DacCh1::new_blocking(dac, dac_pin); let mut adc = Adc::new(adc); #[cfg(feature = "stm32h755zi")] diff --git a/tests/stm32/src/bin/dac_l1.rs b/tests/stm32/src/bin/dac_l1.rs index 925db617d..e6400f28e 100644 --- a/tests/stm32/src/bin/dac_l1.rs +++ b/tests/stm32/src/bin/dac_l1.rs @@ -12,7 +12,6 @@ use defmt::assert; use embassy_executor::Spawner; use embassy_stm32::adc::Adc; use embassy_stm32::dac::{DacCh1, Value}; -use embassy_stm32::dma::NoDma; use embassy_stm32::{bind_interrupts, peripherals}; use embassy_time::Timer; use micromath::F32Ext; @@ -32,7 +31,7 @@ async fn main(_spawner: Spawner) { let dac_pin = peri!(p, DAC_PIN); let mut adc_pin = unsafe { core::ptr::read(&dac_pin) }; - let mut dac = DacCh1::new(dac, NoDma, dac_pin); + let mut dac = DacCh1::new_blocking(dac, dac_pin); let mut adc = Adc::new(adc, Irqs); #[cfg(feature = "stm32h755zi")] diff --git a/tests/stm32/src/bin/hash.rs b/tests/stm32/src/bin/hash.rs index bdb3c9a69..52b84a499 100644 --- a/tests/stm32/src/bin/hash.rs +++ b/tests/stm32/src/bin/hash.rs @@ -6,7 +6,6 @@ mod common; use common::*; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::hash::*; use embassy_stm32::{bind_interrupts, hash, peripherals}; use hmac::{Hmac, Mac}; @@ -36,7 +35,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let p: embassy_stm32::Peripherals = init(); - let mut hw_hasher = Hash::new(p.HASH, NoDma, Irqs); + let mut hw_hasher = Hash::new_blocking(p.HASH, Irqs); let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh"; let test_2: &[u8] = b"fdhalksdjfhlasdjkfhalskdjfhgal;skdjfgalskdhfjgalskdjfglafgadfgdfgdafgaadsfgfgdfgadrgsyfthxfgjfhklhjkfgukhulkvhlvhukgfhfsrghzdhxyfufynufyuszeradrtydyytserr";