Async Transfer
Loading...
Searching...
No Matches
Async Transfer Utility Library - Non-blocking Background Data Transfer for Communication Peripherals

Overview

Async Transfer Utility Library enables non-blocking data transfers on communication peripherals – the application initiates a transfer and continues execution while data moves in the background via CPU copy or DMA.

Features

  • Both read and write transfers via CPU copy or DMA.
  • One pending transfer per direction (read and write) at a time.
  • Callback notification on transfer completion.
  • Abort an in-progress transfer or query availability at any time.
  • Multiple independent instances managing different communication interfaces simultaneously.
  • DCACHE coherency handling for DMA-based transfers.

When to Use

Use this library when you need to:

  • Perform UART, SPI, or I2C data transfers without blocking the application.
  • Overlap communication with processing by offloading transfers to DMA.
  • Manage asynchronous data flow across multiple communication interfaces simultaneously.
  • Build protocol stacks or communication middleware on top of PDL or HAL peripheral drivers.

How to Use

Step 1 - Set Up the Interface

This library is peripheral-agnostic. Populate mtb_async_transfer_interface_t with function pointers and addresses matching your communication peripheral (example using a PDL UART SCB):

interface.inst_ref = UART_HW;
interface.rx_addr = (uint32_t*)&(UART_HW->RX_FIFO_RD);
interface.tx_addr = (uint32_t*)&(UART_HW->TX_FIFO_WR);
interface.get_num_rx_fifo = (mtb_async_transfer_get_num_fifo_t)Cy_SCB_UART_GetNumInRxFifo;
interface.get_num_tx_fifo = uart_get_num_tx_fifo;
interface.set_rx_fifo_level = (mtb_async_transfer_set_fifo_level_t)Cy_SCB_SetRxFifoLevel;
interface.set_tx_fifo_level = (mtb_async_transfer_set_fifo_level_t)Cy_SCB_SetTxFifoLevel;
interface.enable_rx_event = uart_enable_rx_event;
interface.enable_tx_event = uart_enable_tx_event;
interface.get_rx_transfer_len = uart_get_rx_transfer_len;
interface.get_tx_transfer_len = uart_get_tx_transfer_len;
interface.transfer_width = uart_get_transfer_width(UART_HW);
interface.enter_critical_section = Cy_SysLib_EnterCriticalSection;
interface.exit_critical_section = Cy_SysLib_ExitCriticalSection;
void(* mtb_async_transfer_set_fifo_level_t)(void *inst_ref, uint32_t level)
Function pointer to set the fifo level for triggering an interrupt when the number of elements in the...
Definition mtb_async_transfer.h:136
uint32_t(* mtb_async_transfer_get_num_fifo_t)(void *inst_ref)
Function pointer for returning the number of elements that can be read from the FIFO in case of rx or...
Definition mtb_async_transfer.h:127
void * inst_ref
The opaque pointer that is passed as the first argument to all non-DMA functions.
Definition mtb_async_transfer.h:219
Async Transfer interface data structure.
Definition mtb_async_transfer.h:215

For DMA mode, additionally populate the DMA-specific fields:

interface.dma_rx_ref = &dma_Descriptor_0;
interface.dma_set_length = uart_dma_set_len;
interface.dma_set_src = uart_dma_set_src_addr;
interface.dma_set_dest = uart_dma_set_dest_addr;
interface.dma_enable_rx = uart_dma_enable_rx;

Step 2 - Initialize

cy_rslt_t result = mtb_async_transfer_init(&async_context, &interface);
Async Transfer context data structure.
Definition mtb_async_transfer.h:288
cy_rslt_t mtb_async_transfer_init(mtb_async_transfer_context_t *context, const mtb_async_transfer_interface_t *iface)
Initializes an async transfer library instance.
Definition mtb_async_transfer.c:436

Step 3 - Register a Completion Callback (optional)

result = mtb_async_transfer_register_callback(&async_context,
my_transfer_callback,
callback_arg);
cy_rslt_t mtb_async_transfer_register_callback(mtb_async_transfer_context_t *context, mtb_async_transfer_event_callback_t callback, void *arg)
Register a callback to be invoked when a transfer is complete.
Definition mtb_async_transfer.c:624

Step 4 - Start Transfers

/* Initiate a background read */
result = mtb_async_transfer_read(&async_context, rx_buffer, sizeof(rx_buffer));
/* Initiate a background write */
result = mtb_async_transfer_write(&async_context, tx_buffer, sizeof(tx_buffer));
cy_rslt_t mtb_async_transfer_write(mtb_async_transfer_context_t *context, void *source, uint32_t length)
Writes data from memory to the peripheral in the background.
Definition mtb_async_transfer.c:502
cy_rslt_t mtb_async_transfer_read(mtb_async_transfer_context_t *context, void *dest, size_t length)
Reads data from the peripheral to the memory in the background.
Definition mtb_async_transfer.c:454

Transfer completion is driven by interrupts. Wire up the appropriate handler depending on the transfer mode:

CPU mode – call mtb_async_transfer_process_fifo_level_event from the peripheral FIFO-level interrupt:

void uart_interrupt_handler(void)
{
uint32_t rxMasked = Cy_SCB_GetRxInterruptStatusMasked(UART_HW);
uint32_t txMasked = Cy_SCB_GetTxInterruptStatusMasked(UART_HW);
if (0u != (CY_SCB_UART_RX_TRIGGER & rxMasked))
if (0u != (CY_SCB_UART_TX_TRIGGER & txMasked))
if (direction)
mtb_async_transfer_process_fifo_level_event(&async_context, direction);
}
mtb_async_transfer_direction_t
Async Transfer direction.
Definition mtb_async_transfer.h:104
@ MTB_ASYNC_TRANSFER_DIRECTION_WRITE
Write Transfer.
Definition mtb_async_transfer.h:106
@ MTB_ASYNC_TRANSFER_DIRECTION_READ
Read Transfer.
Definition mtb_async_transfer.h:105
cy_rslt_t mtb_async_transfer_process_fifo_level_event(mtb_async_transfer_context_t *context, mtb_async_transfer_direction_t direction)
Handler for when the FIFO in the peripheral reaches the trigger level.
Definition mtb_async_transfer.c:645

DMA mode – call mtb_async_transfer_process_dma_complete from the DMA completion interrupt:

void dma_interrupt_handler(void)
{
cy_en_dma_intr_cause_t cause = Cy_DMA_Channel_GetStatus(DMA_HW, DMA_CHANNEL);
Cy_DMA_Channel_ClearInterrupt(DMA_HW, DMA_CHANNEL);
if (cause == CY_DMA_INTR_CAUSE_COMPLETION)
}
cy_rslt_t mtb_async_transfer_process_dma_complete(mtb_async_transfer_context_t *context, mtb_async_transfer_direction_t direction)
Handler for when a DMA transfer is complete.
Definition mtb_async_transfer.c:675

DCACHE Management

When using DMA on devices with a data cache (DCACHE), cache coherency must be maintained for the buffers passed to mtb_async_transfer_read and mtb_async_transfer_write.

The library assumes the following cache configuration:

  • Write-back with read and write allocate: WB-RWA
  • Cache line size: 32 bytes
  • All application memory is cacheable

Two scenarios require explicit cache maintenance by the application:

  1. CPU writes, DMA reads (TX path) – the CPU write updates only the cache, not SRAM. Clean the cache after writing the TX buffer so the DMA sees the correct data:
    SCB_CleanDCache_by_Addr(tx_buffer, sizeof(tx_buffer));
  2. DMA writes, CPU reads (RX path) – the DMA writes directly to SRAM. Invalidate the cache before reading the RX buffer so the CPU fetches fresh data from SRAM:
    SCB_InvalidateDCache_by_Addr(rx_buffer, sizeof(rx_buffer));

Cache operations work at 32-byte cache-line granularity. All DMA data buffers must be aligned to 32 bytes and padded to a multiple of 32 bytes. Without this, adjacent data can be corrupted. Buffer alignment and padding is the responsibility of the application.

Release Notes and Changelog

  • RELEASE.md - Detailed release notes for all versions

License

Licensed under the Apache License, Version 2.0. You may not use this file except in compliance with the License. A copy of the License is available at http://www.apache.org/licenses/LICENSE-2.0.

  • LICENSE - Apache License 2.0

Copyright

(c) (2025-2026), Infineon Technologies AG, or an affiliate of Infineon Technologies AG. All rights reserved.