PSOC E8XXGP Device Support Library

| PSOC E8XXGP Device Support Library

API Reference | Typedefs | Enumerations | Functions
DMA (Direct Memory Access)
HAL API Reference » HAL Drivers

## 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

- CPU independent memory access
- Access to memory and peripherals
- Multiple independent channels
- Configurable source and destination address
- Configurable data transfer length
- Event completion notification

# 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_DMA_Enable
__STATIC_INLINE void Cy_DMA_Enable(DW_Type *base)
Enables the DMA block.
Definition: cy_dma.h:552
Cy_DMA_Channel_Enable
__STATIC_INLINE void Cy_DMA_Channel_Enable(DW_Type *base, uint32_t channel)
The function is used to enable a DMA channel.
Definition: cy_dma.h:1545
Cy_DMA_Channel_Init
cy_en_dma_status_t Cy_DMA_Channel_Init(DW_Type *base, uint32_t channel, cy_stc_dma_channel_config_t const *channelConfig)
Initializes the DMA channel with a descriptor and other parameters.
Definition: cy_dma.c:259
Cy_DMA_Channel_SetInterruptMask
__STATIC_INLINE void Cy_DMA_Channel_SetInterruptMask(DW_Type *base, uint32_t channel, uint32_t interrupt)
Sets an interrupt mask value for the specified channel.
Definition: cy_dma.h:1859
Cy_DMA_Descriptor_Init
cy_en_dma_status_t Cy_DMA_Descriptor_Init(cy_stc_dma_descriptor_t *descriptor, cy_stc_dma_descriptor_config_t const *config)
Initializes the descriptor structure in SRAM from a pre-initialized configuration structure.
Definition: cy_dma.c:107
cy_en_dma_status_t
cy_en_dma_status_t
Contains the return values of the DMA driver.
Definition: cy_dma.h:251
CY_DMA_INTR_MASK
#define CY_DMA_INTR_MASK
The DMA channel interrupt mask.
Definition: cy_dma.h:158
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.
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.
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.
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.
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.
mtb_hal_dma_t
DMA object.
Definition: mtb_hal_hw_types_dma.h:94
cy_rslt_t
uint32_t cy_rslt_t
Provides the result of an operation as a structured bitfield.
Definition: cy_result.h:459

## 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)
{
mtb_hal_dma_process_interrupt(&dma_obj);
}
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);
mtb_hal_dma_enable_event(&dma_obj, MTB_HAL_DMA_TRANSFER_COMPLETE, true);
}
(void)status;
return rslt;
}
mtb_hal_dma_event_t
mtb_hal_dma_event_t
Flags enum of DMA events.
Definition: mtb_hal_dma.h:151
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.
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.
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.
MTB_HAL_DMA_TRANSFER_COMPLETE
@ 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
CY_RSLT_SUCCESS
#define CY_RSLT_SUCCESS
cy_rslt_t return value indicating success
Definition: cy_result.h:486
cy_stc_sysint_t::intrSrc
IRQn_Type intrSrc
Interrupt source.
Definition: cy_sysint.h:229
cy_stc_sysint_t
Initialization configuration structure for a single interrupt channel.
Definition: cy_sysint.h:227
Cy_SysInt_Init
cy_en_sysint_status_t Cy_SysInt_Init(const cy_stc_sysint_t *config, cy_israddress userIsr)
Initializes the referenced interrupt by setting the priority and the interrupt vector.
Definition: cy_sysint_v2.c:80

## 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,

- Source and destination buffers must be cacheline aligned (__SCB_DCACHE_LINE_SIZE)
- D-cache of DMA descriptor and D-cahe of source's buffers must be cleaned before a DMA transfer
- D-cache of destination buffer must be invalidated after a DMA transfer

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

enum 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] | obj | The HAL driver instance object. The caller must allocate the memory for this object, but the HAL will initialize its contents
  [in] | config | The 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] | obj | The DMA object
  [in] | src_addr | The 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] | obj | The DMA object
  [in] | dst_addr | The 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] | obj | The DMA object
  [in] | length | The 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] | obj | The 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] | obj | The 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] | obj | The 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] | obj | The 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

  obj | HAL 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] | 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

## ◆ 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] | obj | The DMA object
  [in] | event | The DMA event type 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

## ◆ 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] | obj | The DMA object

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