cancel
Showing results for 
Search instead for 
Did you mean: 

Usart received data misaligned in buffer when I try to receive data from 2 modbus slaves. It works fine with 1 slave but when both the slaves are connected, after a period of time, usart stars misaligning received data. Can someone help?

sne_123
Associate III

This is my usart handler

 Also I clear the 1st received frame before receiving the 2nd modbus frame.

void HAL_UART_IRQHandler1(UART_HandleTypeDef *huart)

{

__HAL_UART_CLEAR_PEFLAG(huart);

__HAL_UART_ENABLE_IT(huart, UART_IT_ERR);

__HAL_UART_ENABLE_IT(huart,UART_IT_LBD);

__HAL_UART_ENABLE_IT(huart, UART_IT_PE);

__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);

__HAL_UART_CLEAR_OREFLAG(huart); 

// check if the USART1 receive interrupt flag was set

if( __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE) )

t = (uint8_t)(huart->Instance->DR );

if (t != '\n')

{

// Concat char to buffer

if (k < 13 -1)

{

received_string[k] = t;

k++;

}

else

{

received_string[k] = t;

k = 0;

}

}

}

__HAL_UART_CLEAR_PEFLAG(huart);

__HAL_UART_DISABLE_IT(huart, UART_IT_PE);

__HAL_UART_DISABLE_IT(huart, UART_IT_ERR);

__HAL_UART_DISABLE_IT(huart,UART_IT_LBD);

HAL_NVIC_ClearPendingIRQ(USART3_IRQn);

}

11 REPLIES 11
AvaTar
Lead

I don't do Cube code.

Do you speak about Modbus ASCII, or RTU ?

Check if characters get lost, perhaps the OV flag is set.

If slaves misbehave, you application needs to deal with such a scenario in a robust manner.

sne_123
Associate III

I am speaking about Modbus RTU. I tried to check OV flag in debug mode. It is not set.

None of the error flags are set.

T B
Associate II

May you have a simple buffer overflow after the 13 character.

is k=0 in the correct else path?

BTW1 : this is not MODBUS RTU.

Why to the hell you configure the ISR in the ISR handler?

sne_123
Associate III

when I say Modbus RTU ,it means I am receiving frames from modbus slave in RTU mode. That means I am receiving hex frames from slave !!!

"k" is just the byte count and received buffer is of 13bytes. So i will have to reset the k count if there are no more characters to be received.

T B
Associate II

In RTU mode ‚\n‘ is a normal byte.

In RTU you need the IDLE condition the detect the frame end.

May this helps:

https://stm32f4-discovery.net/2017/07/stm32-tutorial-efficiently-receive-uart-data-using-dma/

sne_123
Associate III

so should I check '\r' instead of '\n' ???

Also Thanks for the link, I will try to configure using DMA.

Jack Peacock_2
Senior III

If you use RTU the end of a frame is defined as a gap, multiple/fractional character times, before the next frame starts. IDLE may or may not work, depending on how your remote node responds. PCs, for instance, have a hard time meeting the inter-character and inter-message gap times with RTU, which is why ASCII mode is so common. Same problem if your remote node has interrupt driven TX out. The interrupt latency, especially if there are higher priorities, can unexpectedly insert gap times inside a frame.

If your remote node inserts gaps between bytes in excess of the IDLE timer you get broken frames. Some STM32s have a fixed IDLE period, which is all but useless. Newer versions do allow for programming the IDLE timer period.

Address match can be used to detect a frame start in RTU, but never the end. It works best if there are long pauses between frames, otherwise you have to disable the IRQ as soon as a frame starts, and enable the moment a frame ends (that gets complicated, especially at high data rates).

Jack Peacock

sne_123
Associate III

@Community member​  Thank you. I will try today with increasing the delay between 2 frames.

sne_123
Associate III

I figured out the issue. The problem was modbus slave sends me incomplete frame at times (last byte was missing in the frame). So the when new frame was received it used to store data in the last byte of buffer as it was empty...the counter 'k' was not resetting itself because of which rest all frames which were received got misaligned and CRC check failed.

So now before receiving a new frame, every time I am resetting the count 'k'. I Also inserted a delay between receiving frames from 2 modbus slaves.

@Community member​ @Community member​ @Bacteriuslocher​  Thanks for helping. :)