HAL DMA How to Use

group DMA_How_To_Use

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

  • Initialization and De-initialization functions

  • Configuration functions

  • Linked-list node management functions

  • Process management functions

  • Callbacks functions

  • Status functions

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

DMA main features

  • DMA transfer modes are divided to 2 major categories (direct transfer and linked-list transfer)

  • The DMA channel can be programmed to allow one-shot transfer by 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 fetch the first linked-list node from SRAM (known as head node). When executed, the next linked list node must be fetched and executed. This operation is repeated until the end of the whole linked-list queue Optionally, 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: linear linked-list is a finite list where the last node (also called tail node) points to null, a linear linked-list transfer execution is finite, ending by the last node. The DMA channel fetches and executes all DMA linked-list queue from first node (head node) to last node (tail node) ones. When the last node is completed, the DMA channel remains in idle state and another transfer can be lunched.

    • Circular linked-list: Circular linked-list where the last node points to one of the previous nodes of the list. a circular linked-list transfer execution must end-up looping from the last node (tail node) to the node where the tail node points to. The DMA channel fetches and executes all DMA linked-list queue from first node (head node) to last node (tail node). When circular node is executed, the DMA channel fetches the next node repeat 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

  • In order to reduce linked-list queue executing time and power consumption, the DMA channel supports executing the dynamic linked-list format. In fact, the DMA supports the execution of 2 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 refer 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 executes the linked-list queue node by node when started, enabling the DMA channel first time allows to fetch the head node from memory then it stops. Then, another DMA channel enable is needed to execute the node. After that, keeping enabling the DMA channel is needed to execute each node until the end of linked-list queue. When the linked-list queue is circular, enabling the DMA channel in an infinite loop is required to keep the DMA channel running. This feature is useful for debug purpose 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 configuration can be :

    • Repeated block configuration : If the feature is supported, the DMA channel can perform a repeated block transfers. Named also 2 dimension addressing transfers, this feature can transfer n iterations of programmed block transfer. Additional to the repeat count of a block, DMA channel addresses can jump after at burst and block level. The jump length is a programmable parameter defined by DMA user.

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

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

    • Trigger configuration : The DMA channel transfers can be conditioned by hardware signals edges (rising or falling) named hardware triggers. Trigger condition 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 detects more than 2 trigger signal edges before executing the current transfer.

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

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

      • Truncation : Truncate section from the source data single when the source data width is bigger than the destination data width.

      • 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 bigger than the destination data width.

      • Exchange : Exchange data at byte or half-word level in destination and 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 application. When trying to suspend an ongoing transfer, the DMA channel is not suspended instantly but complete the current ongoing single/burst then it stops. When the DMA channel is suspended, the current transfer can be resumed instantly.

  • The DMA channel that supports FIFO, can report in real time the number of beats remains on destination (Output) FIFO level.

How to use the DMA HAL module driver

Initialization and De-initialization :

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

  • Use HAL_DMA_DeInit() function to de-initialize a DMA channel, When called, the DMA channel must be in reset. It is mandatory to reinitialize it for next transfer.

Configuration transfer :

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 processing independently of DMA channel hardware. It allows to fill, convert (to dynamic or to static) both nodes and use the Q module services to :

    • Initialize the queue

    • Insert node to queue

    • Remove node from queue

    • Replace node from 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 that can be done are filling a new linked-list node or get a linked-list node information from a filled node. The linked-list nodes have two forms according to 2 dimensions addressing capability. The linear addressing nodes contains the information of all DMA channel features except the 2 dimension addressing features and the 2 dimensions addressing nodes contain the information of all available features.

    • Use HAL_DMA_FillNodeConfig() function to fill the DMA linked-list node according to the specified parameters. Fill operation allow to convert the specified parameter in values known by the DMA channel and place them in memory. Placing DMA linked-list in SRAM must be done in accordance to product specification to ensure that the link access port can access to the specified SRAM. The DMA linked-list node parameter address must be 32bit aligned and must not exceed the 64 KByte addressable space.

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

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

    • To have the best DMA channel linked-list queue execution, it is recommended to convert the still built linked-list queue to dynamic format (Static is the default format). When linked-list queue becomes dynamic, all queue nodes are optimized and only changed parameters must be updated between nodes. So, the DMA must fetch only changes parameters instead of the whole node.

      • Use HAL_DMA_ConvertQNodesToDynamic() function to convert a linked-list queue to dynamic format.

        • This API must be called for static queues format.

        • This API must be called as the last API before starting the DMA channel in linked-list mode.

      • Use HAL_DMA_ConvertQNodesToStatic() function to convert a linked-list queue to static format.

        • This API must be called for dynamic queues format.

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

          • If the execution is linear : This API must be called as the first API after the full execution of linked-list queue.

          • If the execution is circular : This API must be called as the first API after the 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 in order to ensure the full optimization when calling HAL_DMA_ConvertQNodesToDynamic() API. In this case, updated information are only addresses which allow to reduce 4 words of update for linear nodes per node execution and 6 words update for 2 dimensions addressing nodes per node execution.

Process and callback management :

Silent mode IO operation :

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

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

  • Use HAL_DMA_PollForXfer() function to poll for selected transfer level. In this case a fixed Timeout can be configured by User depending on his application. Transfer level can be :

    • HAL_DMA_XFER_HALF_COMPLETE

    • HAL_DMA_XFER_FULL_COMPLETE For circular transfer, this API returns an HAL_INVALID_PARAM.

  • Use HAL_DMA_Suspend() function 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. This API must not be called from an interrupt service routine

  • Use HAL_DMA_Resume() function to resume instantantly any suspended DMA transfer.

  • Use HAL_DMA_Abort() function 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 an HAL_ERROR in this case. This API must not be called 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

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

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

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

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

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

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

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

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

  • Use HAL_DMA_StartLinkedListXfer_IT_Opt() function 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() function called under DMA_IRQHandler interrupt subroutine to handle any DMA interrupt.

  • Use HAL_DMA_Suspend_IT() function to suspend any on-going 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. This API must be called from an interrupt service routine.

  • Use HAL_DMA_Resume() function to resume instantantly any suspended DMA transfer.

  • Use HAL_DMA_Abort_IT() function to abort any on-going 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 an HAL_ERROR in this case. This is to consider asynchronous update of the DMA state to idle within the IRQHandler when the transfer is completed. This API must be called from an interrupt service routine.

Status and errors