Skip to content

Commit 69eab2a

Browse files
committed
more fixes
- Add defmt derives - improve consistency in return values for DataTransformBuilder - Removed side effects from check_transfer_event and added a separate function to clear events - Add drop implementation to abort a transfer - Modified wait_for_transfer_complete and wait_for_half_transform_complete to: - explicitly clear event flags - consume, but forget self, so the drop implementation is not called. - misc documentation improvements
1 parent c65d457 commit 69eab2a

File tree

4 files changed

+91
-65
lines changed

4 files changed

+91
-65
lines changed

src/gpdma.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -493,37 +493,57 @@ impl<'a, CH: DmaChannel> DmaTransfer<'a, CH> {
493493

494494
/// Blocks waiting for a transfer to complete. Returns an error if one occurred during the
495495
/// transfer.
496-
pub fn wait_for_transfer_complete(&self) -> Result<(), Error> {
496+
pub fn wait_for_transfer_complete(self) -> Result<(), Error> {
497497
let result = self.channel.wait_for_transfer_complete();
498498
// Preserve the instruction and bus sequence of the preceding operation and
499499
// the subsequent buffer access.
500500
fence(Ordering::SeqCst);
501+
502+
core::mem::forget(self); // Prevents self from being dropped and attempting to abort
501503
result
502504
}
503505

504506
/// Blocks waiting for the half transfer complete event. Returns an error if one occurred during
505507
/// the transfer.
506-
pub fn wait_for_half_transfer_complete(&self) -> Result<(), Error> {
508+
pub fn wait_for_half_transfer_complete(self) -> Result<(), Error> {
507509
let result = self.channel.wait_for_half_transfer_complete();
508510
// Preserve the instruction and bus sequence of the preceding operation and
509511
// the subsequent buffer access.
510512
fence(Ordering::SeqCst);
513+
514+
core::mem::forget(self); // Prevents self from being dropped and attempting to abort
511515
result
512516
}
513517

518+
/// Enable interrupts for this transfer. This will enable the transfer complete and half
519+
/// transfer complete interrupts, as well as error interrupts.
514520
pub fn enable_interrupts(&self) {
515521
self.channel.enable_transfer_interrupts();
516522
}
517523

524+
/// Disable interrupts for this transfer.
518525
pub fn disable_interrupts(&self) {
519526
self.channel.disable_transfer_interrupts();
520527
}
521528

522529
/// Abort a transaction and wait for it to suspend the transfer before resetting the channel
523-
pub fn abort(&mut self) {
524-
self.channel.abort();
530+
pub fn abort(self) {
531+
// Allow Drop implementation to handle transfer abortion
532+
}
533+
}
525534

526-
// Preserve the instruction and bus sequence of the preceding disable and
535+
impl<'a, CH> Drop for DmaTransfer<'a, CH>
536+
where
537+
CH: DmaChannel,
538+
{
539+
fn drop(&mut self) {
540+
if self.is_running() {
541+
self.channel.abort();
542+
}
543+
544+
self.disable_interrupts();
545+
546+
// Preserve the instruction and bus sequence of the preceding operation and
527547
// the subsequent buffer access.
528548
fence(Ordering::SeqCst);
529549
}

src/gpdma/ch.rs

Lines changed: 51 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ where
196196
self.cr().modify(|_, w| w.susp().not_suspended());
197197
}
198198

199+
/// Clear all event flags in the FCR register.
199200
fn clear_all_event_flags(&self) {
200201
self.fcr().write(|w| {
201202
w.tcf()
@@ -216,27 +217,30 @@ where
216217
}
217218

218219
#[inline(always)]
220+
/// Checks if the specified transfer event has triggered or if an error has occurred. If an
221+
/// error has occurred, it is returned. If the event has triggered, `Ok(true)` is returned.
222+
/// Otherwise, if the event has not triggered, `Ok(false)` is returned.
219223
fn check_transfer_event(
220224
&self,
221225
event: TransferEvent,
222226
) -> Result<bool, Error> {
223227
let sr = self.sr().read();
224-
check_error!(sr).inspect_err(|_| self.clear_all_event_flags())?;
228+
check_error!(sr)?;
225229
let triggered = match event {
226230
TransferEvent::TransferComplete => sr.tcf().is_trigger(),
227231
TransferEvent::HalfTransferComplete => sr.htf().is_trigger(),
228232
};
229233

230-
if triggered {
231-
// Clear the event flag if it has been triggered
232-
self.fcr().write(|w| match event {
233-
TransferEvent::TransferComplete => w.tcf().clear(),
234-
TransferEvent::HalfTransferComplete => w.htf().clear(),
235-
});
236-
}
237234
Ok(triggered)
238235
}
239236

237+
fn clear_transfer_event_flag(&self, event: TransferEvent) {
238+
self.fcr().write(|w| match event {
239+
TransferEvent::TransferComplete => w.tcf().clear(),
240+
TransferEvent::HalfTransferComplete => w.htf().clear(),
241+
});
242+
}
243+
240244
// TODO: Remove clippy allow when FIFO use is implemented
241245
#[allow(unused)]
242246
#[inline(always)]
@@ -482,9 +486,11 @@ pub(super) trait Channel {
482486

483487
/// Blocks waiting for a transfer to complete. Reports any errors that occur during a transfer.
484488
fn wait_for_transfer_complete(&self) -> Result<(), Error>;
489+
485490
/// Blocks waiting for a half transfer event to trigger. Reports any errors that occur during a
486491
/// transfer.
487492
fn wait_for_half_transfer_complete(&self) -> Result<(), Error>;
493+
488494
/// Apply a transfer configuration to the channel
489495
fn apply_config<T: TransferType, S: Word, D: Word>(
490496
&self,
@@ -522,8 +528,13 @@ pub(super) trait Channel {
522528
/// must be aligned with the source data width.
523529
fn set_transfer_size_bytes(&self, size: usize);
524530

531+
/// Enable transfer interrupts for the channel. This enables the transfer complete,
532+
/// half-transfer complete, data transfer error and user setting error interrupts. This is
533+
/// useful for starting a transfer that will be monitored by an interrupt handler.
525534
fn enable_transfer_interrupts(&self);
526535

536+
/// Disable transfer interrupts for the channel. It is expected that this will be called from
537+
/// an interrupt handler after a transfer is completed.
527538
fn disable_transfer_interrupts(&self);
528539
}
529540

@@ -533,46 +544,36 @@ where
533544
CH: ChannelRegs,
534545
Self: Deref<Target = CH>,
535546
{
536-
/// Enable a transfer on the channel
537547
#[inline(always)]
538548
fn enable(&self) {
539549
self.cr().modify(|_, w| w.en().enabled());
540550
}
541551

542-
/// Checks whether the channel is suspended
543552
#[inline(always)]
544553
fn is_suspended(&self) -> bool {
545554
self.sr().read().suspf().bit_is_set()
546555
}
547556

548-
/// Initiates the suspension of a transfer
549557
fn initiate_suspend(&self) {
550558
if self.is_suspended() {
551559
return;
552560
}
553561
self.suspend();
554562
}
555563

556-
/// Resume transfer
557564
#[inline(always)]
558565
fn initiate_resume(&self) {
559566
self.resume();
560567
}
561568

562-
/// Checks whether the channel transfer is complete. If the channel indicates an error occurred,
563-
/// during the transaction an `Error`` is returned.
564569
fn check_transfer_complete(&self) -> Result<bool, Error> {
565570
self.check_transfer_event(TransferEvent::TransferComplete)
566571
}
567572

568-
/// Checks whether the channel half transfer complete event has triggered. If the channel
569-
/// indicates an error occurred, during the transaction an `Error`` is returned.
570573
fn check_half_transfer_complete(&self) -> Result<bool, Error> {
571574
self.check_transfer_event(TransferEvent::HalfTransferComplete)
572575
}
573576

574-
/// Checks whether the channel transfer has started (has transitioned out of the idle state, or
575-
/// the transfer complete event has already triggered if it is idle)
576577
fn check_transfer_started(&self) -> Result<bool, Error> {
577578
// TODO: Resolve multiple status register reads
578579
match self.check_idle() {
@@ -584,34 +585,27 @@ where
584585
}
585586
}
586587

587-
/// Return whether or not a transfer is in progress on the channel.
588588
#[inline(always)]
589589
fn is_running(&self) -> bool {
590590
!self.is_idle()
591591
}
592592

593-
/// Reset the channel registers and clear status flags so the channel can be reused.
594593
fn reset_channel(&self) {
595594
self.reset();
596595
self.clear_all_event_flags();
597596
}
598597

599-
/// Suspend the transfer and blocks until it has been suspended. Reports any that occur while
600-
/// waiting for the transfer to suspend.
601598
fn suspend_transfer(&self) {
602599
self.initiate_suspend();
603600
while !self.is_suspended() {}
604601
}
605602

606-
/// Resumes a suspended transfer and blocks until the channel transitions out of the idle state
607-
/// Reports any errors that occur resuming the transfer.
608603
fn resume_transfer(&self) -> Result<(), Error> {
609604
self.initiate_resume();
610605
while !self.check_transfer_started()? {}
611606
Ok(())
612607
}
613608

614-
/// Aborts an operation by suspending the transfer and resetting the channel.
615609
fn abort(&self) {
616610
if !self.is_idle() {
617611
self.suspend_transfer();
@@ -620,35 +614,49 @@ where
620614
self.reset_channel();
621615
}
622616

623-
/// Blocks waiting for a transfer to be started (or for it to be idle and complete). Reports any
624-
/// errors that occur while waiting for the transfer to start.
625617
fn wait_for_transfer_started(&self) -> Result<(), Error> {
626-
while !self.check_transfer_started()? {}
618+
while !self.check_transfer_started().inspect_err(|_| {
619+
self.clear_all_event_flags();
620+
})? {}
627621
Ok(())
628622
}
629623

630-
/// Blocks waiting for a transfer to complete. Reports any errors that occur during a transfer.
631624
fn wait_for_transfer_complete(&self) -> Result<(), Error> {
632-
if !self.is_running() {
633-
return Ok(());
625+
loop {
626+
match self.check_transfer_complete() {
627+
Ok(true) => {
628+
self.clear_transfer_event_flag(
629+
TransferEvent::TransferComplete,
630+
);
631+
return Ok(());
632+
}
633+
Ok(false) => continue,
634+
Err(error) => {
635+
self.clear_all_event_flags();
636+
return Err(error);
637+
}
638+
}
634639
}
635-
636-
while !self.check_transfer_complete()? {}
637-
Ok(())
638640
}
639641

640-
/// Blocks waiting for a half transfer event to trigger. Reports any errors that occur during a
641-
/// transfer.
642642
fn wait_for_half_transfer_complete(&self) -> Result<(), Error> {
643-
if !self.is_running() {
644-
return Ok(());
643+
loop {
644+
match self.check_half_transfer_complete() {
645+
Ok(true) => {
646+
self.clear_transfer_event_flag(
647+
TransferEvent::HalfTransferComplete,
648+
);
649+
return Ok(());
650+
}
651+
Ok(false) => continue,
652+
Err(error) => {
653+
self.clear_all_event_flags();
654+
return Err(error);
655+
}
656+
}
645657
}
646-
647-
while !self.check_half_transfer_complete()? {}
648-
Ok(())
649658
}
650659

651-
/// Apply a transfer configuration to the channel
652660
fn apply_config<T: TransferType, S: Word, D: Word>(
653661
&self,
654662
config: DmaConfig<T, S, D>,
@@ -674,8 +682,6 @@ where
674682
}
675683
}
676684

677-
/// Apply hardware request configuration to the channel. Not relevant to memory-to-memory
678-
/// transfers.
679685
fn configure_hardware_request<T: HardwareRequest, S: Word, D: Word>(
680686
&self,
681687
config: DmaConfig<T, S, D>,
@@ -684,8 +690,6 @@ where
684690
self.set_request_line(config.transfer_type.request());
685691
}
686692

687-
/// Apply peripheral flow control configuration for transactions where a peripheral is the
688-
/// source
689693
fn configure_peripheral_flow_control<
690694
T: PeripheralSource,
691695
S: Word,
@@ -699,7 +703,6 @@ where
699703
);
700704
}
701705

702-
/// Apply a data transform to the channel transfer
703706
fn apply_data_transform(&self, data_transform: DataTransform) {
704707
self.set_source_byte_exchange(data_transform.source_byte_exchange);
705708
self.set_padding_alignment_mode(data_transform.padding_alignment);
@@ -709,36 +712,27 @@ where
709712
self.set_destination_byte_exchange(data_transform.dest_byte_exchange);
710713
}
711714

712-
/// Set the source address. This sets the source address and data width.
713715
fn set_source<W: Word>(&self, ptr: *const W) {
714716
self.set_source_address(ptr as u32);
715717
self.set_source_data_width(core::mem::size_of::<W>());
716718
}
717719

718-
/// Set the destination address. This sets the destination address and data width
719720
fn set_destination<W: Word>(&self, ptr: *mut W) {
720721
self.set_destination_address(ptr as u32);
721722
self.set_destination_data_width(core::mem::size_of::<W>());
722723
}
723724

724-
/// Set the transfer size in bytes (not words!). Size must be aligned with destination width if
725-
/// source width is greater than destination width and packing mode is used. Otherwise the size
726-
/// must be aligned with the source data width.
727725
fn set_transfer_size_bytes(&self, size: usize) {
728726
self.set_block_size(size as u16);
729727
}
730728

731-
/// Enable transfer interrupts for the channel. This enables the transfer complete,
732-
/// half-transfer complete, data transfer error and user setting error interrupts. This is
733-
/// useful for starting a transfer that will be monitored by an interrupt handler.
734729
#[inline(always)]
735730
fn enable_transfer_interrupts(&self) {
736731
self.cr().modify(|_, w| {
737732
w.tcie().enabled().dteie().enabled().useie().enabled()
738733
});
739734
}
740-
/// Disable transfer interrupts for the channel. It is expected that this will be called from
741-
/// an interrupt handler after a transfer is completed.
735+
742736
#[inline(always)]
743737
fn disable_transfer_interrupts(&self) {
744738
self.cr().modify(|_, w| {

0 commit comments

Comments
 (0)