Currently the UART driver is not usable with hardware flow control due to the rx idle loop, which makes the "rxchar_cb" callback possible.
Suppose you are attempting to receive a packetized protocol. You want to be able to receive a complete packet, and then allow some upper protocol layer to process the packet before receiving the next packet. For overall system performance, you don't want to do this processing in the "rxend_cb" callback.
You can either dedicate a single buffer, or have a queue of buffers available, but in either case you need a way to stall the receiving of the next packet until you have a buffer available.
Unfortunately, because the rx idle loop configures a circular dma transaction, there is no way to prevent reception for some period of time.
Perhaps an option to check if USART_CR3_RTSE is enabled in uart_enter_rx_idle_loop before configuring the dma transaction?
Something like this perhaps?
hal_uart.h
Code: Select all
// this allows disabling the idle loop entirely for all UART's if possible
#if !defined(UART_USE_RX_IDLE_LOOP) || defined(__DOXYGEN__)
#define UART_USE_RX_IDLE_LOOP TRUE
#endif
hal_uart_lld.h
Code: Select all
// this allows leaving idle loop in tact, but disabling it on a per driver basis with some runtime overhead
#if !defined(STM32_UART_RTS_IDLE_LOOP_DETECTION) || defined(__DOXYGEN__)
#define STM32_UART_RTS_IDLE_LOOP_DETECTION FALSE
#endif
hal_uart_lld.c
Code: Select all
static void uart_enter_rx_idle_loop(UARTDriver *uartp) {
#if UART_USE_RX_IDLE_LOOP
#if STM32_UART_RTS_IDLE_LOOP_DETECTION
if ((uartp->usart->CR3 & USART_CR3_RTSE) != 0) return;
#endif // STM32_UART_RTS_IDLE_LOOP_DETECTION
uint32_t mode;
/* RX DMA channel preparation, if the char callback is defined then the
TCIE interrupt is enabled too.*/
if (uartp->config->rxchar_cb == NULL)
mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_CIRC;
else
mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_CIRC | STM32_DMA_CR_TCIE;
dmaStreamSetMemory0(uartp->dmarx, &uartp->rxbuf);
dmaStreamSetTransactionSize(uartp->dmarx, 1);
dmaStreamSetMode(uartp->dmarx, uartp->dmamode | mode);
dmaStreamEnable(uartp->dmarx);
#endif // UART_USE_RX_IDLE_LOOP
}