Question
STM32H5 GPDMA software controlled double buffering
Hello,
im in the process of trying to make a LED Matrix driver with the gpdma on my stm32h562. Currently, I have everything working with one buffer, but want to implement double buffering so i can fill one buffer with data, and read from the other.
I was looking around on the internet on how to implement this, but i found only one thread with the same problem, but i cant figure out how to implement the solution into my project, as there is no LLIx.nextLLI definition anywhere. Im using CubeMx to generate me code.
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : linked_list.c
* Description : This file provides code for the configuration
* of the LinkedList.
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "linked_list.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "main.h"
#include "Colours.h"
#include "Buffers.h"
#include "Fonts.h"
/* USER CODE END Includes */
DMA_NodeTypeDef RGB_transfer1;
DMA_QListTypeDef RGB_queue;
DMA_NodeTypeDef RGB_transfer2;
DMA_NodeTypeDef ACTrans;
DMA_QListTypeDef ACtransQ;
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
extern uint32_t BsrrBuf1[BsrrBufXsize * BsrrBufYsize];
extern uint32_t BsrrBuf2[BsrrBufXsize * BsrrBufYsize];
uint32_t ACtransferLUT[] = {
(1U << (4 + 16)) | (1U << (3 + 16)) | (1U << (2 + 16)) | (1U << (1 + 16)),
(1U << (4)) | (1U << (3 + 16)) | (1U << (2 + 16)) | (1U << (1 + 16)),
(1U << (4 + 16)) | (1U << (3)) | (1U << (2 + 16)) | (1U << (1 + 16)),
(1U << (4)) | (1U << (3)) | (1U << (2 + 16)) | (1U << (1 + 16)),
(1U << (4 + 16)) | (1U << (3 + 16)) | (1U << (2)) | (1U << (1 + 16)),
(1U << (4)) | (1U << (3 + 16)) | (1U << (2)) | (1U << (1 + 16)),
(1U << (4 + 16)) | (1U << (3)) | (1U << (2)) | (1U << (1 + 16)),
(1U << (4)) | (1U << (3)) | (1U << (2)) | (1U << (1 + 16)),
(1U << (4 + 16)) | (1U << (3 + 16)) | (1U << (2 + 16)) | (1U << (1)),
(1U << (4)) | (1U << (3 + 16)) | (1U << (2 + 16)) | (1U << (1)),
(1U << (4 + 16)) | (1U << (3)) | (1U << (2 + 16)) | (1U << (1)),
(1U << (4)) | (1U << (3)) | (1U << (2 + 16)) | (1U << (1)),
(1U << (4 + 16)) | (1U << (3 + 16)) | (1U << (2)) | (1U << (1)),
(1U << (4)) | (1U << (3 + 16)) | (1U << (2)) | (1U << (1)),
(1U << (4 + 16)) | (1U << (3)) | (1U << (2)) | (1U << (1)),
(1U << (4)) | (1U << (3)) | (1U << (2)) | (1U << (1))
};
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/**
* @brief DMA Linked-list RGB_queue configuration
* @param None
* @retval None
*/
HAL_StatusTypeDef MX_RGB_queue_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 = DMA_REQUEST_SW;
pNodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
pNodeConfig.Init.Direction = DMA_MEMORY_TO_MEMORY;
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;
pNodeConfig.TriggerConfig.TriggerMode = DMA_TRIGM_SINGLE_BURST_TRANSFER ;
pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_RISING;
pNodeConfig.TriggerConfig.TriggerSelection = GPDMA2_TRIGGER_TIM12_TRGO;
pNodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
pNodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
pNodeConfig.SrcAddress = (uint32_t)&BsrrBuf1[0];
pNodeConfig.DstAddress = ((uint32_t)&(GPIOC->BSRR));
pNodeConfig.DataSize = 16384U;
/* Build RGB_transfer1 Node */
ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &RGB_transfer1);
/* Insert RGB_transfer1 to Queue */
ret |= HAL_DMAEx_List_InsertNode_Tail(&RGB_queue, &RGB_transfer1);
/* Set node configuration ################################################*/
pNodeConfig.SrcAddress = (uint32_t)&BsrrBuf2[0];
/* Build RGB_transfer2 Node */
ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &RGB_transfer2);
/* Insert RGB_transfer2 to Queue */
ret |= HAL_DMAEx_List_InsertNode_Tail(&RGB_queue, &RGB_transfer2);
ret |= HAL_DMAEx_List_SetCircularModeConfig(&RGB_queue, &RGB_transfer1);
return ret;
}
/**
* @brief DMA Linked-list ACtransQ configuration
* @param None
* @retval None
*/
HAL_StatusTypeDef MX_ACtransQ_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 = DMA_REQUEST_SW;
pNodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
pNodeConfig.Init.Direction = DMA_MEMORY_TO_MEMORY;
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;
pNodeConfig.TriggerConfig.TriggerMode = DMA_TRIGM_SINGLE_BURST_TRANSFER ;
pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_RISING;
pNodeConfig.TriggerConfig.TriggerSelection = GPDMA1_TRIGGER_TIM2_TRGO;
pNodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
pNodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
pNodeConfig.SrcAddress = (uint32_t)&ACtransferLUT[0];
pNodeConfig.DstAddress = ((uint32_t)&(GPIOB->BSRR));
pNodeConfig.DataSize = 64U;
/* Build ACTrans Node */
ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &ACTrans);
/* Insert ACTrans to Queue */
ret |= HAL_DMAEx_List_InsertNode_Tail(&ACtransQ, &ACTrans);
ret |= HAL_DMAEx_List_SetCircularMode(&ACtransQ);
return ret;
}
