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).
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.