cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with UART Idle Line DMA Reception on STM32H563 Microcontroller

mrsthb_qmt
Associate II

I'm working on a project using the STM32H563RIT6 microcontroller where I need to receive data over UART using DMA with idle line detection. The data is sent from a Python script using 'pyserial'. My setup is as follows:

 

typedef enum{
    IDLE,
    SET_FREQUENCY,
    SPI_WRITE,
    SPI_READ,
    SPAM,
    TEST_CONN
} UserCommand_t;

typedef struct{
    UserCommand_t  Command;
    uint8_t        RegAddr;
    uint16_t       WriteData;
    uint32_t       BufferCRC;
} ConfigMsg_t;

#define CRC_SIZE    4U

ConfigMsg_t UART_Rx_MsgBuffer = {0};
ConfigMsg_t ConfigMsg = {0};

uint32_t CRCValue = 0;
uint8_t RxSampleBuffer[20] = {0};

int CallCount = 0;
int SizeBytes = 0;
int CRCFailCount = 0;

int main() {
    
	// Initialization and loop code
	
	printf("RxCount - %u: \t ", RxCount);
	for(int i = 0; i<sizeof(RxSampleBuffer); i++){
	  RxSampleBuffer[i] = 255;
	  printf("%u \t", RxSampleBuffer[i]);
	}
	printf("\n");

	HAL_UARTEx_ReceiveToIdle_DMA(&huart4, (uint8_t*)&UART_Rx_MsgBuffer, sizeof(ConfigMsg_t));
	
	while(1){
		
	}

}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){

	RxCount++;
	SizeBytes = Size;
	CRCValue = HAL_CRC_Calculate(&hcrc, (uint32_t*)&UART_Rx_MsgBuffer, sizeof(ConfigMsg_t) - CRC_SIZE);

	memcpy(&RxSampleBuffer, &UART_Rx_MsgBuffer, sizeof(ConfigMsg_t));

	if(UART_Rx_MsgBuffer.BufferCRC == CRCValue){
		memcpy(&ConfigMsg, &UART_Rx_MsgBuffer, sizeof(ConfigMsg_t));
	}
	else{
		CRCFailCount++;
	}

	printf("RxCount - %u: \t ", RxCount);
	for(int i = 0; i<sizeof(RxSampleBuffer); i++){
	  printf("%u \t", RxSampleBuffer[i]);
	  RxSampleBuffer[i] = 255;
	}
	printf("\n");

	memset(&UART_Rx_MsgBuffer, '\0', sizeof(ConfigMsg_t));
	HAL_UARTEx_ReceiveToIdle_DMA(&huart4, (uint8_t*)&RxSampleBuffer, sizeof(ConfigMsg_t));
}

 

When I transmit {5, 3, 0, 3, 50, 63, 42, 114} from 'pyserial', I get the following output:

RxCount - 0: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255

RxCount - 1: 5 3 0 3 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255

RxCount - 2: 0 0 0 0 0 0 42 114 255 255 255 255 255 255 255 255 255 255 255 255

 

The image below shows the Live Expressions window:

 

Screenshot 2024-08-22 165202.png

 

I'm experiencing an issue where the UART reception seems to split the incoming data into multiple callbacks, even though the data is being sent in a single transmission. Specifically:

  • When I use HAL_UARTEx_ReceiveToIdle_DMA(&huart4, (uint8_t*)&UART_Rx_MsgBuffer, sizeof(UART_Rx_MsgBuffer));, the data appears fragmented, and I observe unexpected zeros in the received buffer.
  • When I increase the size of the receive buffer to (sizeof(UART_Rx_MsgBuffer) + 9), the problem seems to resolve, and the data is received correctly in one callback. However, it only works for the the first reception and doesn't work afterwards.

 

My questions are:

  1. Why is the data being split across multiple callbacks (RxCount = 2) when using the smaller buffer size?
  2. What is causing the extra zeros to appear in the received data?
  3. Why does increasing the buffer size seem to fix the issue, and how can I ensure reliable reception without relying on an oversized buffer?
  4. Shouldn't an early idle line trigger result in the received data being split differently, with no extra zeros?

 

Any insights or suggestions on how to properly configure the UART to avoid this issue would be greatly appreciated!

 

Thank You!

3 REPLIES 3
Metyus
Associate II

I`ve had a similar issue, when it was triggering both HT and FT callback for DMA reception, never filling the buffer properly storing only half of input data. In GPDMA I had adjusted burst size to 1 byte for RX(Increments destination addresses) and TX(Increments source addresses), that solved an issue for me, hopefully it helps.

Karl Yamashita
Lead III

Disable HT callback so that you only get an interrupt for a TC callback

 

 

__HAL_DMA_DISABLE_IT(hdma, DMA_IT_HT);

 

 

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

Hello Karl,

Thank you for your reply. I have tried disabling the interrupt in the following ways and have received varying results, which are listed below:

 

  • Disabling the HT Interrupt before starting the reception:

Code:

 

/* USER CODE BEGIN 2 */ 
 __HAL_DMA_DISABLE_IT(&handle_GPDMA1_Channel0, DMA_IT_HT);

  printf("RxCount - %u: \t ", RxCount);
  for(int i = 0; i<sizeof(RxSampleBuffer); i++){
	  RxSampleBuffer[i] = 255;
	  printf("%u \t", RxSampleBuffer[i]);
  }
  printf("\n");

  HAL_UARTEx_ReceiveToIdle_DMA(&huart4, (uint8_t*)&UART_Rx_MsgBuffer, sizeof(ConfigMsg_t));

/* USER CODE END 2 */

  /* Infinite loop */

 

 

Output:

RxCount - 0: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255

 

On transmitting {5, 3, 0, 3, 50, 63, 42, 114} from 'pyserial' for the first time:

RxCount - 1: 5 3 0 3 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255

RxCount - 2: 0 0 0 0 0 0 42 114 255 255 255 255 255 255 255 255 255 255 255 255

 

On transmitting the same data a second time:

RxCount - 3: 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255

RxCount - 4: 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255

  • Removing 'memset(&UART_Rx_MsgBuffer, '\0', sizeof(ConfigMsg_t))' from HAL_UARTEx_RxEventCallback:

Input:

{5, 3, 0, 3, 50, 63, 42, 114} from 'pyserial'

 

Output:

RxCount - 0: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255

 

First transmission:

RxCount - 1: 5 3 0 3 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255

RxCount - 2: 5 3 0 3 50 63 42 114 255 255 255 255 255 255 255 255 255 255 255 255

 

Second transmission:

RxCount - 3: 5 3 0 3 50 63 42 114 255 255 255 255 255 255 255 255 255 255 255 255

RxCount - 4: 5 3 0 3 50 63 42 114 255 255 255 255 255 255 255 255 255 255 255 255

 

The HAL_UARTEx_RxEventCallback is called twice for every transmission.

  • Disabling the HT Interrupt after starting the reception:

 

Code:

 

  /* USER CODE BEGIN 2 */

  /*
    Code to print initial contents of RxSampleBuffer.
  */

  //HAL_UART_Receive_DMA(&huart4, (uint8_t*)&UART_Rx_MsgBuffer, sizeof(UART_Rx_MsgBuffer));
  HAL_UARTEx_ReceiveToIdle_DMA(&huart4, (uint8_t*)&UART_Rx_MsgBuffer, sizeof(ConfigMsg_t));
  __HAL_DMA_DISABLE_IT(&handle_GPDMA1_Channel0, DMA_IT_HT);
  /* USER CODE END 2 */




// Callback Function:
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){
	RxCount++;
	SizeBytes = Size;
	CRCValue = HAL_CRC_Calculate(&hcrc, (uint32_t*)&UART_Rx_MsgBuffer, sizeof(ConfigMsg_t) - CRC_SIZE);

	memcpy(&RxSampleBuffer, &UART_Rx_MsgBuffer, sizeof(ConfigMsg_t));

	if(UART_Rx_MsgBuffer.BufferCRC == CRCValue){
		memcpy(&ConfigMsg, &UART_Rx_MsgBuffer, sizeof(ConfigMsg_t));
	}
	else{
		HAL_GPIO_TogglePin(LED_USER_GPIO_Port, LED_USER_Pin);
		CRCFailCount++;
	}

	printf("RxCount - %u: \t ", RxCount);
	for(int i = 0; i<sizeof(RxSampleBuffer); i++){
	  printf("%u \t", RxSampleBuffer[i]);
	  RxSampleBuffer[i] = 255;
	}
	printf("\n");

//	memset(&UART_Rx_MsgBuffer, '\0', sizeof(ConfigMsg_t));

	HAL_UARTEx_ReceiveToIdle_DMA(&huart4, (uint8_t*)&RxSampleBuffer, sizeof(ConfigMsg_t));
	__HAL_DMA_DISABLE_IT(&handle_GPDMA1_Channel0, DMA_IT_HT);
}

 

Output:

RxCount - 0: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255

 

First Transmission:

RxCount - 1: 5 3 0 3 50 63 42 114 255 255 255 255 255 255 255 255 255 255 255 255

The data is received correctly for all subsequent transmissions.

 

However, on uncommenting 'memset(&UART_Rx_MsgBuffer, '\0', sizeof(ConfigMsg_t))' in HAL_UARTEx_RxEventCallback, the following data is received:

 

RxCount - 0: 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255

 

First Transmission:

RxCount - 1: 5 3 0 3 50 63 42 114 255 255 255 255 255 255 255 255 255 255 255 255

 

All subsequent transmissions:

RxCount - 2: 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255

 

Although disabling the HT callback works to some extent, it is still unclear to me why the HAL_UARTEx_RxEventCallback is called multiple times, even though the data is being transmitted only once from PySerial. Additionally, I am unable to clear the UART_Rx_MsgBuffer before receiving new data. I would appreciate your advice and clarification on these issues.

 

Thank you.