mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-24 14:03:55 +01:00
Merge pull request #14285 from fjmolinas/pr_uart_nb_race
sam0/stm32: fix possible uart_nonblocking deadlock
This commit is contained in:
commit
07c78efc83
@ -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
|
||||
|
||||
/**
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user