Skip to main content
Graduate
August 22, 2024
Question

Problem with UART Idle Line DMA Reception on STM32H563 Microcontroller

  • August 22, 2024
  • 2 replies
  • 1475 views

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!

    This topic has been closed for replies.

    2 replies

    Explorer
    August 26, 2024

    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.

    Graduate II
    August 26, 2024

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

     

     

    __HAL_DMA_DISABLE_IT(hdma, DMA_IT_HT);

     

     

    Graduate
    September 3, 2024

    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.