How to configure the linked list mode in STM32CubeMX
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Email to a Friend
- Printer Friendly Page
- Report Inappropriate Content
on
2024-10-16
5:30 AM
- edited on
2024-10-23
5:19 AM
by
Laurids_PETERSE
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 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_1
- Set the execution mode to [Linear] and change the priority to [Very High].
GPDMA 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_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.
- For each node, name the source and destination address buffers and specify the data size as follows
Node1 configuration_2
- Do the same for the Node2 and Node3 configuration:
Node2 Configuration
Node3 Configuration
- Note: Make 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 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
- GitHub STMicroelectronics/STM32CubeH5: Full firmware package for STM32H5 series containing CMSIS, HAL-LL, BSP drivers, MW libraries plus a set of projects
- Reference manual 0481: STM32H523/33xx, STM32H562/63xx, and STM32H573xx based 32-bit MCUs
- Datasheet 14258: STM32H562xx and STM32H563xx
- Application note 5593: How to use the GPDMA for STM32 MCUs
- Knowledge article: How to configure the GPDMA
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Email to a Friend
- Report Inappropriate Content
Hello,
Thank you for the fast reply.
Is there any way that I can achieve the same functionality without using interruptions?
Can you suggest me any material, videos, etc... ?
Thank you,
Marc