cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7S3L8 LL DMA USART TX transfer

simo zz
Senior

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

simozz_0-1739974981911.png

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.

0 REPLIES 0