2
\$\begingroup\$

I'm using an MCU board(STM32 with HAL) and basically polling data from a device using serial protocol. The MCU sends a fixed byte array(6 bytes) to the device, and in response it receives a fixed byte array from the device(20 bytes).

MCU <---UART---> Device

The Baudrate is 9600, and the function which polls and returns the byte array is as follows:

    uint8_t * ReturnInfoFromDevice(void)
    {
        static uint8_t Rx_data_Info[20];
    
        uint8_t pollData[] = {0xBB, 0xAA, 0xD1, 0x00, 0x00, 0x00};
        HAL_UART_Transmit(&huart1, pollData, 6, HAL_MAX_DELAY); 
        HAL_UART_Receive(&huart1, Rx_data_Info, 20, HAL_MAX_DELAY);
    
        return Rx_data_Info;

}

Now between two consecutive calls of ReturnInfoFromDevice, I add 200ms delay but something confused me regarding the UART communication in my code regarding polling data using the HAL_UART_Transmit and HAL_UART_Receive.

As you see in my function, between HAL_UART_Transmit and HAL_UART_Receive I don't add any delay but still I receive data without any problem. On the other hand, if I add delay between HAL_UART_Transmit and HAL_UART_Receive I don't get any data.

I was expecting the contrary, since at 9600 Baudrate byte transfer per second requires around 1ms, So in my case the total byte transfer is 20 + 6 = 26 bytes. Doesn't that mean we need minimum 26ms delay between HAL_UART_Transmit and HAL_UART_Receive?

\$\endgroup\$
3
  • \$\begingroup\$ Careful, there's a bug in this code! You can't allocate an array on the stack and then return a pointer to it, the caller will then not be allowed to read anything from it. See this question for more and possible workarounds. \$\endgroup\$ Mar 7 at 9:54
  • 2
    \$\begingroup\$ As the buffer is "static", it will stay in memory and pointers to it will still work. The function simply is not reentrant, because it will use the same memory area for each call. \$\endgroup\$
    – jusaca
    Mar 7 at 10:22
  • \$\begingroup\$ @jusaca Im also not using any multi-threading so being a non-reentrant function is not a problem. \$\endgroup\$
    – user1245
    Mar 7 at 20:23

3 Answers 3

4
\$\begingroup\$

No, because your code must be ready listening back the response before the device starts sending it. The device may start sending the response right aftet MCU has send the last byte of the command to device.

If you put any delay, even 1 millisecond, between transmit and receive function calls, you might miss the first response byte from device.

\$\endgroup\$
2
  • \$\begingroup\$ I agree with this answer, but just want to add that this also depends on the UART FIFO buffer size. I have worked with UARTs with single byte buffers and UARTs with 64 byte buffers (just to mention a span). If OP did the same thing on a model with a 64 byte buffer, then it should just kinda work. But OP only mentions STM32, so I went and looked at a random STM32 model (STM32C0) and that one looks like it has an 8 byte buffer. So, depending on model you may have a bit of slack on how the required timing - but at the end of the day, if you let the buffer overflow that data is just lost. \$\endgroup\$
    – Frodyne
    Mar 7 at 13:29
  • \$\begingroup\$ @Frodyne Yes some models have FIFOs but it is up to user to enable them if user wants. We cannot know if the MCU has FIFOs at all, and even if it does, has user initialized to actually use them. \$\endgroup\$
    – Justme
    Mar 7 at 13:41
4
\$\begingroup\$

...between HAL_UART_Transmit and HAL_UART_Receive I don't add any delay but still I receive data without any problem. On the other hand, if I add delay between HAL_UART_Transmit and HAL_UART_Receive I don't get any data.

In polling mode, the HAL_Receive() function will block for the time informed in the function or until something is received (HAL_MAX_DELAY will wait forever). Probably in your setup, the other device is responding immediately. So if you put a delay between transmission and reception, data may be lost. Without such delay, reception occurs normally. Note that there are other more efficient forms of communication, such as interrupt and DMA (waiting forever may be unacceptable depending on the firmware architecture used).

\$\endgroup\$
0
\$\begingroup\$

UART works by starting and ending one "frame" of data (typically 8 Bit) with a start and a stop bit on the signal line. As long as the receiver does not see any such start bit, it simply waits until finally the start bit arrives (the receiver might also time out at some point, but since you use HAL_MAX_DELAY, the STM will wait for ever).
So without a delay, the STM immediately starts listening for the falling edge of the start bit.
With the delay, the transmitter might already have started sending data when the STM finally starts listening, so you miss the data. enter image description here Imagesource: Chris828 on wikimedia, distributed under a CC-BY 4.0 license.

\$\endgroup\$
3
  • \$\begingroup\$ This is technically correct at extremely high level, but wrong at the level of what roles do the UART and software take when receiving data. It's the UART that listen for start bits and sets a flag when a whole byte is received so the MCU can check if a byte is available from UART or not. \$\endgroup\$
    – Justme
    Mar 7 at 10:51
  • \$\begingroup\$ That does not make any difference at all in this code example, as the code just stays in the UART_Receive call until all 20 Bytes are read into memory. I dont't really get what exact part you think is wrong. The UART hardware waits for the falling edge and the software waits for the bytes to come in. Result is, the controller waits for the other party to send the data. \$\endgroup\$
    – jusaca
    Mar 7 at 14:53
  • \$\begingroup\$ Technically, the code does not wait for start bit, but code waits for UART to indicate it has successfully received a byte (or more) without errors. The difference is that the HAL does not disable or re-enable the reception or flush any receive buffers. Even without a FIFO, if there was a byte or two transferred before MCU code checks if bytes have arrived, it will get them from UART. If FIFOs were enabled, the HAL receive functiom will fetch as many bytes there might be in the FIFO, so it might work after all with some delays. \$\endgroup\$
    – Justme
    Mar 7 at 15:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.