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 can be triggered by software or hardware. Multiple channels can be active at the same time each with their own user-selectable priority and transfer characteristics.
The operational flow of the driver is listed below. This shows the basic order in which each of the functions would generally be called. While Initialize must always be first and Release always last, with care, the other functions can be reordered based on the implementation needs.
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.
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_free
cyhal_dma_configure can be used after DMA initialization to handle a variety of memory layouts.
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().
DMA operations can be initiated by a hardware signal, or initiate a hardware signal on completion.
This snippet shows how either can be done with a timer object.
In the first case, the DMA output signal (cyhal_dma_enable_output) is used so that when the DMA operation complets it in turn causes the timer to run.
NOTE: The cyhal_dma_init_adv can also be used insted of cyhal_dma_enable_output to enable the output. The advantage of using init_adv is it makes sure the DMA instance that is allocated is able to connected to the specified signal.
The second snippet shows how a timer overflow can be used to trigger a DMA operation. It uses cyhal_dma_init_adv to setup the connection, but cyhal_dma_connect_digital could be used instead; with the same note as above about ensuring a connection between instances.
If CPU D-cache is enabled, DMA transfers must be handled using cache management API when dealing with cacheable memory in order to maintain CPU data cache coherency. Regarding the CPU data cache coherence with DMA, the general rules are,
The following snippet initializes a DMA channel and uses it to transfer a single block from one cacheable memory to another cacheable memory. Cleaning D-cache of DMA descriptor is done by calling cyhal_dma_configure. Cleaning D-cache of source's buffer and Invalidating D-cache of destination's buffer should be done explicitly.
Refer to DCACHE_Management for more information.
API Reference | |
DMA HAL Results | |
DMA specific return codes. | |
Data Structures | |
struct | cyhal_dma_cfg_t |
Configuration of a DMA channel. More... | |
struct | cyhal_dma_src_t |
DMA input connection information to setup while initializing the driver. More... | |
struct | cyhal_dma_dest_t |
DMA output connection information to setup while initializing the driver. More... | |
Macros | |
#define | cyhal_dma_init(obj, priority, direction) (cyhal_dma_init_adv(obj, NULL, NULL, NULL, priority, direction)) |
Initialize the DMA peripheral. More... | |
Typedefs | |
typedef void(* | cyhal_dma_event_callback_t) (void *callback_arg, cyhal_dma_event_t event) |
Event handler for DMA interrupts. | |
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. More... | |
cy_rslt_t | cyhal_dma_init_cfg (cyhal_dma_t *obj, const cyhal_dma_configurator_t *cfg) |
Initialize the DMA peripheral using data provided by the configurator. More... | |
void | cyhal_dma_free (cyhal_dma_t *obj) |
Free the DMA object. More... | |
cy_rslt_t | cyhal_dma_configure (cyhal_dma_t *obj, const cyhal_dma_cfg_t *cfg) |
Setup the DMA channel behavior. More... | |
cy_rslt_t | cyhal_dma_enable (cyhal_dma_t *obj) |
Enable the DMA transfer so that it can start transferring data when triggered. More... | |
cy_rslt_t | cyhal_dma_disable (cyhal_dma_t *obj) |
Disable the DMA transfer so that it does not continue to trigger. More... | |
cy_rslt_t | cyhal_dma_start_transfer (cyhal_dma_t *obj) |
Initiates DMA channel transfer for specified DMA object. More... | |
bool | cyhal_dma_is_busy (cyhal_dma_t *obj) |
Checks if the transfer has been triggered, but not yet complete (eg: is pending, blocked or running) More... | |
void | cyhal_dma_register_callback (cyhal_dma_t *obj, cyhal_dma_event_callback_t callback, void *callback_arg) |
Register a DMA callback handler. More... | |
void | cyhal_dma_enable_event (cyhal_dma_t *obj, cyhal_dma_event_t event, uint8_t intr_priority, bool enable) |
Configure DMA event enablement. More... | |
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. More... | |
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. More... | |
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. More... | |
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. More... | |
struct cyhal_dma_cfg_t |
Data Fields | ||
---|---|---|
uint32_t | src_addr | Source address. Some devices can apply special requirements for user data arrays. Please refer to implementation-specific documentation to see whether any limitations exist for used device. |
int16_t | src_increment | Source address auto increment amount in multiples of transfer_width. |
uint32_t | dst_addr | Destination address. Some devices can apply special requirements for user data arrays. Please refer to implementation-specific documentation to see whether any limitations exist for used device. |
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. |
struct cyhal_dma_src_t |
Data Fields | ||
---|---|---|
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. |
struct cyhal_dma_dest_t |
Data Fields | ||
---|---|---|
cyhal_dma_output_t | output | Output signal of DMA. |
cyhal_dest_t | dest | Destination of DMA signal. |
#define cyhal_dma_init | ( | obj, | |
priority, | |||
direction | |||
) | (cyhal_dma_init_adv(obj, NULL, NULL, NULL, priority, direction)) |
Initialize the DMA peripheral.
[out] | obj | Pointer to a DMA object. The caller must allocate the memory for this object but the init function will initialize its contents. |
[in] | priority | 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. |
[in] | direction | The direction memory is copied |
enum cyhal_dma_event_t |
Flags enum of DMA events.
Multiple events can be enabled via cyhal_dma_enable_event and the callback from cyhal_dma_register_callback will be run to notify.
Enumerator | |
---|---|
CYHAL_DMA_NO_INTR | No interrupt. |
CYHAL_DMA_TRANSFER_COMPLETE | Indicates that an individual transfer (burst or full) has completed based on the specified cyhal_dma_transfer_action_t. |
CYHAL_DMA_DESCRIPTOR_COMPLETE | Indicates that the full transfer has completed. |
CYHAL_DMA_SRC_BUS_ERROR | Indicates that there is a source bus error. |
CYHAL_DMA_DST_BUS_ERROR | Indicates that there is a destination bus error. |
CYHAL_DMA_SRC_MISAL | Indicates that the source address is not aligned. |
CYHAL_DMA_DST_MISAL | Indicates that the destination address is not aligned. |
CYHAL_DMA_CURR_PTR_NULL | Indicates that the current descriptor pointer is null. |
CYHAL_DMA_ACTIVE_CH_DISABLED | Indicates that the active channel is disabled. |
CYHAL_DMA_DESCR_BUS_ERROR | Indicates that there has been a descriptor bus error. |
enum cyhal_dma_input_t |
Specifies the transfer type to trigger when an input signal is received.
enum cyhal_dma_output_t |
Specifies the transfer completion event that triggers a signal output.
This defines the behavior of the the channel when transfers are initiated.
It can specify both how the transfer is broken up and what happens at the end of the transfer. If burst_size from cyhal_dma_cfg_t is used, this specifies the granularity of operations that occur. Using CYHAL_DMA_TRANSFER_BURST or CYHAL_DMA_TRANSFER_BURST_DISABLE means a single trigger will transfer a single burst (of burst_size) and raise the CYHAL_DMA_TRANSFER_COMPLETE interrupt. Using CYHAL_DMA_TRANSFER_FULL means a single trigger will transfer all bursts (total size length) and raise the CYHAL_DMA_TRANSFER_COMPLETE interrupt. If burst_size is not used, this has no impact and a single trigger will perform a complete transfer and raise a single interrupt at the end. When the transfer is complete, the channel can be left enabled, or automatically disabled. When left enabled (CYHAL_DMA_TRANSFER_BURST or CYHAL_DMA_TRANSFER_FULL) subsequent triggers will re-start the transfers. If the channel is diabled on completion (CYHAL_DMA_TRANSFER_BURST_DISABLE or CYHAL_DMA_TRANSFER_FULL_DISABLE), cyhal_dma_configure must be called to reconfigure the channel for future transfers.
Enumerator | |
---|---|
CYHAL_DMA_TRANSFER_BURST | A single burst is triggered and a CYHAL_DMA_TRANSFER_COMPLETE will occur after each burst. The channel will be left enabled and can continue to be triggered. |
CYHAL_DMA_TRANSFER_FULL | All bursts are triggered and a single CYHAL_DMA_TRANSFER_COMPLETE will occur at the end. The channel will be left enabled and can continue to be triggered. |
CYHAL_DMA_TRANSFER_BURST_DISABLE | A single burst is triggered and a CYHAL_DMA_TRANSFER_COMPLETE will occur after each burst. When all bursts are complete, the channel will be disabled. |
CYHAL_DMA_TRANSFER_FULL_DISABLE | All bursts are triggered and a single CYHAL_DMA_TRANSFER_COMPLETE will occur at the end. When complete, the channel will be disabled. |
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.
[out] | obj | Pointer to a DMA object. The caller must allocate the memory for this object but the init function will initialize its contents. |
[in] | src | An optional source signal to connect to the DMA |
[in] | dest | An optional destination signal to drive from the DMA |
[out] | dest_source | 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. |
[in] | priority | 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. |
[in] | direction | The direction memory is copied |
cy_rslt_t cyhal_dma_init_cfg | ( | cyhal_dma_t * | obj, |
const cyhal_dma_configurator_t * | cfg | ||
) |
Initialize the DMA peripheral using data provided by the configurator.
[out] | obj | Pointer to a DMA object. The caller must allocate the memory for this object but the init function will initialize its contents. |
[in] | cfg | Configuration structure generated by a configurator. |
void cyhal_dma_free | ( | cyhal_dma_t * | obj | ) |
Free the DMA object.
Freeing a DMA object while a transfer is in progress (cyhal_dma_is_busy) is invalid.
[in,out] | obj | The DMA object |
cy_rslt_t cyhal_dma_configure | ( | cyhal_dma_t * | obj, |
const cyhal_dma_cfg_t * | cfg | ||
) |
Setup the DMA channel behavior.
This will also enable the channel to allow it to be triggered. The transfer can be software triggered by calling cyhal_dma_start_transfer or by hardware. A hardware input signal is setup by cyhal_dma_connect_digital or cyhal_dma_init_adv.
[in] | obj | The DMA object |
[in] | cfg | Configuration parameters for the transfer |
cy_rslt_t cyhal_dma_enable | ( | cyhal_dma_t * | obj | ) |
Enable the DMA transfer so that it can start transferring data when triggered.
A trigger is caused either by calling cyhal_dma_start_transfer or by hardware as a result of a connection made in either cyhal_dma_connect_digital or cyhal_dma_init_adv. The DMA can be disabled by calling cyhal_dma_disable or by setting the cyhal_dma_cfg_t action to CYHAL_DMA_TRANSFER_BURST_DISABLE, or CYHAL_DMA_TRANSFER_FULL_DISABLE.
[in] | obj | The DMA object |
cy_rslt_t cyhal_dma_disable | ( | cyhal_dma_t * | obj | ) |
Disable the DMA transfer so that it does not continue to trigger.
It can be reenabled by calling cyhal_dma_enable or cyhal_dma_configure.
[in] | obj | The DMA object |
cy_rslt_t cyhal_dma_start_transfer | ( | cyhal_dma_t * | obj | ) |
Initiates DMA channel transfer for specified DMA object.
This should only be done after the channel has been configured (cyhal_dma_configure) and any necessary event callbacks setup (cyhal_dma_register_callback cyhal_dma_enable_event)
[in] | obj | The DMA object |
bool cyhal_dma_is_busy | ( | cyhal_dma_t * | obj | ) |
Checks if the transfer has been triggered, but not yet complete (eg: is pending, blocked or running)
[in] | obj | The DMA object |
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.
[in] | obj | The DMA object |
[in] | callback | The callback handler which will be invoked when an event triggers |
[in] | callback_arg | 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.
[in] | obj | The DMA object |
[in] | event | The DMA event type |
[in] | intr_priority | 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. |
[in] | enable | 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.
This connection can also be setup automatically on initialization via cyhal_dma_init_adv. If the signal needs to be disconnected later, cyhal_dma_disconnect_digital can be used.
[in] | obj | The DMA object |
[in] | source | Source signal obtained from another driver's cyhal_<PERIPH>_enable_output |
[in] | input | Which input to enable |
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.
This can also be setup automatically on initialization via cyhal_dma_init_adv. If the output is not needed in the future, cyhal_dma_disable_output can be used.
[in] | obj | The DMA object |
[in] | output | Which event triggers the output |
[out] | source | 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. |
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.
This removes the connection that was established by either cyhal_dma_init_adv or cyhal_dma_connect_digital.
[in] | obj | The DMA object |
[in] | source | Source signal from cyhal_<PERIPH>_enable_output to disable |
[in] | input | Which input to disable |
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.
This turns off the signal that was enabled by either cyhal_dma_init_adv or cyhal_dma_enable_output. It is recommended that the signal is disconnected (cyhal_<PERIPH>_disconnect_digital) from anything it might be driving before being disabled.
[in] | obj | The DMA object |
[in] | output | Which output to disable |