cancel
Showing results for 
Search instead for 
Did you mean: 

How to configure the linked list mode in STM32CubeMX

Sarra.S
ST Employee

Introduction

This article provides a step-by-step guide on configuring the GPDMA linked list in STM32CubeMX. It does not cover the legacy standard DMA approach, which is described in the article "How to configure the GPDMA."

1. Software prerequisites

The versions used in this tutorial are:

2. Hardware prerequisites

3. Theoretical explanation

Alternatively to the direct programming mode, a channel can be programmed by a list of transfers, known as a list of linked-list items (LLI). Each LLI is defined by its data structure. The LLI is mapped in memory and contains an image of the values to be initialized into the DMA channel registers. Thus, the DMA channel registers programming becomes an indirect operation. 

The GPDMA has lists containing configuration nodes that the GPDMA uses. 

Each linked list node will update the following GPDMA registers after the previous GPDMA node is finished:

 

Transfer register 1
Transfer register 2
Block register 1
Source address register
Destination address register
Transfer register 3
Block register 2
Linked list register 
TR1
TR2
BR1
SAR
DAR
TR3
BR2
LLR

4. Step-by-step instructions

4.1. Project configuration

Start a new project and enable the instruction cache [ICACHE] to reach the maximum performance.

ICache configurationICache configuration

4.2. GPDMA configuration

  • Select [GPDMA1] in the System Core category
  • Set the mode to [Linked-list mode] for channel 0. If channel 0 is not available, choose another channel and name the channel 0 request.

GPDMA configuration_1GPDMA configuration_1

  • Set the execution mode to [Linear] and change the priority to [Very High].

GPDMA configuration_2GPDMA configuration_2

4.3. Linked list Queue and nodes configuration 

  • Under Categories  Utilities, add a list by clicking on the [Add List] button and configure the queue.
  • Rename the queue as shown in the screenshot below.

Linked_list_Queue_ConfigLinked_list_Queue_Config

  • Add and rename three nodes as "Node1," "Node2," and "Node3."
  • Enable source and destination transfer increment after transfer and change the data width to Word.
  • Keep data handling, trigger, 2D addressing, and transfer event configuration disabled.
Node1 configuration_1Node1 configuration_1
  • For each node, name the source and destination address buffers and specify the data size as follows

Node1 configuration_2Node1 configuration_2

  • Do the same for the Node2 and Node3 configuration: 

Node2 ConfigurationNode2 Configuration

 

Node3 ConfigurationNode3 Configuration

  •  NoteMake sure to keep the same data width between source and destination in all nodes. 

The first node in the loop is where the LLR from the last node in the queue is pointed. If there is only one node, it reloads the same configuration upon completion.

LLI List QueueLLI List Queue

Now, generate the code and switch to STM32CubeIDE.

4.4. Code configuration

Firstly, include the linked_list.h in the main.c by adding between /*USER CODE BEGIN Includes*\ and /*USER CODE END Includes*\ 

/* USER CODE BEGIN Includes */
#include "linked_list.h"
/* USER CODE END Includes */
  • Add the buffers declaration for the 3 nodes
/* USER CODE BEGIN PV */

extern uint32_t aSRC_Buffer1[8U];
extern uint32_t aSRC_Buffer2[16U];
extern uint32_t aSRC_Buffer3[24U];
extern uint32_t aDST_Buffer1[8U];
extern uint32_t aDST_Buffer2[16U];
extern uint32_t aDST_Buffer3[24U];

/* USER CODE END PV */
  • Add the declaration of TransferComplete and TransferCompleteDetectedflag
/* USER CODE BEGIN PFP */
static void TransferComplete(DMA_HandleTypeDef *hdma);
static void TransferError(DMA_HandleTypeDef *hdma);

/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
__IO uint32_t TransferCompleteDetected = 0U, TransferErrorDetected = 0U;
/* USER CODE END 0 */
  • In your main.h, define the Buffers size for each of the 3 buffers
/* USER CODE BEGIN Private defines */
#define BUFFER1_SIZE 8U
#define BUFFER2_SIZE 16U
#define BUFFER3_SIZE 24U
/* USER CODE END Private defines */
  • In linked_list.c file initialize the three source buffers (aSRC_Buffer1, aSRC_Buffer2, and aSRC_Buffer3) with different sizes and values. Also, declare the three destination buffers (aDST_Buffer1, aDST_Buffer2, and aDST_Buffer3) with the same sizes as their corresponding source buffers but does not initialize them.
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
uint32_t aSRC_Buffer1[BUFFER1_SIZE] =
{
  0x01020304, 0x05060708, 0x090A0B0C, 0x0D0E0F10,
  0x11121314, 0x15161718, 0x191A1B1C, 0x1D1E1F20,
};

 uint32_t aSRC_Buffer2[BUFFER2_SIZE] =
{
  0x01020304, 0x05060708, 0x090A0B0C, 0x0D0E0F10,
  0x11121314, 0x15161718, 0x191A1B1C, 0x1D1E1F20,
  0x21222324, 0x25262728, 0x292A2B2C, 0x2D2E2F30,
  0x31323334, 0x35363738, 0x393A3B3C, 0x3D3E3F40,
};

 uint32_t aSRC_Buffer3[BUFFER3_SIZE] =
{
  0x01020304, 0x05060708, 0x090A0B0C, 0x0D0E0F10,
  0x11121314, 0x15161718, 0x191A1B1C, 0x1D1E1F20,
  0x21222324, 0x25262728, 0x292A2B2C, 0x2D2E2F30,
  0x31323334, 0x35363738, 0x393A3B3C, 0x3D3E3F40,
  0x41424344, 0x45464748, 0x494A4B4C, 0x4D4E4F50,
  0x51525354, 0x55565758, 0x595A5B5C, 0x5D5E5F60,
};
uint32_t aDST_Buffer1[BUFFER1_SIZE];
uint32_t aDST_Buffer2[BUFFER2_SIZE];
uint32_t aDST_Buffer3[BUFFER3_SIZE];

/* USER CODE END PM */
  • Add a queue handle to main.c 
/* USER CODE BEGIN PV */
extern DMA_QListTypeDef Queue;
/* USER CODE END PV */
  • Initialize the nodes and queue  
/* USER CODE BEGIN 2 */
 MX_Queue_Config();
/* USER CODE END 2 */

This function creates the node configuration from the structure by using HAL_DMAEx_List_BuildNode. The node is copied in GPDMA registers without linking the nodes yet. 

To link the nodes together STM32CubeMX, use HAL_DMAEx_List_InsertNode_Tail to create the queue.

  • To connect the queue and GPDMA, we use HAL_DMAEx_List_LinkQ
/* USER CODE BEGIN 2 */
MX_Queue_Config();
HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel0, &Queue);
/* USER CODE END 2 */

  • Define the TransferComplete callback function that is called when a DMA transfer is completed
/* USER CODE BEGIN 4 */
static void TransferComplete(DMA_HandleTypeDef *hdma)
{
  TransferCompleteDetected = 1U;
}
  • Define the TransferError callback function to detect any transfer issues
static void TransferError(DMA_HandleTypeDef *hdma)
{
  TransferErrorDetected = 1U;
}
/* USER CODE END 4 */
  • Call this callback function whenever a transfer is complete
/* USER CODE BEGIN 2 */

MX_Queue_Config();
HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel0, &Queue);
HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel7, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete);
HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel0, HAL_DMA_XFER_ERROR_CB_ID, TransferError);
/* USER CODE END 2 */
  • Start DMA by using HAL_DMAEx_List_Start_IT
 if (HAL_DMAEx_List_Start_IT(&handle_GPDMA1_Channel0) != HAL_OK)
    {
      Error_Handler();
    }
  while ((TransferCompleteDetected == 0) && (TransferErrorDetected == 0U));
  if (TransferErrorDetected == 1U)
    {
      Error_Handler();
    }
  /* USER CODE END 2 */
  • Compile the code and run it. 

By following these steps, you can successfully configure the GPDMA linked list in STM32CubeMX and run it using STM32CubeIDE.

Related links

Version history
Last update:
‎2024-10-23 05:19 AM
Updated by: