How Do You Configure STM32U5 GPDMA Linked-List DMA Transfers?
Last updated 20 July 2026 · 6 min read
Direct Answer
The STM32U5's GPDMA peripheral replaces the classic stream/channel or DMAMUX model used on STM32F4/G4/H7 with a linked-list-capable architecture: each GPDMA channel can execute a chain of transfer descriptors, called nodes, stored in SRAM, with the hardware automatically loading the next node's configuration when the current one completes, without CPU or interrupt involvement between nodes. CubeMX and the STM32U5 HAL expose this through the HAL_DMAEx_List_* API, which builds a queue of nodes and attaches it to a channel, rather than the single HAL_DMA_Init() call classic STM32 DMA uses. The U5 also has a separate, simpler LPDMA1 controller for the few peripherals that must keep transferring data while the MCU is in Stop mode; LPDMA1 does not support linked lists.
Detailed Explanation
STM32U5 replaces the DMA architecture used on STM32F4, G4, and H7 with GPDMA (General Purpose DMA), a controller built around linked lists rather than the stream/channel model or DMAMUX request routing those families use. See STM32 HAL DMA configuration for how classic DMA works; this page covers what's different on GPDMA and why a design migrating from an L4 or F4-based product should budget real time for it, a gap already flagged in the STM32 family selection guide's comparison table.
On classic STM32 DMA, one HAL_DMA_Init() call configures a single transfer descriptor: one source, one destination, one mode (normal or circular), one data width. Chaining a sequence of different transfers means the CPU has to reconfigure and restart the DMA in an interrupt callback after each one completes. GPDMA removes that CPU round-trip: a channel can be handed a chain of transfer descriptors, called nodes, stored as a linked list in SRAM, and the hardware loads each node's configuration automatically as soon as the previous one finishes.
The Node and Queue Model
Each GPDMA node holds a complete transfer descriptor: source address, destination address, data width, transfer count, and the address of the next node in the chain. When a channel completes the transfer described by its current node, it reads the next node's address directly from the current node's linked-list pointer and continues without CPU intervention or an interrupt firing in between. A chain can end (the last node has no next-node pointer, so the channel stops) or loop back to its first node to run indefinitely.
This makes GPDMA well suited to scenarios that would otherwise need constant reconfiguration on classic DMA: alternating between two peripherals on a fixed schedule, applying a different data width or address-increment pattern partway through a transfer, or streaming a repeating sequence of register writes to a peripheral without CPU wake-ups between each one.
Configuring GPDMA in CubeMX
CubeMX exposes GPDMA configuration through the same peripheral DMA Settings tab used for classic DMA, plus a dedicated linked-list queue builder for cases that need more than a single node:
- In the peripheral's DMA Settings tab, add a GPDMA request as usual. For a simple one-shot or circular transfer, this alone is enough. CubeMX generates a single-node configuration and the familiar
HAL_UART_Transmit_DMA()-style call still works. - For a multi-node chain, use CubeMX's linked-list queue editor to define each node's source, destination, and transfer parameters, and the order they execute in.
- CubeMX generates the corresponding
HAL_DMAEx_List_*calls:HAL_DMAEx_List_Init()to prepare the queue structure,HAL_DMAEx_List_BuildNode()for each node,HAL_DMAEx_List_InsertNode()to add nodes to the queue in order, andHAL_DMAEx_List_SetCircularMode()if the chain should loop rather than stop after the last node.
// Simplified structure of a generated linked-list queue setup
DMA_NodeConfTypeDef node_config;
DMA_NodeTypeDef node1, node2;
DMA_QListTypeDef transfer_queue;
// Build each node's transfer descriptor
HAL_DMAEx_List_BuildNode(&node_config, &node1);
HAL_DMAEx_List_BuildNode(&node_config2, &node2);
// Assemble the queue in execution order
HAL_DMAEx_List_InsertNode(&transfer_queue, NULL, &node1);
HAL_DMAEx_List_InsertNode(&transfer_queue, &node1, &node2);
// Attach the queue to the channel and start it
HAL_DMAEx_List_LinkQ(&handle_gpdma, &transfer_queue);
HAL_DMAEx_List_Start(&handle_gpdma);
The exact generated code depends on the queue structure chosen in CubeMX; the pattern above is the shape of it, not a literal drop-in. For the underlying GPDMA register set (channel transfer registers, the linked-list address register, and per-channel request routing), see the GPDMA chapter of the STM32U5 reference manual.
GPDMA1 vs LPDMA1
STM32U5 has two separate DMA controllers with different capabilities:
- GPDMA1 is the general-purpose controller described above, with linked-list support, available to most peripherals and both memory-to-memory and memory-to-peripheral transfers.
- LPDMA1 is a smaller, simpler controller intended to keep a limited set of low-power peripherals (such as LPUART1) transferring data while the MCU is in Stop mode, when GPDMA1 itself is not clocked. LPDMA1 supports only the classic normal and circular transfer modes, not linked lists, and is only connected to a limited peripheral set. A design that needs DMA to continue operating in Stop mode must route that specific transfer through LPDMA1, not GPDMA1.
Design Considerations
- Don't reach for the linked-list API for a simple transfer. If a peripheral only needs one fixed configuration (a normal one-shot transfer or a circular streaming buffer), CubeMX's single-node GPDMA setup and the familiar peripheral-level
_DMA()HAL calls are simpler and sufficient. Reserve linked-list queues for sequences that genuinely need to chain multiple distinct transfer configurations. - Route Stop-mode-active transfers through LPDMA1, not GPDMA1. GPDMA1 is not clocked during Stop mode; only LPDMA1 and its limited peripheral set can keep transferring data while the rest of the MCU is asleep. Confirm during low-power mode selection which specific peripherals a product needs active in Stop mode, since that determines whether LPDMA1's simpler transfer model is sufficient.
- Budget real migration time when porting a DMA-heavy design from L4, F4, or H7. The node/queue programming model is a genuinely different way of thinking about DMA configuration, not a renamed API on top of the same concepts, and code written against classic
HAL_DMA_Init()semantics does not port directly. - STM32U5 GPDMA and LPDMA firmware: getting a linked-list transfer chain, or the GPDMA/LPDMA split for low-power designs, right the first time is exactly the kind of platform-specific firmware work Zeus Design's embedded team handles for production STM32U5 products.
Common Mistakes
- Assuming GPDMA's peripheral request routing works identically to DMAMUX on H7/G4/L4 and skipping verification against the U5-specific request mapping, when the underlying request assignments differ by family even though both use flexible per-channel routing.
- Building a linked-list queue without setting circular mode when the transfer is meant to repeat indefinitely, causing the channel to correctly execute the chain once and then stop, which looks like a hang rather than the actual cause (a terminated, non-looping chain).
- Trying to keep a GPDMA1-routed transfer active through Stop mode, when only LPDMA1 and its limited peripheral set remain clocked in that low-power state.
- Treating the linked-list API as a mandatory replacement for the simple single-node case, adding queue-building complexity to a transfer that only ever needed one fixed configuration.
Frequently Asked Questions
- Can I use the classic HAL_DMA_Init() and HAL_UART_Transmit_DMA()-style API on STM32U5?
- For a single, fixed one-shot or circular transfer, yes: the STM32U5 HAL still provides the same peripheral-level DMA-mode functions (HAL_UART_Transmit_DMA(), HAL_SPI_TransmitReceive_DMA(), and similar) as classic STM32 DMA, and CubeMX can configure a GPDMA channel to run a single node exactly like a classic DMA stream. The linked-list API is only necessary when a transfer needs to chain multiple different configurations automatically, which the classic single-descriptor model has no way to express.
- Why does my linked-list DMA chain stop after the first node instead of continuing?
- The most common cause is an unset or incorrectly built CLLR (linked-list address register) on the final configured node before the chain should repeat or continue. If the intent is a circular chain (the last node loops back to the first), the queue must be built with circular mode explicitly set; if it's a one-shot chain, the last node's linked-list pointer should be null so the channel correctly stops rather than reading an uninitialised address as the next node.
- Does LPDMA1 support linked lists like GPDMA1?
- No. LPDMA1 is a deliberately simpler, smaller controller intended only to keep a small number of low-power peripherals (such as LPUART1 or ADC4) transferring data while most of the MCU is in Stop mode, and it supports only normal and circular transfer modes, the same model as classic STM32 DMA. Linked-list transfers are a GPDMA1-only capability.
References
Related Questions
How Do You Configure STM32 HAL DMA for UART, SPI, and ADC?
Configure STM32 HAL DMA for UART, SPI, and ADC — normal vs circular mode, interrupt callbacks, double buffering, and cache coherency on STM32H7/F7.
Which STM32 Family Should You Use?
Compare STM32 families for new designs: G0, G4, F4, H7, L4, U5, WB, and WL — performance tiers, power profiles, peripheral sets, and which to choose.
How Do You Configure STM32 Peripherals with HAL and CubeMX?
STM32CubeMX generates HAL initialisation code for UART, SPI, and I2C from a GUI. This guide explains key settings and how generated code maps to the hardware.
How Do You Configure STM32 Low-Power Modes (Sleep, Stop, Standby)?
Configure STM32 Sleep, Stop, and Standby modes: current draw and wake latency by mode, wake-up sources (EXTI, RTC), and the RTC backup domain.
How Does DMA (Direct Memory Access) Work in Embedded Systems?
DMA lets a dedicated hardware controller move data between memory and peripherals without CPU involvement — how it works, transfer modes, and common pitfalls.
How Do You Configure STM32 NVIC Interrupt Priorities?
Learn how to configure STM32 NVIC interrupt priorities using HAL, priority grouping, and the FreeRTOS configMAX_SYSCALL_INTERRUPT_PRIORITY constraint.
Related Forum Discussions
STM32L4 never wakes from Stop mode — button EXTI interrupt just doesn't fire
Working on a battery-powered sensor node, STM32L476RG (Nucleo board for now). Idea is: device sits in Stop 2 mode most of the time, wakes wh
STM32F401 UART printing garbage after switching to 84 MHz PLL — same 115200 baud in CubeMX and PuTTY
Got a WeAct Black Pill (STM32F401CCU6) project that's been running happily on the default HSI clock at 16 MHz. Using USART1 on PA9/PA10 thro
STM32H743 HAL_UART_Receive_DMA fires error callback immediately — TEIF1 set, RxCplt never fires
Upgrading a project from STM32F4 to STM32H743. UART DMA receive worked on the F4 without any issues: standard CubeMX setup, call HAL_UART_Re
STM32 GPIO interrupt configured but ISR never fires — what am I missing?
Trying to use a button on PA0 to trigger an interrupt on an STM32F411 Nucleo board. Using HAL, generated the init code with CubeMX. The GPIO