cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 USART with unknown data length from the computer

Duy Tran
Associate II
Posted on June 01, 2018 at 09:21

Hello,

I am receiving UART data from the computer using my STM32 MCU with dynamic length. Sometimes the computer send 6 bytes and some time 10 bytes etc...and there is no rule for this.

Can anyone help me how to use the HAL_UART_Receive_IT in this case? Or I have to use the HAL_UART_Receive and wait for the timeout?

Thank you very much

#stm32-uart #stm32
5 REPLIES 5
David SIORPAES
ST Employee
Posted on June 01, 2018 at 14:30

This discussion may help you:

https://community.st.com/0D50X00009XkW2nSAF

Posted on June 01, 2018 at 14:46

The USART itself interrupts on each character reception, you can manage things in the IRQHandler, or call into the HAL and let it call you back when it has accumulated the specified number of characters.

You are not compelled to use the HAL defined methods, if your problem can be solved with a simple ring-buffer implementation then do that. I've posted GPS examples where a line of data is accumulated in the IRQHandler and then the whole line is passed off for processing.

>>..and there is no rule for this.

But there is presumably some method or structure to the data received, if not how else can you parse it. If the data is totally lacking form do you separate groups of data by the gaps between them?

If it is a protocol you have defined you might want to refine it, or pass length details.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
T J
Lead
Posted on June 01, 2018 at 15:36

using a circular RxDMA buffer

initialize before while(1)

U1RxBufferPtrOUT = 0;

HAL_UART_Receive_DMA(&huart1, (uint8_t *)Usart1RxDMABuffer, U1RxBufSize);

you can Peek at the buffer level ;

U1RxBufferPtrIN   this is pointing to the next Rx byte position.

char readableU1(void) {      // returns length in DMA not read.

    U1RxBufferPtrIN =  U1RxBufSize - huart1.hdmarx->Instance->CNDTR;

    return U1RxBufferPtrIN - U1RxBufferPtrOUT;

}

if you want to read some bytes you use U1RxBufferPtrOUT.  As you read bytes from the buffer, you must increment your U1RxBufferPtrOUT and wrap it at the DMA circular buffer length.

ie

The correct method to check the current receive buffer length is

RxLength = readableU1() //  reads zero after initialization

just after initialization; 

      if you receive 10 bytes 

         U1RxBufferPtrIN = 10

         and since U1RxBufferPtrOUT  is still zero. :     RxLength becomes 10.

You can poll this value readableU1() for your required packet size without reading a byte.

as you read each byte from that packet, you increment U1RxBufferPtrOUT and wrap at U1RxBufSize

char readU1(void) {

    char readByte = Usart1RxDMABuffer[U1RxBufferPtrOUT++];

    if (U1RxBufferPtrOUT >= U1RxBufSize) U1RxBufferPtrOUT = 0;

    return readByte;

}
Posted on June 01, 2018 at 15:30

Thank you so much for your reply,

Actually I am using modbus and my MCU is a slave in an inverter which is controlled by another MCU so I can't patch guess exactly the data length from the master.

Posted on June 01, 2018 at 15:31

Thank you very much. I am following the instruction

:)