diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index 2dd5839aad..9796867d6d 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -194,8 +194,8 @@ typedef enum { /** * @brief Size of the UART TX buffer for non-blocking mode. */ -#ifndef SAM0_UART_TXBUF_SIZE -#define SAM0_UART_TXBUF_SIZE (64) +#ifndef UART_TXBUF_SIZE +#define UART_TXBUF_SIZE (64) #endif /** diff --git a/cpu/sam0_common/periph/uart.c b/cpu/sam0_common/periph/uart.c index 366edbae9e..d080a82057 100644 --- a/cpu/sam0_common/periph/uart.c +++ b/cpu/sam0_common/periph/uart.c @@ -41,7 +41,7 @@ #ifdef MODULE_PERIPH_UART_NONBLOCKING #include "tsrb.h" static tsrb_t uart_tx_rb[UART_NUMOF]; -static uint8_t uart_tx_rb_buf[UART_NUMOF][SAM0_UART_TXBUF_SIZE]; +static uint8_t uart_tx_rb_buf[UART_NUMOF][UART_TXBUF_SIZE]; #endif static uart_isr_ctx_t uart_ctx[UART_NUMOF]; @@ -68,7 +68,7 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) #ifdef MODULE_PERIPH_UART_NONBLOCKING /* set up the TX buffer */ - tsrb_init(&uart_tx_rb[uart], uart_tx_rb_buf[uart], SAM0_UART_TXBUF_SIZE); + tsrb_init(&uart_tx_rb[uart], uart_tx_rb_buf[uart], UART_TXBUF_SIZE); #endif /* configure pins */ @@ -176,7 +176,17 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len) { #ifdef MODULE_PERIPH_UART_NONBLOCKING for (const void* end = data + len; data != end; ++data) { - while (tsrb_add_one(&uart_tx_rb[uart], *data) < 0) {} + if (irq_is_in() || __get_PRIMASK()) { + /* if ring buffer is full free up a spot */ + if (tsrb_full(&uart_tx_rb[uart])) { + while (!dev(uart)->INTFLAG.bit.DRE) {} + dev(uart)->DATA.reg = tsrb_get_one(&uart_tx_rb[uart]); + } + tsrb_add_one(&uart_tx_rb[uart], *data); + } + else { + while (tsrb_add_one(&uart_tx_rb[uart], *data) < 0) {} + } dev(uart)->INTENSET.reg = SERCOM_USART_INTENSET_DRE; } #else diff --git a/cpu/stm32/include/periph_cpu.h b/cpu/stm32/include/periph_cpu.h index 2b3f6e60a3..c9bc9f1007 100644 --- a/cpu/stm32/include/periph_cpu.h +++ b/cpu/stm32/include/periph_cpu.h @@ -550,8 +550,8 @@ typedef enum { /** * @brief Size of the UART TX buffer for non-blocking mode. */ -#ifndef STM32_UART_TXBUF_SIZE -#define STM32_UART_TXBUF_SIZE (64) +#ifndef UART_TXBUF_SIZE +#define UART_TXBUF_SIZE (64) #endif #ifndef DOXYGEN diff --git a/cpu/stm32/periph/uart.c b/cpu/stm32/periph/uart.c index ea0d8b26ae..d7888971fb 100644 --- a/cpu/stm32/periph/uart.c +++ b/cpu/stm32/periph/uart.c @@ -61,7 +61,7 @@ * @brief Allocate for tx ring buffers */ static tsrb_t uart_tx_rb[UART_NUMOF]; -static uint8_t uart_tx_rb_buf[UART_NUMOF][STM32_UART_TXBUF_SIZE]; +static uint8_t uart_tx_rb_buf[UART_NUMOF][UART_TXBUF_SIZE]; #endif /** @@ -168,7 +168,7 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) #ifdef MODULE_PERIPH_UART_NONBLOCKING /* set up the TX buffer */ - tsrb_init(&uart_tx_rb[uart], uart_tx_rb_buf[uart], STM32_UART_TXBUF_SIZE); + tsrb_init(&uart_tx_rb[uart], uart_tx_rb_buf[uart], UART_TXBUF_SIZE); #endif uart_init_pins(uart, rx_cb); @@ -207,6 +207,10 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) dev(uart)->CR1 = (USART_CR1_UE | USART_CR1_TE); } +#ifdef MODULE_PERIPH_UART_NONBLOCKING + NVIC_EnableIRQ(uart_config[uart].irqn); +#endif + #ifdef MODULE_PERIPH_UART_HW_FC if (uart_config[uart].cts_pin != GPIO_UNDEF) { dev(uart)->CR3 |= USART_CR3_CTSE; @@ -318,22 +322,18 @@ static inline void uart_init_lpuart(uart_t uart, uint32_t baudrate) #endif /* MODULE_PERIPH_LPUART */ #endif /* STM32L0 || STM32L4 || STM32WB */ -#ifndef MODULE_PERIPH_UART_NONBLOCKING static inline void send_byte(uart_t uart, uint8_t byte) { while (!(dev(uart)->ISR_REG & ISR_TXE)) {} dev(uart)->TDR_REG = byte; } -#endif +#ifndef MODULE_PERIPH_UART_NONBLOCKING static inline void wait_for_tx_complete(uart_t uart) { -#ifdef MODULE_PERIPH_UART_NONBLOCKING - (void) uart; -#else while (!(dev(uart)->ISR_REG & ISR_TC)) {} -#endif } +#endif void uart_write(uart_t uart, const uint8_t *data, size_t len) { @@ -383,17 +383,28 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len) return; } #endif - for (size_t i = 0; i < len; i++) { #ifdef MODULE_PERIPH_UART_NONBLOCKING + for (size_t i = 0; i < len; i++) { dev(uart)->CR1 |= (USART_CR1_TCIE); - while (tsrb_add_one(&uart_tx_rb[uart], data[i]) < 0) {} + if (irq_is_in() || __get_PRIMASK()) { + /* if ring buffer is full free up a spot */ + if (tsrb_full(&uart_tx_rb[uart])) { + send_byte(uart, tsrb_get_one(&uart_tx_rb[uart])); + } + tsrb_add_one(&uart_tx_rb[uart], data[i]); + } + else { + while (tsrb_add_one(&uart_tx_rb[uart], data[i]) < 0) {} + } + } #else + for (size_t i = 0; i < len; i++) { send_byte(uart, data[i]); -#endif } /* make sure the function is synchronous by waiting for the transfer to * finish */ wait_for_tx_complete(uart); +#endif } void uart_poweron(uart_t uart) diff --git a/tests/periph_uart_nonblocking/main.c b/tests/periph_uart_nonblocking/main.c index 62e2f6fabb..d5e1bbf631 100644 --- a/tests/periph_uart_nonblocking/main.c +++ b/tests/periph_uart_nonblocking/main.c @@ -30,8 +30,21 @@ static inline uint32_t puts_delay(const char* str) return LINE_DELAY_MS * 1000; } +static void _irq_disabled_print(void) +{ + unsigned state = irq_disable(); + /* fill the transmit buffer */ + for (uint8_t i = 0; i < UART_TXBUF_SIZE; i++) { + printf(" "); + } + puts("\nputs with disabled interrupts and a full transmit buffer"); + irq_restore(state); +} + int main(void) { + _irq_disabled_print(); + uint32_t total_us = 0; xtimer_ticks32_t counter = xtimer_now(); diff --git a/tests/periph_uart_nonblocking/tests/01-run.py b/tests/periph_uart_nonblocking/tests/01-run.py index 0a412e5086..028db2dcdf 100755 --- a/tests/periph_uart_nonblocking/tests/01-run.py +++ b/tests/periph_uart_nonblocking/tests/01-run.py @@ -14,6 +14,7 @@ PRECISION = 1.002 def testfunc(child): + child.expect_exact("puts with disabled interrupts and a full transmit buffer") child.expect(r'== printed in (\d+)/(\d+) µs ==') time_actual = int(child.match.group(1)) time_expect = int(child.match.group(2))