USART3_IRQHandler() постоянно вызывается с установленным LL_USART_IsActiveFlag_TXE
Я разрабатываю свой собственный последовательный код (вместо использования CubeMX HAL) для взаимодействия с существующей кодовой базой протокола, которая требует низкоуровневых последовательных функций.
USART3_IRQHandler()
вызывается повторно (и, следовательно, serial::serial_irq_handler()
слишком.
/**
* @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
в коде выше.)
Я думаю, что проблема в том, что я сбрасываю неправильный флаг (TC вместо TXE).
Это причина проблемы?
Я не могу очистить TXE, так как LL_USART_ClearFlag_TXE()
не существует.
Если я закомментирую LL_USART_EnableIT_TXE(serial->usart);
в коде инициализации проблема исчезает (но тогда я не могу увидеть, свободен ли последовательный порт для записи).
2 ответа
Неправильная логика.
Прерывание TXE следует разрешать, только если у вас есть данные для отправки.
Когда закончишь кормить регистр данных - отключаешь.
Логично, что нет флага сброса TXE. Флаг EMPTY можно сбросить, только сделав его не пустым
но тогда я не могу увидеть, свободен ли последовательный порт для записи на
Вам нужно реализовать буфер. И проверьте, есть ли у вас место в буфере для размещения новых данных для отправки.
У меня была неправильная логика, как указал P__J__.
Новый код выглядит так и работает.
serial.c:
int serial_tx(struct serial *serial, uint8_t byte) {
if (serial->txbusy) {
serial->stats.txbusy++;
return -1;
}
serial->txbusy = 1;
LL_USART_TransmitData8(serial->usart, byte);
LL_USART_EnableIT_TXE(serial->usart);
serial->stats.txbytes++;
return 0;
}
int serial_rx(struct serial *serial, uint8_t *out) {
return circbuf_pop(&serial->rxcircbuf, out);
}
/*
* @brief Should be called only by void 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_DisableIT_TXE(serial->usart);
serial->txbusy = 0;
}
}
Мне пришлось реализовать байтовый ввод-вывод, а не буферизовать, поскольку это то, что требовалось для более высоких (ранее существовавших) уровней связи.
-- Обновить --
Небольшие вариации этого кода не работают. Я попытался задействовать флаг TXC, прежде чем мне дали ссылку на более 3000 страниц руководства для этого чипа. Глава 48 содержит подробности USART.