Skip to content

Commit 4e62c26

Browse files
kilograhamWren6991
andauthored
Add documentation to dma_channel_abort regarding errata RP2040-E13 (#816)
Co-authored-by: Luke Wren <[email protected]>
1 parent 5a92779 commit 4e62c26

File tree

1 file changed

+27
-1
lines changed
  • src/rp2_common/hardware_dma/include/hardware

1 file changed

+27
-1
lines changed

src/rp2_common/hardware_dma/include/hardware/dma.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,14 +473,40 @@ static inline void dma_channel_start(uint channel) {
473473
*
474474
* Function will only return once the DMA has stopped.
475475
*
476+
* Note that due to errata RP2040-E13, aborting a channel which has transfers
477+
* in-flight (i.e. an individual read has taken place but the corresponding write has not), the ABORT
478+
* status bit will clear prematurely, and subsequently the in-flight
479+
* transfers will trigger a completion interrupt once they complete.
480+
*
481+
* The effect of this is that you \em may see a spurious completion interrupt
482+
* on the channel as a result of calling this method.
483+
*
484+
* The calling code should be sure to ignore a completion IRQ as a result of this method. This may
485+
* not require any additional work, as aborting a channel which may be about to complete, when you have a completion
486+
* IRQ handler registered, is inherently race-prone, and so code is likely needed to disambiguate the two occurrences.
487+
*
488+
* If that is not the case, but you do have a channel completion IRQ handler registered, you can simply
489+
* disable/re-enable the IRQ around the call to this method as shown by this code fragment (using DMA IRQ0).
490+
*
491+
* \code
492+
* // disable the channel on IRQ0
493+
* dma_channel_set_irq0_enabled(channel, false);
494+
* // abort the channel
495+
* dma_channel_abort(channel);
496+
* // clear the spurious IRQ (if there was one)
497+
* dma_channel_acknowledge_irq0(channel);
498+
* // re-enable the channel on IRQ0
499+
* dma_channel_set_irq0_enabled(channel, true);
500+
*\endcode
501+
*
476502
* \param channel DMA channel
477503
*/
478504
static inline void dma_channel_abort(uint channel) {
479505
check_dma_channel_param(channel);
480506
dma_hw->abort = 1u << channel;
481507
// Bit will go 0 once channel has reached safe state
482508
// (i.e. any in-flight transfers have retired)
483-
while (dma_hw->abort & (1ul << channel)) tight_loop_contents();
509+
while (dma_hw->ch[channel].ctrl_trig & DMA_CH0_CTRL_TRIG_BUSY_BITS) tight_loop_contents();
484510
}
485511

486512
/*! \brief Enable single DMA channel's interrupt via DMA_IRQ_0

0 commit comments

Comments
 (0)