Skip to content

Commit cd0921d

Browse files
authored
Add dma fn read_available and uart-dma-rx example (#116)
* Add dma fn read_available and uart-dma-rx example * Remove debug code * Enable circular buffer * Rename uart-dma example * DMA: Add some useful methods for checking for trasfer errors
1 parent 4df3c72 commit cd0921d

File tree

5 files changed

+148
-0
lines changed

5 files changed

+148
-0
lines changed

examples/uart-dma-rx.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#![deny(warnings)]
2+
#![deny(unsafe_code)]
3+
#![no_main]
4+
#![no_std]
5+
6+
extern crate cortex_m_rt as rt;
7+
8+
use hal::dma::{config::DmaConfig, stream::DMAExt, TransferExt};
9+
use hal::prelude::*;
10+
use hal::pwr::PwrExt;
11+
use hal::serial::*;
12+
use hal::{rcc, stm32};
13+
use stm32g4xx_hal as hal;
14+
15+
use cortex_m_rt::entry;
16+
use utils::logger::info;
17+
18+
#[macro_use]
19+
mod utils;
20+
21+
#[entry]
22+
fn main() -> ! {
23+
utils::logger::init();
24+
25+
info!("Initializing...");
26+
27+
let dp = stm32::Peripherals::take().expect("cannot take peripherals");
28+
29+
let rcc = dp.RCC.constrain();
30+
let pwr = dp.PWR.constrain().freeze();
31+
let mut rcc = rcc.freeze(rcc::Config::hsi(), pwr);
32+
33+
let streams = dp.DMA1.split(&rcc);
34+
let config = DmaConfig::default()
35+
.transfer_complete_interrupt(false)
36+
.circular_buffer(true)
37+
.memory_increment(true);
38+
39+
info!("Init UART");
40+
//let gpioa = dp.GPIOA.split(&mut rcc);
41+
//let tx = gpioa.pa2.into_alternate();
42+
//let rx = gpioa.pa3.into_alternate();
43+
let gpioc = dp.GPIOC.split(&mut rcc);
44+
let tx = gpioc.pc10.into_alternate();
45+
let rx = gpioc.pc11.into_alternate();
46+
47+
let usart = dp
48+
//.USART2
49+
.USART3
50+
.usart(
51+
tx,
52+
rx,
53+
FullConfig::default()
54+
.baudrate(115200.bps())
55+
.receiver_timeout_us(1000), // Timeout after 1ms
56+
&mut rcc,
57+
)
58+
.unwrap();
59+
60+
//let mut led = gpioa.pa5.into_push_pull_output();
61+
62+
info!("Start reading");
63+
64+
let rx_buffer = cortex_m::singleton!(: [u8; 256] = [0; 256]).unwrap();
65+
66+
let (_tx, rx) = usart.split();
67+
68+
let mut transfer = streams.0.into_circ_peripheral_to_memory_transfer(
69+
rx.enable_dma(),
70+
&mut rx_buffer[..],
71+
config,
72+
);
73+
74+
transfer.start(|_rx| {});
75+
loop {
76+
while !transfer.timeout_lapsed() {}
77+
transfer.clear_timeout();
78+
79+
let mut data = [0; 256];
80+
loop {
81+
let data = transfer.read_available(&mut data);
82+
if data.is_empty() {
83+
break;
84+
}
85+
if let Ok(data) = core::str::from_utf8(&*data) {
86+
info!("Received: '{}'", data);
87+
} else {
88+
info!("Received: {:?}", data);
89+
}
90+
info!("Sup");
91+
}
92+
//led.toggle().unwrap();
93+
}
94+
}
File renamed without changes.

src/dma/stream.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,13 @@ macro_rules! dma_stream {
250250
dma.isr.read().$tcisr().bit_is_set()
251251
}
252252

253+
#[inline(always)]
254+
fn get_transfer_error_flag() -> bool {
255+
//NOTE(unsafe) Atomic read with no side effects
256+
let dma = unsafe { &*I::ptr() };
257+
dma.isr.read().$teisr().bit_is_set()
258+
}
259+
253260
#[inline(always)]
254261
unsafe fn enable(&mut self) {
255262
//NOTE(unsafe) We only access the registers that belongs to the StreamX

src/dma/traits.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ pub trait Stream: Sealed {
4747
/// Get transfer complete flag.
4848
fn get_transfer_complete_flag() -> bool;
4949

50+
/// Get transfer error flag.
51+
fn get_transfer_error_flag() -> bool;
52+
5053
/// Enable the DMA stream.
5154
///
5255
/// # Safety

src/dma/transfer.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,11 @@ where
265265
STREAM::get_transfer_complete_flag()
266266
}
267267

268+
#[inline(always)]
269+
pub fn get_transfer_error_flag(&self) -> bool {
270+
STREAM::get_transfer_error_flag()
271+
}
272+
268273
/// Clear half transfer interrupt (htif) for the DMA stream.
269274
#[inline(always)]
270275
pub fn clear_half_transfer_interrupt(&mut self) {
@@ -378,6 +383,19 @@ where
378383
read
379384
}
380385

386+
pub fn read_available<'a>(
387+
&mut self,
388+
data: &'a mut [<PERIPHERAL as TargetAddress<PeripheralToMemory>>::MemSize],
389+
) -> &'a mut [<PERIPHERAL as TargetAddress<PeripheralToMemory>>::MemSize] {
390+
let blen = unsafe { self.transfer.buf.static_write_buffer().1 };
391+
let available = self.elements_available();
392+
let len = data.len().min(available).min(blen - 1);
393+
let result = &mut data[0..len];
394+
self.read_exact(result);
395+
396+
result
397+
}
398+
381399
/// Starts the transfer, the closure will be executed right after enabling
382400
/// the stream.
383401
pub fn start<F>(&mut self, f: F)
@@ -424,6 +442,11 @@ where
424442
self.transfer.get_transfer_complete_flag()
425443
}
426444

445+
#[inline(always)]
446+
pub fn get_transfer_error_flag(&self) -> bool {
447+
self.transfer.get_transfer_error_flag()
448+
}
449+
427450
/// Clear half transfer interrupt (htif) for the DMA stream.
428451
#[inline(always)]
429452
pub fn clear_half_transfer_interrupt(&mut self) {
@@ -487,6 +510,27 @@ impl_adc_overrun!(ADC3,);
487510
))]
488511
impl_adc_overrun!(ADC4, ADC5,);
489512

513+
macro_rules! impl_serial_timeout {
514+
($($uart:ident, )*) => {$(
515+
impl<STREAM, BUF, Pin> CircTransfer<STREAM, crate::serial::Rx<crate::stm32::$uart, Pin, crate::serial::DMA>, BUF>
516+
where
517+
STREAM: Stream,
518+
/*BUF: StaticWriteBuffer + Deref*/ {
519+
pub fn timeout_lapsed(&self) -> bool {
520+
self.transfer.peripheral.timeout_lapsed()
521+
}
522+
523+
pub fn clear_timeout(&mut self) {
524+
self.transfer.peripheral.clear_timeout();
525+
}
526+
}
527+
)*};
528+
}
529+
530+
impl_serial_timeout!(USART1, USART2, USART3, UART4,);
531+
#[cfg(not(any(feature = "stm32g431", feature = "stm32g441")))]
532+
impl_serial_timeout!(UART5,);
533+
490534
pub trait TransferExt<STREAM>
491535
where
492536
STREAM: traits::Stream,

0 commit comments

Comments
 (0)