Skip to main content
MÇETİ.1
Associate III
April 8, 2023
Solved

UART only receive one byte

  • April 8, 2023
  • 9 replies
  • 9407 views

I'm trying to receive more than 1 byte but it receive only 1 byte. Poll method or IT, it doesn't matter. Always receives 1 byte and writes it in rx_buffer[0]. When I search it I found out the reason is timeout, I increase timeout 1000 from 100ms but nothing changes. Can anyone help me please? 

Here is my code for poll

/* Includes ------------------------------------------------------------------*/

#include "main.h"

#include "string.h"

/* Private variables ---------------------------------------------------------*/

UART_HandleTypeDef huart1;

UART_HandleTypeDef huart6;

DMA_HandleTypeDef hdma_usart1_rx;

/* Private function prototypes -----------------------------------------------*/

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_DMA_Init(void);

static void MX_USART1_UART_Init(void);

static void MX_USART6_UART_Init(void);

USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */

char rx_buffer[50];

char tx_buffer[50];

 while (1)

 {

HAL_UART_Receive(&huart1,(uint8_t*)rx_buffer,4,1000);

memcpy(tx_buffer,rx_buffer,4);

HAL_UART_Transmit(&huart6,(uint8_t*)tx_buffer,strlen(tx_buffer),1000);

  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

 }

This topic has been closed for replies.
Best answer by Karl Yamashita

From what i see, main_buffer is pointless as you are not doing anything with it.

My UART2 is your UART1 and my UART1 is your UART6 which this is working on a Nucleo-L432 board

uint8_t tx_buffer[rx_buff];
 
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if (huart->Instance == USART2)
	{
	
		/* start the DMA again */
		memset(&tx_buffer, 0, sizeof(tx_buffer)); // clear tx buffer
		memcpy(&tx_buffer, &rx_buffer, Size); // copy only what was received
		
		HAL_UART_Transmit_DMA(&huart1, tx_buffer, Size); // use Size instead of sizeof(rx_buffer)
		
		HAL_UARTEx_ReceiveToIdle_DMA(&huart2, (uint8_t *) rx_buffer, sizeof(rx_buffer));
	}
}

9 replies

Tesla DeLorean
Guru
April 9, 2023

You don't check the return error/status.

It's not really a guarantee you'll receive data, that depends on a source sending data, and when and how often it does that.

If you know that 4 characters will come in, increase the timeout to near infinite.

Consider receiving bytes at a time and building a buffer, usually these things are bounded by specific characters or protocol dependent.

You don't know when things align or synchronize, or if you miss things.

Most STM32 interrupt on a per byte basis, you can handle streams in a stateful manner.

strlen() perhaps not appropriate in this situation, it expects NULs

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
MÇETİ.1
MÇETİ.1Author
Associate III
April 16, 2023

Hi,

Thank you for your reply!

I tried to increase timeout but it does not work. I used dma and solve the receiving problem now it's time to figure out how to send whole data.

Ghofrane GSOURI
Technical Moderator
April 10, 2023

Hello @MÇETİ.1 

First let me thank you for posting.

It looks like you are trying to receive multiple bytes using the HAL_UART_Receive function, but it is only receiving a single byte. There are a few things you can check to try and solve this issue:

  1. Try increasing the timeout value of the HAL_UART_Receive function to a higher value, such as 5000 or 10000, to see if it makes any difference. If the timeout is too short, it might not allow enough time for all the bytes to be received.
  2. Check the configuration of your UART peripherals, especially the baud rate, data bits, parity, and stop bits. If any of these settings are incorrect, it could cause issues with receiving data.
  3. Try using the DMA method to receive data instead of the polling method. The DMA method can be more efficient and reliable for receiving large amounts of data.
  4. Make sure that the UART peripheral is configured correctly and that there are no other conflicting settings or functions that might be interfering with the receive function.

I hope this helps!

Thx

Ghofrane

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
MÇETİ.1
MÇETİ.1Author
Associate III
April 16, 2023

Hello,

Firstly, I wanna thank you for your suggestings.

I checked my settings then used DMA with Idle Line. It really improved the way receiving data. Now, I'm trying to learn how to transmite whole data that I received.

Thx

Mine

Karl Yamashita
Principal
April 10, 2023

More than likely your device transmitting is only sending a single byte. A timeout of 100ms is more than enough to receive 4 bytes let alone 1000ms.

You don't clear the rx and tx buffers. So after the first reception, rx buffer will always have the same data. Then you copy that data again to the tx buffer. So you'll see the same data being transmitted over and over with a pause of your receive timeout delay.

Check this post that I replied to https://community.st.com/s/question/0D53W00002CeLaOSAV/cannot-receive-full-string-on-uart-receive-st32h745-disco-board

I have an example of receiving from UART 2 and transmitting to UART 1 which loops back. It uses DMA with idle so you can receive any variable size string. It also uses a ring buffer so the code knows when there is new data received and new data to be transmitted.

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
MÇETİ.1
MÇETİ.1Author
Associate III
April 16, 2023

I'm so grateful for your answer.

I used dma with idle line and receive 1.091 bytes but I couldn't figure out how to use TX functions to work them properly.I saw Karl's answer but it is so complex for me actually. I need a bit simplified solution. Could I use HAL_UART_Transmit_DMA ?

Karl Yamashita
Principal
April 16, 2023

Yes you can use HAL_UART_Transmit_DMA.

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
MÇETİ.1
MÇETİ.1Author
Associate III
April 16, 2023

I used it, first it sent just one time then I also call it in HAL_UARTEx_RxEventCallback at the end. It work exactly what I want I meant when I send a data from UART1 it sends data back from UART6. However, when I send new data it writes it first byte and sends new data and the data I sent before it. I want to receive only last data.
_legacyfs_online_stmicro_images_0693W00000biAKvQAM.pngIt receives 1 and then changes first byte of the data I sent before 1, and transmite them together.

I receive data with rx_buffer but store whole data sequentially in main_buffer. I tried to transmit both of them but nothing change.

HAL_UART_Transmit_DMA(&huart6,rx_buffer, sizeof(rx_buffer));

Karl Yamashita
Principal
April 16, 2023

post your code

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
MÇETİ.1
MÇETİ.1Author
Associate III
April 16, 2023
/* 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 */
/* USER CODE END PD */
 
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
 
/* USER CODE END PM */
 
/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart6;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart6_tx;
 
/* USER CODE BEGIN PV */
 
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_USART6_UART_Init(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
#define rx_buff 512
#define main_buff 2048
 
uint8_t rx_buffer[rx_buff];
uint8_t main_buffer[main_buff];
 
uint16_t oldPos;
uint16_t newPos;
 
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if (huart->Instance == USART1)
	{
		oldPos = newPos; // Update the last position before copying new data
 
		if (oldPos+Size > main_buff) // If the current position + new data size is greater than the main buffer
		{
			uint16_t datatocopy = main_buff-oldPos; // find out how much space is left in the main buffer
			memcpy ((uint8_t *)main_buffer+oldPos, rx_buffer, datatocopy); // copy data in that remaining space
 
			oldPos = 0; // point to the start of the buffer
			memcpy ((uint8_t *)main_buffer, (uint8_t *)rx_buffer+datatocopy, (Size-datatocopy)); // copy the remaining data
			newPos = (Size-datatocopy); // update the position
		}
 
		/* if the current position + new data size is less than the main buffer
		 * we will simply copy the data into the buffer and update the position
		 */
		else
		{
			memcpy ((uint8_t *)main_buffer+oldPos, rx_buffer, Size);
			newPos = Size+oldPos;
		}
 
 
		/* start the DMA again */
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t *) rx_buffer, rx_buff);
		__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
		HAL_UART_Transmit_DMA(&huart6,rx_buffer, sizeof(rx_buffer));
	}
}
 
 
 
/* USER CODE END 0 */
 
/**
 * @brief The application entry point.
 * @retval int
 */
int main(void)
{
 /* USER CODE BEGIN 1 */
 
 /* USER CODE END 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 SysInit */
 
 /* USER CODE END SysInit */
 
 /* Initialize all configured peripherals */
 MX_GPIO_Init();
 MX_DMA_Init();
 MX_USART1_UART_Init();
 MX_USART6_UART_Init();
 /* USER CODE BEGIN 2 */
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rx_buffer, rx_buff);
HAL_UART_Transmit_DMA(&huart6, rx_buffer, sizeof(rx_buffer));
 /* USER CODE END 2 */
 
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
 /* USER CODE END WHILE */

Karl Yamashita
Karl YamashitaBest answer
Principal
April 16, 2023

From what i see, main_buffer is pointless as you are not doing anything with it.

My UART2 is your UART1 and my UART1 is your UART6 which this is working on a Nucleo-L432 board

uint8_t tx_buffer[rx_buff];
 
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if (huart->Instance == USART2)
	{
	
		/* start the DMA again */
		memset(&tx_buffer, 0, sizeof(tx_buffer)); // clear tx buffer
		memcpy(&tx_buffer, &rx_buffer, Size); // copy only what was received
		
		HAL_UART_Transmit_DMA(&huart1, tx_buffer, Size); // use Size instead of sizeof(rx_buffer)
		
		HAL_UARTEx_ReceiveToIdle_DMA(&huart2, (uint8_t *) rx_buffer, sizeof(rx_buffer));
	}
}

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
MÇETİ.1
MÇETİ.1Author
Associate III
April 17, 2023

Thank you so much!!!! It works!!

Karl Yamashita
Principal
April 17, 2023

You're welcome! Can you please select as best answer?

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source