Embedded Design Handbook

ID 683689
Date 8/28/2023
Public
Document Table of Contents

4.2.3.3.4. Direct Memory Access Devices

The HAL Direct Memory Access (DMA) model uses DMA transmit and receive channels. A DMA operation places a transaction request on a channel. A DMA peripheral can have a transmit channel, a receive channel, or both. This section describes three possible hardware configurations for a DMA peripheral, and shows how to activate each kind of DMA channel using the HAL memory access functions.

The DMA peripherals are initialized by the alt_sys_init() function call, and are automatically enabled by the nios2-bsp script.

DMA Configuration and Use Model

The following examples illustrate use of the DMA transmit and receive channels in a system. The information complements the information available in “Using DMA Devices” in the Developing Programs Using the Hardware Abstraction Layer chapter of the Nios® II Gen2 Software Developer's Handbook.

Regardless of the DMA peripheral connections in the system, initialize a transmit channel by running the alt_dma_txchan_open() function, and initialize a receive DMA channel by running the alt_dma_rxchan_open() function. The following sections describe the use model for some specific cases.

RX-Only DMA Component

A typical RX-only DMA component moves the data it receives from another component to memory. In this case, the receive channel of the DMA peripheral reads continuously from a fixed location in memory, which is the other peripheral's data register. The following sequence of operations directs the DMA peripheral:

  1. Open the DMA peripheral—Call the alt_dma_rxchan_open() function to open the receive DMA channel.
  2. Enable DMA ioctl operations—Call the alt_dma_rxchan_ioctl() function to set the ALT_DMA_RX_ONLY_ON flag. Use the ALT_DMA_SET_MODE_<n> flag to set the data width to match that of the other peripheral’s data register.
  3. Configure the other peripheral to run—The Nios® II processor configures the other peripheral to begin loading new data in its data register.
  4. Queue the DMA transaction requests—Call the alt_avalon_dma_prepare() function to begin a DMA operation. In the function call, you specify the DMA receive channel, the other peripheral’s data register address, the number of bytes to transfer, and a callback function to run when the transaction is complete.

TX-Only DMA Component

A typical TX-only DMA component moves data from memory to another component. In this case, the transmit channel of the DMA peripheral writes continuously to a fixed location in memory, which is the other peripheral's data register. The following sequence of operations directs the DMA peripheral:

  1. Open the DMA peripheral—Call the alt_dma_txchan_open() function to open the transmit DMA channel.
  2. Enable DMA ioctl operations—Call the alt_dma_txchan_ioctl() function to set the ALT_DMA_TX_ONLY_ON flag. Use the ALT_DMA_SET_MODE_<n> flag to set the data width to match that of the other peripheral’s data register.
  3. Configure the other peripheral to run—The Nios® II processor configures the other peripheral to begin receiving new data in its data register.
  4. Queue the DMA transaction requests—Call the alt_avalon_dma_send() function to begin a DMA operation. In the function call, you specify the DMA transmit channel, the other peripheral’s data register address, the number of bytes to transfer, and a callback function to run when the transaction is complete.

RX and TX DMA Component

A typical RX and TX DMA component performs memory-to-memory copy operations. The application must open, configure, and assign transaction requests to both DMA channels explicitly. The following sequence of operations directs the DMA peripheral:

  1. Open the DMA RX channel—Call the alt_dma_rxchan_open() function to open the DMA receive channel.
  2. Enable DMA RX ioctl operations—Call the alt_dma_rxchan_ioctl() function to set the ALT_DMA_RX_ONLY_OFF flag. Use the ALT_DMA_SET_MODE_<n> flag to set the data width to the correct value for the memory transfers.
  3. Open the DMA TX channel—Call the alt_dma_txchan_open() function to open the DMA transmit channel.
  4. Enable DMA TX ioctl operations—Call the alt_dma_txchan_ioctl() function to set the ALT_DMA_TX_ONLY_OFF flag. Use the ALT_DMA_SET_MODE_<n> flag to set the data width to the correct value for the memory transfers.
  5. Queue the DMA RX transaction requests—Call the alt_avalon_dma_prepare() function to begin a DMA RX operation. In the function call, you specify the DMA receive channel, the address from which to begin reading, the number of bytes to transfer, and a callback function to run when the transaction is complete.
  6. Queue the DMA TX transaction requests—Call the alt_avalon_dma_send() function to begin a DMA TX operation. In the function call, you specify the DMA transmit channel, the address to which to begin writing, the number of bytes to transfer, and a callback function to run when the transaction is complete.

The DMA peripheral does not begin the transaction until the DMA TX transaction request is issued.

For examples of DMA device use, refer to “Using DMA Devices” in the Developing Programs Using the Hardware Abstraction Layer chapter of the Nios II Gen2 Software Developer's Handbook.

DMA Data-Width Parameter

The DMA data-width parameter is configured in Platform Designer to specify the widths that are supported. In writing the software application, you must specify the width to use for a particular transaction. The width of the data you transfer must match the hardware capability of the component.

Consider the following points about the data-width parameter before you implement a DMA peripheral:

  • Peripheral width—When a DMA component moves data from another peripheral, the DMA component must use a single-operation transfer size equal to the width of the peripheral’s data register.
  • Transfer length—The byte transfer length specified to the DMA peripheral must be a multiple of the data width specified.
  • Odd transfer sizes—If you must transfer an uneven number of bytes between memory and a peripheral using a DMA component, you must divide up your data transfer operation. Implement the longest allowed transfer using the DMA component, and transfer the remaining bytes using the Nios® II processor. For example, if you must transfer 1023 bytes of data from memory to a peripheral with a 32-bit data register, perform 255 32-bit transfers with the DMA and then have the Nios® II processor write the remaining 3 bytes.

Configuration and Use Limitations

If you use DMA components in your system, be aware of the following properties of these components:

  • Hardware configuration—The following aspects of the hardware configuration of the DMA peripheral determine the HAL service:
    • DMA components connected to peripherals other than memory support only half of the HAL API (receive or transmit functionality). The application software should not attempt to call API functions that are not available.
    • The hardware parameterization of the DMA component determines the data width of its transfers, a value which the application software must take into account.
  • IOCTL control—The DMA ioctl() function call enables the setting of a single flag only. To set multiple flags for a DMA channel, you must call ioctl() multiple times.
  • DMA transaction slots—The current driver is limited to four transaction slots. If you must increase the number of transaction slots, you can specify the number of slots using the macro ALT_AVALON_DMA_NSLOTS. The value of this macro must be a power of two.
  • Interrupts—The HAL DMA service requires that the DMA peripheral's interrupt line be connected in the system.
  • User controlled DMA accesses—If the default HAL DMA access routines are too unwieldy for your application, you can create your own access functions. For information about how to remove the default HAL DMA driver routines, refer to “Reducing Code Size”.

For more information about the HAL API for accessing DMA devices, refer to “Using DMA Devices” in the Developing Programs Using the Hardware Abstraction Layer chapter of the Nios® II Gen2 Software Developer's Handbook and to the HAL API Reference chapter of the Nios® II Gen2 Software Developer's Handbook.