2
\$\begingroup\$

I am implementing communication between Nucleo-F072RB board and an evaluation board with TI BQ75614 BMS IC.

I have succeeded to communicate with the IC using 1 Mbps UART interface, successfully sending commands and getting a response, which I confirmed using a logic analyzer:
UART Communication frames: the upper one is sent from microcontroller, the second one is the response frame UART Communication frames: the upper one is sent from microcontroller, the second one is the response frame

The upper is Read command send from MCU, and the second is the response from the BQ75614 IC. As it can be seen, the frame consists of following data: 01 01 05 36 00 00 DC C8

The communication is implemented using simple, blocking HAL_UART_Receive function:
(data_length is 2)

HAL_StatusTypeDef UART_STATUS;
UART_STATUS = HAL_UART_Receive(huart, UART_RX_Buffer, 6+data_length, 5);

Right before the HAL_UART_Receive, I am transmitting the command frame (the upper 80 01 05 36 01 E2 43).

The problem: HAL_UART_Receive always adds an empty byte at the beginning. That is, instead of getting 01 01 05 36 00 00 DC C8, the UART_RX_Buffer (which is a statically allocated 128 byte array) is populated with 00 01 01 05 36 00 00 DC - the last byte is not received, because the HAL_UART_Receive was prompted to receive 8 bytes, and the existence of the random 0x00 byte prevented the last byte from being read.

I have tried reproducing this problem trying to parse frames with e.g. different length. Again, there always is a 0x00 byte at the beginning. This really gives me headache, because in reality the logic analyzer does not find any such "shadow" byte at the beginning.

Here is my UART configuration:

UART configuration as seen in CubeMX

\$\endgroup\$
5
  • 1
    \$\begingroup\$ What if there is a zero byte received before you even send this command? If this is the first commanf, what if there is zero byte received because the other chip is still powering up and there was garbage on the wire? Why don't you receive data until none is received before you start sending a command and expecting a response? Take a new logic capture with the board powering up and sending the first command and receiving first command, do you see anything that can be interpreted as 0x00, such as the data line being low until it rises? \$\endgroup\$
    – Justme
    Nov 18, 2023 at 13:24
  • 1
    \$\begingroup\$ You are probably enabling the UART (thus also its receiver) while the line is still low, for example while the BQ75614 has not powered up or some pullup is not activated. Set a pin to GPIO output and toggle it just before UART is initialized, and observe that and the Rx line on oscilloscope/LA. \$\endgroup\$
    – wek
    Nov 18, 2023 at 13:26
  • \$\begingroup\$ Here are the lines from the reset.. On the upper (MCU's TX) line, there is a WAKE command for the BQ75614 (2,5 ms low). Next, there is a WRITE command that clears all IC's faults, and three consecutive reads (the same, as in the main post) that are visible on the lower (MCU's RX) line. All the three reads after zooming in look exactly the same, as the screen in the main post. The first one returns 0x00 as the first byte, and the two next return the same garbage (0xC8) first. The RX and TX lines have pullup to 3.3V to avoid random states during reset \$\endgroup\$
    – block3r
    Nov 18, 2023 at 13:40
  • \$\begingroup\$ C8 is likely not 'garbage' but is instead the remaining byte from your 1st command response. You're off by one byte due to the 00 that's there form startup, and you continue to remain off by 1 byte every time you read from the UART because you only ever read the exact number of bytes you expect. You need to clear the UART buffer and/or FIFO before you start reading from it. \$\endgroup\$
    – brhans
    Nov 18, 2023 at 14:28
  • \$\begingroup\$ You are right. I have checked and this is the last, CRC byte of the previous response - thank you very much for this hint! I have resolved the issue by clearing the RX buffer this way, once, right after startup: while(HAL_TIMEOUT != HAL_UART_Receive(&huart1, &tmp, 1, 10)); I definitely need to improve my understanding how HAL drivers work, though. I am curious what caused the 0x00 to be in the buffer in the first place, and why it affected next readings - I thought that the buffer is flushed by HAL before every read. \$\endgroup\$
    – block3r
    Nov 18, 2023 at 15:00

1 Answer 1

2
\$\begingroup\$

As brhans mentioned, the problem was that after reset, an empty 0x00 byte came into the buffer and caused every next frame to be shifted by 1 byte - the first byte was the last byte from the previous reponse.

The issue was resolved by clearing the buffer until timeout with:

while(HAL_TIMEOUT != HAL_UART_Receive(&huart1, &tmp, 1, 10));

After initializing the UART and before starting any communication.

\$\endgroup\$
1
  • \$\begingroup\$ If the version of the STM32 HAL you're using supports it, __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST); might be a better way to empty the UART's RX buffer. \$\endgroup\$
    – brhans
    Nov 20, 2023 at 17:09

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.