0
0
AutocadHow-ToIntermediate · 4 min read

How to Use DMA in Arduino Due for Efficient Data Transfer

To use DMA on the Arduino Due, you configure the Peripheral DMA Controller (PDC) registers to transfer data between memory and peripherals without CPU intervention. This involves setting up source and destination addresses, transfer size, and enabling the DMA channel. Using DMA improves performance by offloading data movement tasks from the CPU.
📐

Syntax

DMA on Arduino Due is controlled through the Peripheral DMA Controller (PDC) registers associated with each peripheral. The main steps are:

  • Set source address: Where data comes from (memory or peripheral).
  • Set destination address: Where data goes (memory or peripheral).
  • Set transfer size: Number of bytes or words to transfer.
  • Enable DMA channel: Start the transfer.

These steps are done by writing to specific registers like PERIPH->PERIPH_RPR (Receive Pointer Register), PERIPH->PERIPH_RCR (Receive Counter Register), and control registers.

c
PDC_Type *pdc = PERIPH->PERIPH_PDC;  // Get PDC pointer for peripheral
pdc->PERIPH_TPR = (uint32_t)source_address;  // Set source address
pdc->PERIPH_TCR = transfer_size;             // Set transfer size
pdc->PERIPH_TNPR = 0;                        // Next buffer pointer (optional)
pdc->PERIPH_TNCR = 0;                        // Next buffer size (optional)
pdc->PERIPH_PTCR = PERIPH_PTCR_TXTEN;       // Enable transmitter transfer
💻

Example

This example shows how to use DMA to transfer data from a buffer to the UART peripheral on Arduino Due. It sends a string without CPU copying each byte.

c++
#include <Arduino.h>

const char message[] = "Hello DMA on Arduino Due!\n";

void setup() {
  Serial.begin(115200);
  while (!Serial) {}

  // Get PDC pointer for UART
  Pdc *pdc = uart_get_pdc_instance(UART);

  // Disable PDC transfers before configuring
  pdc_disable_transfer(pdc, PERIPH_PTCR_TXTDIS);

  // Set transmit pointer and counter
  pdc_tx_init(pdc, (uint8_t *)message, sizeof(message) - 1);

  // Enable PDC transmit
  pdc_enable_transfer(pdc, PERIPH_PTCR_TXTEN);
}

void loop() {
  // Do nothing, DMA handles transmission
}
Output
Hello DMA on Arduino Due!
⚠️

Common Pitfalls

  • Not disabling DMA before configuring: Always disable DMA channel before setting addresses and counters to avoid undefined behavior.
  • Incorrect buffer size: Transfer size must match the actual data length; otherwise, data corruption or crashes can occur.
  • Not enabling peripheral clocks: Ensure the peripheral clock is enabled before using DMA.
  • Forgetting to enable DMA channel: After setup, you must enable the DMA channel to start transfer.
  • Using wrong peripheral PDC pointer: Each peripheral has its own PDC instance; using the wrong one will fail.
c
/* Wrong way: Not disabling DMA before config */
Pdc *pdc = uart_get_pdc_instance(UART);
pdc_tx_init(pdc, (uint8_t *)buffer, size);
pdc_enable_transfer(pdc, PERIPH_PTCR_TXTEN); // Might cause issues

/* Right way: Disable before config */
pdc_disable_transfer(pdc, PERIPH_PTCR_TXTDIS);
pdc_tx_init(pdc, (uint8_t *)buffer, size);
pdc_enable_transfer(pdc, PERIPH_PTCR_TXTEN);
📊

Quick Reference

Summary tips for using DMA on Arduino Due:

  • Use uart_get_pdc_instance() or similar to get PDC pointer for your peripheral.
  • Always disable DMA channel before configuring.
  • Set source/destination addresses and transfer size carefully.
  • Enable DMA channel to start transfer.
  • Check peripheral clock is enabled.

Key Takeaways

DMA on Arduino Due uses the Peripheral DMA Controller (PDC) to transfer data without CPU load.
Always disable the DMA channel before configuring source, destination, and transfer size.
Use the correct PDC instance for the peripheral you want to use DMA with.
Enable the DMA channel after setup to start the transfer.
Ensure peripheral clocks are enabled before using DMA.