cancel
Showing results for 
Search instead for 
Did you mean: 

UART only receive one byte

MÇETİ.1
Associate III

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 */

 }

1 ACCEPTED SOLUTION

Accepted Solutions
Karl Yamashita
Lead III

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));
	}
}

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.

View solution in original post

13 REPLIES 13

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 Venmo
Up vote any posts that you find helpful, it shows what's working..
Ghofrane GSOURI
ST Employee

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

Karl Yamashita
Lead III

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.

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,

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

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.

MÇETİ.1
Associate III

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
Lead III

Yes you can use HAL_UART_Transmit_DMA.

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.

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
Lead III

post your code

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.