How to prevent unwanted DMA transactions after enabling a DMA channel with queued transaction requests.
If a disabled DMA channel receives a request to perform a transfer, the request will be queued up similar to a pending interrupt. When the channel is enabled, the pending transfer request will be executed, resulting in a transaction that may not be desired.
The workaround is to queue up a “terminate channel” request. This request takes precedence over the transfer request. As soon as the channel is enabled, the terminate request is executed instead of the transfer request. This clears the pending transfer requests and disables the channel. The channel must be re-enabled afterward to function as intended.
This problem was discovered when an ADC End Of Conversion (EOC) was connected to the DMA ReQuest (DRQ) terminal of a DMA channel. The DMA channel was only really needed during a brief high speed sampling window. The ADC would be used normally other times, with software requesting a start of conversion and the "conversion done" bit being polled by the CPU to determine when the conversion was complete.
It was observed that when the ADC was disabled and the DMA channel was turned on (enabled), a sample would mysteriously appear in RAM. This was occurring even though it was guaranteed that the EOC signal was not asserted when the channel was enabled.
It was determined that when the ADC was used normally, the EOC was asserting the DRQ of the disabled DMA channel. This request was remembered by the DMA channel, even though the DMA channel was disabled. When the channel was enabled, this "remembered" DRQ was being executed immediately, resulting in an unexpected DMA transfer.
The fix is to assert a CPU request to terminate the chain before enabling the channel. By doing this, both requests (the transfer request and the terminate request) will be queued up in the DMA channel, waiting for the channel to be enabled. When the channel is enabled, the terminate request will take precedence over the transfer request and the DMA channel will terminate immediately, erasing the pending transfer request. The channel needs to be re-enabled after being enabled the first time since the terminate request will also disable the channel.
Below is example code, showing how the terminate request should be made before enabling the channel:
// Your DMA configuration code goes here
// End DMA config code
// To clear unwanted transfer requests (DRQ), issue a CPU terminate chain request
// Enable the DMA channel, This enable kills the spurious DMA transaction if there is one
// and disables the channel, must re-enable
// re-enable the DMA channel