Hardware Abstraction Layer (HAL)
DMA (Direct Memory Access)

General Description

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 are available with user-selectable priority and transfer characteristics.

Features

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_free

cy_rslt_t rslt;
{
.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 */
/* Configure the channel for the upcoming transfer */
rslt = cyhal_dma_configure(&dma, &cfg);
/* Begin the transfer */
/* If the DMA channel is no longer needed, it can be freed up for other uses */
if (!cyhal_dma_is_busy(&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;
uint32_t buffer[BUFFER_SIZE];
/* Allocate the DMA channel for transfering from memory to a peripheral */
{
.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))
{
}
}
void snippet_cyhal_dma_events()
{
cy_rslt_t rslt;
{
.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 */
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);
/* Begin the transfer */
}

API Reference

 DMA HAL Results
 DMA specific return codes.
 

Data Structures

struct  cyhal_dma_cfg_t
 Configuration of a DMA channel. More...
 

Typedefs

typedef void(* cyhal_dma_event_callback_t) (void *callback_arg, cyhal_dma_event_t event)
 Event handler for DMA interrupts.
 

Enumerations

enum  cyhal_dma_direction_t {
  CYHAL_DMA_DIRECTION_MEM2MEM,
  CYHAL_DMA_DIRECTION_MEM2PERIPH,
  CYHAL_DMA_DIRECTION_PERIPH2MEM,
  CYHAL_DMA_DIRECTION_PERIPH2PERIPH
}
 Direction for DMA transfers. More...
 
enum  cyhal_dma_event_t {
  CYHAL_DMA_NO_INTR = 0,
  CYHAL_DMA_TRANSFER_COMPLETE = 1 << 0,
  CYHAL_DMA_SRC_BUS_ERROR = 1 << 1,
  CYHAL_DMA_DST_BUS_ERROR = 1 << 2,
  CYHAL_DMA_SRC_MISAL = 1 << 3,
  CYHAL_DMA_DST_MISAL = 1 << 4,
  CYHAL_DMA_CURR_PTR_NULL = 1 << 5,
  CYHAL_DMA_ACTIVE_CH_DISABLED = 1 << 6,
  CYHAL_DMA_DESCR_BUS_ERROR = 1 << 7
}
 Flags enum of DMA events. More...
 
enum  cyhal_dma_transfer_action_t {
  CYHAL_DMA_TRANSFER_BURST,
  CYHAL_DMA_TRANSFER_FULL
}
 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). More...
 

Functions

cy_rslt_t cyhal_dma_init (cyhal_dma_t *obj, uint8_t priority, cyhal_dma_direction_t direction)
 Initialize the DMA peripheral. 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 a DMA descriptor for specified resource. 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 whether a transfer is pending or running on the DMA channel. 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...
 

Data Structure Documentation

◆ cyhal_dma_cfg_t

struct cyhal_dma_cfg_t
Data Fields
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.

Enumeration Type Documentation

◆ cyhal_dma_direction_t

Direction for DMA transfers.

Enumerator
CYHAL_DMA_DIRECTION_MEM2MEM 

Memory to memory.

CYHAL_DMA_DIRECTION_MEM2PERIPH 

Memory to peripheral.

CYHAL_DMA_DIRECTION_PERIPH2MEM 

Peripheral to memory.

CYHAL_DMA_DIRECTION_PERIPH2PERIPH 

Peripheral to peripheral.

◆ cyhal_dma_event_t

Flags enum of DMA events.

Multiple events can be enabled.

Enumerator
CYHAL_DMA_NO_INTR 

No interrupt.

CYHAL_DMA_TRANSFER_COMPLETE 

Indicates that a burst or 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.

◆ 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 select when a trigger complete event will occur; after each burst or after the full transfer

Enumerator
CYHAL_DMA_TRANSFER_BURST 

A single burst is triggered and a transfer completion event will occur after the burst.

CYHAL_DMA_TRANSFER_FULL 

All bursts are triggered and a single transfer completion event will occur at the end of all of them.

Function Documentation

◆ cyhal_dma_init()

cy_rslt_t cyhal_dma_init ( cyhal_dma_t obj,
uint8_t  priority,
cyhal_dma_direction_t  direction 
)

Initialize the DMA peripheral.

Parameters
[out]objPointer to a DMA object. The caller must allocate the memory for this object but the init function will initialize its contents.
[in]priorityThe 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]directionThe direction memory is copied
Returns
The status of the init request

◆ cyhal_dma_free()

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
[in,out]objThe DMA object

◆ cyhal_dma_configure()

cy_rslt_t cyhal_dma_configure ( cyhal_dma_t obj,
const cyhal_dma_cfg_t cfg 
)

Setup a DMA descriptor for specified resource.

Parameters
[in]objThe DMA object
[in]cfgConfiguration parameters for the transfer
Returns
The status of the configure request

◆ cyhal_dma_start_transfer()

cy_rslt_t cyhal_dma_start_transfer ( cyhal_dma_t obj)

Initiates DMA channel transfer for specified DMA object.

Parameters
[in]objThe DMA object
Returns
The status of the start_transfer request

◆ cyhal_dma_is_busy()

bool cyhal_dma_is_busy ( cyhal_dma_t obj)

Checks whether a transfer is pending or running on the DMA channel.

Parameters
[in]objThe DMA object
Returns
True if DMA channel is busy

◆ cyhal_dma_register_callback()

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
[in]objThe DMA object
[in]callbackThe callback handler which will be invoked when an event triggers
[in]callback_argGeneric argument that will be provided to the callback when called

◆ cyhal_dma_enable_event()

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
[in]objThe DMA object
[in]eventThe DMA event type
[in]intr_priorityThe 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]enableTrue to turn on interrupts, False to turn off