Skip to main content
Deimos
Associate II
October 10, 2025
Solved

STM32H7RS GPDMA Circular w/ Linked List issue

  • October 10, 2025
  • 3 replies
  • 476 views

Hello,

Using a NUCLEO H7S3L8, I'm trying to run a test where, using circular DMA with a linked list, I'm trying to send a buffer in memory over to the SAI for audio playback, using an external DAC. This configuration is based on either other tutorials or the reference manual, but it always throws a User Error flag and calls the DMA's IRQ handler, right after the HAL_DMAEx_List_Start_IT() call (whether done on its own after the necessary configuration, or as part of HAL_SAI_Transmit_DMA()). 
Even with some changes, it always yields the same results. The only one that seemed to have any effect was setting the Transfer Event mode to trigger the TC flag for each linked list item, which confirmed that a transfer might have been completed, despite the error flag.

I have also seen GPDMA being configured with circular, using both Standard Request Mode and a Linked List, but haven't gotten any success out of that myself (with even TC flag not being raised).
In case it causes any complications, the board also is configured as a USB Audio device (leftover from previous test, not used currently), and the SAI is configured at 16 bits, at 48 kHz.

Below are images of the configuration:

GPDMA.png

 

LL1.png

 

 

LL2.png

I'll also leave main.c of the application project, where the only parts of relevant user code have been written.

Any help or advice would be greatly appreciated.

Best answer by AScha.3

So...seems to work.

But i changed many...see and try.

( core clock etc. lower , 360M , just to get no problem.)

3 replies

AScha.3
Super User
October 10, 2025

Hi,

>I'm trying to send a buffer in memory over to the SAI for audio playback, using an external DAC.

So what should it do finally ?   Audio-player ?

I made an Audio-player with H743, plays wav/flac/mp3 from SD-card and USB, DAC is ES9038 + TDA1387.

And DMA is normal mode, circular.

So why this linked list ? (just makes it more complicated, imho.)

"If you feel a post has answered your question, please click ""Accept as Solution""."
Deimos
DeimosAuthor
Associate II
October 11, 2025
@AScha.3 wrote:

So what should it do finally ?   Audio-player ?


Yes, the end result I have in mind is a USB audio interface, using the Nucleo's secondary USB port for power and receiving data, to then forward to the SAI via DMA, and finally to an external PCM5102 DAC (on a WMCU-5120 breakout board, to be exact).

 


@AScha.3 wrote:

So why this linked list ? (just makes it more complicated, imho.)


GPDMA on the newer STM32 MCUs (U5, H5, H7RS, etc.) seems to differ quite a bit from the DMA controller used on the H743 and others (from my limited experience with a Nucleo H743ZI). The functionality for circular DMA without using any linked lists is now considered a legacy approach, and not available as far as I can tell.

Unfortunately, that makes using a linked list necessary, with the only "alternative" I considered, being using non-circular DMA to send bulk-like DMA transfers to fill the SAI's FIFO, which will then be played while waiting to refill the FIFO with more data.
That, from my tests, may work if transmitting an unchanged buffer repeatedly every couple ms.
However, when gathering USB data into half of a larger buffer, transmitting that half when full, and proceeding to fill the other (simulating circular double buffering), only noise akin to a square wave is produced, I'm assuming due to intermittent silence from the SAI being starved of data to transmit.
So, other than being unorthodox, it's also non-functional.

Sorry for the long answer, but I wanted to offer any information that might be relevant.

AScha.3
Super User
October 11, 2025

>Sorry for the long answer

No, thats fine. So i know more...

I have a NUCLEO H7S3L8 , so if you give me your project (maybe main.c + .ioc could be enough),

i could try it. 

(I had similar thing running on H563 , with linked list, just to test it. + Azure rtos.)

"If you feel a post has answered your question, please click ""Accept as Solution""."
Deimos
DeimosAuthor
Associate II
October 11, 2025

Yes, sure thing, I'll post both files.

Also, this section below was changed from the CubeMX generated linker script for XSPI2, to accomodate a larger non-cacheable buffer.

__RAM_BEGIN = 0x24000000;
__RAM_SIZE = 0x71800;
__RAM_NONCACHEABLEBUFFER_SIZE = 0x800;

Thank you for your help and time!

Visitor II
February 20, 2026

Hi Deimos,

I tried to understand the solution but I could not understand how enabling the D-cache has solved the problem. I am facing similar problem. I am working on sending the data on DAC. I am using DMA and linked list.

Problem Statement:

I want to generate limited node sinewave, not continuous. I did the configuration for different nodes and created DAC Queue as well. But, the Error call back is being called, when I start the transmission. The error code which is coming is value 4.

Code flow for DACQueue_Config: Function given in example but modified by me.

HAL_StatusTypeDef DACQueue_Config(void)
{
HAL_StatusTypeDef ret = HAL_OK;
/* DMA node configuration declaration */
DMA_NodeConfTypeDef pNodeConfig;

/* Set node configuration ################################################*/
pNodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
pNodeConfig.Init.Mode = DMA_NORMAL;
pNodeConfig.Init.Request = GPDMA1_REQUEST_DAC1_CH1;
pNodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
pNodeConfig.Init.Direction = DMA_MEMORY_TO_PERIPH;
pNodeConfig.Init.SrcInc = DMA_SINC_INCREMENTED;
pNodeConfig.Init.DestInc = DMA_DINC_FIXED;
pNodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
pNodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
pNodeConfig.Init.SrcBurstLength = 1;
pNodeConfig.Init.DestBurstLength = 1;
pNodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
pNodeConfig.Init.TransferEventMode = DMA_TCEM_LAST_LL_ITEM_TRANSFER;
pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
pNodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
pNodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;

pNodeConfig.SrcAddress = (uint32_t)sinewaveArray;
pNodeConfig.DstAddress = (uint32_t)&DAC1->DHR12R1;
pNodeConfig.DataSize = 26;
/* Build DACNode Node */
ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &dmaNode[0]);

/* Insert DACNode to Queue */
ret |= HAL_DMAEx_List_InsertNode_Tail(&mxDACQueue, &dmaNode[0]);

return ret;
}

 

Code Flow for main():

MX_GPDMA1_Init - Auto generated code

MX_DAC1_Init - Auto generated code

HAL_DMAEx_List_Init(&handle_GPDMA1_Channel6);

call Function: DACQueue_Config

/* Link DAC queue to DMA channel */
if( HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel6, &DACQueue)!= HAL_OK)
{
Error_Handler();
}

///* Associate the initialized GPDMA handle to the the DAC handle */
__HAL_LINKDMA(&hdac1, DMA_Handle1, handle_GPDMA1_Channel6);

HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel6, HAL_DMA_XFER_CPLT_CB_ID, transferDmaDone);
HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel6, HAL_DMA_XFER_ERROR_CB_ID, transferDmaErr);
HAL_DAC_Start(&hdac1, DAC_CHANNEL_1);
/* Enable All the DMA interrupts */
if (HAL_DMAEx_List_Start_IT(&handle_GPDMA1_Channel6) != HAL_OK)
{
Error_Handler();
}
TIM_DAC_Start() - timer Responsible for giving the trigger to DAC

Every time it calls the call back function transferDmaErr.

Can you please suggest what could be missing configuration? I am not using D-Cache.

Regards,

Malay

Deimos
DeimosAuthor
Associate II
February 20, 2026

Hello @Malay,

In my case, disabling the D-Cache solved my problem, because with it on, the DMA configuration options in the linked list could not be passed to the necessary registers and remained empty instead. It's one of two approaches for solving the cache coherency issue, the other would be manually maintaining it.

Now, I could tell that the configuration was faulty by monitoring these register values in CubeIDE using breakpoints and step-by-step execution for the DMA configuration and DMA transmission call (for example, the SAI DMA transmit call reconfigures the node, so I could tell that the same behavior was repeated). You can find them within your MCU's programmer manual. Error codes are also reported within these, so they could be somewhat helpful (if a bit limited).

As far as I can tell from your code, it seems fine, but it could be worth to look for any error codes before/after it reaches transferDmaErr.
Though personally, I'd also look into two things:
First off, as far as I'm aware, usually the DMA handle in most peripheral handles in HAL is required to be hdmatx, while you are using DMA_Handle1. Is it defined this way in the struct definition of the DAC handle? Though I'll say that I haven't yet seen the DAC related HAL code at all, so this could be ignorance on my part. 
Second, in case there is some HAL function for starting a DAC transmission using DMA, maybe check it out and see whether there are any other function calls/flag configs missing from your code. For example, for my SAI application, there was a function HAL_SAI_Transmit_DMA(), that enabled some flags, after calling HAL_DMAEx_List_Start_IT().

In any case, feel free to send your project's .ioc and code, and I could maybe help look.

Visitor II
February 23, 2026

Hello @Deimos ,

 

Thank you for your reply.

I have tried to take the reference from example code: DMA_LinkedList and DAC_SignalGeneration_DMA. If I run both this examples as it is then they work well. But if I modify DMA_LinkedList for sending output on external pin then it does not work. 

1. DAC_SignalGeneration_DMA - This example if you see then it has the linked_list.c file in it. Also, in main.c file queue is linked and other important steps. But actually at the start of transmission, src buffer is passed in argument. In main.c file,

if (HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, &data_sin[0], 128, DAC_ALIGN_12B_R) != HAL_OK)
 {
 /* Start DMA Error */
 Error_Handler();
 }

I feel like it is pure DMA transmission only for DAC. Not DMA+linked list transmission. In linkedlist.c file, Node's source address and dest address are set to 0. In this way the node is added and queue is circular queue.

2. DMA_LinkedList - This example is transferring data between RAM to RAM using linked list. it does not have DAC into it. 

So, I tried to combine these examples.  

I have attached the DAC_SignalsGeneration_DMA.ioc which can be found in STM32U575 examples as well. 

I am not using it for Audio output purpose.

Thank you very much again.

Regards,

Malay