diff --git a/os/hal/include/hal_uart.h b/os/hal/include/hal_uart.h index 02537aa29..01a505c9a 100644 --- a/os/hal/include/hal_uart.h +++ b/os/hal/include/hal_uart.h @@ -279,7 +279,6 @@ typedef enum { _uart_wakeup_rx_error_isr(uartp); \ } - /** * @brief Common ISR code for RX on idle. * @details This code handles the portable part of the ISR code: @@ -298,6 +297,27 @@ typedef enum { if ((uartp)->config->rxchar_cb != NULL) \ (uartp)->config->rxchar_cb(uartp, (uartp)->rxbuf); \ } + + +/** + * @brief Timeout ISR code for receiver. + * @details This code handles the portable part of the ISR code: + * - Callback invocation. + * - Waiting thread wakeup, if any. + * - Driver state transitions. + * . + * @note This macro is meant to be used in the low level drivers + * implementation only. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @notapi + */ +#define _uart_timeout_isr_code(uartp) { \ + if ((uartp)->config->timeout_cb != NULL) \ + (uartp)->config->timeout_cb(uartp); \ +} + /** @} */ /*===========================================================================*/ diff --git a/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c b/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c index ceb14fe67..0012ef259 100644 --- a/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c +++ b/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c @@ -220,6 +220,7 @@ static void usart_stop(UARTDriver *uartp) { */ static void usart_start(UARTDriver *uartp) { uint32_t cr1; + const uint32_t tmo = uartp->config->timeout; USART_TypeDef *u = uartp->usart; /* Defensive programming, starting from a clean state.*/ @@ -242,6 +243,13 @@ static void usart_start(UARTDriver *uartp) { cr1 = USART_CR1_UE | USART_CR1_PEIE | USART_CR1_TE | USART_CR1_RE; u->CR1 = uartp->config->cr1 | cr1; + /* Set receive timeout and check it appliance */ + if (tmo > 0) { + osalDbgAssert(tmo <= USART_RTOR_RTO, "Timeout overflow"); + u->RTOR = tmo; + osalDbgAssert(tmo == u->RTOR, "Timeout feature unsupported in this UART"); + } + /* Starting the receiver idle loop.*/ uart_enter_rx_idle_loop(uartp); } @@ -325,6 +333,10 @@ static void serve_usart_irq(UARTDriver *uartp) { /* End of transmission, a callback is generated.*/ _uart_tx2_isr_code(uartp); } + + if ((isr & USART_ISR_IDLE) || (isr & USART_ISR_RTOF)) { + _uart_timeout_isr_code(uartp); + } } /*===========================================================================*/ diff --git a/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.h b/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.h index abb9bce0a..84afee0e1 100644 --- a/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.h +++ b/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.h @@ -585,6 +585,16 @@ typedef struct { */ uartecb_t rxerr_cb; /* End of the mandatory fields.*/ + /** + * @brief Receiver timeout callback. + */ + uartcb_t timeout_cb; + /** + * @brief Receiver timeout value in terms of number of bit duration. + * @details Set it to 0 when you want to handle IDLE interrupt instead of + * hardware timeout. + */ + uint32_t timeout; /** * @brief Bit rate. */ diff --git a/testhal/STM32/STM32F0xx/UART/main.c b/testhal/STM32/STM32F0xx/UART/main.c index 16a7ba582..08c60b9ad 100644 --- a/testhal/STM32/STM32F0xx/UART/main.c +++ b/testhal/STM32/STM32F0xx/UART/main.c @@ -91,6 +91,14 @@ static void rxend(UARTDriver *uartp) { (void)uartp; } +/* + * This callback is invoked when configured timeout reached. + */ +static void rxtimeout(UARTDriver *uartp) { + + (void)uartp; +} + /* * UART driver configuration structure. */ @@ -100,6 +108,8 @@ static UARTConfig uart_cfg_1 = { rxend, rxchar, rxerr, + rxtimeout, + 0, 38400, 0, USART_CR2_LINEN, diff --git a/testhal/STM32/STM32F37x/UART/main.c b/testhal/STM32/STM32F37x/UART/main.c index c31077c79..431763070 100644 --- a/testhal/STM32/STM32F37x/UART/main.c +++ b/testhal/STM32/STM32F37x/UART/main.c @@ -91,6 +91,14 @@ static void rxend(UARTDriver *uartp) { (void)uartp; } +/* + * This callback is invoked when configured timeout reached. + */ +static void rxtimeout(UARTDriver *uartp) { + + (void)uartp; +} + /* * UART driver configuration structure. */ @@ -100,6 +108,8 @@ static UARTConfig uart_cfg_1 = { rxend, rxchar, rxerr, + rxtimeout, + 0, 38400, 0, USART_CR2_LINEN, diff --git a/testhal/STM32/STM32F3xx/UART/main.c b/testhal/STM32/STM32F3xx/UART/main.c index 30abb55d3..1ef5bb6b9 100644 --- a/testhal/STM32/STM32F3xx/UART/main.c +++ b/testhal/STM32/STM32F3xx/UART/main.c @@ -91,6 +91,14 @@ static void rxend(UARTDriver *uartp) { (void)uartp; } +/* + * This callback is invoked when configured timeout reached. + */ +static void rxtimeout(UARTDriver *uartp) { + + (void)uartp; +} + /* * UART driver configuration structure. */ @@ -100,6 +108,8 @@ static UARTConfig uart_cfg_1 = { rxend, rxchar, rxerr, + rxtimeout, + 0, 38400, 0, USART_CR2_LINEN,