From 84cc949df649c9b3625a65c2cc14e09155deeede Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 30 Jun 2025 00:18:44 +0200 Subject: [PATCH] stm32/dma: fix packing/unpacking not working. --- embassy-stm32/src/cryp/mod.rs | 13 ++----- embassy-stm32/src/dma/dma_bdma.rs | 63 ++++++++++++++++++++----------- embassy-stm32/src/dma/gpdma.rs | 12 +++--- embassy-stm32/src/dma/util.rs | 6 +-- embassy-stm32/src/spi/mod.rs | 2 +- examples/stm32f7/src/bin/cryp.rs | 4 +- tests/stm32/src/bin/cryp.rs | 2 +- 7 files changed, 57 insertions(+), 45 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index fba3c0fd7..35d9f8cce 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -2,7 +2,6 @@ #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] use core::cmp::min; use core::marker::PhantomData; -use core::ptr; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; @@ -1814,14 +1813,12 @@ impl<'d, T: Instance> Cryp<'d, T, Async> { 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) }; + let dma_transfer = unsafe { dma.write_raw(blocks, dst_ptr, options) }; T::regs().dmacr().modify(|w| w.set_dien(true)); // Wait for the transfer to complete. dma_transfer.await; @@ -1836,14 +1833,12 @@ impl<'d, T: Instance> Cryp<'d, T, Async> { 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) }; + let dma_transfer = unsafe { dma.write_raw(blocks, dst_ptr, options) }; T::regs().dmacr().modify(|w| w.set_dien(true)); // Wait for the transfer to complete. dma_transfer.await; @@ -1857,14 +1852,12 @@ impl<'d, T: Instance> Cryp<'d, T, Async> { assert_eq!(blocks.len() % block_size, 0); // Configure DMA to get output from crypto core. 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); let options = TransferOptions { #[cfg(not(gpdma))] priority: crate::dma::Priority::VeryHigh, ..Default::default() }; - let dma_transfer = unsafe { dma.read_raw(src_ptr, dst_ptr, options) }; + let dma_transfer = unsafe { dma.read_raw(src_ptr, blocks, 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/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index caf135989..464823bfc 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -341,7 +341,7 @@ impl AnyChannel { mem_len: usize, incr_mem: bool, mem_size: WordSize, - peripheral_size: WordSize, + peri_size: WordSize, options: TransferOptions, ) { // "Preceding reads and writes cannot be moved past subsequent writes." @@ -357,8 +357,6 @@ impl AnyChannel { #[cfg(dmamux)] super::dmamux::configure_dmamux(&info.dmamux, _request); - assert!(mem_len > 0 && mem_len <= 0xFFFF); - match self.info().dma { #[cfg(dma)] DmaInfo::Dma(r) => { @@ -368,14 +366,39 @@ impl AnyChannel { state.complete_count.store(0, Ordering::Release); self.clear_irqs(); + // NDTR is the number of transfers in the *peripheral* word size. + // ex: if mem_size=1, peri_size=4 and ndtr=3 it'll do 12 mem transfers, 3 peri transfers. + let ndtr = match (mem_size, peri_size) { + (WordSize::FourBytes, WordSize::OneByte) => mem_len * 4, + (WordSize::FourBytes, WordSize::TwoBytes) | (WordSize::TwoBytes, WordSize::OneByte) => mem_len * 2, + (WordSize::FourBytes, WordSize::FourBytes) + | (WordSize::TwoBytes, WordSize::TwoBytes) + | (WordSize::OneByte, WordSize::OneByte) => mem_len, + (WordSize::TwoBytes, WordSize::FourBytes) | (WordSize::OneByte, WordSize::TwoBytes) => { + assert!(mem_len % 2 == 0); + mem_len / 2 + } + (WordSize::OneByte, WordSize::FourBytes) => { + assert!(mem_len % 4 == 0); + mem_len / 4 + } + }; + + assert!(ndtr > 0 && ndtr <= 0xFFFF); + ch.par().write_value(peri_addr as u32); ch.m0ar().write_value(mem_addr as u32); - ch.ndtr().write_value(pac::dma::regs::Ndtr(mem_len as _)); + ch.ndtr().write_value(pac::dma::regs::Ndtr(ndtr as _)); ch.fcr().write(|w| { if let Some(fth) = options.fifo_threshold { // FIFO mode w.set_dmdis(pac::dma::vals::Dmdis::DISABLED); w.set_fth(fth.into()); + } else if mem_size != peri_size { + // force FIFO mode if msize != psize + // packing/unpacking doesn't work in direct mode. + w.set_dmdis(pac::dma::vals::Dmdis::DISABLED); + w.set_fth(FifoThreshold::Half.into()); } else { // Direct mode w.set_dmdis(pac::dma::vals::Dmdis::ENABLED); @@ -384,7 +407,7 @@ impl AnyChannel { ch.cr().write(|w| { w.set_dir(dir.into()); w.set_msize(mem_size.into()); - w.set_psize(peripheral_size.into()); + w.set_psize(peri_size.into()); w.set_pl(options.priority.into()); w.set_minc(incr_mem); w.set_pinc(false); @@ -404,6 +427,8 @@ impl AnyChannel { } #[cfg(bdma)] DmaInfo::Bdma(r) => { + assert!(mem_len > 0 && mem_len <= 0xFFFF); + #[cfg(bdma_v2)] critical_section::with(|_| r.cselr().modify(|w| w.set_cs(info.num, _request))); @@ -417,7 +442,7 @@ impl AnyChannel { ch.mar().write_value(mem_addr as u32); ch.ndtr().write(|w| w.set_ndt(mem_len as u16)); ch.cr().write(|w| { - w.set_psize(peripheral_size.into()); + w.set_psize(peri_size.into()); w.set_msize(mem_size.into()); w.set_minc(incr_mem); w.set_dir(dir.into()); @@ -587,11 +612,11 @@ impl<'a> Transfer<'a> { } /// Create a new read DMA transfer (peripheral to memory), using raw pointers. - pub unsafe fn new_read_raw( + pub unsafe fn new_read_raw( channel: Peri<'a, impl Channel>, request: Request, - peri_addr: *mut W, - buf: *mut [W], + peri_addr: *mut PW, + buf: *mut [MW], options: TransferOptions, ) -> Self { Self::new_inner( @@ -599,11 +624,11 @@ impl<'a> Transfer<'a> { request, Dir::PeripheralToMemory, peri_addr as *const u32, - buf as *mut W as *mut u32, + buf as *mut MW as *mut u32, buf.len(), true, - W::size(), - W::size(), + MW::size(), + PW::size(), options, ) } @@ -672,22 +697,14 @@ impl<'a> Transfer<'a> { mem_addr: *mut u32, mem_len: usize, incr_mem: bool, - data_size: WordSize, - peripheral_size: WordSize, + mem_size: WordSize, + peri_size: WordSize, options: TransferOptions, ) -> Self { assert!(mem_len > 0 && mem_len <= 0xFFFF); channel.configure( - _request, - dir, - peri_addr, - mem_addr, - mem_len, - incr_mem, - data_size, - peripheral_size, - options, + _request, dir, peri_addr, mem_addr, mem_len, incr_mem, mem_size, peri_size, options, ); channel.start(); Self { channel } diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index ade70fb55..151e4ab9f 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs @@ -125,11 +125,11 @@ impl<'a> Transfer<'a> { } /// Create a new read DMA transfer (peripheral to memory), using raw pointers. - pub unsafe fn new_read_raw( + pub unsafe fn new_read_raw( channel: Peri<'a, impl Channel>, request: Request, - peri_addr: *mut W, - buf: *mut [W], + peri_addr: *mut PW, + buf: *mut [MW], options: TransferOptions, ) -> Self { Self::new_inner( @@ -137,11 +137,11 @@ impl<'a> Transfer<'a> { request, Dir::PeripheralToMemory, peri_addr as *const u32, - buf as *mut W as *mut u32, + buf as *mut MW as *mut u32, buf.len(), true, - W::size(), - W::size(), + PW::size(), + MW::size(), options, ) } diff --git a/embassy-stm32/src/dma/util.rs b/embassy-stm32/src/dma/util.rs index 8bf89e2fe..3245887c1 100644 --- a/embassy-stm32/src/dma/util.rs +++ b/embassy-stm32/src/dma/util.rs @@ -20,10 +20,10 @@ impl<'d> ChannelAndRequest<'d> { Transfer::new_read(self.channel.reborrow(), self.request, peri_addr, buf, options) } - pub unsafe fn read_raw<'a, W: Word>( + pub unsafe fn read_raw<'a, MW: Word, PW: Word>( &'a mut self, - peri_addr: *mut W, - buf: *mut [W], + peri_addr: *mut PW, + buf: *mut [MW], options: TransferOptions, ) -> Transfer<'a> { Transfer::new_read_raw(self.channel.reborrow(), self.request, peri_addr, buf, options) diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 9e2ba093a..c8d83f07e 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -843,7 +843,7 @@ impl<'d> Spi<'d, Async> { set_rxdmaen(self.info.regs, true); - let rx_src = self.info.regs.rx_ptr(); + 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: *mut W = self.info.regs.tx_ptr(); diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs index 235853cb9..a31e9b4f2 100644 --- a/examples/stm32f7/src/bin/cryp.rs +++ b/examples/stm32f7/src/bin/cryp.rs @@ -68,7 +68,9 @@ async fn main(_spawner: Spawner) -> ! { ); // Decrypt in software using AES-GCM 128-bit - let _ = cipher.decrypt_in_place(&iv.into(), aad.into(), &mut payload_vec); + cipher + .decrypt_in_place(&iv.into(), aad.into(), &mut payload_vec) + .unwrap(); let sw_end_time = Instant::now(); let sw_execution_time = sw_end_time - sw_start_time; diff --git a/tests/stm32/src/bin/cryp.rs b/tests/stm32/src/bin/cryp.rs index 028775ac8..f54c99cc3 100644 --- a/tests/stm32/src/bin/cryp.rs +++ b/tests/stm32/src/bin/cryp.rs @@ -72,7 +72,7 @@ async fn main(_spawner: Spawner) { 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); + cipher.decrypt_in_place(&iv.into(), &aad, &mut payload_vec).unwrap(); info!("Test OK"); cortex_m::asm::bkpt();