Most embedded processors have one or more DMA controllers integrated on the chip. These are bus master devices which can be used to transfer data to and from other devices which are not able to access the bus on their own.
- Note:
- The term DMA does not necessarily imply that DMA controllers are being used -- some devices have their own bus master interfaces, and setting those devices up to access sytem memory is also referred to as "DMA" even though no DMA controllers are involved. DMA controllers are only necessary to do DMA against devices with no bus master interfaces on their own.
In order to use a DMA controller to transfer data to or from a device, the device needs a way to signal the DMA controller that it is ready to transfer data. This is done using chip-internal signals known as
handshaking interfaces. In systems with multiple DMA controllers, each device is normally only connected to one of them, so it's important to select the correct one. In the context of a single DMA controller, each handshaking interface is identified by an integer. The chip-defined enum
dmac_periph_id encodes this integer along with a number identifying which DMA controller to use.
To allocate a DMA channel for use with a slave peripheral, call
dmac_alloc_channel(). If a unidirectional channel is needed, pass
DMAC_PERIPH_NONE as the rx_periph or tx_periph parameter.
To free a DMA channel which is no longer needed, call dmac_free_channel().
To submit an asynchronous DMA transfer request, call
dmac_chan_submit_request(). The following fields of the
dmac_request structure passed as a parameter must be properly initialized first:
- buf_list - List of buffer structures holding the data to be transfered
- direction - Either DMA_FROM_DEVICE or DMA_TO_DEVICE
- reg_width - The width of each register access (8, 16 or 32 bits)
- req_done - Callback to be called when the transfer is complete (optional)
- context - Arbitrary data associated with the request (optional)
The DMAC layer will ensure that all of these fields have the same value when the request is done as they had when it was submitted, though some of the fields may be altered while the request is being processed.
When the request is complete, the status and bytes_xfered fields will be updated to reflect the status of the request before the req_done() callback is called (if present).
When other parts of the systems fail, it might be necessary to terminate DMA requests before they are complete. Calling
dmac_chan_reset() will forcibly stop the DMA controller hardware and terminate all queued requests with a negative status code. The req_done() callback of the flushed requests will be called; it's the client's responsibility to ensure that none of those callbacks cause any new requests to be queued.
DMA controllers may have implementation-specific constraints that limit the number of bytes that can be transfered in one go. Working around such limitations in a generic manner tends to take quite a lot of additional logic in a code path which is meant to be very fast, so this is a bad option performance-wise.
Instead, the DMA controller may export such limits in each channel's struct dma_channel so that the client can prevent the buffers from exceeding this limit when they are created. This may require the same information to be exported to higher layers as well so that the client doesn't end up having to split buffers to satisfy the DMAC limitations.