cancel
Showing results for 
Search instead for 
Did you mean: 

UART losing the first byte

FTrom
Associate II

Hi

I am a beginner and I am studding STM32F448 with a nucleo board. Program used "System Workbench for STM32". My problem is quite ***** and I hope that someone can help me.

That program allow to the the user to send a string and the cpu, when receive the character "\n", send back the string. so if I send "Home\n", the cpu should send me back the same string.

What is happening is that at the first connection sending "Home\n", I receive "ome\n" where "H" is replaced with a null character (0x00). After this first communication, all is fine: i receive what i send. it seems like that i loose the first byte.

Thanks a lot in advance

4 REPLIES 4
TDK
Guru

After UART2_Init(), but before you use the UART, insert a delay of 1 character in length. HAL_Delay(1) will do.

Your TX line is probably low initially and the receiving end doesn't know how to handle the sudden change high then low again.

If you feel a post has answered your question, please click "Accept as Solution".
MiguelVicens
Associate

Hello,

For me, something similar to what my colleague says is happening, but a little bit different

I'm describing the project I'm doing to see if I can solve it.

I am using the USART1 configured as LIN mode with the following parameters:

/* USER CODE BEGIN USART1_Init 1 */

/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 19200;
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;
if (HAL_LIN_Init(&huart1, UART_LINBREAKDETECTLENGTH_10B) != HAL_OK)
{
Error_Handler();
}

In the picture "linrequest and linresponse" you can see on channel 3 sending the LIN break+ sync+protectedID signal and on the channel 1 signal you can see the response of the LIN slave DATA(8 bytes)+ CHK.

The code I have implemented asks the slave if it is on the bus and if it is on the bus it sends me back information.

 

void LIN_Request(uint8_t addr){
 
uint8_t addrbyte = (addr&0x3f) | addrParity(addr);
uint8_t sync = 0x55;
uint8_t header[2] = {sync, addrbyte};
 
 
//preguntamos al esclavo si responde
HAL_LIN_SendBreak(&huart1);
HAL_UART_Transmit(&huart1, header, sizeof(header), 5);
 
HAL_GPIO_WritePin(LIN_RX_GPIO_Port, LIN_RX_Pin, GPIO_PIN_SET);
 
//Datos que nos envia el esclavo al responder
 
HAL_UART_Receive(&huart1, response, 10, 5);
HAL_GPIO_WritePin(LIN_RX_GPIO_Port, LIN_RX_Pin, GPIO_PIN_RESET);
 
}
 
and this is the code I use to see the result of the variable. I use the printf and the USART2 to see the data of the variable "response" through the COM port.
 
global variable
uint8_t response[20];
 
 
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
   while (1)
  {
 
  for(counter = 1; counter < 6;counter ++)
  {
  LIN_Request(counter);
 
  printf("We ask the slave %d", counter);
  printf("Byte0: %d, ", response[0]);
  printf("Byte1: %d, ", response[1]);
  printf("Byte2: %d, ", response[2]);
  printf("Byte3: %d, ", response[3]);
  printf("Byte4: %d, ", response[4]);
  printf("Byte5: %d, ", response[5]);
  printf("Byte6: %d, ", response[6]);
  printf("Byte7: %d, ", response[7]);
  printf("Byte8: %d, ", response[8]);
  printf("Byte9: %d, ", response[9]);
  printf("Byte10: %d\n, ", response[10]);
  bzero(response,10);
  HAL_Delay(1000);
  }
}
 
I have some suspicions that the 0 position of the receive buffer when receiving with the USART does not work.
I always get 0 in response[0].
 
 
If I comment the line of :
printf("Byte0: %d, ", response[0]);
printf("Byte0: %d, ", response[10]);
 
Reception of the message is correct
 
  printf("We ask the slave %d", counter);
  //printf("Byte0: %d, ", response[0]);
  printf("Byte1: %d, ", response[1]);
  printf("Byte2: %d, ", response[2]);
  printf("Byte3: %d, ", response[3]);
  printf("Byte4: %d, ", response[4]);
  printf("Byte5: %d, ", response[5]);
  printf("Byte6: %d, ", response[6]);
  printf("Byte7: %d, ", response[7]);
  printf("Byte8: %d, ", response[8]);
  printf("Byte9: %d, ", response[9]);
  //printf("Byte10: %d\n ", response[10]);
  bzero(response,10);
 
When you read data from the USART and you want to access the first position of the receive buffer (first byte) do you have to point to position 0 or 1?

 

Karl Yamashita
Lead III

You have to stay consistent when you call HAL_UART_Receive_IT. The first call uses data_buffer so on the first interrupt you receive the first character at index 0 but you replace it with rx_data. However rx_data is zero . Then you call HAL_UART_Receive_IT again but now point to rx_data. So now receiving works correctly, at least on the first message. You don't reset your "count" so now you're going to be transmitting previous messages as well.

You are using a blocking code when transmitting which you should never use in an interrupt. Set a flag instead and then transmit. You need to learn how to use the HAL status to your advantage so you can make sure your rx interrupt is always working and to make sure you did transmit.

Below is a working example on a Nucleo-G431KB

 

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

#include "main.h"
#include "PollingRoutine.h"


extern UART_HandleTypeDef huart2;


typedef struct
{
	uint8_t rx[1]; // for rx only
	uint8_t data_buffer[100];
	uint32_t size;
	uint32_t ptr;
	bool ready;
	bool recIntError;
}UartDataStruct;


char *user_data = "The application is running\r";

UartDataStruct rxData = {0};
UartDataStruct txData = {0};

// called before main while loop
void PollingInit(void)
{
	uint16_t len_of_data = strlen(user_data);

	HAL_UART_Transmit(&huart2,(uint8_t*)user_data, len_of_data, 100);

	UART_EnableReceive(); // init enabling of rx interrupt
}

// called from main while loop
void PollingRoutine(void)
{
	UART_ErrorStatus();
	UART_RxDataReady();
	UART_TxDataReady();
}

// check rx error status, try and enable rx interrupt again
void UART_ErrorStatus(void)
{
	if(rxData.recIntError)
	{
		rxData.recIntError = false;
		UART_EnableReceive();
	}
}

// enable rx interrupt
void UART_EnableReceive(void)
{
	if(HAL_UART_Receive_IT(&huart2, rxData.rx, 1) != HAL_OK)
	{
		rxData.recIntError = true;
	}
}


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(rxData.rx[0] == '\r')
	{
		rxData.data_buffer[rxData.ptr] = '\r';
		rxData.size = rxData.ptr + 1; // save the size
		rxData.ptr = 0; // reset pointer
		rxData.ready = true;
	}
	else
	{
		rxData.data_buffer[rxData.ptr] = rxData.rx[0];
		rxData.ptr++;
	}
	UART_EnableReceive();
}

// if rx data available, copy to tx and set tx ready flag
void UART_RxDataReady(void)
{
	if(rxData.ready)
	{
		rxData.ready = false; // reset
		memcpy(&txData.data_buffer, rxData.data_buffer, rxData.size); // copy rx to tx buffer
		txData.size = rxData.size;
		txData.ready = true; // set tx data is ready to send
	}
}

// if tx data available, transmit it and clear flag only if HAL_OK. If not then it'll retry to send again until successful.
void UART_TxDataReady(void)
{
	if(txData.ready)
	{
		if(HAL_UART_Transmit_IT(&huart2, txData.data_buffer, txData.size) == HAL_OK)
		{
			txData.ready = false;
		}
	}
}

 

 

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.
MHanc.1
Associate

I had the similar effect on the STM32L4+. The first byte received via interrupt was always 0. I think this is related to the "double buffering". So on the first IRQ you need to read the buffer "manually" again.

Something like this

if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE)) {

  if ((bytesRcvd1 == 0) && (serRxBuffer[0] == 0)) { // if this is first byte
    HAL_UART_Receive(&huart1, &serRxBuffer[0],1,1); // READ again
  }
  else {
    if (serRxBuffer[bytesRcvd1] == (uint8_t)'\r') { // return received?
      // reset the bytes counter
      bytesRcvd1 = 0; 
      // indicate line reception complete here
    }
  }
  bytesRcvd1++; // increase number of bytes received
  HAL_UART_Receive_IT(&huart1, &serRxBuffer[bytesRcvd1], 1);
}