cancel
Showing results for 
Search instead for 
Did you mean: 

STM32Cube Linked List generation issue

fsorin
Associate II

Hi all,

I'm using STM32Cube IDE (version 1.13.1, build 17479_20230728_0839 ) to manage my company project based on a STM32U5 MCU.

More specifically, I'm using linked list feature (for playing audio with SAI + DMA transfer) and I have noticed what appears to me as a bug in auto-generated code.

Basically, I have created through CubeMx one list named SAIQueue, with one node named NodeTx and the auto-generated initialization code is the following:

 

 

/**
  * @brief  DMA Linked-list SAIQueue configuration
  * @PAram  None
  * @retval None
  */
HAL_StatusTypeDef MX_SAIQueue_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.Request = GPDMA1_REQUEST_SAI1_B;
  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_HALFWORD;
  pNodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_HALFWORD;
  pNodeConfig.Init.SrcBurstLength = 1;
  pNodeConfig.Init.DestBurstLength = 1;
  pNodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
  pNodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
  pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
  pNodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
  pNodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
  pNodeConfig.SrcAddress = 0;
  pNodeConfig.DstAddress = 0;
  pNodeConfig.DataSize = 0;

  /* Build NodeTx Node */
  ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &NodeTx);

  /* Insert NodeTx to Queue */
  ret |= HAL_DMAEx_List_InsertNode_Tail(&SAIQueue, &NodeTx);

  ret |= HAL_DMAEx_List_SetCircularMode(&SAIQueue);

   return ret;
}

 

If I run this code without modification, I encounter an assert failure in HAL_DMAEx_List_BuildNode (line 1069 of file stm32u5xx_hal_dma_ex.c):

 

assert_param(IS_DMA_MODE(pNodeConfig->Init.Mode));

 

This is fixed by adding the following missing line in "pNodeConfig" structure initialization:

 

pNodeConfig.Init.Mode = DMA_NORMAL;

 

Obviously, if I do any modification on the ioc file and relaunch code generation, this line is deleted and the issue is back.

Am I missing something on the UI to generate this line properly? Should this be fixed?

Thanks in advance for any insights.

9 REPLIES 9
Mahmoud Ben Romdhane
ST Employee

Hello @fsorin,

First let me thank you for posting and welcome to ST Community.

I would like to know where you added this line of code:

 

pNodeConfig.Init.Mode = DMA_NORMAL

Thanks.

Mahmoud.

 

fsorin
Associate II

Hello @Mahmoud Ben Romdhane,

Thank you for your quick reply.

I have added this line after all the "pNodeConfig.Init.x" in the auto-generated code, meaning between line 24 and 25 on the code I posted, which basically become the following one:

/**
  * @brief  DMA Linked-list SAIQueue configuration
  * @param  None
  * @retval None
  */
HAL_StatusTypeDef MX_SAIQueue_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.Request = GPDMA1_REQUEST_SAI1_B;
  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_HALFWORD;
  pNodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_HALFWORD;
  pNodeConfig.Init.SrcBurstLength = 1;
  pNodeConfig.Init.DestBurstLength = 1;
  pNodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
  pNodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
  pNodeConfig.Init.Mode = DMA_NORMAL;
  pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
  pNodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
  pNodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
  pNodeConfig.SrcAddress = 0;
  pNodeConfig.DstAddress = 0;
  pNodeConfig.DataSize = 0;

  /* Build NodeTx Node */
  ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &NodeTx);

  /* Insert NodeTx to Queue */
  ret |= HAL_DMAEx_List_InsertNode_Tail(&SAIQueue, &NodeTx);

  ret |= HAL_DMAEx_List_SetCircularMode(&SAIQueue);

   return ret;
}

 Best regards

Hello @fsorin,

Can you please provide your IOC file.

Thanks.

Mahmoud

Hello @Mahmoud Ben Romdhane,

Here is the ioc file. Please note that I only renamed it and changed project name for confidentiality purpose. I also renamed it as .txt because uploading was refused otherwise for some reason.

Best regards 

fsorin
Associate II

@Mahmoud Ben Romdhane,

Regardless of this specific project, I was looking for the explanation of why the structure field "Mode" (pNodeConfig.Init.Mode here) was left uninitialized by the auto-generated code.

If there is something to be modified in MX configuration I would be glad to know what, but it appears to me that it's just missing. I am guessing that the assumption is made that its value will be zero, which is the value of "DMA_NORMAL", the only accepted value by "assert_param(IS_DMA_MODE(pNodeConfig->Init.Mode))", but it can in fact takes any random number, as it is uninitialized.

Could not this line be integrated on a next release, as initializing every parameter to a known value is considered as best practice?

Thank you for considering this.

Best regards

AScha.3
Chief II

same problem on H563/nucleo-H563zi cube generated code never gets dma working. not in standard or in list-mode.

using list-mode on GPDMA1 and insert line 

pNodeConfig.Init.Mode = DMA_NORMAL;

 it starts working in a magical way.  Quite an outstanding achievement.

If you feel a post has answered your question, please click "Accept as Solution".
fsorin
Associate II

Hello @AScha.3,

I'm glad that I helped you solve your issue.

This is still a workaround though, and will be lost after the next auto-generation. Let's hope for a real fix from ST team on this one!

you made my day ! 🙂

and no, not lost always: because the cube generated code didnt work in any way, i tried to copy from git example 

and make it my way, in a function. so in cube its just set to list mode, GPDMA1 ch 7 .

then in main:   (is really "main_task" in Azure rtos -- just for fun (to test it) )

define:

 

 

  DMA_NodeTypeDef NodeTx;
  DMA_QListTypeDef SAIQueue;

/* USER CODE END PV */

 

 

 

 

 

   /* Associate the DMA handle */
    __HAL_LINKDMA(&hsai_BlockA2, hdmatx, handle_GPDMA1_Channel7);		
    MX_SAIQueue_Config();
    HAL_DMAEx_List_SetCircularMode(&SAIQueue);
    /* Link SAI queue to DMA channel */
    HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel7, &SAIQueue);
// start dma
 fresult = HAL_SAI_Transmit_DMA(&hsai_BlockA2,(uint8_t *)playbuf, sizeof(playbuf))/4);

 

 

 

 

and the config..:

 

 

 

 

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
  HAL_StatusTypeDef MX_SAIQueue_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.Request = GPDMA1_REQUEST_SAI2_A;
    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_BLOCK_TRANSFER;
    pNodeConfig.Init.Mode = DMA_NORMAL;			// new ??!!!
    pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
    pNodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
    pNodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
    pNodeConfig.SrcAddress = 0;
    pNodeConfig.DstAddress = 0;
    pNodeConfig.DataSize = 0;
    /* Build NodeTx Node */
    ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &NodeTx);
    /* Insert NodeTx to Queue */
    ret |= HAL_DMAEx_List_InsertNode_Tail(&SAIQueue, &NodeTx);
     return ret;
  }

 

 

 

 

and nothing removed!

AScha3_0-1699293444969.png

 

If you feel a post has answered your question, please click "Accept as Solution".
fsorin
Associate II

Ok so basically you don't generate the linked list code from Cube anymore, but manually implement it in user code section. I guess I will end up doing the same thing but it would be great if the auto-generated code managed that properly...