2024-02-14 11:23 PM
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?
Solved! Go to Solution.
2024-02-15 12:56 AM
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.
2024-02-15 12:01 AM
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.
2024-02-15 12:15 AM
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?
2024-02-15 12:18 AM - edited 2024-02-15 12:19 AM
What I understood from reading the interface specification and datasheet, as well as looking at some examples, I figured that the NeoM8N had continuous uart transmission, with not enough time between transmissions to actually trigger the idle event in HAL_UARTEx_ReceiveToIdle_DMA().
II also could not find any exact solutions discussing interfacing with the NeoM8 using an STM32.
But I might just be wrong, and not understand the UART protocol.
2024-02-15 12:26 AM
@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.
2024-02-15 12:40 AM - edited 2024-02-15 12:46 AM
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--;
}
2024-02-15 12:44 AM
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.
2024-02-15 12:56 AM
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.
2024-02-15 01:00 AM
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!
2024-02-15 01:06 AM - edited 2024-02-15 01:23 AM
Using the RX interrupt, Just receive 1 byte at a time, into a ting* buffer.
Process the ring buffer in your main loop (non-interrupt) code.
This is a pretty standard way to handle "streaming" UART data on any microcontroller - not specific to STM32
EDIT
* ring buffer !
aka "circular buffer"