STM32H753ZI UART TX DMA
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-02-12 9:29 PM
Hi,
I am using STM32H753ZI nucleo board, developing with Keil IDE. I am using UART RX and TX DMA. I want to check if there is a possibility of corruption of UART data while transmitting with DMA Tx.
The sending device will send 8-byte defined command to STM32H753ZI and then STM after performing the required operation will send response in a 8-byte defined format.
My system works very well, but sometimes the UART data which is transmitted back to sending device in response to some specific command is seen to be corrupt or any random data other than defined protocol or packet message data
Also, it is seen that the data is sent to sending device without any command which the code never does (that data are mostly 0 0 0 0 0 0 0 0 all 0's of 8 byte).
I am doubting something has gone bad on USB to UART TTL module or USB hub or something in hardware. But just wanted to be sure if there is nothing missed from firmware side for DMA Tx with respect to corruption since DMA uses memory to store data.
Anything to be taken care with respect to memory assignment (stack and heap) in startup file for this?
- Labels:
-
STM32H7 Series
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-02-12 9:41 PM
How often are you receiving data? Are you possibly receiving data while transmitting?
Show relevant code
TimerCallback tutorial! | UART and DMA Idle tutorial!
If you find my solution useful, please click the Accept as Solution so others see the solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-02-12 11:58 PM
How often are you receiving data?
The data is not receiving very often. It is based on operations to perform. It is an 8-byte command based on which certain operations are performed and then response is sent back in an 8-byte format.
In an operation, if you want to see the timing difference between the command sent from sending device:
1 sec, 2.5 min, 2 min 20 sec, 5 min 20 sec, 2 min, 1 sec,14 sec,3 sec 2.5 min etc
Are you possibly receiving data while transmitting?
No, I don't think. But let me know if any check required to be added in code. Attaching UART code file.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-02-13 6:03 AM - edited ‎2025-02-13 6:04 AM
> My system works very well, but sometimes the UART data which is transmitted back to sending device in response to some specific command is seen to be corrupt or any random data other than defined protocol or packet message data
Almost certainly this is a code bug, not a hardware bug.
Is the DMA buffer valid during the transfer? It should be in global memory, not on the stack.
Edit: show your calls to sendUart1Data and surrounding context. That's likely where the bug is.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-02-16 12:33 PM
Is the DMA buffer valid during the transfer?
How can we know? The status message which is sent is in different global variable at different instances of particular device operation, but it is in global variable and pointer to the variable is hence passed on from task to task and then through function call.
Attached file contains the call from sendUart1Data and also its surrounding flow and call flow.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-02-17 9:37 PM
Hi,
Any findings on the issue
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-02-18 12:53 AM
@A3 wrote:Hi,
Any findings on the issue
You've shown your functions but you haven't shown any code on how you parse the command and transmit back.
TimerCallback tutorial! | UART and DMA Idle tutorial!
If you find my solution useful, please click the Accept as Solution so others see the solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-02-18 6:14 AM
Here's your function calls:
handleMsg -> sendHostData -> SendData -> sendUart1Data -> HAL_UART_Transmit_DMA
Just a bunch of functions passing pointers to each other. But you haven't shown the call to handleMsg, so who knows.
My guess is the buffer is being overwritten after it is sent, either because it is on the stack or because something else changes it before the transfer is done.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-04-23 6:02 AM
Hi,
As per analysis, all the command's response was updated on global buffer. But for few commands, the response was sent through general sendStatus() and sendError() function (refer last functions in the earlier attached UART_DMA.txt file). Pointer to the global variable was passed to this function as an argument. Here, this function copies the data into its local variable and then further for transmission, pointer to this local variable is passed to task and its subsequent functions. Will check by making this variable as static.
But there is one more issue in addition to what all explained in this POST start description. The issue is in response to the command, STM sends response, but sometimes there is no response at all. Looks like Tx DMA got stucked. Only after STM restart, it recovers. I am doubting below errata sheet issue:
Can you explain how to recover from this issue using HAL functions.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-04-23 9:13 AM
Use the </> to show your code. That way it is formatted for easier reading
/**
* @brief UART MSP Initialization
* This function configures the hardware resources used in this example:
* - Peripheral's clock enable
* - Peripheral's GPIO Configuration
* - DMA configuration for transmission request by peripheral
* - NVIC configuration for DMA interrupt request enable
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
static DMA_HandleTypeDef hdma_tx;
static DMA_HandleTypeDef hdma_rx;
GPIO_InitTypeDef GPIO_InitStruct;
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* Enable GPIO TX/RX clock */
USARTx_TX_GPIO_CLK_ENABLE();
USARTx_RX_GPIO_CLK_ENABLE();
/* Enable USARTx clock */
USARTx_CLK_ENABLE();
/* Enable DMA clock */
DMAx_CLK_ENABLE();
/*##-2- Configure peripheral GPIO ##########################################*/
/* UART TX GPIO pin configuration */
GPIO_InitStruct.Pin = USARTx_TX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = USARTx_TX_AF;
HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);
/* UART RX GPIO pin configuration */
GPIO_InitStruct.Pin = USARTx_RX_PIN;
GPIO_InitStruct.Alternate = USARTx_RX_AF;
HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);
/*##-3- Configure the DMA ##################################################*/
/* Configure the DMA handler for Transmission process */
hdma_tx.Instance = USARTx_TX_DMA_STREAM;
hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_tx.Init.Mode = DMA_NORMAL;
hdma_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_tx.Init.MemBurst = DMA_MBURST_INC4;
hdma_tx.Init.PeriphBurst = DMA_PBURST_INC4;
hdma_tx.Init.Request = USARTx_TX_DMA_REQUEST;
HAL_DMA_Init(&hdma_tx);
/* Associate the initialized DMA handle to the UART handle */
__HAL_LINKDMA(huart, hdmatx, hdma_tx);
/* Configure the DMA handler for reception process */
hdma_rx.Instance = USARTx_RX_DMA_STREAM;
hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_rx.Init.Mode = DMA_CIRCULAR;
hdma_rx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_rx.Init.MemBurst = DMA_MBURST_INC4;
hdma_rx.Init.PeriphBurst = DMA_PBURST_INC4;
hdma_rx.Init.Request = USARTx_RX_DMA_REQUEST;
HAL_DMA_Init(&hdma_rx);
/* Associate the initialized DMA handle to the the UART handle */
__HAL_LINKDMA(huart, hdmarx, hdma_rx);
/*##-4- Configure the NVIC for DMA #########################################*/
/* NVIC configuration for DMA transfer complete interrupt (USART6_TX) */
HAL_NVIC_SetPriority(USARTx_DMA_TX_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(USARTx_DMA_TX_IRQn);
/* NVIC configuration for DMA transfer complete interrupt (USART6_RX) */
HAL_NVIC_SetPriority(USARTx_DMA_RX_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USARTx_DMA_RX_IRQn);
/* NVIC for USART, to catch the TX complete */
HAL_NVIC_SetPriority(USARTx_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(USARTx_IRQn);
}
/**
* @brief UART MSP De-Initialization
* This function frees the hardware resources used in this example:
* - Disable the Peripheral's clock
* - Revert GPIO, DMA and NVIC configuration to their default state
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)
{
/*##-1- Reset peripherals ##################################################*/
USARTx_FORCE_RESET();
USARTx_RELEASE_RESET();
/*##-2- Disable peripherals and GPIO Clocks #################################*/
/* Configure USARTx Tx as alternate function */
HAL_GPIO_DeInit(USARTx_TX_GPIO_PORT, USARTx_TX_PIN);
/* Configure USARTx Rx as alternate function */
HAL_GPIO_DeInit(USARTx_RX_GPIO_PORT, USARTx_RX_PIN);
/*##-3- Disable the DMA #####################################################*/
/* De-Initialize the DMA channel associated to reception process */
if(huart->hdmarx != 0)
{
HAL_DMA_DeInit(huart->hdmarx);
}
/* De-Initialize the DMA channel associated to transmission process */
if(huart->hdmatx != 0)
{
HAL_DMA_DeInit(huart->hdmatx);
}
/*##-4- Disable the NVIC for DMA ###########################################*/
HAL_NVIC_DisableIRQ(USARTx_DMA_TX_IRQn);
HAL_NVIC_DisableIRQ(USARTx_DMA_RX_IRQn);
}
/**
* @brief This function handles DMA interrupt request.
* @param None
* @retval None
* @Note This function is redefined in "main.h" and related to DMA
* used for USART data transmission
*/
void USARTx_DMA_RX_IRQHandler(void)
{
HAL_DMA_IRQHandler(UartHandle.hdmarx);
}
/**
* @brief This function handles DMA interrupt request.
* @param None
* @retval None
* @Note This function is redefined in "main.h" and related to DMA
* used for USART data reception
*/
void USARTx_DMA_TX_IRQHandler(void)
{
HAL_DMA_IRQHandler(UartHandle.hdmatx);
}
/**
* @brief This function handles UART interrupt request.
* @param None
* @retval None
* @Note This function is redefined in "main.h" and related to DMA
* used for USART data transmission
*/
void USARTx_IRQHandler(void)
{
HAL_UART_IRQHandler(&UartHandle);
}
/**
******************************************************************************
* @file uart.c
* @author
* @brief This file contains all the UART communication functions
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <stdarg.h>
#include <string.h>
#include "uart.h"
#include "event.h"
#include "taskConfig.h"
#include "platform.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* UART handler declaration */
UART_HandleTypeDef UartHandle;
static uart_Info_t uart1_Info;
/* Buffer used for reception */
uint8_t aRxBuffer[RXBUFFERSIZE];
/* Private functions ---------------------------------------------------------*/
/**
* @brief Initialize UART 1. This is configured for the platform logger.
* @param
* @retval None
*/
void Uart1Init(void)
{
uart1_Info.uart_state = E_uart_State_Init;
/*##-1- Configure the UART peripheral ######################################*/
/* Put the USART peripheral in the Asynchronous mode (UART Mode) */
/* UART configured as follows:
- Word Length = 8 Bits
- Stop Bit = One Stop bit
- Parity = none parity
- BaudRate = 230400 baud
- Hardware flow control disabled (RTS and CTS signals) */
UartHandle.Instance = LOGGER_USART;
UartHandle.Init.BaudRate = 230400;
UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
UartHandle.Init.StopBits = UART_STOPBITS_1;
UartHandle.Init.Parity = UART_PARITY_NONE;
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
UartHandle.Init.Mode = UART_MODE_TX_RX;
UartHandle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if(HAL_UART_DeInit(&UartHandle) != HAL_OK)
{
//TODO: error handler
}
if (HAL_UART_Init(&UartHandle) != HAL_OK)
{
/* Initialization Error */
//TODO: error handler
}
if(HAL_UARTEx_ReceiveToIdle_DMA(&UartHandle, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)
{
}
uart1_Info.uart_state = E_uart_State_Ready;
}
/**
* @brief Send Uart1 Data
* @param buff: uint8_t buffer pointer
* @param length: uint8_t data length
* @retval None
*/
void sendUart1Data(uint8_t * buff, uint8_t length)
{
uart1_Info.uart_state = E_uart_State_Busy;
HAL_UART_Transmit_DMA(&UartHandle, (uint8_t *)buff, length);
HAL_Delay(1u);
uart1_Info.uart_state = E_uart_State_Ready;
}
/**
* @brief Tx Transfer completed callback
* @param huart: UART handle.
* @note This example shows a simple way to report end of DMA Tx transfer, and
* you can add your own implementation.
* @retval None
*/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
/* Transfer in transmission process is correct */
if(huart->Instance == USART1)
{
/* do nothing */
}
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
event_t event;
event_Initialize(&event);
if(huart->Instance == USART1)
{
if (HAL_UARTEx_GetRxEventType(huart) == HAL_UART_RXEVENT_TC)
{
if (aRxBuffer[0]==0x01)
{
//UartPuts("TCsize: %d\r\n",Size);
memcpy(&event,&aRxBuffer,sizeof(event_t));
//send message to communication task
}
else
{
memset(&aRxBuffer,0x00,sizeof(aRxBuffer));
HAL_UART_AbortReceive(huart);
HAL_UARTEx_ReceiveToIdle_DMA(&UartHandle, (uint8_t *)aRxBuffer, RXBUFFERSIZE);
}
}
else if (HAL_UARTEx_GetRxEventType(huart) == HAL_UART_RXEVENT_IDLE)
{
//UartPuts("Idlesize: %d\r\n",Size);
memset(&aRxBuffer,0x00,sizeof(aRxBuffer));
HAL_UART_AbortReceive(huart);
HAL_UARTEx_ReceiveToIdle_DMA(&UartHandle, (uint8_t *)aRxBuffer, RXBUFFERSIZE);
}
else
{
//UartPuts("HTsize: %d\r\n",Size);
}
}
}
/**
* @brief UART error callback
* @param UartHandle: UART handle
* @note This callback is triggered when a UART error is observed
* @retval None
*/
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
uart1_Info.errorCounter ++;
//UartPuts("ErrorHandler: DMA stop and restart\r\n");
memset(&aRxBuffer,0x00,sizeof(aRxBuffer));
HAL_UART_DMAStop(huart);
HAL_UARTEx_ReceiveToIdle_DMA(huart, (uint8_t *)aRxBuffer, RXBUFFERSIZE);
}
}
/****END OF FILE****/
/**
* @brief send data.
* @param buff: Pointer to transmit buffer.
* @param length: Length of tx data.
* @retval None
*/
void SendData(uint8_t * buff, uint8_t length)
{
/* Send data to Logger UART */
sendUart1Data(buff, length);
}
/**
* @brief Send Host Data.
* @param buff: uint8_t buffer pointer
* @param length: uint8_t length of the data
* @retval None
*/
void sendHostData(uint8_t * buff, uint8_t length)
{
SendData((uint8_t *)buff, length);
}
/*******Below from logger task*****/
/**
* @brief Handle messages
* @param event: message pointer
* @retval bool
*/
static bool handleMsg(const event_t *event)
{
bool ret = true;
switch (event->msgID)
{
/*******Send command response i.e. status or error through UART******/
case A:
case B:
case C:
case D:
{
sendHostData((uint8_t *)event,MESSAGE_SIZE);
}
break;
default:
break;
}
return ret;
}
/*******Below from communication task*****/
/**
* @brief Handle messages
* @param event: message pointer
* @retval bool
*/
static bool handleMsg(event_t *event)
{
bool ret = true;
if (event->msgType == E_msg_typ_Cmd)
{
switch (event->msgID)
{
case A:
case B:
case C:
case D:
{
/*******Send command to control task for executing******/
}
break;
default:
//UartPuts("Default\r\n");
break;
}
}
else if ((event->msgType == E_msg_typ_Status) || (event->msgType == E_msg_typ_Error))
{
switch (event->msgID)
{
case A:
case B:
case C:
case D:
{
/*******Send command response i.e. status or error response to logger task which will send it through UART******/
}
break;
default:
break;
}
}
return ret;
}
/****Below shown one of the instance where status or error response is sent back from control task to communication task*****/
sendStatusResponse(&s_Context[E_ModuleX]);
where, s_Context is the global structure of type sContext
void sendStatusResponse(sContext* context)
{
event_t outEvent;
event_Initialize(&outEvent);
memcpy(&outEvent,&(context->cmd),sizeof(event_t));
outEvent.msgType = E_msg_typ_Status;
switch (outEvent.msgID)
{
case A:
case B:
case C:
case D:
{
// update status field in outEvent
}
break;
default:
break;
}
/*******Send command response i.e. status or error response to communication task which will send it through UART******/
}
You still haven't shown how you're parsing the aRxBuffer data and the code sending particular data back. Are you using any of the aRxBuffer when sending data back?
You have 2 handleMsg in your code.
As @TDK stated, you have several functions passing pointers. Why not just directly call sendUart1Data instead? Do you have other tasks that periodically transmit data besides you responding to the receive packets?
Show what you're doing in sendUart1Data as that may clear things up in why you're receiving 0's.
/**
* @brief send data.
* @param buff: Pointer to transmit buffer.
* @param length: Length of tx data.
* @retval None
*/
void SendData(uint8_t * buff, uint8_t length)
{
/* Send data to Logger UART */
sendUart1Data(buff, length);
}
/**
* @brief Send Host Data.
* @param buff: uint8_t buffer pointer
* @param length: uint8_t length of the data
* @retval None
*/
void sendHostData(uint8_t * buff, uint8_t length)
{
SendData((uint8_t *)buff, length);
}
TimerCallback tutorial! | UART and DMA Idle tutorial!
If you find my solution useful, please click the Accept as Solution so others see the solution.
