DMA (Direct Memory Access)¶
-
group
group_hal_dma
High level interface for interacting with the direct memory access (DMA).
The DMA driver allows for initializing and configuring a DMA channel in order to trigger data transfers to and from memory and peripherals. The transfers occur independently of the CPU and are triggered in software. Multiple channels can be active at the same time each with their own user-selectable priority and transfer characteristics.
Features
CPU independent memory access
Access to memory and peripherals
Multiple independent channels
Configurable transer sizes and bursts
Configurable priorities
Event completion notification
Quick Start
See Snippet 1: Simple DMA initialization and transfer for a code snippet that sets up a DMA transfer to move memory from one location to another.
Code snippets
note
Error handling code has been intentionally left out of snippets to highlight API usage.
Snippet 1: Simple DMA initialization and transfer
The following snippet initializes a DMA channel and uses it to transfer a a single block of memory. The DMA channel is reserved by calling cyhal_dma_init. It then needs to be configured with cyhal_dma_configure and then the transfer is started with cyhal_dma_start_transfer
.
If the DMA channel is not needed anymore, it can be released by calling
cyhal_dma_freecy_rslt_t rslt; cyhal_dma_t dma; cyhal_dma_cfg_t cfg = { .src_addr = 0x8000000, // Start from address .src_increment = 1, // Increment source by 1 word .dst_addr = 0x8001000, // Destination from address .dst_increment = 1, // Increment destination by 1 word .transfer_width = 32, // 32 bit transfer .length = 0x10, // Transfer 64 bytes (16 transfers of 4 bytes) .burst_size = 0, // Transfer everything in a single burst .action = CYHAL_DMA_TRANSFER_FULL, // Notify when everything is done }; // Allocate the DMA channel for use rslt = cyhal_dma_init(&dma, CYHAL_DMA_PRIORITY_DEFAULT, CYHAL_DMA_DIRECTION_MEM2MEM); // Configure the channel for the upcoming transfer rslt = cyhal_dma_configure(&dma, &cfg); // Begin the transfer rslt = cyhal_dma_start_transfer(&dma); // If the DMA channel is no longer needed, it can be freed up for other uses if (!cyhal_dma_is_busy(&dma)) { cyhal_dma_free(&dma); }
Snippet 2: Configuring the DMA channel based on memory requirements
cyhal_dma_configure can be used after DMA initialization to handle a variety of memory layouts.
#define BUFFER_SIZE (32) #define PERIPHERAL_FIFO_ADDR (0x4001000) cy_rslt_t rslt; cyhal_dma_t dma; uint32_t buffer[BUFFER_SIZE]; // Allocate the DMA channel for transfering from memory to a peripheral rslt = cyhal_dma_init(&dma, CYHAL_DMA_PRIORITY_DEFAULT, CYHAL_DMA_DIRECTION_MEM2PERIPH); cyhal_dma_cfg_t cfg = { .src_addr = (uint32_t)buffer, // Start from address .src_increment = 1, // Increment source by 1 word .dst_addr = PERIPHERAL_FIFO_ADDR, // Destination from address .dst_increment = 0, // Don't increment the destination .transfer_width = 32, // 32 bit transfer .length = BUFFER_SIZE, // Transfer 64 bytes (16 transfers of 4 bytes) .burst_size = 0, // Transfer everything in a single burst .action = CYHAL_DMA_TRANSFER_FULL, // Notify when everything is done }; rslt = cyhal_dma_configure(&dma, &cfg);
Snippet 3: Interrupts and retriggering DMA transfers
DMA events like transfer complete or error events can be used to trigger a callback function.
This snippet uses
cyhal_dma_configure to break the full transfer into multiple bursts. This allows higher priority items access to the memory bus if necessary while the DMA operation is still in progress. It then uses cyhal_dma_enable_event() to enable the transfer complete event to trigger the callback function registered by cyhal_dma_register_callback().void dma_event_callback(void* callback_arg, cyhal_dma_event_t event) { CY_UNUSED_PARAMETER(event); cyhal_dma_t* dma = (cyhal_dma_t*)callback_arg; // Do work specific to each burst complete // If all bursts are complete, start another if (!cyhal_dma_is_busy(dma)) { cyhal_dma_start_transfer(dma); } } void snippet_cyhal_dma_events() { cy_rslt_t rslt; cyhal_dma_t dma; cyhal_dma_cfg_t cfg = { .src_addr = 0x8000000, // Start from address .src_increment = 1, // Increment source by 1 word .dst_addr = 0x8001000, // Destination from address .dst_increment = 1, // Increment destination by 1 word .transfer_width = 32, // 32 bit transfer .length = 0x10, // Transfer 64 bytes (16 transfers of 4 bytes) .burst_size = 4, // Transfer 4 words a a time .action = CYHAL_DMA_TRANSFER_BURST, // Notify when each burst is done }; // Allocate the DMA channel for use rslt = cyhal_dma_init(&dma, CYHAL_DMA_PRIORITY_LOW, CYHAL_DMA_DIRECTION_MEM2MEM); CY_ASSERT(CY_RSLT_SUCCESS == rslt); // Configure the channel for the upcoming transfer rslt = cyhal_dma_configure(&dma, &cfg); // Register an event callback handler and enable events cyhal_dma_register_callback(&dma, &dma_event_callback, &dma); cyhal_dma_enable_event(&dma, CYHAL_DMA_TRANSFER_COMPLETE, CYHAL_ISR_PRIORITY_DEFAULT, true); // Begin the transfer rslt = cyhal_dma_start_transfer(&dma); }
Defines
-
cyhal_dma_init
(obj, priority, direction)¶ Initialize the DMA peripheral.
- Parameters
obj – [out] Pointer to a DMA object. The caller must allocate the memory for this object but the init function will initialize its contents.
priority – [in] The priority of this DMA operation relative to others. The number of priority levels which are supported is hardware dependent. All implementations define a CYHAL_DMA_PRIORITY_DEFAULT constant which is always valid. If supported, implementations will also define CYHAL_DMA_PRIORITY_HIGH, CYHAL_DMA_PRIORITY_MEDIUM, and CYHAL_DMA_PRIORITY_LOW. The behavior of any other value is implementation defined. See the implementation-specific DMA documentation for more details.
direction – [in] The direction memory is copied
- Returns
The status of the init request
Typedefs
-
typedef void (*
cyhal_dma_event_callback_t
)(void *callback_arg, cyhal_dma_event_t event)¶ Event handler for DMA interrupts.
Enums
-
enum
cyhal_dma_direction_t
¶ cyhal_dma_direction_t: Direction for DMA transfers.
Values:
-
enumerator
CYHAL_DMA_DIRECTION_MEM2MEM
¶ Memory to memory.
-
enumerator
CYHAL_DMA_DIRECTION_MEM2PERIPH
¶ Memory to peripheral.
-
enumerator
CYHAL_DMA_DIRECTION_PERIPH2MEM
¶ Peripheral to memory.
-
enumerator
CYHAL_DMA_DIRECTION_PERIPH2PERIPH
¶ Peripheral to peripheral.
-
enumerator
-
enum
cyhal_dma_event_t
¶ cyhal_dma_event_t: Flags enum of DMA events.
Multiple events can be enabled.
Values:
-
enumerator
CYHAL_DMA_NO_INTR
¶ No interrupt.
-
enumerator
CYHAL_DMA_TRANSFER_COMPLETE
¶ Indicates that a burst or full transfer has completed.
-
enumerator
CYHAL_DMA_SRC_BUS_ERROR
¶ Indicates that there is a source bus error.
-
enumerator
CYHAL_DMA_DST_BUS_ERROR
¶ Indicates that there is a destination bus error.
-
enumerator
CYHAL_DMA_SRC_MISAL
¶ Indicates that the source address is not aligned.
-
enumerator
CYHAL_DMA_DST_MISAL
¶ Indicates that the destination address is not aligned.
-
enumerator
CYHAL_DMA_CURR_PTR_NULL
¶ Indicates that the current descriptor pointer is null.
-
enumerator
CYHAL_DMA_ACTIVE_CH_DISABLED
¶ Indicates that the active channel is disabled.
-
enumerator
CYHAL_DMA_DESCR_BUS_ERROR
¶ Indicates that there has been a descriptor bus error.
-
enumerator
-
enum
cyhal_dma_input_t
¶ cyhal_dma_input_t: Specifies the transfer type to trigger when an input signal is received.
Values:
-
enumerator
CYHAL_DMA_INPUT_TRIGGER_SINGLE_ELEMENT
¶ Transfer a single element when an input signal is received.
-
enumerator
CYHAL_DMA_INPUT_TRIGGER_SINGLE_BURST
¶ Transfer a single burst when an input signal is received.
-
enumerator
CYHAL_DMA_INPUT_TRIGGER_ALL_ELEMENTS
¶ Transfer all elements when an input signal is received.
-
enumerator
-
enum
cyhal_dma_output_t
¶ cyhal_dma_output_t: Specifies the transfer completion event that triggers a signal output.
Values:
-
enumerator
CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_ELEMENT
¶ Trigger an output when a single element is transferred.
-
enumerator
CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_BURST
¶ Trigger an output when a single burst is transferred.
-
enumerator
CYHAL_DMA_OUTPUT_TRIGGER_ALL_ELEMENTS
¶ Trigger an output when all elements are transferred.
-
enumerator
-
enum
cyhal_dma_transfer_action_t
¶ cyhal_dma_transfer_action_t: If burst_size is used, selects whether a single trigger of the channel transfers a single burst of burst_size or a full transfer of size length (that is, every burst is triggered).
This will also set the initial transfer type that will trigger an output signal on completion.
Values:
-
enumerator
CYHAL_DMA_TRANSFER_BURST
¶ A single burst is triggered and a transfer completion event will occur after the burst.
-
enumerator
CYHAL_DMA_TRANSFER_FULL
¶ All bursts are triggered and a single transfer completion event will occur at the end of all of them.
-
enumerator
Functions
-
cy_rslt_t
cyhal_dma_init_adv
(cyhal_dma_t *obj, cyhal_dma_src_t *src, cyhal_dma_dest_t *dest, cyhal_source_t *dest_source, uint8_t priority, cyhal_dma_direction_t direction)¶ Initialize the DMA peripheral.
If a source signal is provided for src, this will connect the provided signal to the DMA just as would be done by calling cyhal_dma_connect_digital. Similarly, if a destination target is provided for dest this will enable the specified output just as would be done by calling cyhal_dma_enable_output.
- Parameters
obj – [out] Pointer to a DMA object. The caller must allocate the memory for this object but the init function will initialize its contents.
src – [in] An optional source signal to connect to the DMA
dest – [in] An optional destination singal to drive from the DMA
dest_source – [out] An optional pointer to user-allocated source signal object which will be initialized by enable_output. If dest is non-null, this must also be non-null. dest_source should be passed to (dis)connect_digital functions to (dis)connect the associated endpoints.
priority – [in] The priority of this DMA operation relative to others. The number of priority levels which are supported is hardware dependent. All implementations define a CYHAL_DMA_PRIORITY_DEFAULT constant which is always valid. If supported, implementations will also define CYHAL_DMA_PRIORITY_HIGH, CYHAL_DMA_PRIORITY_MEDIUM, and CYHAL_DMA_PRIORITY_LOW. The behavior of any other value is implementation defined. See the implementation-specific DMA documentation for more details.
direction – [in] The direction memory is copied
- Returns
The status of the init request
-
void
cyhal_dma_free
(cyhal_dma_t *obj)¶ Free the DMA object.
Freeing a DMA object while a transfer is in progress (see cyhal_dma_is_busy) is invalid.
- Parameters
obj – [inout] The DMA object
-
cy_rslt_t
cyhal_dma_configure
(cyhal_dma_t *obj, const cyhal_dma_cfg_t *cfg)¶ Setup a DMA descriptor for specified resource.
- Parameters
obj – [in] The DMA object
cfg – [in] Configuration parameters for the transfer
- Returns
The status of the configure request
-
cy_rslt_t
cyhal_dma_start_transfer
(cyhal_dma_t *obj)¶ Initiates DMA channel transfer for specified DMA object.
- Parameters
obj – [in] The DMA object
- Returns
The status of the start_transfer request
-
bool
cyhal_dma_is_busy
(cyhal_dma_t *obj)¶ Checks whether a transfer is pending or running on the DMA channel.
- Parameters
obj – [in] The DMA object
- Returns
True if DMA channel is busy
-
void
cyhal_dma_register_callback
(cyhal_dma_t *obj, cyhal_dma_event_callback_t callback, void *callback_arg)¶ Register a DMA callback handler.
This function will be called when one of the events enabled by cyhal_dma_enable_event occurs.
- Parameters
obj – [in] The DMA object
callback – [in] The callback handler which will be invoked when an event triggers
callback_arg – [in] Generic argument that will be provided to the callback when called
-
void
cyhal_dma_enable_event
(cyhal_dma_t *obj, cyhal_dma_event_t event, uint8_t intr_priority, bool enable)¶ Configure DMA event enablement.
When an enabled event occurs, the function specified by cyhal_dma_register_callback will be called.
- Parameters
obj – [in] The DMA object
event – [in] The DMA event type
intr_priority – [in] The priority for NVIC interrupt events. The priority from the most recent call will take precedence, i.e all events will have the same priority.
enable – [in] True to turn on interrupts, False to turn off
-
cy_rslt_t
cyhal_dma_connect_digital
(cyhal_dma_t *obj, cyhal_source_t source, cyhal_dma_input_t input)¶ Connects a source signal and enables the specified input to the DMA channel.
- Parameters
obj – [in] The DMA object
source – [in] Source signal obtained from another driver’s cyhal_<PERIPH>_enable_output
input – [in] Which input to enable
- Returns
The status of the connection
-
cy_rslt_t
cyhal_dma_enable_output
(cyhal_dma_t *obj, cyhal_dma_output_t output, cyhal_source_t *source)¶ Enables the specified output signal from a DMA channel that is triggered when a transfer is completed.
- Parameters
obj – [in] The DMA object
output – [in] Which event triggers the output
source – [out] Pointer to user-allocated source signal object which will be initialized by enable_output. source should be passed to (dis)connect_digital functions to (dis)connect the associated endpoints.
- Returns
The status of the output enable
-
cy_rslt_t
cyhal_dma_disconnect_digital
(cyhal_dma_t *obj, cyhal_source_t source, cyhal_dma_input_t input)¶ Disconnects a source signal and disables the specified input to the DMA channel.
- Parameters
obj – [in] The DMA object
source – [in] Source signal from cyhal_<PERIPH>_enable_output to disable
input – [in] Which input to disable
- Returns
The status of the disconnect
-
cy_rslt_t
cyhal_dma_disable_output
(cyhal_dma_t *obj, cyhal_dma_output_t output)¶ Disables the specified output signal from a DMA channel.
- Parameters
obj – [in] The DMA object
output – [in] Which output to disable
- Returns
The status of the disablement
-
struct
cyhal_dma_cfg_t
¶ - #include <>
Configuration of a DMA channel.
When configuring address, increments, and transfer width keep in mind your hardware may have more stringent address and data alignment requirements.
Public Members
-
uint32_t
src_addr
¶ Source address.
-
int16_t
src_increment
¶ Source address auto increment amount in multiples of transfer_width.
-
uint32_t
dst_addr
¶ Destination address.
-
int16_t
dst_increment
¶ Destination address auto increment amount in multiples of transfer_width.
-
uint8_t
transfer_width
¶ Transfer width in bits. Valid values are: 8, 16, or 32.
-
uint32_t
length
¶ Number of elements to be transferred in total.
-
uint32_t
burst_size
¶ Number of elements to be transferred per trigger. If set to 0 every element is transferred, otherwise burst_size must evenly divide length.
-
cyhal_dma_transfer_action_t
action
¶ Sets the behavior of the channel when triggered (using start_transfer). Ignored if burst_size is not configured.
-
uint32_t
-
struct
cyhal_dma_src_t
¶ - #include <>
DMA input connection information to setup while initializing the driver.
Public Members
-
cyhal_source_t
source
¶ Source of signal to DMA; obtained from another driver’s cyhal_<PERIPH>_enable_output.
-
cyhal_dma_input_t
input
¶ DMA input signal to be driven.
-
cyhal_source_t
-
struct
cyhal_dma_dest_t
¶ - #include <>
DMA output connection information to setup while initializing the driver.
Public Members
-
cyhal_dma_output_t
output
¶ Output signal of DMA.
-
cyhal_dest_t
dest
¶ Destination of DMA signal.
-
cyhal_dma_output_t