2025-02-19 06:38 AM - edited 2025-02-19 08: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.