summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwdfk-prog <[email protected]>2026-06-15 14:31:59 +0800
committerRbb666 <[email protected]>2026-06-27 11:39:10 +0800
commit1f9146897be1d898bea2a3ed0492c2d0a0507320 (patch)
tree403e514c1afc015fa9112a7c18fdc42b4636ac6c
parent187dc3fddfe45202f4c1000a724f38cdc742dd2e (diff)
feat[serial][v2]: add RX DMA event mode control
add serial v2 RX DMA event mode configuration for DMA-enabled builds support STM32 UART RX DMA half/full transfer interrupt policy selection validate RX DMA event mode before applying serial configuration restore serial configuration when backend configure fails
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/drv_usart_v2.c116
-rw-r--r--components/drivers/include/drivers/dev_serial_v2.h47
-rw-r--r--components/drivers/serial/dev_serial_v2.c39
3 files changed, 179 insertions, 23 deletions
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_usart_v2.c b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_usart_v2.c
index f766edb962..13412872c7 100644
--- a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_usart_v2.c
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_usart_v2.c
@@ -269,7 +269,7 @@ static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *ar
if (ctrl_arg & (RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX))
{
#ifdef RT_SERIAL_USING_DMA
- stm32_uart_dma_config(serial, ctrl_arg);
+ return stm32_uart_dma_config(serial, ctrl_arg);
#else
return -RT_ENOSYS;
#endif
@@ -411,12 +411,113 @@ static rt_ssize_t stm32_transmit(struct rt_serial_device *serial,
}
#ifdef RT_SERIAL_USING_DMA
+/**
+ * @brief Resolve effective STM32 UART RX DMA event mode.
+ * @param request Requested RX DMA event mode.
+ * @param effective Pointer to the output effective mode.
+ * @return Operation status.
+ */
+static rt_err_t stm32_uart_resolve_rx_dma_event_mode(enum rt_serial_rx_dma_event_mode request,
+ enum rt_serial_rx_dma_event_mode *effective)
+{
+ if (effective == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (request == RT_SERIAL_RX_DMA_EVENT_AUTO)
+ {
+ *effective = RT_SERIAL_RX_DMA_EVENT_HALF_FULL;
+ return RT_EOK;
+ }
+
+ if ((request != RT_SERIAL_RX_DMA_EVENT_NONE) &&
+ (request != RT_SERIAL_RX_DMA_EVENT_FULL_ONLY) &&
+ (request != RT_SERIAL_RX_DMA_EVENT_HALF_FULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ *effective = request;
+ return RT_EOK;
+}
+
+/**
+ * @brief Configure STM32 UART RX DMA transfer event interrupts.
+ * @param dma_handle Pointer to the RX DMA handle linked to the UART.
+ * @param mode Effective serial RX DMA event mode.
+ */
+static void stm32_uart_configure_rx_dma_events(DMA_HandleTypeDef *dma_handle, enum rt_serial_rx_dma_event_mode mode)
+{
+ if (dma_handle == RT_NULL)
+ {
+ return;
+ }
+
+ if (mode == RT_SERIAL_RX_DMA_EVENT_NONE)
+ {
+ __HAL_DMA_DISABLE_IT(dma_handle, DMA_IT_HT);
+ __HAL_DMA_DISABLE_IT(dma_handle, DMA_IT_TC);
+ }
+ else if (mode == RT_SERIAL_RX_DMA_EVENT_FULL_ONLY)
+ {
+ __HAL_DMA_DISABLE_IT(dma_handle, DMA_IT_HT);
+ __HAL_DMA_ENABLE_IT(dma_handle, DMA_IT_TC);
+ }
+ else
+ {
+ __HAL_DMA_ENABLE_IT(dma_handle, DMA_IT_HT);
+ __HAL_DMA_ENABLE_IT(dma_handle, DMA_IT_TC);
+ }
+}
+
+/**
+ * @brief Check whether one STM32 UART RX DMA event should be handled.
+ * @param serial Pointer to the serial device.
+ * @param isr_flag UART RX DMA ISR source flag.
+ * @return RT_TRUE if the event should be handled.
+ */
+static rt_bool_t stm32_uart_rx_dma_event_enabled(struct rt_serial_device *serial, rt_uint8_t isr_flag)
+{
+ enum rt_serial_rx_dma_event_mode mode;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ if (isr_flag == UART_RX_DMA_IT_IDLE_FLAG)
+ {
+ return RT_TRUE;
+ }
+
+ if (stm32_uart_resolve_rx_dma_event_mode(serial->config.rx_dma_event_mode, &mode) != RT_EOK)
+ {
+ return RT_FALSE;
+ }
+
+ if (isr_flag == UART_RX_DMA_IT_HT_FLAG)
+ {
+ return (mode == RT_SERIAL_RX_DMA_EVENT_HALF_FULL) ? RT_TRUE : RT_FALSE;
+ }
+
+ if (isr_flag == UART_RX_DMA_IT_TC_FLAG)
+ {
+ return (mode != RT_SERIAL_RX_DMA_EVENT_NONE) ? RT_TRUE : RT_FALSE;
+ }
+
+ return RT_FALSE;
+}
+
static void dma_recv_isr(struct rt_serial_device *serial, rt_uint8_t isr_flag)
{
struct stm32_uart *uart;
rt_size_t recv_len, counter;
RT_ASSERT(serial != RT_NULL);
+
+ if (stm32_uart_rx_dma_event_enabled(serial, isr_flag) != RT_TRUE)
+ {
+ return;
+ }
+
uart = rt_container_of(serial, struct stm32_uart, serial);
counter = __HAL_DMA_GET_COUNTER(&(uart->dma_rx.handle));
@@ -431,7 +532,7 @@ static void dma_recv_isr(struct rt_serial_device *serial, rt_uint8_t isr_flag)
rt_uint8_t *ptr = NULL;
rt_hw_serial_control_isr(serial, RT_HW_SERIAL_CTRL_GET_DMA_PING_BUF, (void *)&ptr);
SCB_InvalidateDCache_by_Addr((uint32_t *)ptr, serial->config.dma_ping_bufsz);
-#endif
+#endif /* defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) */
uart->dma_rx.remaining_cnt = counter;
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8));
}
@@ -494,13 +595,13 @@ static void uart_isr(struct rt_serial_device *serial)
}
#ifdef RT_SERIAL_USING_DMA
- if ((uart->uart_dma_flag) && (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_IDLE))
+ if ((uart->uart_dma_flag & RT_DEVICE_FLAG_DMA_RX) && (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_IDLE))
&& (__HAL_UART_GET_IT_SOURCE(&(uart->handle), UART_IT_IDLE)))
{
dma_recv_isr(serial, UART_RX_DMA_IT_IDLE_FLAG);
__HAL_UART_CLEAR_IDLEFLAG(&uart->handle);
}
-#endif
+#endif /* RT_SERIAL_USING_DMA */
if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_ORE))
{
@@ -1113,6 +1214,7 @@ static rt_err_t stm32_uart_dma_config(struct rt_serial_device *serial, rt_ubase_
DMA_HandleTypeDef *DMA_Handle;
const struct stm32_dma_config *dma_config;
struct stm32_uart *uart;
+ enum rt_serial_rx_dma_event_mode event_mode;
RT_ASSERT(serial != RT_NULL);
RT_ASSERT(flag == RT_DEVICE_FLAG_DMA_TX || flag == RT_DEVICE_FLAG_DMA_RX);
@@ -1122,6 +1224,11 @@ static rt_err_t stm32_uart_dma_config(struct rt_serial_device *serial, rt_ubase_
{
DMA_Handle = &uart->dma_rx.handle;
dma_config = uart->config->dma_rx;
+ if (stm32_uart_resolve_rx_dma_event_mode(serial->config.rx_dma_event_mode, &event_mode) != RT_EOK)
+ {
+ LOG_E("%s invalid uart dma rx event mode", uart->config->name);
+ return -RT_EINVAL;
+ }
}
else /* RT_DEVICE_FLAG_DMA_TX == flag */
{
@@ -1172,6 +1279,7 @@ static rt_err_t stm32_uart_dma_config(struct rt_serial_device *serial, rt_ubase_
DMA_Handle->Parent = RT_NULL;
return -RT_ERROR;
}
+ stm32_uart_configure_rx_dma_events(DMA_Handle, event_mode);
CLEAR_BIT(uart->handle.Instance->CR3, USART_CR3_EIE);
__HAL_UART_ENABLE_IT(&(uart->handle), UART_IT_IDLE);
}
diff --git a/components/drivers/include/drivers/dev_serial_v2.h b/components/drivers/include/drivers/dev_serial_v2.h
index b987bc4543..2a8d9145e6 100644
--- a/components/drivers/include/drivers/dev_serial_v2.h
+++ b/components/drivers/include/drivers/dev_serial_v2.h
@@ -225,21 +225,37 @@
#define RT_SERIAL_FLOWCONTROL_CTSRTS 1
#define RT_SERIAL_FLOWCONTROL_NONE 0
+#ifdef RT_SERIAL_USING_DMA
+/**
+ * @brief Serial RX DMA data event mode.
+ * @note This mode controls only DMA half/full transfer data events.
+ * UART IDLE interrupt remains enabled in RX DMA mode.
+ */
+enum rt_serial_rx_dma_event_mode
+{
+ RT_SERIAL_RX_DMA_EVENT_AUTO = 0, /**< Use the default RX DMA event mode. */
+ RT_SERIAL_RX_DMA_EVENT_NONE, /**< Disable DMA half/full data events; UART IDLE still reports received data. */
+ RT_SERIAL_RX_DMA_EVENT_FULL_ONLY, /**< Report only DMA transfer-complete data events plus UART IDLE. */
+ RT_SERIAL_RX_DMA_EVENT_HALF_FULL /**< Report both DMA half-transfer and transfer-complete data events plus UART IDLE. */
+};
+#endif /* RT_SERIAL_USING_DMA */
+
/* Default config for serial_configure structure */
#ifdef RT_SERIAL_USING_DMA
-#define RT_SERIAL_CONFIG_DEFAULT \
-{ \
- BAUD_RATE_115200, /* 115200 bits/s */ \
- DATA_BITS_8, /* 8 databits */ \
- STOP_BITS_1, /* 1 stopbit */ \
- PARITY_NONE, /* No parity */ \
- BIT_ORDER_LSB, /* LSB first sent */ \
- NRZ_NORMAL, /* Normal mode */ \
- RT_SERIAL_RX_MINBUFSZ, /* rxBuf size */ \
- RT_SERIAL_TX_MINBUFSZ, /* txBuf size */ \
- RT_SERIAL_FLOWCONTROL_NONE, /* Off flowcontrol */ \
- 0, /* reserved */ \
- RT_SERIAL_RX_MINBUFSZ / 2, /* dma_ping_bufsz */ \
+#define RT_SERIAL_CONFIG_DEFAULT \
+{ \
+ BAUD_RATE_115200, /* 115200 bits/s */ \
+ DATA_BITS_8, /* 8 databits */ \
+ STOP_BITS_1, /* 1 stopbit */ \
+ PARITY_NONE, /* No parity */ \
+ BIT_ORDER_LSB, /* LSB first sent */ \
+ NRZ_NORMAL, /* Normal mode */ \
+ RT_SERIAL_RX_MINBUFSZ, /* rxBuf size */ \
+ RT_SERIAL_TX_MINBUFSZ, /* txBuf size */ \
+ RT_SERIAL_FLOWCONTROL_NONE, /* Off flowcontrol */ \
+ 0, /* reserved */ \
+ RT_SERIAL_RX_MINBUFSZ / 2, /* dma_ping_bufsz */ \
+ RT_SERIAL_RX_DMA_EVENT_AUTO, /* rx dma event mode */ \
}
#else
#define RT_SERIAL_CONFIG_DEFAULT \
@@ -255,7 +271,7 @@
RT_SERIAL_FLOWCONTROL_NONE, /* Off flowcontrol */ \
0, /* reserved */ \
}
-#endif
+#endif /* RT_SERIAL_USING_DMA */
/**
* @brief Serial receive indicate hook function type
@@ -280,7 +296,8 @@ struct serial_configure
#ifdef RT_SERIAL_USING_DMA
rt_uint32_t dma_ping_bufsz :16;
-#endif
+ enum rt_serial_rx_dma_event_mode rx_dma_event_mode; /**< RX DMA half/full data event mode. */
+#endif /* RT_SERIAL_USING_DMA */
};
/**
diff --git a/components/drivers/serial/dev_serial_v2.c b/components/drivers/serial/dev_serial_v2.c
index d8cc2e0cb5..e7851f07ea 100644
--- a/components/drivers/serial/dev_serial_v2.c
+++ b/components/drivers/serial/dev_serial_v2.c
@@ -102,7 +102,7 @@ static int serial_fops_open(struct dfs_file *fd)
rt_device_close(device);
ret = rt_device_open(device, flags);
-
+
if (ret == RT_EOK)
{
serial = (struct rt_serial_device *)device;
@@ -1388,6 +1388,21 @@ static void _tc_flush(struct rt_serial_device *serial, int queue)
}
#endif /* RT_USING_POSIX_TERMIOS */
+#ifdef RT_SERIAL_USING_DMA
+/**
+ * @brief Check whether one serial RX DMA event mode value is valid.
+ * @param mode RX DMA event mode value.
+ * @return RT_TRUE if the mode value is valid.
+ */
+static rt_bool_t rt_serial_rx_dma_event_mode_valid(enum rt_serial_rx_dma_event_mode mode)
+{
+ return ((mode == RT_SERIAL_RX_DMA_EVENT_AUTO) ||
+ (mode == RT_SERIAL_RX_DMA_EVENT_NONE) ||
+ (mode == RT_SERIAL_RX_DMA_EVENT_FULL_ONLY) ||
+ (mode == RT_SERIAL_RX_DMA_EVENT_HALF_FULL)) ? RT_TRUE : RT_FALSE;
+}
+#endif /* RT_SERIAL_USING_DMA */
+
/**
* @brief Control the serial device.
* @param dev The pointer of device driver structure
@@ -1425,20 +1440,36 @@ static rt_err_t rt_serial_control(struct rt_device *dev,
else
{
struct serial_configure *pconfig = (struct serial_configure *)args;
+ struct serial_configure old_config = serial->config;
+
+#ifdef RT_SERIAL_USING_DMA
+ if (rt_serial_rx_dma_event_mode_valid(pconfig->rx_dma_event_mode) != RT_TRUE)
+ {
+ ret = -RT_EINVAL;
+ break;
+ }
+#endif /* RT_SERIAL_USING_DMA */
+
if (((pconfig->rx_bufsz != serial->config.rx_bufsz) || (pconfig->tx_bufsz != serial->config.tx_bufsz)
#ifdef RT_SERIAL_USING_DMA
|| (pconfig->dma_ping_bufsz != serial->config.dma_ping_bufsz)
-#endif
+ || (pconfig->rx_dma_event_mode != serial->config.rx_dma_event_mode)
+#endif /* RT_SERIAL_USING_DMA */
) &&
serial->parent.ref_count != 0)
{
- /*can not change buffer size*/
+ /* can not change buffer or DMA event configuration while opened */
ret = -RT_EBUSY;
break;
}
+
/* set serial configure */
serial->config = *pconfig;
- serial->ops->configure(serial, (struct serial_configure *)args);
+ ret = serial->ops->configure(serial, (struct serial_configure *)args);
+ if (ret != RT_EOK)
+ {
+ serial->config = old_config;
+ }
}
break;
case RT_SERIAL_CTRL_GET_CONFIG: