Search code examples
serial-portstm32interruptirqstm32h743

USART3_IRQHandler() is continuously called with LL_USART_IsActiveFlag_TXE set


I'm to developing my own serial code (rather than using CubeMX's HAL) to interface an existing protocol codebase which needs low-level serial features.

USART3_IRQHandler() is being called repeatedly (and hence serial::serial_irq_handler() too.

/**
  * @brief This function handles USART3 global interrupt.
  */
void USART3_IRQHandler(void)
{
  /* USER CODE BEGIN USART3_IRQn 0 */
  serial_irq_handler(&usart3);
  /* USER CODE END USART3_IRQn 0 */
  /* USER CODE BEGIN USART3_IRQn 1 */

  /* USER CODE END USART3_IRQn 1 */
}

serial.c:

/**
 * @brief Should be called only by UART/USARTx_IRQHandler()
 */
void serial_irq_handler(struct serial *serial)
{
    // "while" is used in case we decide to turn on the limited FIFOs (USARTs only).
    while (LL_USART_IsActiveFlag_RXNE(serial->usart)) {
        uint8_t b = LL_USART_ReceiveData8(serial->usart);
        circbuf_push(&serial->rxcircbuf, b);
    }

    if (LL_USART_IsActiveFlag_TXE(serial->usart)) {
        LL_USART_ClearFlag_TC(serial->usart);
        serial->txbusy = 0;
    }
}

(serial->usart == USART3 in the code above.)

I think that the problem is that I am clearing the wrong flag (TC instead of TXE).

Is this the cause of the issue?

I cannot clear TXE, as LL_USART_ClearFlag_TXE() does not exist.

If I comment out LL_USART_EnableIT_TXE(serial->usart); in the intialisation code, the issue goes away (but I then cannot then see if the serial port is free to write to).


Solution

  • Wrong logic.

    TXE interrupt should be enbled only if you have some data to send.

    When you finish feeding the data register - you disable it.

    It is logical that there is no TXE clear flag. EMPTY flag can be only cleared by making it not empty

    but I then cannot then see if the serial port is free to write to

    You need to implement a buffer. And check if you have space in the buffer to place new data to send.