aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/dma
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-04-18 16:16:33 +0200
committerDario Nieuwenhuis <[email protected]>2023-04-18 16:41:24 +0200
commitefc70debb3bbf7fb7e9b1a23a42e5db149de8ed6 (patch)
tree26fd40195c0d9e5d546b78de697e42c3c36f4789 /embassy-stm32/src/dma
parent173c65b5430e57548cc747f0387dd001e30b1ac1 (diff)
stm32/dma: add double buffered mode for DMA, update DCMI.
Diffstat (limited to 'embassy-stm32/src/dma')
-rw-r--r--embassy-stm32/src/dma/dma.rs159
1 files changed, 158 insertions, 1 deletions
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 9052aa110..62c092241 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -1,7 +1,8 @@
1use core::future::Future; 1use core::future::Future;
2use core::marker::PhantomData;
2use core::pin::Pin; 3use core::pin::Pin;
3use core::sync::atomic::{fence, Ordering}; 4use core::sync::atomic::{fence, Ordering};
4use core::task::{Context, Poll}; 5use core::task::{Context, Poll, Waker};
5 6
6use embassy_cortex_m::interrupt::Priority; 7use embassy_cortex_m::interrupt::Priority;
7use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 8use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
@@ -440,3 +441,159 @@ impl<'a, C: Channel> Future for Transfer<'a, C> {
440 } 441 }
441 } 442 }
442} 443}
444
445// ==================================
446
447#[must_use = "futures do nothing unless you `.await` or poll them"]
448pub struct DoubleBuffered<'a, C: Channel, W: Word> {
449 channel: PeripheralRef<'a, C>,
450 _phantom: PhantomData<W>,
451}
452
453impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
454 pub unsafe fn new_read(
455 channel: impl Peripheral<P = C> + 'a,
456 _request: Request,
457 peri_addr: *mut W,
458 buf0: *mut W,
459 buf1: *mut W,
460 len: usize,
461 options: TransferOptions,
462 ) -> Self {
463 into_ref!(channel);
464 assert!(len > 0 && len <= 0xFFFF);
465
466 let dir = Dir::PeripheralToMemory;
467 let data_size = W::bits();
468
469 let channel_number = channel.num();
470 let dma = channel.regs();
471
472 // "Preceding reads and writes cannot be moved past subsequent writes."
473 fence(Ordering::SeqCst);
474
475 let mut this = Self {
476 channel,
477 _phantom: PhantomData,
478 };
479 this.clear_irqs();
480
481 #[cfg(dmamux)]
482 super::dmamux::configure_dmamux(&mut *this.channel, _request);
483
484 let ch = dma.st(channel_number);
485 ch.par().write_value(peri_addr as u32);
486 ch.m0ar().write_value(buf0 as u32);
487 ch.m1ar().write_value(buf1 as u32);
488 ch.ndtr().write_value(regs::Ndtr(len as _));
489 ch.fcr().write(|w| {
490 if let Some(fth) = options.fifo_threshold {
491 // FIFO mode
492 w.set_dmdis(vals::Dmdis::DISABLED);
493 w.set_fth(fth.into());
494 } else {
495 // Direct mode
496 w.set_dmdis(vals::Dmdis::ENABLED);
497 }
498 });
499 ch.cr().write(|w| {
500 w.set_dir(dir.into());
501 w.set_msize(data_size.into());
502 w.set_psize(data_size.into());
503 w.set_pl(vals::Pl::VERYHIGH);
504 w.set_minc(vals::Inc::INCREMENTED);
505 w.set_pinc(vals::Inc::FIXED);
506 w.set_teie(true);
507 w.set_tcie(true);
508 #[cfg(dma_v1)]
509 w.set_trbuff(true);
510
511 #[cfg(dma_v2)]
512 w.set_chsel(_request);
513
514 w.set_pburst(options.pburst.into());
515 w.set_mburst(options.mburst.into());
516 w.set_pfctrl(options.flow_ctrl.into());
517
518 w.set_en(true);
519 });
520
521 this
522 }
523
524 fn clear_irqs(&mut self) {
525 let channel_number = self.channel.num();
526 let dma = self.channel.regs();
527 let isrn = channel_number / 4;
528 let isrbit = channel_number % 4;
529
530 unsafe {
531 dma.ifcr(isrn).write(|w| {
532 w.set_tcif(isrbit, true);
533 w.set_teif(isrbit, true);
534 })
535 }
536 }
537
538 pub unsafe fn set_buffer0(&mut self, buffer: *mut W) {
539 let ch = self.channel.regs().st(self.channel.num());
540 ch.m0ar().write_value(buffer as _);
541 }
542
543 pub unsafe fn set_buffer1(&mut self, buffer: *mut W) {
544 let ch = self.channel.regs().st(self.channel.num());
545 ch.m1ar().write_value(buffer as _);
546 }
547
548 pub fn is_buffer0_accessible(&mut self) -> bool {
549 let ch = self.channel.regs().st(self.channel.num());
550 unsafe { ch.cr().read() }.ct() == vals::Ct::MEMORY1
551 }
552
553 pub fn set_waker(&mut self, waker: &Waker) {
554 STATE.ch_wakers[self.channel.index()].register(waker);
555 }
556
557 pub fn request_stop(&mut self) {
558 let ch = self.channel.regs().st(self.channel.num());
559
560 // Disable the channel. Keep the IEs enabled so the irqs still fire.
561 unsafe {
562 ch.cr().write(|w| {
563 w.set_teie(true);
564 w.set_tcie(true);
565 })
566 }
567 }
568
569 pub fn is_running(&mut self) -> bool {
570 let ch = self.channel.regs().st(self.channel.num());
571 unsafe { ch.cr().read() }.en()
572 }
573
574 /// Gets the total remaining transfers for the channel
575 /// Note: this will be zero for transfers that completed without cancellation.
576 pub fn get_remaining_transfers(&self) -> u16 {
577 let ch = self.channel.regs().st(self.channel.num());
578 unsafe { ch.ndtr().read() }.ndt()
579 }
580
581 pub fn blocking_wait(mut self) {
582 while self.is_running() {}
583
584 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
585 fence(Ordering::SeqCst);
586
587 core::mem::forget(self);
588 }
589}
590
591impl<'a, C: Channel, W: Word> Drop for DoubleBuffered<'a, C, W> {
592 fn drop(&mut self) {
593 self.request_stop();
594 while self.is_running() {}
595
596 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
597 fence(Ordering::SeqCst);
598 }
599}