HAL DMA How to Use

group DMA_How_To_Use

This file provides firmware functions to manage the following DMA peripheral functionalities:

  • Initialization and de-initialization functions

  • Configuration functions

  • Linked list node management functions

  • Process management functions

  • Callback functions

  • Status functions

The direct memory access (DMA) controller is a bus master and system peripheral. It performs programmable data transfers between memory-mapped peripherals and/or memories via linked list upon the control of an off-loaded CPU.

DMA main features

  • DMA transfer modes are divided into two major categories (direct transfer and linked list transfer)

  • The DMA channel can be programmed to allow one-shot transfers using direct mode transfer APIs

  • Alternatively to the direct programming mode, a DMA channel can be programmed by a list of transfers, known as linked list (list of Node items).

    • Each node is defined by its data structure

    • Each node specifies a standalone DMA channel transfer When enabled, the DMA channel fetches the first linked list node from SRAM (known as head node). After execution, the next linked list node is fetched and executed. This operation is repeated until the end of the whole linked list queue. The linked list can be linear, where the last linked list queue node is not linked to another queue node, or circular, where the last linked list node is linked to any linked list queue node.

    • Linear linked list: A linear linked list is a finite list where the last node (also called the tail node) points to NULL. A linear linked list transfer execution is finite and ends at the last node. The DMA channel fetches and executes the DMA linked list queue from the first node (head node) to the last node (tail node) once. When the last node is completed, the DMA channel remains idle and another transfer can be launched.

    • Circular linked list: A circular linked list is a list where the last node points to one of the previous nodes of the list. A circular linked list transfer execution must loop from the last node (tail node) to the node where the tail node points to. The DMA channel fetches and executes the DMA linked list queue from the first node (head node) to the last node (tail node). When the circular node is executed, the DMA channel fetches the next node and repeats the same sequence in an infinite loop (circular transfer). To stop the DMA channel, an abort operation is required.

    • Use the stm32tnxx_hal_q module to create a DMA queue based on DMA transfer nodes

  • To reduce linked list queue execution time and power consumption, the DMA channel supports executing the dynamic linked list format. In fact, the DMA supports the execution of two types of linked list formats: static and dynamic.

    • Static linked list: The static linked list format refers to the full linked list node where all DMA channel parameters are fetched and executed independently of the redundancy of information.

    • Dynamic linked list: The dynamic linked list format refers to the customized linked list node where only DMA channel necessary parameters are fetched and executed (Example: data size = 20 on previous node, and data size = 20 on the current node => no need to update it).

  • For linked list transfers, the DMA channel can execute the linked list queue node by node when started. Enable the DMA channel once to fetch the head node from memory, then it stops. Enable the DMA channel again to execute the node. After that, keep enabling the DMA channel to execute each node until the end of the linked list queue. When the linked list queue is circular, enable the DMA channel in an infinite loop to keep the DMA channel running. This feature is useful for debugging purposes or asynchronously executing queue nodes.

  • Each DMA channel transfer (direct or linked list), is highly configurable according to DMA channel instance integrated in devices. These configurations can be:

    • Repeated block configuration: If the feature is supported, the DMA channel can perform repeated block transfers, also called 2D addressing transfers. This feature can transfer n iterations of a programmed block transfer. In addition to the repeat count of a block, DMA channel addresses can jump after each burst and block level. The jump length is a programmable parameter defined by the DMA user.

      • Jump at burst level: The DMA channel keeps an empty area between each of two consecutive bursts transmitted.

      • Jump at block level: The DMA channel keeps an empty area between each of two consecutive blocks transmitted.

    • Trigger configuration: The DMA channel transfers can be conditioned by hardware signal edges (rising or falling) named hardware triggers. Trigger conditions can be applied at:

      • Single/Burst level : Each single/burst data transmission is conditioned by a signal trigger hit.

      • Block level : Each block data transmission is conditioned by a signal trigger hit.

      • Repeated block level : Each repeated block data transmission is conditioned by a signal trigger hit.

      • Node level : Each node execution is conditioned by a signal trigger hit. The DMA channel can report a trigger overrun when it detects more than 2 trigger signal edges before executing the current transfer.

    • Data handling configuration: The data handling feature can be:

      • Padding pattern: Pad with the selected pattern (zero padding or sign extension) when the source data width is smaller than the destination data width at single level.

      • Truncation : Truncate data from the source when the source data width is larger than the destination data width at single level.

      • Pack/Unpack : Pack a set of data when source data width is smaller than the destination data width. Unpack a set of data when source data width is larger than the destination data width.

      • Exchange : Exchange data at byte, half-word or word level in destination or at byte level in source.

  • Each DMA channel transfer (direct or linked list), when it is active, can be suspended and resumed at run time by the application. When suspending an ongoing transfer, the DMA channel is not suspended immediately but completes the current single/burst transfer, then stops. When the DMA channel is suspended, the current transfer can be resumed immediately.

  • The DMA channel that supports FIFO can report in real time the number of beats remaining in the destination (output) FIFO level.

  • A DMA burst means moving several pieces of data at once, instead of one by one (single transfer).

  • A DMA block is a larger chunk of data that the DMA will move from one place to another. It can be made up of several bursts or single transfers.

How to use the DMA HAL module driver

Initialization and de-initialization:

  • For a given channel, call the function HAL_DMA_Init() to initialize the DMA channel handle and associate the physical channel instance as direct mode by default.

  • Call the function HAL_DMA_DeInit() to de-initialize a DMA channel. After this function is called, the DMA channel is in reset. It is mandatory to reinitialize it for the next transfer.

Transfer configuration:

Set the DMA channel direct transfer configuration

Set the DMA channel linked list transfer configuration

Linked list node management:

  • The linked list node management is a software process independent of DMA channel hardware. Use it to fill, convert (to dynamic or to static) nodes and use the Q module services to:

    • Initialize the queue

    • Insert a node into the queue

    • Remove a node from the queue

    • Replace a node in the queue

    • Circularize queue in order to perform infinite transfers. Linked list APIs and types are adapted to reduce memory footprint.

  • At node level, the operations are filling a new linked list node or getting linked list node information from a filled node. The linked list nodes have two forms based on 2D addressing capability. The linear addressing nodes contain the information of all DMA channel features except the 2D addressing features, and the 2D addressing nodes contain the information of all available features.

    • Call the function HAL_DMA_FillNodeConfig() to fill the DMA linked list node according to the specified parameters. The fill operation converts the specified parameters into values recognized by the DMA channel and stores them in memory. When placing the DMA linked list in SRAM, ensure compliance with the product specifications to guarantee proper memory access. The DMA linked list node parameter address must be 32-bit aligned and must not exceed the 64 KB addressable space.

    • Call the function HAL_DMA_GetNodeConfig() to get the specified configuration parameter on filling node. This API can be used when a few parameters need to be changed to fill a new node.

    • As optional, fill the DMA channel linked list node feature configuration :

    • To optimize DMA channel linked list queue execution, convert the built linked list queue to dynamic format (static is the default format). When the linked list queue becomes dynamic, all queue nodes are optimized and only changed parameters are updated between nodes. As a result, the DMA fetches only changed parameters instead of the whole node.

      • Call the function HAL_DMA_ConvertQNodesToDynamic() to convert a linked list queue to dynamic format.

        • Call this API for static queue format.

        • Call this API as the last API before starting the DMA channel in linked list mode.

      • Call the function HAL_DMA_ConvertQNodesToStatic() to convert a linked list queue to static format.

        • Call this API for dynamic queue format.

        • If the execution is dynamic and an update is needed on the linked list queue, then:

          • If the execution is linear : Call this API as the first API after the full execution of linked list queue.

          • If the execution is circular : Call this API as the first API after aborting the execution of the current linked list queue.

    • When converting a circular queue to dynamic format and when the first circular node is the last queue node, it is recommended to duplicate the last circular node to ensure full optimization when calling HAL_DMA_ConvertQNodesToDynamic() API. In this case, the updated information is only addresses, which reduces 4 words of update for linear nodes per node execution and 6 words of update for 2D addressing nodes per node execution.

Process and callback management :

Silent mode IO operation:

  • Call the function HAL_DMA_StartDirectXfer() to start a DMA transfer in direct mode after the configuration of source address, destination address and the size of data to be transferred.

  • Call the function HAL_DMA_StartLinkedListXfer() to start a DMA transfer in linked list mode after the configuration of linked list queue.

  • Call the function HAL_DMA_PollForXfer() to poll for selected transfer level. In this case, configure a fixed timeout based on the application. Transfer level can be :

    • HAL_DMA_XFER_HALF_COMPLETE

    • HAL_DMA_XFER_FULL_COMPLETE For circular transfer, this API returns HAL_INVALID_PARAM.

  • Call the function HAL_DMA_Suspend() to suspend any ongoing DMA transfer in blocking mode. This API returns HAL_ERROR when there is no ongoing transfer or timeout is reached when disabling the DMA channel. Do not call this API from an interrupt service routine.

  • Call the function HAL_DMA_Resume() to resume any suspended DMA transfer immediately.

  • Call the function HAL_DMA_Abort() to abort any ongoing DMA transfer in blocking mode. The DMA FIFO is drained when the transfer direction is memory to memory or peripheral to memory. This API returns HAL_ERROR when there is no ongoing transfer or timeout is reached when disabling the DMA channel. This API accepts the idle state when trying to abort a yet finished transfer. It returns HAL_ERROR in this case. Do not call this API from an interrupt service routine.

Interrupt mode IO operation:

  • Configure the DMA interrupt priority using HAL_CORTEX_NVIC_SetPriority() function

  • Enable the DMA IRQ handler using HAL_CORTEX_NVIC_EnableIRQ() function

  • Call the function HAL_DMA_RegisterXferHalfCpltCallback() to register half transfer complete user callbacks.

  • Call the function HAL_DMA_RegisterXferCpltCallback() to register transfer complete user callbacks.

  • Call the function HAL_DMA_RegisterXferAbortCallback() to register transfer abort user callbacks.

  • Call the function HAL_DMA_RegisterXferSuspendCallback() to register transfer suspend user callbacks.

  • Call the function HAL_DMA_RegisterXferErrorCallback() to register transfer error user callbacks.

  • Call the function HAL_DMA_StartDirectXfer_IT() to start the DMA transfer in direct mode after enabling the DMA default optional interrupts and the configuration of source address, destination address and the size of data to be transferred.

  • Call the function HAL_DMA_StartDirectXfer_IT_Opt() to start the DMA transfer in direct mode after enabling the DMA customized optional interrupts and the configuration of source address, destination address and the size of data to be transferred.

  • Call the function HAL_DMA_StartPeriphXfer_IT_Opt()

    to start a DMA channel peripheral transfer in direct or circular mode according to source address, destination address and the size of data to be transferred in byte parameters after enabling of the DMA channel mandatory interrupts for the process and enabling or disabling of the DMA channel optional interrupts for the process.

    Note: This function is intended exclusively for internal use by HAL PPP drivers for transfers over DMA.

  • Call the function HAL_DMA_StartLinkedListXfer_IT() to start a DMA transfer in linked list mode after enabling the DMA default optional interrupts and configuration of linked list queue.

  • Call the function HAL_DMA_StartLinkedListXfer_IT_Opt() to start a DMA transfer in linked list mode after the enable of DMA customized optional interrupts and configuration of linked list queue.

  • Use HAL_DMA_IRQHandler() in the DMA_IRQHandler interrupt handler to handle DMA interrupts.

  • Call the function HAL_DMA_Suspend_IT() to suspend any ongoing DMA transfer in interrupt mode. This API suspends the DMA channel execution. When the transfer is effectively suspended, an interrupt is generated and HAL_DMA_IRQHandler() must reset the channel and executes the transfer suspend user callbacks. Call this API from an interrupt service routine.

  • Call the function HAL_DMA_Resume() to resume any suspended DMA transfer immediately.

  • Call the function HAL_DMA_Abort_IT() to abort any ongoing DMA transfer in interrupt mode. This API suspends the DMA channel execution and drains the DMA FIFO. The DMA FIFO is drained when the transfer direction is memory to memory or peripheral to memory. When the transfer is effectively suspended, an interrupt is generated and HAL_DMA_IRQHandler() must reset the channel and executes the transfer abort user callbacks. This API accepts the idle state when trying to abort a yet finished transfer. It returns HAL_ERROR in this case. This accounts for asynchronous update of the DMA state to idle within the IRQHandler when the transfer is completed. Call this API from an interrupt service routine.

Status and errors

Interconnect limitations

  • This series supports both GPDMA and HPDMA. Data transfers can be conducted via AXI or AHB interfaces.

    • HPDMA supports transfers through:

      • Port 0 (AXI)

      • Port 1 (AHB)

    • GPDMA supports transfers through:

      • Port 0 (AHB)

      • Port 1 (AHB)

  • The table below outlines the supported HPDMA configurations. It specifies the allowed transfers based on the source allocated port (CTR1.SAP bit) and destination allocated port (CTR1.DAP bit).

Source/Destination

AXI_SRAM1,2,3,4

AHB_SRAM1,2,3

BACKUP_RAM

DTCM

FDCAN_RAM

XSPI1

FMC

AXI_SRAM1,2,3,4

0/0

0/0-1

0/0-1

0/0

0/1

0/0

0/0

AHB_SRAM1,2,3

0-1/0

0-1/0-1

0-1/0-1

0-1/0

0-1/1

0-1/0

0-1/0

BACKUP_RAM

0-1/0

0-1/0-1

0-1/0-1

0-1/0

0-1/1

0-1/0

0-1/0

DTCM

0/0

0/0-1

0/0-1

0/0

0/1

0/0

0/0

FLASH

0/0

0/0-1

0/0-1

0/0

0/1

0/0

0/0

FDCAN_RAM

1/0

1/0-1

1/0-1

1/0

1/1

1/0

1/0

ITCM

0/0

0/0-1

0/0-1

0/0

0/1

0/0

0/0

XSPI1

0/0

0/0-1

0/0-1

0/0

0/1

0/0

0/0

FMC

0/0

0/0-1

0/0-1

0/0

0/1

0/0

0/0

  • 0/0 : Access is possible only via source port 0 and destination port 0.

  • 0-1/0 : Access is possible via source ports 0 and 1, but only destination port 0 allows access.

  • 0/0-1 : Access is possible only via source port 0, with destination ports 0 and 1 both allowing access.

  • 0-1/0-1 : Access is possible on all ports: source ports 0 and 1, and destination ports 0 and 1.

When making transfers to or from peripherals on AHB1, APB1, AHB2, APB2, AHB3, AHB4, APB4, or AHB5 buses, only HPDMA port 1 is supported on the peripheral side.

  • All source and destination ports are supported by GPDMA, except for peripherals on the AHB5 bus, where no transfers are possible.

  • An unsupported configuration will cause a GPDMA or HPDMA data error, indicated by the flag xPDMA_CxSR.DTEF = 1.

Linked-list transfers require the nodes to be located in a memory that can be accessed by the HPDMA/GPDMA.

  • The table below outlines the supported linked-List allocated port (LPA in CCR register) versus node memory location:

Node location

Port (HPDMA)

Port (GPDMA)

AXI_SRAM1,2,3,4

0

0-1

AHB_SRAM1,2,3

0-1

0-1

BACKUP_RAM

0-1

0-1

DTCM

0

0-1

FLASH

0

0-1

FDCAN_RAM

1

0-1

  • An unsupported link configuration will cause a GPDMA/HPDMA data link error, indicated by the flag xPDMA_CxSR.ULEF = 1.