cancel
Showing results for 
Search instead for 
Did you mean: 

Cannot receive full string on UART Receive -ST32H745 Disco Board

Krautermann
Senior II

I am sending a string "Chicken" word on UART Transmit and I want to check if I can receive the full string in the UART receive. To do that, I have physically connected the TX and RX pin together via a wire.

I am able to check that Transmit is working properly via Hterm (I can see the full string) and also on oscilloscope. But for Receive, I am seeing only the 1st character which is 'C', the rest does not appear.

Can someone help with that? I can't figure out why...

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * USART 1 Bridging test: Using a wire to create physical bridge between TX & RX
  * of Arduino connector D0 & D1 to verify that char received is the same as char sent
  ******************************************************************************
  * Problem:
  * 1. RX Interrupt does not work
  * 2. Only works with char and not string - maybe???
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include <string.h>
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
 
/* USER CODE END Includes */
 
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
 
/* USER CODE END PTD */
 
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
 
#ifndef HSEM_ID_0
#define HSEM_ID_0 (0U) /* HW semaphore 0*/
#endif
/* USER CODE END PD */
 
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
 
/* USER CODE END PM */
 
/* Private variables ---------------------------------------------------------*/
 
UART_HandleTypeDef huart1;
 
/* USER CODE BEGIN PV */
#define LED_YELLOW 	(1<<2)
#define LED_RED		(1<<13)
 
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t TX_String[] = "Chicken";
uint8_t RX_String[10], *RX_String2;
 
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	HAL_UART_Transmit_IT(&huart1, TX_String, sizeof(TX_String));
}
 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	HAL_UART_Receive_IT(&huart1, RX_String, sizeof(RX_String));
}
 
void check_alpha(void)
{
	if(strcmp((char*)RX_String, (char*)TX_String)==0)
	{
		HAL_GPIO_TogglePin(GPIOJ, GPIO_PIN_2);
	}
	else
	{
		HAL_GPIO_TogglePin(GPIOI, GPIO_PIN_13);
	}
}
/* USER CODE END 0 */
 
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
/* USER CODE BEGIN Boot_Mode_Sequence_0 */
  int32_t timeout;
/* USER CODE END Boot_Mode_Sequence_0 */
 
/* USER CODE BEGIN Boot_Mode_Sequence_1 */
  /* Wait until CPU2 boots and enters in stop mode or timeout*/
  timeout = 0xFFFF;
  while((__HAL_RCC_GET_FLAG(RCC_FLAG_D2CKRDY) != RESET) && (timeout-- > 0));
  if ( timeout < 0 )
  {
  Error_Handler();
  }
/* USER CODE END Boot_Mode_Sequence_1 */
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
/* USER CODE BEGIN Boot_Mode_Sequence_2 */
/* When system initialization is finished, Cortex-M7 will release Cortex-M4 by means of
HSEM notification */
/*HW semaphore Clock enable*/
__HAL_RCC_HSEM_CLK_ENABLE();
/*Take HSEM */
HAL_HSEM_FastTake(HSEM_ID_0);
/*Release HSEM in order to notify the CPU2(CM4)*/
HAL_HSEM_Release(HSEM_ID_0,0); // This is making green LED blink
/* wait until CPU2 wakes up from stop mode */
timeout = 0xFFFF;
while((__HAL_RCC_GET_FLAG(RCC_FLAG_D2CKRDY) == RESET) && (timeout-- > 0));
if ( timeout < 0 )
{
Error_Handler();
}
/* USER CODE END Boot_Mode_Sequence_2 */
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	//HAL_UART_Receive(&huart1, RX_String, 11,100);
//	  HAL_UART_Receive(&huart1, RX_String2, 12,1000);
	HAL_UART_Transmit(&huart1, TX_String, sizeof(TX_String),10);
	HAL_UART_Receive(&huart1, RX_String, sizeof(RX_String),10);
 
	//HAL_UART_Receive(&huart1, RX_String2, 7,1000);
	//HAL_UART_TxCpltCallback(&huart1);
////	HAL_UART_RxCpltCallback(&huart1); //RX Interrupt not working!
 
	check_alpha();
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
 
/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_DIRECT_SMPS_SUPPLY);
 
  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
 
  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
 
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
}
 
/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{
 
  /* USER CODE BEGIN USART1_Init 0 */
 
  /* USER CODE END USART1_Init 0 */
 
  /* USER CODE BEGIN USART1_Init 1 */
 
  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */
 
  /* USER CODE END USART1_Init 2 */
 
}
 
/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
 
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOI_CLK_ENABLE();
  __HAL_RCC_GPIOJ_CLK_ENABLE();
 
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOI, GPIO_PIN_13, GPIO_PIN_SET);
 
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_2, GPIO_PIN_SET);
 
  /*Configure GPIO pin : PI13 */
  GPIO_InitStruct.Pin = GPIO_PIN_13;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
 
  /*Configure GPIO pin : PJ2 */
  GPIO_InitStruct.Pin = GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOJ, &GPIO_InitStruct);
 
}
 
#endif /* USE_FULL_ASSERT */

1 ACCEPTED SOLUTION

Accepted Solutions
Guenael Cadier
ST Employee

Hi @Krautermann​ 

2 remarks :

a) it seems your are using HAL_UART_Transmit() to send the TX_String buffer; sizeof(TX_String) will return 7 bytes, so 7 bytes will be sent.

Reception is handled using HAL_UART_Receive(), with expected length is sizeof(RX_String), so 10. Reception could never goes till end, as only 7 bytes will be sent.

b) as HAL_UART_Transmit() and HAL_UART_Receive() are blocking API (blocking mode), it means that transmit will be completed, when reception will start. Unless Fifo mode is enabled, this could not work. Overrun flag will be raised, as received data are not read from UART reception register before new data comes in.

Just for trial purpose, what you could try :

  • use reception in Interrupt mode : HAL_UART_Receive_IT() with the real expected length (for example size of sent data). As Interrupt mode API is not blocking, you could start reception prior transmit :
reception_complete = 0;
        HAL_UART_Receive_IT(&huart1, RX_String, sizeof(TX_String));
	HAL_UART_Transmit(&huart1, TX_String, sizeof(TX_String),10);
 
	/* wait for reception to be completed */
	while (reception_complete ==0) {}
 
	/* at this step, reception is completed, compare Tx and Rx strings */
	check_alpha();
  • In Rx Complete Callback, indicate reception is completed
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	reception_complete = 1;
}
  • Declare your global variable as volatile, as it could be accessed from IRQ side and in main
uint8_t reception_complete = 0;
  • in check_alpha() function, be sure to compare only received data. Might rather use strncmp with size equals to size of transmitted and received buffers

This should allow to implement loop between TX and Rx pins on your uart.

Hope this helps.

View solution in original post

9 REPLIES 9
Guenael Cadier
ST Employee

Hi @Krautermann​ 

2 remarks :

a) it seems your are using HAL_UART_Transmit() to send the TX_String buffer; sizeof(TX_String) will return 7 bytes, so 7 bytes will be sent.

Reception is handled using HAL_UART_Receive(), with expected length is sizeof(RX_String), so 10. Reception could never goes till end, as only 7 bytes will be sent.

b) as HAL_UART_Transmit() and HAL_UART_Receive() are blocking API (blocking mode), it means that transmit will be completed, when reception will start. Unless Fifo mode is enabled, this could not work. Overrun flag will be raised, as received data are not read from UART reception register before new data comes in.

Just for trial purpose, what you could try :

  • use reception in Interrupt mode : HAL_UART_Receive_IT() with the real expected length (for example size of sent data). As Interrupt mode API is not blocking, you could start reception prior transmit :
reception_complete = 0;
        HAL_UART_Receive_IT(&huart1, RX_String, sizeof(TX_String));
	HAL_UART_Transmit(&huart1, TX_String, sizeof(TX_String),10);
 
	/* wait for reception to be completed */
	while (reception_complete ==0) {}
 
	/* at this step, reception is completed, compare Tx and Rx strings */
	check_alpha();
  • In Rx Complete Callback, indicate reception is completed
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	reception_complete = 1;
}
  • Declare your global variable as volatile, as it could be accessed from IRQ side and in main
uint8_t reception_complete = 0;
  • in check_alpha() function, be sure to compare only received data. Might rather use strncmp with size equals to size of transmitted and received buffers

This should allow to implement loop between TX and Rx pins on your uart.

Hope this helps.

Karl Yamashita
Lead III

You are using HAL_UART_Transmit which is blocking so it has to transmit all the characters that you've specified before it can go to HAL_UART_Receive. The Rx register only holds one byte so it only received the first character. The rest of the string is lost.

Instead of HAL_UART_Receive you need to use HAL_UART_Receive_IT so it interrupts on each character received and in the callback you save the characters to a buffer but you'll have to use an index pointer

Or you can use HAL_UARTEx_ReceiveToIdle_DMA which will save the string to the char array without having to deal with an index pointer.

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.

Don't send the NUL at the end of the string, use strlen()

Don't expect UART received data to be NUL terminated, don't use string functions directly on the data, or make assumptions about length or synchronization.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Bob S
Principal

Thank you so much for your detailed answer! This works!!! Using Receive Interrupt and modifying the code accordingly made UART to receive the whole string instead of only the 1st char!

Thank you for your explanation. I guess it does make sense since HAL_UART_Transmit and HAL_UART_Receive are polling method. But by using HAL_UART_Receive_IT, it interrupts after each character and hence, enabling the reception of the whole string instead of receiving only 1 char.

I don't know who that guy is. He definitely copied my post and no, this is not homework assignment. I work for an automobile company and we are trying to use ST32H745 Disco board for our application.

Hi, thank you for your contribution to my question.

I spent half a day already trying to implement what you said but encountered some other problems.

  1. Don't send the NUL at the end of the string, use strlen()

I followed your advice by using strlen() in the HAL_UART_Transmit function in order to omit the NULL character at the end of the string, I believe this is what you meant:

HAL_UART_Transmit(&huart1, TX_String, strlen((char*)TX_String),10);

2. don't use string functions directly on the data, or make assumptions about length or synchronization.

What alternative should I use instead to compare TX and RX?

In what condition will UART RX not be NULL terminated? Is that when it is abruptly disconnected in the middle of a transmission?

Karl Yamashita
Lead III

@Krautermann​ 

The problem with HAL_UART_Receive_IT is that you need to know ahead of time exactly how many characters to receive before it interrupts. Strings can vary in length.

To get around this you can interrupt on each character and save it to a buffer. Then this involves a ring buffer. But you're going to need a delimiter like a LF to know that the string is complete before you can parse the string.

But if you were to use HAL_UARTEx_ReceiveToIdle_DMA  then you don't need a delimiter.

The code below is using a Nucleo-G431KB dev board. UART1 is the loopback. UART2 is using the Virtual COM Port. I am using Docklight to send messages to UART2 where it gets parsed and looks for a command to turn On/Off the green led. Else it'll copy what it received and transmit it to UART1. Since UART1 it in loopback, it'll receive that string and interrupt even if there is no delimiter because the Idle bit is enabled. Then the UART1 Rx buffer is parsed and transmitted back to UART2. I am utilizing a ring buffer (size 4) so multiple commands/strings can be sent and not be missed.

Below is some text that I am sending to UART2. That gets sent to UART1 and loops back and gets sent back to UART2.

The "grn_led:n" command is turning the LED On and Off.

0693W00000bh9BxQAI.png 

/*
 * PollingRoutine.c
 *
 *  Created on: Mar 29, 2023
 *      Author: karl.yamashita
 */
 
#include "main.h"
 
extern UART_HandleTypeDef huart1; // loopback
extern UART_HandleTypeDef huart2; // Virtual COM Port
 
UartDataStruct uart1Rx = {0};
UartDataStruct uart1Tx = {0};
 
UartDataStruct uart2Rx = {0};
UartDataStruct uart2Tx = {0};
 
// Is called before main while loop
void PollingInit(void)
{
	UART_EnableRx(&huart1, &uart1Rx); // init Rx reception
	UART_EnableRx(&huart2, &uart2Rx); // init Rx reception
}
 
// Is called from inside main while loop
void PollingRoutine(void)
{
	UART1_Parse();
	UART2_Parse();
 
	UART_Send(&huart1, &uart1Tx);
	UART_Send(&huart2, &uart2Tx);
 
	UART_RxStatus(&huart1, &uart1Tx);
	UART_RxStatus(&huart2, &uart2Tx);
}
 
// Enable UART reception. Set flag if failed to enable
void UART_EnableRx(UART_HandleTypeDef *huart, UartDataStruct *msg)
{
	if(HAL_UARTEx_ReceiveToIdle_DMA(huart, msg->Queue[msg->ptr.iIndexIN].data, RX_BUFFER_SIZE) != HAL_OK)
	{
		msg->uartRxIsEnabled = false;
	}
	else
	{
		msg->uartRxIsEnabled = true;
	}
}
 
// HAL callback
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart->Instance == huart1.Instance)
	{
		uart1Rx.Queue[uart1Rx.ptr.iIndexIN].size = Size; // save data length
		DRV_RingBuffPtr__Input(&uart1Rx.ptr, UART_QUEUE_SIZE); // increment pointer
		UART_EnableRx(&huart1, &uart1Rx); // re-enable UART reception
	}
	else if(huart->Instance == huart2.Instance)
	{
		uart2Rx.Queue[uart2Rx.ptr.iIndexIN].size = Size; // save data length
		DRV_RingBuffPtr__Input(&uart2Rx.ptr, UART_QUEUE_SIZE); // increment pointer
		UART_EnableRx(&huart2, &uart2Rx); // re-enable UART reception
	}
}
 
// TX and RX is in loopback
void UART1_Parse(void)
{
	if(uart1Rx.ptr.iCnt_Handle)
	{
		memcpy(&uart2Tx.Queue[uart2Tx.ptr.iIndexIN].data, uart1Rx.Queue[uart1Rx.ptr.iIndexOUT].data, uart1Rx.Queue[uart1Rx.ptr.iIndexOUT].size); // copy data
		uart2Tx.Queue[uart2Tx.ptr.iIndexIN].size = uart1Rx.Queue[uart1Rx.ptr.iIndexOUT].size; // copy data length
		DRV_RingBuffPtr__Input(&uart2Tx.ptr, UART_QUEUE_SIZE); // increment tx in pointer
		DRV_RingBuffPtr__Output(&uart1Rx.ptr, UART_QUEUE_SIZE); // increment rx out pointer
	}
}
 
// From VCP. Using Docklight to send string messages to this UART.
void UART2_Parse(void)
{
	char *token;
	char *token2;
	char *rest;
	if(uart2Rx.ptr.iCnt_Handle)
	{
		rest = (char*)uart2Rx.Queue[uart2Rx.ptr.iIndexOUT].data;
 
		token = strtok_r(rest, ":", &rest); // command
		token2 = strtok_r(rest, "\0", &rest); // argument
 
		if(strncmp(token, "grn_led", strlen("grn_led")) == 0) // original string "grn_led:n" where n = 0 or 1
		{
			if(atoi(token2) == 0)
			{
				HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
			}
			else if(atoi(token2) == 1)
			{
				HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
			}
		}
		else
		{
			memcpy(&uart1Tx.Queue[uart1Tx.ptr.iIndexIN].data, uart2Rx.Queue[uart2Rx.ptr.iIndexOUT].data, uart2Rx.Queue[uart2Rx.ptr.iIndexOUT].size); // copy data
			uart1Tx.Queue[uart1Tx.ptr.iIndexIN].size = uart2Rx.Queue[uart2Rx.ptr.iIndexOUT].size; // copy data length
			DRV_RingBuffPtr__Input(&uart1Tx.ptr, UART_QUEUE_SIZE); // increment tx in pointer
		}
		DRV_RingBuffPtr__Output(&uart2Rx.ptr, UART_QUEUE_SIZE); // increment rx out pointer
	}
}
 
// Send any available messages in buffer
void UART_Send(UART_HandleTypeDef *huart, UartDataStruct *msg)
{
	if(msg->ptr.iCnt_Handle)
	{
		if(HAL_UART_Transmit_IT(huart, msg->Queue[msg->ptr.iIndexOUT].data, msg->Queue[msg->ptr.iIndexOUT].size) == HAL_OK)
		{
			DRV_RingBuffPtr__Output(&msg->ptr, UART_QUEUE_SIZE); // Successful so we can increment pointer
		}
	}
}
 
// Poll this to Enable UART RX if not currently enabled
void UART_RxStatus(UART_HandleTypeDef *huart, UartDataStruct *msg)
{
	if(!msg->uartRxIsEnabled)
	{
		UART_EnableRx(huart, msg);
	}
}
 
 
 
/*
 * PollingRoutine.h
 *
 *  Created on: Mar 29, 2023
 *      Author: karl.yamashita
 */
 
#ifndef INC_POLLINGROUTINE_H_
#define INC_POLLINGROUTINE_H_
 
 
#define RX_BUFFER_SIZE 64
#define UART_QUEUE_SIZE 4
 
 
typedef struct
{
	struct
	{
		uint8_t data[RX_BUFFER_SIZE];
		uint32_t size;
	}Queue[UART_QUEUE_SIZE];
	RING_BUFF_INFO ptr;
	bool uartRxIsEnabled; // only needed for Rx
}UartDataStruct;
 
void PollingInit(void);
void PollingRoutine(void);
 
void UART_EnableRx(UART_HandleTypeDef *huart, UartDataStruct *msg);
 
void UART1_Parse(void);
void UART2_Parse(void);
void UART_Send(UART_HandleTypeDef *huart, UartDataStruct *msg);
void UART_RxStatus(UART_HandleTypeDef *huart, UartDataStruct *msg);
 
#endif /* INC_POLLINGROUTINE_H_ */
/*
 * RingBuff.c
 *
 *  Created on: Sep 18, 2019
 *      Author: Karl
 *
 *
*/
 
#include "main.h"
#include "ringBuff.h"
 
/*
typedef struct {
    uint16_t iIndexIN; // change all these if need more than 16bits.
    uint16_t iIndexOUT;
    uint16_t iCnt_Handle;
    uint16_t iCnt_OverFlow;
}RING_BUFF_INFO;
*/
 
//==========================================================
// Layer : DRIVER
//==========================================================
 
void DRV_RingBuffPtr__Clean(RING_BUFF_INFO *ptr) {
	ptr->iIndexIN = 0;
	ptr->iIndexOUT = 0;
 
	ptr->iCnt_Handle = 0;
	ptr->iCnt_OverFlow = 0;
}
 
void DRV_RingBuffPtr__Input(RING_BUFF_INFO *ptr, unsigned int iBufferSize) {
	ptr->iIndexIN++;
	if (ptr->iIndexIN >= iBufferSize)
		ptr->iIndexIN = 0;
 
	ptr->iCnt_Handle++;
	if (ptr->iIndexIN == ptr->iIndexOUT) {
		ptr->iCnt_OverFlow++;
		if (ptr->iCnt_OverFlow > 50000)
			ptr->iCnt_OverFlow = 0;
		if (ptr->iIndexIN == 0) {
			ptr->iIndexOUT = iBufferSize - 1;
		} else {
			ptr->iIndexOUT = ptr->iIndexIN - 1;
		}
		ptr->iCnt_Handle = 1;
	}
}
 
void DRV_RingBuffPtr__Output(RING_BUFF_INFO *ptr, unsigned int iBufferSize) {
	if (ptr->iCnt_Handle) {
		ptr->iIndexOUT++;
		if (ptr->iIndexOUT >= iBufferSize)
			ptr->iIndexOUT = 0;
		ptr->iCnt_Handle--;
	}
}
 
#ifndef RINGBUFF_H
#define RINGBUFF_H
 
#include "main.h"
#include <stdint.h>
 
typedef struct {
	uint16_t iIndexIN; // change all these if need more than 16bits.
	uint16_t iIndexOUT;
	uint16_t iCnt_Handle;
	uint16_t iCnt_OverFlow;
}RING_BUFF_INFO;
 
 
//================================================
// FUNCTION
//================================================
 
void DRV_RingBuffPtr__Clean(RING_BUFF_INFO *ptr);
 
void DRV_RingBuffPtr__Input(RING_BUFF_INFO *ptr, unsigned int iBufferSize);
 
void DRV_RingBuffPtr__Output(RING_BUFF_INFO *ptr, unsigned int iBufferSize);
 
#endif // RINGBUFF_H

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.