diff --git a/examples/uart-dma-rx.rs b/examples/uart-dma-rx.rs new file mode 100644 index 00000000..5a1742fb --- /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(true) + .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/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 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 f7bda0ab..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) { @@ -378,6 +383,19 @@ 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 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) @@ -424,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) { @@ -487,6 +510,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,