From 3b161298272ccf9b61e98a661757895118b83e29 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Fri, 5 Jan 2024 11:05:54 +0100 Subject: [PATCH 1/5] Add dma fn read_available and uart-dma-rx example --- examples/uart-dma-rx.rs | 94 +++++++++++++++++++++++++++++++++++++++++ src/dma/transfer.rs | 42 ++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 examples/uart-dma-rx.rs diff --git a/examples/uart-dma-rx.rs b/examples/uart-dma-rx.rs new file mode 100644 index 00000000..bab86054 --- /dev/null +++ b/examples/uart-dma-rx.rs @@ -0,0 +1,94 @@ +#![deny(warnings)] +#![deny(unsafe_code)] +#![no_main] +#![no_std] + +extern crate cortex_m_rt as rt; + +use hal::dma::{config::DmaConfig, stream::DMAExt, TransferExt}; +use hal::prelude::*; +use hal::pwr::PwrExt; +use hal::serial::*; +use hal::{rcc, stm32}; +use stm32g4xx_hal as hal; + +use cortex_m_rt::entry; +use utils::logger::info; + +#[macro_use] +mod utils; + +#[entry] +fn main() -> ! { + utils::logger::init(); + + info!("Initializing..."); + + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + + let rcc = dp.RCC.constrain(); + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = rcc.freeze(rcc::Config::hsi(), pwr); + + let streams = dp.DMA1.split(&rcc); + let config = DmaConfig::default() + .transfer_complete_interrupt(false) + .circular_buffer(false) + .memory_increment(true); + + info!("Init UART"); + //let gpioa = dp.GPIOA.split(&mut rcc); + //let tx = gpioa.pa2.into_alternate(); + //let rx = gpioa.pa3.into_alternate(); + let gpioc = dp.GPIOC.split(&mut rcc); + let tx = gpioc.pc10.into_alternate(); + let rx = gpioc.pc11.into_alternate(); + + let usart = dp + //.USART2 + .USART3 + .usart( + tx, + rx, + FullConfig::default() + .baudrate(115200.bps()) + .receiver_timeout_us(1000), // Timeout after 1ms + &mut rcc, + ) + .unwrap(); + + //let mut led = gpioa.pa5.into_push_pull_output(); + + info!("Start reading"); + + let rx_buffer = cortex_m::singleton!(: [u8; 256] = [0; 256]).unwrap(); + + let (_tx, rx) = usart.split(); + + let mut transfer = streams.0.into_circ_peripheral_to_memory_transfer( + rx.enable_dma(), + &mut rx_buffer[..], + config, + ); + + transfer.start(|_rx| {}); + loop { + while !transfer.timeout_lapsed() {} + transfer.clear_timeout(); + + let mut data = [0; 256]; + loop { + let data = transfer.read_available(&mut data); + if data.is_empty() { + break; + } + if let Ok(data) = core::str::from_utf8(&*data) { + info!("Received: '{}'", data); + } else { + info!("Received: {:?}", data); + } + info!("Sup"); + } + //led.toggle().unwrap(); + } +} diff --git a/src/dma/transfer.rs b/src/dma/transfer.rs index f7bda0ab..42d89bd1 100644 --- a/src/dma/transfer.rs +++ b/src/dma/transfer.rs @@ -378,6 +378,27 @@ where read } + pub fn read_available<'a>( + &mut self, + data: &'a mut [>::MemSize], + ) -> &'a mut [>::MemSize] { + let blen = unsafe { self.transfer.buf.static_write_buffer().1 }; + let available = self.elements_available(); + let ndtr = STREAM::get_number_of_transfers() as usize; + defmt::trace!( + "ndtr: {}, pos: {}, available: {}", + ndtr, + self.r_pos, + available + ); + assert!(available < blen, "available: {}, blen: {}", available, blen); + let len = data.len().min(available).min(blen - 1); + let result = &mut data[0..len]; + self.read_exact(result); + + result + } + /// Starts the transfer, the closure will be executed right after enabling /// the stream. pub fn start(&mut self, f: F) @@ -487,6 +508,27 @@ impl_adc_overrun!(ADC3,); ))] impl_adc_overrun!(ADC4, ADC5,); +macro_rules! impl_serial_timeout { + ($($uart:ident, )*) => {$( + impl CircTransfer, BUF> + where + STREAM: Stream, + /*BUF: StaticWriteBuffer + Deref*/ { + pub fn timeout_lapsed(&self) -> bool { + self.transfer.peripheral.timeout_lapsed() + } + + pub fn clear_timeout(&mut self) { + self.transfer.peripheral.clear_timeout(); + } + } + )*}; +} + +impl_serial_timeout!(USART1, USART2, USART3, UART4,); +#[cfg(not(any(feature = "stm32g431", feature = "stm32g441")))] +impl_serial_timeout!(UART5,); + pub trait TransferExt where STREAM: traits::Stream, From 5c2b27c997548039425ffe2a99b9fbbe7846e3b8 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Fri, 5 Jan 2024 11:33:13 +0100 Subject: [PATCH 2/5] Remove debug code --- src/dma/transfer.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/dma/transfer.rs b/src/dma/transfer.rs index 42d89bd1..a0ea7665 100644 --- a/src/dma/transfer.rs +++ b/src/dma/transfer.rs @@ -384,14 +384,6 @@ where ) -> &'a mut [>::MemSize] { let blen = unsafe { self.transfer.buf.static_write_buffer().1 }; let available = self.elements_available(); - let ndtr = STREAM::get_number_of_transfers() as usize; - defmt::trace!( - "ndtr: {}, pos: {}, available: {}", - ndtr, - self.r_pos, - available - ); - assert!(available < blen, "available: {}, blen: {}", available, blen); let len = data.len().min(available).min(blen - 1); let result = &mut data[0..len]; self.read_exact(result); From 28c842e63a826ed4d11ea9e5e91a02f8fc3a5ea8 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Fri, 5 Jan 2024 11:33:52 +0100 Subject: [PATCH 3/5] Enable circular buffer --- examples/uart-dma-rx.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/uart-dma-rx.rs b/examples/uart-dma-rx.rs index bab86054..5a1742fb 100644 --- a/examples/uart-dma-rx.rs +++ b/examples/uart-dma-rx.rs @@ -33,7 +33,7 @@ fn main() -> ! { let streams = dp.DMA1.split(&rcc); let config = DmaConfig::default() .transfer_complete_interrupt(false) - .circular_buffer(false) + .circular_buffer(true) .memory_increment(true); info!("Init UART"); From 9fbaab83fc61a68325545a26b96a6acacf6473f5 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Fri, 5 Jan 2024 11:37:19 +0100 Subject: [PATCH 4/5] Rename uart-dma example --- examples/{uart-dma.rs => uart-dma-tx.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{uart-dma.rs => uart-dma-tx.rs} (100%) diff --git a/examples/uart-dma.rs b/examples/uart-dma-tx.rs similarity index 100% rename from examples/uart-dma.rs rename to examples/uart-dma-tx.rs From 1ea1f4b3fadaf0b369017aca27e7bcd1d90cd884 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Thu, 14 Sep 2023 10:14:16 +0200 Subject: [PATCH 5/5] DMA: Add some useful methods for checking for trasfer errors --- src/dma/stream.rs | 7 +++++++ src/dma/traits.rs | 3 +++ src/dma/transfer.rs | 10 ++++++++++ 3 files changed, 20 insertions(+) diff --git a/src/dma/stream.rs b/src/dma/stream.rs index 9f053192..6908384b 100644 --- a/src/dma/stream.rs +++ b/src/dma/stream.rs @@ -250,6 +250,13 @@ macro_rules! dma_stream { dma.isr.read().$tcisr().bit_is_set() } + #[inline(always)] + fn get_transfer_error_flag() -> bool { + //NOTE(unsafe) Atomic read with no side effects + let dma = unsafe { &*I::ptr() }; + dma.isr.read().$teisr().bit_is_set() + } + #[inline(always)] unsafe fn enable(&mut self) { //NOTE(unsafe) We only access the registers that belongs to the StreamX diff --git a/src/dma/traits.rs b/src/dma/traits.rs index a33ba8cf..d33a965e 100644 --- a/src/dma/traits.rs +++ b/src/dma/traits.rs @@ -47,6 +47,9 @@ pub trait Stream: Sealed { /// Get transfer complete flag. fn get_transfer_complete_flag() -> bool; + /// Get transfer error flag. + fn get_transfer_error_flag() -> bool; + /// Enable the DMA stream. /// /// # Safety diff --git a/src/dma/transfer.rs b/src/dma/transfer.rs index a0ea7665..ab9d1efb 100644 --- a/src/dma/transfer.rs +++ b/src/dma/transfer.rs @@ -265,6 +265,11 @@ where STREAM::get_transfer_complete_flag() } + #[inline(always)] + pub fn get_transfer_error_flag(&self) -> bool { + STREAM::get_transfer_error_flag() + } + /// Clear half transfer interrupt (htif) for the DMA stream. #[inline(always)] pub fn clear_half_transfer_interrupt(&mut self) { @@ -437,6 +442,11 @@ where self.transfer.get_transfer_complete_flag() } + #[inline(always)] + pub fn get_transfer_error_flag(&self) -> bool { + self.transfer.get_transfer_error_flag() + } + /// Clear half transfer interrupt (htif) for the DMA stream. #[inline(always)] pub fn clear_half_transfer_interrupt(&mut self) {