Understand dsPIC33/PIC24 DMA Data Transfer Modes: One-Shot vs. Continuous vs. Repeated vs. Non-repeated
You’re not alone if those four modes‘ names sound confusing to you. I spent some time digging a little bit deeper into the modes, and here is my understanding of them:
One-Shot vs. Continuous
One-Shot only performs one single transfer per trigger while as Continuous performs multiple transfers. The direct proof is that in One-Shot mode, the default reset value of DMACNTn is 0001h. So every time a trigger signal happens, only one transfer of data is performed, the DMACNTn decrements to 0, and disables the DMA channel (by clearing CHEN). Of course, DMACNTn greater than 1 is allowed by user input. In this case, DMACNTn still decrements for every single transfer, but following transfer will need to be externally triggered again (either by software setting of CHREQ, or peripheral’s trigger signal). When DMACNTn reaches 0, it will disable the DMA channel. On the other side, Continuous mode has no default reset value of DMACNTn, totally defined by user. DMACNTn decrements for every single transfer, which is same as One-Shot, but following transfer will happen automatically after previous transfer until DMACNTn reaches 0, thus disabling the DMA channel. This is why it is called continuous — following transfers happen automatically, do not need new trigger. The number of the allowed continuous transfers is defined by DMACNT.
Repeated vs. Non-repeated
If you’ve read my previous paragraph, you should’ve figured out that the DMA channel will be automatically disabled when DMACNTn reaches 0. In order for more transfers to happen, manual re-enabling the DMA channel is necessary. Repeated mode is doing this re-enabling for you — the CHEN bit won’t be cleared when DMACNTn reaches 0, keeping the DMA channel active for more action.
You might have the question — what exactly is the word “transfer”. One transfer is the movement of “one” data (either BYTE or WORD defined by the DMACHn, SIZE register) from DMASRCn to DMADSTn. The key is “one”!
Example of UART
Using UART + DMA as example makes better explanation because UART peripheral supports user-definable number of data(byte/word) before a trigger is generated. UxSTAH[10:8], or URXISEL[2:0] defines the number of the data for each trigger signal, ranging from 1 to 8. For example, URXISEL = 0b111 will send trigger to DMA when there are eight data in the UART RX buffer. Accordingly, DMA’s mode should be set to Continuous and DMACNTn to 8. Such that, DMA will continuously perform eight transfers when UART trigger arrives. This will move all RX buffer’s data to DMA’s destination, emptying out UART’s receiver buffer. Similarly, if URXISEL is set to 0b11 (UART triggers upon 4 words/bytes in buffer), DMACNTn will need to be set to 4.
This is similar to RAM-to-RAM transfer when the source RAM has only eight data. Difference is that the source address won’t increment because UART RX buffer is FIFO, new data will show up at the same address (UxRXREG).
Please note: issues will occur when DMACNTn is stored with a larger value in continuous mode and source, however, hasn’t had the data ready yet. This situation is possible for the peripherals as source because data is to be arrived. Since DMA has no idea if the source is ready or not, it will keep transferring data from source upon the trigger signal until the DMACNTn reaches zero. The source, or in this case, the UART module has no new data in the buffer, DMA will transfer garbage data from the UART RX buffer. In order to solve this issue, or if you want to make DMA wait for certain amount of incoming data until it reaches expected quantity, TRMODE should be set to 0b01 — repeated one-shot, and UART’s URXISEL to 0 — trigger upon 1 word/byte. So that, every time data arrives in UART’s RX buffer, UART will issue a trigger to activate the DMA’s transfer. Once this single data is transferred, DMA will “repeat”, waiting for next trigger from UART.