cancel
Showing results for 
Search instead for 
Did you mean: 

Did I find a bug in the UART HAL Library for the STM32H7xx processor?

JSpon
Associate

I was building a test application to make sure I understood the operation of the UARTs on the STM32H743 series MCUs. Using a NUCLEO-H743ZI board, I mapped USART1 and USART2 to exposed pins, and connect those pins in a crossover so UART1 and UART2 can send/ receive from each other. Using the CubeMX I created a project with the UARTs enabled and both UARTs had the FIFO disabled.

.Init.FIFOMode = UART_FIFOMODE_DISABLE;

Running the following code: (assume messagebuffers are allocated, RXComplete is a global)

RXComplete=0;
HAL_UART_Receive_IT(&huart1,&messagerx,1);
HAL_UART_Transmit(&huart2,&messagetx,1,HAL_MAX_DELAY);
while (RXComplete==0);

with the addition of

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	RXComplete=1;
}

The behavior was exactly as expected. A single character was sent and received. The Receive_IT call sets up the interrupt receive, and the RxCpltCallback is called after single byte is received. The transmit is done after the receive interrupt is setup, and All is good.

If you modify that code simply to send more data, say 16 bytes:

RXComplete=0;
HAL_UART_Receive_IT(&huart1,&messagerx,16);
HAL_UART_Transmit(&huart2,&messagetx,16,HAL_MAX_DELAY);
while (RXComplete==0);

This code executes as above, sending and receiving 16 bytes and all is well. If you then change USART1 to use the FIFO (it makes no difference what you do with USART2)

huart1.Init.FIFOMode = UART_FIFOMODE_ENABLE;

And run the test with 1 byte sent and 1 byte received it works as expected. However, if you run the test with 16 bytes sent and received AND the FIFO enabled the code never goes past the while statement, and UART1 appears to only get 15 bytes. (You can verify this by also incrementing a flag in the UART1 interrupt and see that there are only 15 interrupts). If you change the code such that 17 bytes are transmitted, you get the correct first 16 bytes, but in the next cycle (assuming you loop that code) you get that 17th byte first before the next 15. That is exactly as you would expect, with the exception of not getting the interrupt on the 16th byte the first time. I should note there is a setting for the RXFIFO interrupt threshold (1/8 to 8/8ths), but that setting does not solve this problem regardless of setting.

If you look at HAL_UART_Receive_IT() in stm32h7xx_hal_uart.c you find this segment of code:

if (READ_BIT(huart->Instance->CR1, USART_CR1_FIFOEN) != RESET)
    {
      SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);          
      SET_BIT(huart->Instance->CR3, USART_CR3_RXFTIE);
    }
    else
    {
      SET_BIT(huart->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);
    }

Sure enough if the FIFO is enabled, the FiFO Full interrupt (RXFT) is enabled, but the RX Buffer Not Empty (RXNE) interrupt is not. This means you will get an interrupt for the FIFO fill level (based on the RXThreshold setting), but not when the last byte is transferred out of the FIFO and into the UART receive register. If there is only 1 byte received you will still get 1 interrupt, which is why the code works when you are only receiving one byte,

If you change the code by adding the the additional USART_CR1_RXNEIE if the FIFO is enabled -

if (READ_BIT(huart->Instance->CR1, USART_CR1_FIFOEN) != RESET)
    {
    	SET_BIT(huart->Instance->CR1, USART_CR1_PEIE| USART_CR1_RXNEIE);         
    	SET_BIT(huart->Instance->CR3, USART_CR3_RXFTIE);
    }
    else
    {
      SET_BIT(huart->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);
    }

Now the original code works as expected when you transmit and receive 1 byte, 16 bytes, or an other size. This would seem to be a bug in that library since as written you will wait forever for the complete callback if you request anything over 1 byte AND receive exactly that number of bytes.

Is there a different place for a bug submission for the STM32H7xx HAL?

Jeff Sponaugle

0 REPLIES 0