2025-02-19 6:38 AM - edited 2025-02-19 8:41 AM
Hi,
I want to setup USART3 TX transfers using GPDMA, however, without success.
For such purpose I also followed this article: https://community.st.com/t5/stm32-mcus/how-to-configure-the-gpdma/ta-p/49412
STM32CubeMX setup is:
USART TX DMA Chan
The code for usart is the following:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file usart.h
* @brief This file contains all the function prototypes for
* the usart.c file
******************************************************************************
* @attention
*
* Copyright (c) 2025 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 */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USART_H__
#define __USART_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
#include <string.h>
/* USER CODE END Includes */
/* USER CODE BEGIN Private defines */
#define DBG_USART
#define VCP_USART (USART_TypeDef *) USART3
#ifdef DBG_USART
#ifndef VCP_USART
#error "VCP_USART must be defined"
#endif
#endif
#define USART_MAX_BUFF_SIZE 32
#define USART3_TX_BSY_B 0
#define USART3_RX_BSY_B 1
#define USART3_TX_BSY_M (1 << USART3_TX_BSY_B)
#define USART3_RX_BSY_M (1 << USART3_RX_BSY_B)
/* USER CODE END Private defines */
void MX_USART3_UART_Init(void);
/* USER CODE BEGIN Prototypes */
extern uint8_t usartTxBuff[USART_MAX_BUFF_SIZE];
extern uint8_t usartRxBuff[USART_MAX_BUFF_SIZE];
extern uint8_t usart3StFlag;
void USART_Printf (char *p_str, uint32_t p_len);
void USART_DMA_Printf (char *p_str, uint32_t p_len);
void USART_Tx(USART_TypeDef *USARTx, uint32_t p_char);
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /* __USART_H__ */
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file usart.c
* @brief This file provides code for the configuration
* of the USART instances.
******************************************************************************
* @attention
*
* Copyright (c) 2025 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 "usart.h"
/* USER CODE BEGIN 0 */
uint8_t usartTxBuff[USART_MAX_BUFF_SIZE];
uint8_t usartRxBuff[USART_MAX_BUFF_SIZE];
uint8_t usart3StFlag;
/* USER CODE END 0 */
/* USART3 init function */
void MX_USART3_UART_Init(void)
{
/* USER CODE BEGIN USART3_Init 0 */
/* USER CODE END USART3_Init 0 */
LL_USART_InitTypeDef USART_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
LL_DMA_InitTypeDef DMA_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the peripherals clock
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;
PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
/* Peripheral clock enable */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART3);
LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOD);
/**USART3 GPIO Configuration
PD8 ------> USART3_TX
PD9 ------> USART3_RX
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_8|LL_GPIO_PIN_9;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_7;
LL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* USART3 DMA Init */
/* GPDMA1_REQUEST_USART3_TX Init */
DMA_InitStruct.SrcAddress = 0x00000000U;
DMA_InitStruct.DestAddress = 0x00000000U;
DMA_InitStruct.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
DMA_InitStruct.BlkHWRequest = LL_DMA_HWREQUEST_SINGLEBURST;
DMA_InitStruct.DataAlignment = LL_DMA_DATA_ALIGN_ZEROPADD;
DMA_InitStruct.SrcBurstLength = 1;
DMA_InitStruct.DestBurstLength = 1;
DMA_InitStruct.SrcDataWidth = LL_DMA_SRC_DATAWIDTH_BYTE;
DMA_InitStruct.DestDataWidth = LL_DMA_DEST_DATAWIDTH_BYTE;
DMA_InitStruct.SrcIncMode = LL_DMA_SRC_FIXED;
DMA_InitStruct.DestIncMode = LL_DMA_DEST_FIXED;
DMA_InitStruct.Priority = LL_DMA_LOW_PRIORITY_LOW_WEIGHT;
DMA_InitStruct.BlkDataLength = 0x00000000U;
DMA_InitStruct.TriggerMode = LL_DMA_TRIGM_BLK_TRANSFER;
DMA_InitStruct.TriggerPolarity = LL_DMA_TRIG_POLARITY_MASKED;
DMA_InitStruct.TriggerSelection = 0x00000000U;
DMA_InitStruct.Request = LL_GPDMA1_REQUEST_USART3_TX;
DMA_InitStruct.TransferEventMode = LL_DMA_TCEM_BLK_TRANSFER;
DMA_InitStruct.SrcAllocatedPort = LL_DMA_SRC_ALLOCATED_PORT0;
DMA_InitStruct.DestAllocatedPort = LL_DMA_DEST_ALLOCATED_PORT0;
DMA_InitStruct.LinkAllocatedPort = LL_DMA_LINK_ALLOCATED_PORT1;
DMA_InitStruct.LinkStepMode = LL_DMA_LSM_FULL_EXECUTION;
DMA_InitStruct.LinkedListBaseAddr = 0x00000000U;
DMA_InitStruct.LinkedListAddrOffset = 0x00000000U;
LL_DMA_Init(GPDMA1, LL_DMA_CHANNEL_2, &DMA_InitStruct);
/* USER CODE BEGIN USART3_Init 1 */
/* USER CODE END USART3_Init 1 */
USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
USART_InitStruct.BaudRate = 115200;
USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
USART_InitStruct.Parity = LL_USART_PARITY_NONE;
USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
LL_USART_Init(USART3, &USART_InitStruct);
LL_USART_SetTXFIFOThreshold(USART3, LL_USART_FIFOTHRESHOLD_1_8);
LL_USART_SetRXFIFOThreshold(USART3, LL_USART_FIFOTHRESHOLD_1_8);
LL_USART_DisableFIFO(USART3);
LL_USART_ConfigAsyncMode(USART3);
LL_USART_Enable(USART3);
/* USER CODE BEGIN USART3_Init 2 */
// LL_USART_EnableIT_TC(USART3);
// LL_USART_EnableIT_RXNE(USART3);
usart3StFlag = 0;
memset(usartTxBuff, 0, sizeof(usartTxBuff));
memset(usartRxBuff, 0, sizeof(usartTxBuff));
/* USER CODE END USART3_Init 2 */
}
/* USER CODE BEGIN 1 */
void USART_Printf (char *p_str, uint32_t p_len) {
USART_TypeDef *usart_dbg = VCP_USART;
LL_USART_EnableIT_TC(usart_dbg);
for(uint32_t i = 0; i < p_len; i++) {
USART_Tx(usart_dbg, p_str[i]);
}
USART_Tx(usart_dbg, '\r');
USART_Tx(usart_dbg, '\n');
}
void USART_DMA_Printf (char *p_str, uint32_t p_len) {
USART_TypeDef *usart_dbg = VCP_USART;
uint32_t txLen = 0;
if (p_len >= USART_MAX_BUFF_SIZE) {
return;
}
txLen = p_len + 2;
for (uint8_t i = 0; i < p_len; i++) {
usartTxBuff[i] = p_str[i];
}
usartTxBuff[p_len] = '\r';
usartTxBuff[p_len + 1] = '\n';
LL_USART_ClearFlag_TC(usart_dbg);
LL_USART_ClearFlag_TXFE(usart_dbg);
LL_USART_ClearFlag_TCBGT(usart_dbg);
LL_DMA_DisableChannel(GPDMA1, LL_DMA_CHANNEL_2);
// 1. Write the USART_TDR register address in the DMA control register to configure it as
// the destination of the transfer. The data is moved to this address from memory after
// each TXE (or TXFNF if FIFO mode is enabled) event.
LL_DMA_SetDestAddress(GPDMA1, LL_DMA_CHANNEL_2, LL_USART_DMA_GetRegAddr(usart_dbg, LL_USART_DMA_REG_DATA_TRANSMIT));
// 2. Write the memory address in the DMA control register to configure it as the source of
// the transfer. The data is loaded into the USART_TDR register from this memory area
// after each TXE (or TXFNF if FIFO mode is enabled) event.
LL_DMA_SetSrcAddress(GPDMA1, LL_DMA_CHANNEL_2, (uint32_t) &usartTxBuff[0]);
// 3. Configure the total number of bytes to be transferred to the DMA control register.
LL_DMA_SetSrcBurstLength(GPDMA1, LL_DMA_CHANNEL_2, txLen);
LL_DMA_SetSrcDataWidth(GPDMA1, LL_DMA_CHANNEL_2, sizeof(uint8_t));
LL_DMA_SetDestBurstLength(GPDMA1, LL_DMA_CHANNEL_2, txLen);
LL_DMA_SetDestDataWidth(GPDMA1, LL_DMA_CHANNEL_2, sizeof(uint8_t));
// 4. Configure the channel priority in the DMA register
LL_DMA_SetChannelPriorityLevel(GPDMA1, LL_DMA_CHANNEL_2, LL_DMA_HIGH_PRIORITY);
// 5. Configure DMA interrupt generation after half/ full transfer as required by the
// application.
LL_DMA_EnableIT_TC(GPDMA1, LL_DMA_CHANNEL_2);
// 6. Clear the TC flag in the USART_ISR register by setting the TCCF bit in the
// USART_ICR register.
LL_USART_ClearFlag_TC(usart_dbg);
// 7. Activate the channel in the DMA register
LL_DMA_EnableChannel(GPDMA1, LL_DMA_CHANNEL_2);
LL_USART_EnableDMAReq_TX(usart_dbg);
// usart3StFlag |= USART3_TX_BSY_M;
}
void USART_Tx(USART_TypeDef *USARTx, uint32_t p_char) {
LL_USART_TransmitData8(USARTx, p_char);
while(!LL_USART_IsActiveFlag_TC(USARTx))
;
}
/* USER CODE END 1 *//**
* @brief This function handles GPDMA1 Channel 2 global interrupt.
*/
void GPDMA1_Channel2_IRQHandler(void)
{
/* USER CODE BEGIN GPDMA1_Channel2_IRQn 0 */
if (LL_DMA_IsActiveFlag_TO(GPDMA1, LL_DMA_CHANNEL_2)) {
LL_DMA_ClearFlag_TO(GPDMA1, LL_DMA_CHANNEL_2);
}
if (LL_DMA_IsActiveFlag_SUSP(GPDMA1, LL_DMA_CHANNEL_2)) {
LL_DMA_ClearFlag_SUSP(GPDMA1, LL_DMA_CHANNEL_2);
}
if (LL_DMA_IsActiveFlag_USE(GPDMA1, LL_DMA_CHANNEL_2)) {
LL_DMA_ClearFlag_USE(GPDMA1, LL_DMA_CHANNEL_2);
}
if (LL_DMA_IsActiveFlag_ULE(GPDMA1, LL_DMA_CHANNEL_2)) {
LL_DMA_ClearFlag_ULE(GPDMA1, LL_DMA_CHANNEL_2);
}
if (LL_DMA_IsActiveFlag_DTE(GPDMA1, LL_DMA_CHANNEL_2)) {
LL_DMA_ClearFlag_DTE(GPDMA1, LL_DMA_CHANNEL_2);
}
if (LL_DMA_IsActiveFlag_HT(GPDMA1, LL_DMA_CHANNEL_2)) {
LL_DMA_ClearFlag_HT(GPDMA1, LL_DMA_CHANNEL_2);
}
if (LL_DMA_IsActiveFlag_TC(GPDMA1, LL_DMA_CHANNEL_2)) {
LL_DMA_ClearFlag_TC(GPDMA1, LL_DMA_CHANNEL_2);
}
if (LL_DMA_IsActiveFlag_IDLE(GPDMA1, LL_DMA_CHANNEL_2)) {
// LL_DMA_ClearFlag_IDLE(GPDMA1, LL_DMA_CHANNEL_2);
}
if (LL_DMA_IsActiveFlag_MIS(GPDMA1, LL_DMA_CHANNEL_2)) {
// LL_DMA_ClearFlag_MIS(GPDMA1, LL_DMA_CHANNEL_2);
}
/* USER CODE END GPDMA1_Channel2_IRQn 0 */
/* USER CODE BEGIN GPDMA1_Channel2_IRQn 1 */
/* USER CODE END GPDMA1_Channel2_IRQn 1 */
}
If I use the USART transmission without DMA, it works fine (using USART_Printf function).
But using the DMA nothing is transmitted (using USART_DMA_Printf function), and neither IRQ is generated.
So what is wrong in this setup?
Thanks,
s.
2025-02-26 7:53 AM
Hi @simo zz ,
Try to start with an example ready to use available examples in STM32CubeH7RS like STM32CubeH7RS/Projects/NUCLEO-H7S3L8/Examples/USART/USART_SlaveMode_DMA.
You can even take the .ioc file and update it depending on your application case.
-Amel
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
We’re moving the ST Community to a new platform to give you a better and more reliable community experience.