[Revised]STM32 UART Part 9: LIN Bus Receiving Data

In this guide, we shall see how to receive data using UART in LIN configuration.

In this guide, we shall cover the following:

  • STM32CubeMX setup.
  • Firmware modification.
  • Hardware connection.
  • Results.

1. STM32CubeMX Setup:

We shall pickup from the previous guide from here.

Open LIN_Bus project from STM32CubeMX.

Once the project has been opened, enable USART6 in LIN mode as follows:

This will enable PC6 and PC7 for USART6_TX and USART_RX respectively.

Next, from NVIC Settings, enable global interrupt for USART6, once it has been enabled, click on generate code as follows:

2. Firmware Modification:

Once the project has been generated, open the project in STM32CubeIDE.

Open LIN.h header and declare the checksum function as follows:

uint8_t checksum_Calc (uint8_t PID, uint8_t *data, int size);

In the source LIN.c file, modify the following function:

static uint8_t checksum_Calc (uint8_t PID, uint8_t *data, int size)

To become:

uint8_t checksum_Calc (uint8_t PID, uint8_t *data, int size)

This will allow us to access the function from another source files.

Next, in main.c source file, in user code PV section, declare the following:

uint8_t data_rx[20];

uint8_t LIN_Rx_Data[8];
  • data_rx is the buffer to receive LIN frame data.
  • LIN_Rx_Data is the 8 received bytes.

Also, declare the following:

uint32_t previous_ticks=0;

uint8_t numDataBytes;

volatile uint8_t isDataValid;
  • previous_ticks which store the ticks.
  • numDataBytes is the amount of received data.
  • isDataValid indicates the success of reception of the data.

In user code begin 0:

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	 numDataBytes = Size - 4;
	uint8_t checksum = checksum_Calc(data_rx[2], data_rx+3, numDataBytes);
	ID = data_rx[2]&0x3F;
	if (checksum != data_rx[Size-1])
	{
		isDataValid = 0;

	}
	else
	{
		isDataValid = 1;
	}
	HAL_UARTEx_ReceiveToIdle_IT(&huart6, data_rx, 20);
}

This function is a UART receive callback used with the STM32F4 HAL driver when Receive-to-IDLE interrupt modeis enabled.

The callback HAL_UARTEx_RxEventCallback() is automatically called by the HAL when the UART detects an IDLE line condition, meaning that a complete frame has been received or the sender has stopped transmitting.

The parameter Size represents the number of bytes actually received before the IDLE condition occurred.

The line:

numDataBytes = Size - 4;

indicates that the communication protocol reserves 4 bytes for non-payload data, such as header, ID, control fields, and checksum. The remaining bytes are considered payload data.

Next, a checksum is calculated:

checksum_Calc(data_rx[2], data_rx + 3, numDataBytes);

Here:

  • data_rx[2] is likely a command or device ID field.
  • data_rx + 3 points to the beginning of the payload.
  • numDataBytes specifies how many payload bytes are included in the checksum calculation.

The device ID is then extracted using:

ID = data_rx[2] & 0x3F;

The bitmask 0x3F keeps only the lower 6 bits of the ID field, discarding any control or flag bits stored in the upper bits.

The received checksum (last byte of the frame) is compared with the calculated checksum:

data_rx[Size - 1]

If the two values do not match, the received data is marked as invalid. Otherwise, it is marked as valid.

Finally, UART reception is restarted:

HAL_UARTEx_ReceiveToIdle_IT(&huart6, data_rx, 20);

This re-arms USART6 to receive the next frame using IDLE line detection, with a maximum buffer size of 20 bytes.

In summary, this callback:

  • Handles variable-length UART frames
  • Extracts payload and ID information
  • Verifies data integrity using a checksum
  • Automatically restarts reception for continuous communication

In user code begin 2 in main function, start the USART6 to receive data until IDLE detected as follows:

HAL_UARTEx_ReceiveToIdle_IT(&huart6, data_rx, 20);

In user code begin 3 in while 1 loop:

	  if(HAL_GetTick()-previous_ticks>100)
	  {
		  for (int i=0;i<8;i++)
		  {
			  data[i]=random()%255;
		  }
		  ID=random()%255;

		  LIN_State=LinTransmit(ID,data);

		  if(LIN_State==Timeout)
		  {
			  uint16_t len=sprintf(uart_data,"Timeout communication\r\n");
			  HAL_UART_Transmit(&huart2, uart_data, len, 1000);

		  }

		  if(LIN_State==InvalideID)
		  {
			  uint16_t len=sprintf(uart_data,"Invalid ID\r\n");
			  HAL_UART_Transmit(&huart2, uart_data, len, 1000);
		  }

		  previous_ticks=HAL_GetTick();

	  }

	  if(isDataValid==1)
	  {
		  uint16_t len=sprintf(uart_data,"LIN Data Received\r\n");
		  HAL_UART_Transmit(&huart2, uart_data, len, 1000);

		  for (int i=0; i<numDataBytes; i++)
		  {
			  LIN_Rx_Data[i] = data_rx[i+3];
		  }
		  isDataValid = 0;
	  }

Save the project, build it and run it in debugging mode on your STM32F4 board.

3. Hardware Setup:

The connection is as simple as connecting PC7 to PA9 using jumper wire as following:

Simply, connect a wire from D8 to D9 of the arduino header.

4. Results:

In live expression of the debug session, add data and LIN_Rx_Data to live expression.

Run the project, you should see from time to time there is incoming data as follows:

Using serial terminal application, you should see the following:

We have successfully received LIN also, transmitted data and prevent incorrect ID to be send.

Happy coding 😉

Add Comment

Your email address will not be published. Required fields are marked *