Hardware Abstraction Layer (HAL)
All Data Structures Functions Variables Typedefs Enumerations Enumerator Modules Pages
DMA (Direct Memory Access)

General Description

High level interface for interacting with the direct memory access (DMA).

The DMA driver allows for setting up the DMA object 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.

Features

Flow

The operational flow of the driver is listed below. This shows the basic order in which each of the functions would generally be called.

  1. Initialize: Inititialize the DMA descriptor and channel
  2. Setup: Set up the HAL DMA object with the pre-initialized DMA HW mtb_hal_dma_setup
  3. Enable the DMA channel and the DMA HW
  4. Configure and Enable the DMA interrupt
  5. Configure: mtb_hal_dma_set_src_addr, mtb_hal_dma_set_dst_addr, mtb_hal_dma_set_length
  6. Enable the event and callback: mtb_hal_dma_register_callback, mtb_hal_dma_enable_event
Note
In case of DMA being used by other peripheral drivers, initialize and set up the DMA before the peripheral driver is initialized and setup

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. mtb_hal_dma_set_src_addr, mtb_hal_dma_set_dst_addr, mtb_hal_dma_set_length can be used after DMA initialization to handle a variety of memory layouts.

/* HAL DMA object */
mtb_hal_dma_t dma_hal_obj;
void snippet_mtb_hal_dma_simple_init(void)
{
#define BUFFER_SIZE (32u)
//Source Buffer
uint32_t src_buf[BUFFER_SIZE];
//Destination Buffer
uint32_t dst_buf[BUFFER_SIZE];
cy_rslt_t rslt;
cy_en_dma_status_t status;
uint32_t src_addr = (uint32_t)src_buf;
uint32_t dst_addr = (uint32_t)dst_buf;
uint32_t length = sizeof(src_buf);
/* Setting up the descriptor and the channel */
status = Cy_DMA_Descriptor_Init(&dma_Descriptor_0, &dma_Descriptor_0_config);
status = Cy_DMA_Channel_Init(dma_HW, dma_CHANNEL, &dma_channelConfig);
Cy_DMA_Channel_SetInterruptMask(dma_HW, dma_CHANNEL, CY_DMA_INTR_MASK);
/* Set up the HAL DMA object */
rslt = mtb_hal_dma_setup(&dma_hal_obj, &dma_hal_config);
/* Enable channel and DMA block to start descriptor execution process */
Cy_DMA_Channel_Enable(dma_HW, dma_CHANNEL);
Cy_DMA_Enable(dma_HW);
/* Configure the source for the upcoming transfer */
rslt = mtb_hal_dma_set_src_addr(&dma_hal_obj, src_addr);
/* Configure the destination for the upcoming transfer */
rslt = mtb_hal_dma_set_dst_addr(&dma_hal_obj, dst_addr);
/* Configure the length for the upcoming transfer */
rslt = mtb_hal_dma_set_length(&dma_hal_obj, length);
/* Begin the transfer */
rslt = mtb_hal_dma_start_transfer(&dma_hal_obj);
(void)rslt;
(void)status;
}
cy_rslt_t mtb_hal_dma_set_src_addr(mtb_hal_dma_t *obj, uint32_t src_addr)
Set the source address for the DMA transfer.
cy_rslt_t mtb_hal_dma_set_length(mtb_hal_dma_t *obj, uint32_t length)
Set the length for the DMA transfer.
cy_rslt_t mtb_hal_dma_start_transfer(mtb_hal_dma_t *obj)
Initiates DMA channel transfer for specified DMA object.
cy_rslt_t mtb_hal_dma_set_dst_addr(mtb_hal_dma_t *obj, uint32_t dst_addr)
Set the destination address for the DMA transfer.
cy_rslt_t mtb_hal_dma_setup(mtb_hal_dma_t *obj, const mtb_hal_dma_configurator_t *config)
Sets up a HAL instance to use the specified hardware resource.
DMA object.
Definition: mtb_hal_hw_types_dma.h:92
uint32_t cy_rslt_t
Provides the result of an operation as a structured bitfield.
Definition: cy_result.h:457

Snippet 2: Interrupts and triggering DMA transfers

DMA events like transfer complete or error events can be used to trigger a callback function.
This snippet uses mtb_hal_dma_enable_event() to enable the transfer complete event to trigger the callback function registered by mtb_hal_dma_register_callback().

/* HAL DMA object */
mtb_hal_dma_t dma_obj;
void dma_interrupt_handler(void)
{
}
void dma_event_callback(void* callback_arg, mtb_hal_dma_event_t event)
{
CY_UNUSED_PARAMETER(callback_arg);
CY_UNUSED_PARAMETER(event);
}
cy_rslt_t snippet_mtb_hal_dma_events(void)
{
#define BUFFER_SIZE (32u)
#define PERIPHERAL_FIFO_ADDR (0x4001000)
//Source Buffer
uint32_t src_buf[BUFFER_SIZE];
cy_rslt_t rslt;
cy_en_dma_status_t status;
cy_stc_sysint_t dma_int_cfg =
{
#if defined (CY_IP_M7CPUSS)
.intrSrc = _mtb_hal_get_intSrc(dma_IRQ),
#else
.intrSrc = (IRQn_Type)_mtb_hal_get_intSrc(dma_IRQ),
#endif
.intrPriority = 3u,
};
uint32_t src_addr = (uint32_t)src_buf;
uint32_t dst_addr = (uint32_t)PERIPHERAL_FIFO_ADDR;
uint32_t length = sizeof(src_buf);
/* Setting up the descriptor and the channel */
status = Cy_DMA_Descriptor_Init(&dma_Descriptor_0, &dma_Descriptor_0_config);
status = Cy_DMA_Channel_Init(dma_HW, dma_CHANNEL, &dma_channelConfig);
Cy_DMA_Channel_SetInterruptMask(dma_HW, dma_CHANNEL, CY_DMA_INTR_MASK);
/* Set up the HAL DMA object */
rslt = mtb_hal_dma_setup(&dma_obj, &dma_hal_config);
/* Enable channel and DMA block to start descriptor execution process */
Cy_DMA_Channel_Enable(dma_HW, dma_CHANNEL);
Cy_DMA_Enable(dma_HW);
Cy_SysInt_Init(&dma_int_cfg, dma_interrupt_handler);
NVIC_EnableIRQ((IRQn_Type)_mtb_hal_get_intVec(dma_IRQ));
/* Configure the source for the upcoming transfer */
rslt = mtb_hal_dma_set_src_addr(&dma_obj, src_addr);
/* Configure the destination for the upcoming transfer */
rslt = mtb_hal_dma_set_dst_addr(&dma_obj, dst_addr);
/* Configure the length for the upcoming transfer */
rslt = mtb_hal_dma_set_length(&dma_obj, length);
// Register an event callback handler and enable events
if (CY_RSLT_SUCCESS == rslt)
{
mtb_hal_dma_register_callback(&dma_obj, &dma_event_callback, &dma_obj);
}
(void)status;
return rslt;
}
mtb_hal_dma_event_t
Flags enum of DMA events.
Definition: mtb_hal_dma.h:151
void mtb_hal_dma_register_callback(mtb_hal_dma_t *obj, mtb_hal_dma_event_callback_t callback, void *callback_arg)
Register a DMA callback handler.
cy_rslt_t mtb_hal_dma_process_interrupt(mtb_hal_dma_t *obj)
Process interrupts related related to a DMA instance.
void mtb_hal_dma_enable_event(mtb_hal_dma_t *obj, mtb_hal_dma_event_t event, bool enable)
Configure DMA event enablement.
@ MTB_HAL_DMA_TRANSFER_COMPLETE
Indicates that an individual transfer (burst or full) has completed based on the dma hardware configu...
Definition: mtb_hal_dma.h:153
#define CY_RSLT_SUCCESS
cy_rslt_t return value indicating success
Definition: cy_result.h:484

Snippet 3: DMA transfers with D-cache

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 mtb_hal_dma_set_src_addr, mtb_hal_dma_set_dst_addr, mtb_hal_dma_set_length and mtb_hal_dma_setup. Cleaning D-cache of source's buffer and Invalidating D-cahe of destination's buffer should be done explicitly.

Refer to DCACHE_Management for more information.

#define BUF_SIZE (32) /* multiple of cache line size */
CY_ALIGN(__SCB_DCACHE_LINE_SIZE) uint8_t tx_buffer[BUF_SIZE];
CY_ALIGN(__SCB_DCACHE_LINE_SIZE) uint8_t rx_buffer[BUF_SIZE]; /* Memory address should be
cacheline-aligned */
void snippet_mtb_hal_dma_with_dcache(void)
{
cy_rslt_t rslt;
cy_en_dma_status_t status;
uint32_t src_addr = (uint32_t)tx_buffer;
uint32_t dst_addr = (uint32_t)rx_buffer;
uint32_t length = sizeof(tx_buffer);
/* Setting up the descriptor and the channel */
status = Cy_DMA_Descriptor_Init(&dma_Descriptor_0, &dma_Descriptor_0_config);
status = Cy_DMA_Channel_Init(dma_HW, dma_CHANNEL, &dma_channelConfig);
Cy_DMA_Channel_SetInterruptMask(dma_HW, dma_CHANNEL, CY_DMA_INTR_MASK);
/* Set up the HAL DMA object */
rslt = mtb_hal_dma_setup(&dma_hal_obj, &dma_hal_config);
/* Before enabling DMA channel, clean dcahe of tx_buffer. */
SCB_CleanDCache_by_Addr((void*)tx_buffer, BUF_SIZE);
SCB_CleanDCache_by_Addr((void*)rx_buffer, BUF_SIZE); /* This maybe ptional. */
/* Enable channel and DMA block to start descriptor execution process */
Cy_DMA_Channel_Enable(dma_HW, dma_CHANNEL);
Cy_DMA_Enable(dma_HW);
/* Configure the source for the upcoming transfer */
rslt = mtb_hal_dma_set_src_addr(&dma_hal_obj, src_addr);
/* Configure the destination for the upcoming transfer */
rslt = mtb_hal_dma_set_dst_addr(&dma_hal_obj, dst_addr);
/* Configure the length for the upcoming transfer */
rslt = mtb_hal_dma_set_length(&dma_hal_obj, length);
/* Begin the transfer */
rslt = mtb_hal_dma_start_transfer(&dma_hal_obj);
/* Before reading rx_buffer, invalidate dcache of rx_buffer. */
SCB_InvalidateDCache_by_Addr((void*)rx_buffer, BUFFER_SIZE * sizeof(uint32_t));

API Reference

 DMA HAL Results
 DMA specific return codes.
 

Typedefs

typedef void(* mtb_hal_dma_event_callback_t) (void *callback_arg, mtb_hal_dma_event_t event)
 Event handler for DMA interrupts.
 

Enumerations

enum  mtb_hal_dma_event_t {
  MTB_HAL_DMA_NO_INTR = 0 ,
  MTB_HAL_DMA_TRANSFER_COMPLETE = 1 << 0 ,
  MTB_HAL_DMA_DESCRIPTOR_COMPLETE = 1 << 1 ,
  MTB_HAL_DMA_SRC_BUS_ERROR = 1 << 2 ,
  MTB_HAL_DMA_DST_BUS_ERROR = 1 << 3 ,
  MTB_HAL_DMA_SRC_MISAL = 1 << 4 ,
  MTB_HAL_DMA_DST_MISAL = 1 << 5 ,
  MTB_HAL_DMA_CURR_PTR_NULL = 1 << 6 ,
  MTB_HAL_DMA_ACTIVE_CH_DISABLED = 1 << 7 ,
  MTB_HAL_DMA_DESCR_BUS_ERROR = 1 << 8 ,
  MTB_HAL_DMA_GENERIC_ERROR = 1 << 9
}
 Flags enum of DMA events. More...
 

Functions

cy_rslt_t mtb_hal_dma_setup (mtb_hal_dma_t *obj, const mtb_hal_dma_configurator_t *config)
 Sets up a HAL instance to use the specified hardware resource. More...
 
cy_rslt_t mtb_hal_dma_set_src_addr (mtb_hal_dma_t *obj, uint32_t src_addr)
 Set the source address for the DMA transfer. More...
 
cy_rslt_t mtb_hal_dma_set_dst_addr (mtb_hal_dma_t *obj, uint32_t dst_addr)
 Set the destination address for the DMA transfer. More...
 
cy_rslt_t mtb_hal_dma_set_length (mtb_hal_dma_t *obj, uint32_t length)
 Set the length for the DMA transfer. More...
 
cy_rslt_t mtb_hal_dma_enable (mtb_hal_dma_t *obj)
 Enable the DMA transfer so that it can start transferring data when triggered. More...
 
cy_rslt_t mtb_hal_dma_disable (mtb_hal_dma_t *obj)
 Disable the DMA transfer so that it does not continue to trigger. More...
 
cy_rslt_t mtb_hal_dma_start_transfer (mtb_hal_dma_t *obj)
 Initiates DMA channel transfer for specified DMA object. More...
 
bool mtb_hal_dma_is_busy (mtb_hal_dma_t *obj)
 Checks if the transfer has been triggered, but not yet complete (eg: is pending, blocked or running) More...
 
cy_rslt_t mtb_hal_dma_process_interrupt (mtb_hal_dma_t *obj)
 Process interrupts related related to a DMA instance. More...
 
void mtb_hal_dma_register_callback (mtb_hal_dma_t *obj, mtb_hal_dma_event_callback_t callback, void *callback_arg)
 Register a DMA callback handler. More...
 
void mtb_hal_dma_enable_event (mtb_hal_dma_t *obj, mtb_hal_dma_event_t event, bool enable)
 Configure DMA event enablement. More...
 
uint32_t mtb_hal_dma_get_max_elements_per_burst (mtb_hal_dma_t *obj)
 Max number of elements, that can be transferred by one burst. More...
 

Enumeration Type Documentation

◆ mtb_hal_dma_event_t

Flags enum of DMA events.

Multiple events can be enabled via mtb_hal_dma_enable_event and the callback from mtb_hal_dma_register_callback will be run to notify.

Enumerator
MTB_HAL_DMA_NO_INTR 

No interrupt.

MTB_HAL_DMA_TRANSFER_COMPLETE 

Indicates that an individual transfer (burst or full) has completed based on the dma hardware configuration.

MTB_HAL_DMA_DESCRIPTOR_COMPLETE 

Indicates that the full transfer has completed.

MTB_HAL_DMA_SRC_BUS_ERROR 

Indicates that there is a source bus error.

MTB_HAL_DMA_DST_BUS_ERROR 

Indicates that there is a destination bus error.

MTB_HAL_DMA_SRC_MISAL 

Indicates that the source address is not aligned.

MTB_HAL_DMA_DST_MISAL 

Indicates that the destination address is not aligned.

MTB_HAL_DMA_CURR_PTR_NULL 

Indicates that the current descriptor pointer is null.

MTB_HAL_DMA_ACTIVE_CH_DISABLED 

Indicates that the active channel is disabled.

MTB_HAL_DMA_DESCR_BUS_ERROR 

Indicates that there has been a descriptor bus error.

MTB_HAL_DMA_GENERIC_ERROR 

Indicates that there has been a generic error during the DMA transfer.

Function Documentation

◆ mtb_hal_dma_setup()

cy_rslt_t mtb_hal_dma_setup ( mtb_hal_dma_t obj,
const mtb_hal_dma_configurator_t config 
)

Sets up a HAL instance to use the specified hardware resource.

This hardware resource must have already been configured via the PDL.

Parameters
[out]objThe HAL driver instance object. The caller must allocate the memory for this object, but the HAL will initialize its contents
[in]configThe configurator-generated HAL config structure for this peripheral instance
Returns
the status of the HAL setup
Note
If D-cache is enabled, this function cleans D-cache of DMA descriptor.
Not all the DMA configuration is supported in the HAL. Only 1D transfer and 2D transfer DMA Descriptor types are supported in the HAL Only X loop transfer (M loop in case of AXIDMAC) and decriptor transfer interrupt types are supported in the HAL

◆ mtb_hal_dma_set_src_addr()

cy_rslt_t mtb_hal_dma_set_src_addr ( mtb_hal_dma_t obj,
uint32_t  src_addr 
)

Set the source address for the DMA transfer.

Parameters
[in]objThe DMA object
[in]src_addrThe source address
Returns
The status of the request
Note
If D-cache is enabled, this function cleans D-cache of DMA descriptor.

◆ mtb_hal_dma_set_dst_addr()

cy_rslt_t mtb_hal_dma_set_dst_addr ( mtb_hal_dma_t obj,
uint32_t  dst_addr 
)

Set the destination address for the DMA transfer.

Parameters
[in]objThe DMA object
[in]dst_addrThe destination address
Returns
The status of the request
Note
If D-cache is enabled, this function cleans D-cache of DMA descriptor.

◆ mtb_hal_dma_set_length()

cy_rslt_t mtb_hal_dma_set_length ( mtb_hal_dma_t obj,
uint32_t  length 
)

Set the length for the DMA transfer.

Parameters
[in]objThe DMA object
[in]lengthThe transfer length, in bytes
Returns
The status of the request
Note
If D-cache is enabled, this function cleans D-cache of DMA descriptor.

◆ mtb_hal_dma_enable()

cy_rslt_t mtb_hal_dma_enable ( mtb_hal_dma_t obj)

Enable the DMA transfer so that it can start transferring data when triggered.

A trigger is caused either by calling mtb_hal_dma_start_transfer or by hardware as a result of connection made using the interconnect components in the device configurator. The DMA can be disabled by calling mtb_hal_dma_disable

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

◆ mtb_hal_dma_disable()

cy_rslt_t mtb_hal_dma_disable ( mtb_hal_dma_t obj)

Disable the DMA transfer so that it does not continue to trigger.

It can be reenabled by calling mtb_hal_dma_enable

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

◆ mtb_hal_dma_start_transfer()

cy_rslt_t mtb_hal_dma_start_transfer ( mtb_hal_dma_t obj)

Initiates DMA channel transfer for specified DMA object.

This should only be done after the channel has been configured and setup and any necessary event callbacks setup (mtb_hal_dma_register_callback mtb_hal_dma_enable_event)

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

◆ mtb_hal_dma_is_busy()

bool mtb_hal_dma_is_busy ( mtb_hal_dma_t obj)

Checks if the transfer has been triggered, but not yet complete (eg: is pending, blocked or running)

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

◆ mtb_hal_dma_process_interrupt()

cy_rslt_t mtb_hal_dma_process_interrupt ( mtb_hal_dma_t obj)

Process interrupts related related to a DMA instance.

Parameters
objHAL object for which the interrupt should be processed
Returns
CY_RSLT_SUCCESS if the interrupt was processed successfully; otherwise an error

◆ mtb_hal_dma_register_callback()

void mtb_hal_dma_register_callback ( mtb_hal_dma_t obj,
mtb_hal_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 mtb_hal_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

◆ mtb_hal_dma_enable_event()

void mtb_hal_dma_enable_event ( mtb_hal_dma_t obj,
mtb_hal_dma_event_t  event,
bool  enable 
)

Configure DMA event enablement.

When an enabled event occurs, the function specified by mtb_hal_dma_register_callback will be called.

Parameters
[in]objThe DMA object
[in]eventThe DMA event type recent call will take precedence, i.e all events will have the same priority.
[in]enableTrue to turn on interrupts, False to turn off

◆ mtb_hal_dma_get_max_elements_per_burst()

uint32_t mtb_hal_dma_get_max_elements_per_burst ( mtb_hal_dma_t obj)

Max number of elements, that can be transferred by one burst.

Parameters
[in]objThe DMA object
Returns
Max number of elements, that can be transferred by one burst