aboutsummaryrefslogtreecommitdiff
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
parent173c65b5430e57548cc747f0387dd001e30b1ac1 (diff)
stm32/dma: add double buffered mode for DMA, update DCMI.
-rw-r--r--embassy-stm32/src/dcmi.rs37
-rw-r--r--embassy-stm32/src/dma/dma.rs159
2 files changed, 182 insertions, 14 deletions
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index 0b34553cf..c19be86c6 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -434,9 +434,13 @@ where
434 result 434 result
435 } 435 }
436 436
437 #[cfg(not(dma))]
437 async fn capture_giant(&mut self, _buffer: &mut [u32]) -> Result<(), Error> { 438 async fn capture_giant(&mut self, _buffer: &mut [u32]) -> Result<(), Error> {
438 todo!() 439 panic!("capturing to buffers larger than 0xffff is only supported on DMA for now, not on BDMA or GPDMA.");
439 /* 440 }
441
442 #[cfg(dma)]
443 async fn capture_giant(&mut self, buffer: &mut [u32]) -> Result<(), Error> {
440 use crate::dma::TransferOptions; 444 use crate::dma::TransferOptions;
441 445
442 let data_len = buffer.len(); 446 let data_len = buffer.len();
@@ -460,16 +464,24 @@ where
460 let r = self.inner.regs(); 464 let r = self.inner.regs();
461 let src = r.dr().ptr() as *mut u32; 465 let src = r.dr().ptr() as *mut u32;
462 466
463 unsafe { 467 let mut transfer = unsafe {
464 channel.start_double_buffered_read(request, src, m0ar, m1ar, chunk_size, TransferOptions::default()); 468 crate::dma::DoubleBuffered::new_read(
465 } 469 &mut self.dma,
470 request,
471 src,
472 m0ar,
473 m1ar,
474 chunk_size,
475 TransferOptions::default(),
476 )
477 };
466 478
467 let mut last_chunk_set_for_transfer = false; 479 let mut last_chunk_set_for_transfer = false;
468 let mut buffer0_last_accessible = false; 480 let mut buffer0_last_accessible = false;
469 let dma_result = poll_fn(|cx| { 481 let dma_result = poll_fn(|cx| {
470 channel.set_waker(cx.waker()); 482 transfer.set_waker(cx.waker());
471 483
472 let buffer0_currently_accessible = unsafe { channel.is_buffer0_accessible() }; 484 let buffer0_currently_accessible = transfer.is_buffer0_accessible();
473 485
474 // check if the accessible buffer changed since last poll 486 // check if the accessible buffer changed since last poll
475 if buffer0_last_accessible == buffer0_currently_accessible { 487 if buffer0_last_accessible == buffer0_currently_accessible {
@@ -480,21 +492,21 @@ where
480 if remaining_chunks != 0 { 492 if remaining_chunks != 0 {
481 if remaining_chunks % 2 == 0 && buffer0_currently_accessible { 493 if remaining_chunks % 2 == 0 && buffer0_currently_accessible {
482 m0ar = unsafe { m0ar.add(2 * chunk_size) }; 494 m0ar = unsafe { m0ar.add(2 * chunk_size) };
483 unsafe { channel.set_buffer0(m0ar) } 495 unsafe { transfer.set_buffer0(m0ar) }
484 remaining_chunks -= 1; 496 remaining_chunks -= 1;
485 } else if !buffer0_currently_accessible { 497 } else if !buffer0_currently_accessible {
486 m1ar = unsafe { m1ar.add(2 * chunk_size) }; 498 m1ar = unsafe { m1ar.add(2 * chunk_size) };
487 unsafe { channel.set_buffer1(m1ar) }; 499 unsafe { transfer.set_buffer1(m1ar) };
488 remaining_chunks -= 1; 500 remaining_chunks -= 1;
489 } 501 }
490 } else { 502 } else {
491 if buffer0_currently_accessible { 503 if buffer0_currently_accessible {
492 unsafe { channel.set_buffer0(buffer.as_mut_ptr()) } 504 unsafe { transfer.set_buffer0(buffer.as_mut_ptr()) }
493 } else { 505 } else {
494 unsafe { channel.set_buffer1(buffer.as_mut_ptr()) } 506 unsafe { transfer.set_buffer1(buffer.as_mut_ptr()) }
495 } 507 }
496 if last_chunk_set_for_transfer { 508 if last_chunk_set_for_transfer {
497 channel.request_stop(); 509 transfer.request_stop();
498 return Poll::Ready(()); 510 return Poll::Ready(());
499 } 511 }
500 last_chunk_set_for_transfer = true; 512 last_chunk_set_for_transfer = true;
@@ -542,7 +554,6 @@ where
542 unsafe { Self::toggle(false) }; 554 unsafe { Self::toggle(false) };
543 555
544 result 556 result
545 */
546 } 557 }
547} 558}
548 559
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}