Skip to main content
Graduate II
February 15, 2024
Solved

Handle Variable Length Transmission over Uart

  • February 15, 2024
  • 5 replies
  • 3574 views

Hi!

I am somewhat unclear on how to handle variable length transmissions using the STM32F4xx HAL. I have looked at other solutions, and suggestions have been made to use HAL_UARTEx_ReceiveToIdle_DMA() or the ISR equivalent.

My situation however, involves a continuous non stopping transmission from a NEOM8N GPS Module. The GPS has a default baud rate of 9600, which I have observed in my code. It uses the NMEA0183 protocol, which has a max sentence length of 83 characters.

 

Any suggestions on how to implement the receive function for this GPS?

    This topic has been closed for replies.
    Best answer by Pavel A.

    The _DMA function will call your callback and pass the number of received bytes (less than the buffer size, in case of timeout). Other two kinds of "HAL" functions, _IT and the blocking/polling one are TL;DR broken and useless. Better roll your own, this is not too hard and examples are available.  If you need help with coding, please say so and someone may respond in PM.

    5 replies

    Super User
    February 15, 2024

    Hi, Why do you think your device is different from many others? The same solutions that you've already found very likely will work for you.

    Visitor II
    February 15, 2024

    Is this the same question again I saw recently here in this forum?

    You should be able to receive any number of bytes via UART. When it comes to "synchronization" and to realize the "frame start" - there might be some hints already in this forum (e.g. to use CRC, to know a frame start byte, to measure a gap between frames...).

    What is your exact question?

    You can receive any variable number of bytes via UART (e.g. in INT mode). I guess you are asking how to know when a new frame came in, right?

    Graduate II
    February 15, 2024

    I am just confused on how the STM32 HAL functions for UART handle continuous packet reception with variable length.

     

    Say if the packet is less than the max buffer size (max size of a nmea sentence), than would the func simply fill the buffer until end of the packet content? Or would it run into some error?



    If the former is true, than wouldn't it be possible to simply use HAL_UART_Receive() func to handle reception?

    Looking at the source code, I think that might be possible

     

     while (huart->RxXferCount > 0U)
     {
     if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
     {
     huart->RxState = HAL_UART_STATE_READY;
    
     return HAL_TIMEOUT;
     }
     if (pdata8bits == NULL)
     {
     *pdata16bits = (uint16_t)(huart->Instance->DR & 0x01FF);
     pdata16bits++;
     }
     else
     {
     if ((huart->Init.WordLength == UART_WORDLENGTH_9B) || ((huart->Init.WordLength == UART_WORDLENGTH_8B) && (huart->Init.Parity == UART_PARITY_NONE)))
     {
     *pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
     }
     else
     {
     *pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
     }
     pdata8bits++;
     }
     huart->RxXferCount--;
     }

     

    Super User
    February 15, 2024

    @Liferafter The receive process will yield a chunk of data either because the buffer is full (received fixed number of bytes) or because of timeout. If timeout won't occur then the former will occur. Then you parse the chunk and store left-over for later.

    Visitor II
    February 15, 2024

    There is not an UART protocol in an MCU: the "protocol" is defined by the chip you use (and you have to understand the intended chip, its "protocol").

    UART is just single byte transfer, with START and STOP bits for every byte - nothing else. Any other "protocol", such as: "which bytes are sent", "how many bytes", with "frames" and a gap between "frames" (pausing), with a handshake (Start/Stop, e.g. via CTRL-characters) - all is on the external chip - nothing in MCU or HAL drivers.

    You have to "implement" the "protocol" yourself, using UART primitives for byte/character reception on MCU. You will not find anything in HAL drivers: it is external chip specific stuff ("protocol"). Maybe you find some other people's projects or a demo using the same chip.
    I guess, this forum can give you guidance how to "understand your chip", but you have to digest the datasheet of the chip you want to use. Sorry.

    Graduate II
    February 15, 2024

    I might have confused you a bit when I said protocol. Yes the chips NMEA communication protocol, is what defines the UART interfacing. The problem here is that the chip has variable length packets. The STM32 only reads the start and stop for bytes adds them to the buffer, until buffer size (max Nmea sentence length) is reached. This is where I was asking for help: How would I go about doing this if the buffer size is reached, but with information from two different sentences from?

    But I think @Pavel A. solution should work, and I might have just been overthinking due to my lack of knowledge on how UART works. The solution I suppose is a circular buffer as was highlighted in another forum post.

     

    Thank you again for your help!

    Pavel A.Answer
    Super User
    February 15, 2024

    The _DMA function will call your callback and pass the number of received bytes (less than the buffer size, in case of timeout). Other two kinds of "HAL" functions, _IT and the blocking/polling one are TL;DR broken and useless. Better roll your own, this is not too hard and examples are available.  If you need help with coding, please say so and someone may respond in PM.

    Super User
    February 15, 2024

     The STM32 only reads the start and stop for bytes adds them to the buffer, until buffer size (max Nmea sentence length) is reached.

    No this is not STM32. This is the little poor "HAL library", suitable for quick bring-up tests and reference but not for production code. STM32 hardware itself is great, it supports continuous RX with DMA or interrupts - the latter is trivial at 9600 and simpler than DMA. Just do the proper code.

     

    Graduate II
    February 15, 2024

    Will do thank you for your help!

    Graduate II
    February 16, 2024

    Well the interrupt into a ring buffer works, it is preferable to do the parsing outside of the handler, as doing a lot of math and processing can be time consuming.

    One could use a circular DMA buffer, acting like the HW FIFO from earlier systems, which gets swept periodically, I do that rather than this idle stuff.The parser drops through quickly if there's insufficient data to close out a NMEA Sentence.

    UBX Packets have length information in the header.