cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with UART communication functions.

MMust.5
Senior II

All these functions have one problem, let's say in this function HAL_UART_Receive_IT(&huart4, data,5);

the third parameter is the number of transmitted characters.

If you enter more or less characters in the COM port of the terminal than specified in the HAL_UART_Receive_IT function, then various reception problems begin. Either there is no data reception or the function works several times and combines different data transfers into one array.

My code may not be entirely correct, but it works and shows what the problem is.

//main.c

#include <stdio.h>

extern uint8_t data[5];

 void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)

{

printf("%s\n", data);

}

while (1)

{

HAL_UARTEx_ReceiveToIdle_IT (&huart4, data,5);

}

//stm32f4xx_it.c

uint8_t data[5]={0};

void UART4_IRQHandler(void)

{

 HAL_UARTEx_ReceiveToIdle_IT (&huart4, data,5);

 HAL_UART_IRQHandler(&huart4);

}

Enter less than 5 characters or more than 5 characters into the COM port terminal.

1 ACCEPTED SOLUTION

Accepted Solutions
S.Ma
Principal

Yeah, well documented limitation, the simplest example that shows the HAL_UART limitation is implementing a console. Go LL for UART.

2 options : Byte by byte interrupt, or DMA cycling through a big RAM buffer and check its content periodically. Choose between latency and interrupt frequency

View solution in original post

2 REPLIES 2
S.Ma
Principal

Yeah, well documented limitation, the simplest example that shows the HAL_UART limitation is implementing a console. Go LL for UART.

2 options : Byte by byte interrupt, or DMA cycling through a big RAM buffer and check its content periodically. Choose between latency and interrupt frequency

Karl Yamashita
Lead II

Yes the problem is with your code.

1. You have HAL_UARTEx_ReceiveToIdle_IT before HAL_UART_IRQHandler, which is the wrong place. You need to call it after HAL_UART_IRQHandler, or the best place would be in HAL_UARTEx_RxEventCallback.
2. You keep calling HAL_UARTEx_ReceiveToIdle_IT in a while loop which is bad coding. It may work because HAL will be busy when receiving data so the call to HAL_UARTEx_ReceiveToIdle_IT will return HAL_BUSY so it's ignored for the time being. You only need to call it after you've received an interrupt.

You have to understand how HAL_UARTEx_RxEventCallback interrupts works. It will interrupt on half callback of half of the data you are expecting or after idle. Just double the data size of the largest data packet you know you will be receiving. So if you know you are only getting 5 bytes per receive then set to receive 10 bytes or more.

Below code has a buffer of 128 bytes which is the largest size of packet that i'll ever expect. I set to receive 256 bytes so I know if I do get 128 bytes it'll interrupt on half callback. If it's less than 128 bytes, 1 byte or 3 bytes and it idles, i still get HAL_UARTEx_RxEventCallback interrupt.

I also show how to make use of the HAL status and if it returns HAL_BUSY I set a flag so I can re-enable again for Rx or Tx. 

This very basic buffer. If you are expecting lots of data packets then a message queue needs to be implemented.

 

 

/*
 * PollingRoutine.c
 *
 *  Created on: Jun 16, 2023
 *      Author: karl.yama**bleep**a
 */


#include "main.h"


extern UART_HandleTypeDef huart2;


#define UART_RECEIVE_SIZE 128
#define UART_BUFFER_SIZE 128

typedef struct
{
	uint8_t data[UART_BUFFER_SIZE];
	uint32_t size;
	uint32_t msgReadyFlag;
	uint32_t errorFlag;
}UartStruct;

UartStruct uart2Rx = {0};
UartStruct uart2Tx = {0};

// called before main while loop
void PollingInit(void)
{
	UART_RxEn(); // init interrupt
}

// called from inside main while loop
void PollingRoutine(void)
{
	UART_CheckErrorFlag();
	UART_Received();
	UART_Send();
}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	uart2Rx.size = Size;
	uart2Rx.msgReadyFlag = 1;
	UART_RxEn(); // enable receive interrupt again
}

// enable received
void UART_RxEn(void)
{
	if(HAL_UARTEx_ReceiveToIdle_IT (&huart2, uart2Rx.data, (UART_RECEIVE_SIZE << 1)) != HAL_OK)
	{
		uart2Rx.errorFlag = 1;
	}
}

// check for error flag and try to enable again
void UART_CheckErrorFlag(void)
{
	if(uart2Rx.errorFlag)
	{
		uart2Rx.errorFlag = 0;
		UART_RxEn(); // try to enable again
	}
}

// check for received data, copy to transmit buffer
void UART_Received(void)
{
	if(uart2Rx.msgReadyFlag)
	{
		uart2Rx.msgReadyFlag = 0;
		memcpy(uart2Tx.data, uart2Rx.data, uart2Rx.size);
		uart2Tx.size = uart2Rx.size;
		uart2Tx.msgReadyFlag = 1;
	}
}

// check to see if data needs to be sent
void UART_Send(void)
{
	if(uart2Tx.msgReadyFlag)
	{
		if(HAL_UART_Transmit_IT(&huart2, uart2Tx.data, uart2Tx.size) == HAL_OK)
		{
			uart2Tx.msgReadyFlag = 0;
		}
	}
}