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 debug 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:

    • 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.

      • 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.

  • 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 does not suspend instantly but completes the current single/burst transfer, then it stops. When the DMA channel is suspended, the current transfer can be resumed instantly.

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 32bit aligned and must not exceed the 64 KByte 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 instantly.

  • Call the function HAL_DMA_Abort() to abort 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. 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 instantly.

  • Call the function HAL_DMA_Abort_IT() to abort 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 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