summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/action.yml2
-rw-r--r--bsp/bluetrum/libraries/hal_drivers/SConscript5
-rw-r--r--bsp/bluetrum/libraries/hal_drivers/drv_usartX.c348
-rw-r--r--bsp/bluetrum/libraries/hal_drivers/drv_usartX.h40
-rw-r--r--bsp/gd32/arm/libraries/gd32_drivers/SConscript5
-rw-r--r--bsp/gd32/arm/libraries/gd32_drivers/drv_usartX.c848
-rw-r--r--bsp/gd32/arm/libraries/gd32_drivers/drv_usartX.h64
-rw-r--r--bsp/n32/libraries/n32_drivers/SConscript2
-rw-r--r--bsp/n32/libraries/n32_drivers/drv_usartX.c839
-rw-r--r--bsp/n32/libraries/n32_drivers/drv_usartX.h39
-rw-r--r--bsp/nuvoton/libraries/nuc980/rtt_port/drv_common.c4
-rw-r--r--bsp/nuvoton/libraries/nuc980/rtt_port/drv_uartX.c390
-rw-r--r--bsp/nuvoton/libraries/nuc980/rtt_port/drv_uartX.h79
-rw-r--r--bsp/renesas/libraries/HAL_Drivers/SConscript2
-rw-r--r--bsp/renesas/libraries/HAL_Drivers/drv_usartX.c625
-rw-r--r--bsp/renesas/libraries/HAL_Drivers/drv_usartX.h39
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/SConscript2
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drv_usartX.c939
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drv_usartX.h73
-rw-r--r--bsp/stm32/stm32f429-armfly-v6/board/Kconfig5
-rw-r--r--bsp/stm32/stm32f429-atk-apollo/board/Kconfig15
-rw-r--r--bsp/stm32/stm32f429-fire-challenger/board/Kconfig10
-rw-r--r--bsp/stm32/stm32f429-st-disco/board/Kconfig10
-rwxr-xr-xcomponents/drivers/Kconfig34
-rw-r--r--components/drivers/include/drivers/serialX.h216
-rw-r--r--components/drivers/include/rtdevice.h5
-rw-r--r--components/drivers/serial/SConscript3
-rw-r--r--components/drivers/serial/serialX-doc/serialX User Manual.md124
-rw-r--r--components/drivers/serial/serialX.c1637
-rw-r--r--include/rtdef.h9
-rw-r--r--include/rtthread.h1
-rw-r--r--src/device.c40
32 files changed, 6446 insertions, 8 deletions
diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml
index a15feed198..1ad6634774 100644
--- a/.github/workflows/action.yml
+++ b/.github/workflows/action.yml
@@ -8,7 +8,7 @@ on:
- cron: '0 16 1 * *'
push:
branches:
- - master
+ - serialX-dev
paths-ignore:
- documentation/**
- '**/README.md'
diff --git a/bsp/bluetrum/libraries/hal_drivers/SConscript b/bsp/bluetrum/libraries/hal_drivers/SConscript
index b35a6e89cc..50a895e1d9 100644
--- a/bsp/bluetrum/libraries/hal_drivers/SConscript
+++ b/bsp/bluetrum/libraries/hal_drivers/SConscript
@@ -12,7 +12,10 @@ if GetDepend('RT_USING_PIN'):
src += ['drv_gpio.c']
if GetDepend('RT_USING_SERIAL'):
- src += ['drv_usart.c']
+ if GetDepend(['RT_USING_SERIAL_X']):
+ src += ['drv_usartX.c']
+ else:
+ src += ['drv_usart.c']
if GetDepend('RT_USING_SDIO'):
src += ['drv_sdio.c']
diff --git a/bsp/bluetrum/libraries/hal_drivers/drv_usartX.c b/bsp/bluetrum/libraries/hal_drivers/drv_usartX.c
new file mode 100644
index 0000000000..c3b0e9299b
--- /dev/null
+++ b/bsp/bluetrum/libraries/hal_drivers/drv_usartX.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2020-2022, Bluetrum Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020-11-20 greedyhao first version
+ * 2022-06-08 THEWON first version for serialX
+ */
+
+#include "board.h"
+#include <drv_usartX.h>
+
+#ifdef RT_USING_SERIAL
+
+//#define DRV_DEBUG
+#define LOG_TAG "drv.usart"
+#include <drv_log.h>
+
+enum
+{
+#ifdef BSP_USING_UART0
+ UART0_INDEX,
+#endif
+#ifdef BSP_USING_UART1
+ UART1_INDEX,
+#endif
+#ifdef BSP_USING_UART2
+ UART2_INDEX,
+#endif
+};
+
+static struct ab32_uart_config uart_config[] =
+{
+#ifdef BSP_USING_UART0
+ {
+ .name = "uart0",
+ .instance = UART0_BASE,
+ .mode = UART_MODE_TX_RX | UART_MODE_1LINE,
+ },
+#endif
+#ifdef BSP_USING_UART1
+ {
+ .name = "uart1",
+ .instance = UART1_BASE,
+ .mode = UART_MODE_TX_RX,
+ },
+#endif
+#ifdef BSP_USING_UART2
+ {
+ .name = "uart2",
+ .instance = UART2_BASE,
+ .mode = UART_MODE_TX_RX,
+ }
+#endif
+};
+
+static struct ab32_uart uart_obj[sizeof(uart_config) / sizeof(uart_config[0])] = {0};
+
+static rt_err_t ab32_init(struct rt_serial_device *serial)
+{
+ struct ab32_uart *uart;
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct ab32_uart, serial);
+ uart->handle.instance = uart->uart_config->instance;
+ uart->handle.init.baud = serial->config->baud_rate;
+ uart->handle.init.mode = uart->uart_config->mode;
+
+ switch (serial->config->data_bits)
+ {
+ case DATA_BITS_8:
+ uart->handle.init.word_len = UART_WORDLENGTH_8B;
+ break;
+ case DATA_BITS_9:
+ uart->handle.init.word_len = UART_WORDLENGTH_9B;
+ break;
+ default:
+ uart->handle.init.word_len = UART_WORDLENGTH_8B;
+ break;
+ }
+
+ switch (serial->config->stop_bits)
+ {
+ case STOP_BITS_1:
+ uart->handle.init.stop_bits = UART_STOPBITS_1;
+ break;
+ case STOP_BITS_2:
+ uart->handle.init.stop_bits = UART_STOPBITS_2;
+ break;
+ default:
+ uart->handle.init.stop_bits = UART_STOPBITS_1;
+ break;
+ }
+
+ hal_uart_init(&uart->handle);
+
+ return RT_EOK;
+}
+
+static rt_err_t ab32_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
+{
+ struct ab32_uart *uart;
+ RT_ASSERT(serial != RT_NULL);
+ RT_ASSERT(cfg != RT_NULL);
+
+ uart = rt_container_of(serial, struct ab32_uart, serial);
+ uart->handle.instance = uart->uart_config->instance;
+ uart->handle.init.baud = cfg->baud_rate;
+ uart->handle.init.mode = uart->uart_config->mode;
+
+ switch (cfg->data_bits)
+ {
+ case DATA_BITS_8:
+ uart->handle.init.word_len = UART_WORDLENGTH_8B;
+ break;
+ case DATA_BITS_9:
+ uart->handle.init.word_len = UART_WORDLENGTH_9B;
+ break;
+ default:
+ uart->handle.init.word_len = UART_WORDLENGTH_8B;
+ break;
+ }
+
+ switch (cfg->stop_bits)
+ {
+ case STOP_BITS_1:
+ uart->handle.init.stop_bits = UART_STOPBITS_1;
+ break;
+ case STOP_BITS_2:
+ uart->handle.init.stop_bits = UART_STOPBITS_2;
+ break;
+ default:
+ uart->handle.init.stop_bits = UART_STOPBITS_1;
+ break;
+ }
+
+ hal_uart_init(&uart->handle);
+
+ return RT_EOK;
+}
+
+static rt_err_t ab32_control(struct rt_serial_device *serial, int cmd, void *arg)
+{
+ struct ab32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+ uart = rt_container_of(serial, struct ab32_uart, serial);
+
+ switch (cmd)
+ {
+ case RT_DEVICE_CTRL_OPEN:
+ uart->intTxing = RT_FALSE;
+ break;
+ /* disable interrupt */
+ case RT_DEVICE_CTRL_CLR_INT:
+ hal_uart_control(uart->handle.instance, UART_RXIT_ENABLE, HAL_DISABLE);
+ break;
+ /* enable interrupt */
+ case RT_DEVICE_CTRL_SET_INT:
+ hal_uart_clrflag(uart->handle.instance, UART_FLAG_RXPND);
+ hal_uart_control(uart->handle.instance, UART_RXIT_ENABLE, HAL_ENABLE);
+ break;
+ case RT_DEVICE_CTRL_CLOSE:
+ hal_uart_deinit(uart->handle.instance);
+ break;
+ }
+
+ return RT_EOK;
+}
+
+static int ab32_putc(struct rt_serial_device *serial, char ch)
+{
+ struct ab32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct ab32_uart, serial);
+
+ hal_uart_write(uart->handle.instance, ch);
+
+ return 1;
+}
+
+static int ab32_getc(struct rt_serial_device *serial)
+{
+ int ch;
+ struct ab32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct ab32_uart, serial);
+
+ ch = -1;
+ if (hal_uart_getflag(UART0_BASE, UART_FLAG_RXPND)) {
+ ch = hal_uart_read(uart->handle.instance);
+ hal_uart_clrflag(UART0_BASE, UART_FLAG_RXPND);
+ }
+
+ return ch;
+}
+
+static int ab32_flush(struct rt_serial_device *serial)
+{
+ struct ab32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct ab32_uart, serial);
+ while(hal_uart_getflag(uart->handle.instance, UART_FLAG_TXPND) == 0);
+}
+
+rt_bool_t ab32_int_txing(struct rt_serial_device *serial)
+{
+ struct ab32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct ab32_uart, serial);
+
+ return uart->intTxing;
+}
+
+static void ab32_start_tx(struct rt_serial_device *serial, rt_uint8_t ch)
+{
+ struct ab32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct ab32_uart, serial);
+ uart->intTxing = RT_TRUE;
+ hal_uart_control(uart->handle.instance, UART_TXIT_ENABLE, HAL_ENABLE);
+ hal_uart_write(uart->handle.instance, ch);
+}
+
+static void ab32_stop_tx(struct rt_serial_device *serial)
+{
+ struct ab32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct ab32_uart, serial);
+ hal_uart_control(uart->handle.instance, UART_TXIT_ENABLE, HAL_DISABLE);
+ uart->intTxing = RT_FALSE;
+}
+
+RT_SECTION(".irq.usart")
+static void uart_isr(int vector, void *param)
+{
+ rt_interrupt_enter();
+
+#ifdef BSP_USING_UART0
+ if(hal_uart_getflag(UART0_BASE, UART_FLAG_RXPND)) //RX one byte finish
+ {
+ rt_hw_serial_isr(&(uart_obj[UART0_INDEX].serial), RT_SERIAL_EVENT_RX_IND);
+ hal_uart_clrflag(UART0_BASE, UART_FLAG_RXPND);
+ }
+ if(hal_uart_getflag(UART0_BASE, UART_FLAG_TXPND)) //TX one byte finish
+ {
+ rt_hw_serial_isr(&(uart_obj[UART0INDEX].serial), RT_SERIAL_EVENT_TX_DONE);
+ hal_uart_clrflag(UART0_BASE, UART_FLAG_TXPND);
+ }
+#endif
+#ifdef BSP_USING_UART1
+ if(hal_uart_getflag(UART1_BASE, UART_FLAG_RXPND)) //RX one byte finish
+ {
+ rt_hw_serial_isr(&(uart_obj[UART1_INDEX].serial), RT_SERIAL_EVENT_RX_IND);
+ hal_uart_clrflag(UART1_BASE, UART_FLAG_RXPND);
+ }
+ if(hal_uart_getflag(UART1_BASE, UART_FLAG_TXPND)) //TX one byte finish
+ {
+ rt_hw_serial_isr(&(uart_obj[UART1_INDEX].serial), RT_SERIAL_EVENT_TX_DONE);
+ hal_uart_clrflag(UART1_BASE, UART_FLAG_TXPND);
+ }
+#endif
+#ifdef BSP_USING_UART2
+ if(hal_uart_getflag(UART2_BASE, UART_FLAG_RXPND)) //RX one byte finish
+ {
+ rt_hw_serial_isr(&(uart_obj[UART2_INDEX].serial), RT_SERIAL_EVENT_RX_IND);
+ hal_uart_clrflag(UART2_BASE, UART_FLAG_RXPND);
+ }
+ if(hal_uart_getflag(UART2_BASE, UART_FLAG_TXPND)) //TX one byte finish
+ {
+ rt_hw_serial_isr(&(uart_obj[UART2_INDEX].serial), RT_SERIAL_EVENT_TX_DONE);
+ hal_uart_clrflag(UART2_BASE, UART_FLAG_TXPND);
+ }
+#endif
+
+ rt_interrupt_leave();
+}
+
+#ifdef HUART_ENABLE
+RT_SECTION(".irq.huart")
+void huart_timer_isr(void)
+{
+ huart_if_rx_ovflow();
+
+ if (0 == huart_get_rxcnt()) {
+ return;
+ }
+}
+#else
+RT_SECTION(".irq.huart")
+void huart_timer_isr(void)
+{
+}
+#endif
+
+static const struct rt_uart_ops ab32_uart_ops =
+{
+ .init = ab32_init,
+ .configure = ab32_configure,
+ .control = ab32_control,
+ .putc = ab32_putc,
+ .getc = ab32_getc,
+ .flush = ab32_flush,
+ .is_int_txing = ab32_int_txing,
+ .start_tx = ab32_start_tx,
+ .stop_tx = ab32_stop_tx,
+};
+
+int rt_hw_usart_init(void)
+{
+ rt_size_t obj_num = sizeof(uart_obj) / sizeof(struct ab32_uart);
+ rt_err_t result = 0;
+
+ rt_hw_interrupt_install(IRQ_UART0_2_VECTOR, uart_isr, RT_NULL, "ut_isr");
+
+ for (int i = 0; i < obj_num; i++)
+ {
+ /* init UART object */
+ uart_obj[i].uart_config = &uart_config[i];
+ uart_obj[i].serial.ops = &ab32_uart_ops;
+
+ /* register UART device */
+ result = rt_hw_serial_register(&uart_obj[i].serial, uart_obj[i].uart_config->name,
+ RT_DEVICE_FLAG_RDWR
+ | RT_DEVICE_FLAG_INT_RX
+ | RT_DEVICE_FLAG_INT_TX
+ , RT_NULL);
+ RT_ASSERT(result == RT_EOK);
+ }
+
+ return result;
+}
+
+#endif
diff --git a/bsp/bluetrum/libraries/hal_drivers/drv_usartX.h b/bsp/bluetrum/libraries/hal_drivers/drv_usartX.h
new file mode 100644
index 0000000000..acd4b63a84
--- /dev/null
+++ b/bsp/bluetrum/libraries/hal_drivers/drv_usartX.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020-2022, Bluetrum Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020-11-20 greedyhao first version
+ * 2022-06-08 THEWON first version for serialX
+ */
+
+#ifndef DRV_USART_H__
+#define DRV_USART_H__
+
+#include "drv_common.h"
+
+#ifdef RT_USING_SERIAL
+
+/* an32 config class */
+struct ab32_uart_config
+{
+ const char *name;
+ hal_sfr_t instance;
+ uint8_t mode;
+};
+
+/* ab32 uart driver class */
+struct ab32_uart
+{
+ struct uart_handle handle;
+ struct rt_serial_device serial;
+ struct ab32_uart_config *uart_config;
+ rt_bool_t intTxing;
+};
+
+#endif
+
+int rt_hw_usart_init(void);
+
+#endif
diff --git a/bsp/gd32/arm/libraries/gd32_drivers/SConscript b/bsp/gd32/arm/libraries/gd32_drivers/SConscript
index f2ed0f2d71..65ba16b0a6 100644
--- a/bsp/gd32/arm/libraries/gd32_drivers/SConscript
+++ b/bsp/gd32/arm/libraries/gd32_drivers/SConscript
@@ -14,7 +14,10 @@ if GetDepend('RT_USING_PIN'):
# add usart drivers.
if GetDepend(['RT_USING_SERIAL']):
- src += ['drv_usart.c']
+ if GetDepend(['RT_USING_SERIAL_X']):
+ src += ['drv_usartX.c']
+ else:
+ src += ['drv_usart.c']
# add i2c drivers.
if GetDepend(['RT_USING_I2C', 'RT_USING_I2C_BITOPS']):
diff --git a/bsp/gd32/arm/libraries/gd32_drivers/drv_usartX.c b/bsp/gd32/arm/libraries/gd32_drivers/drv_usartX.c
new file mode 100644
index 0000000000..9327225066
--- /dev/null
+++ b/bsp/gd32/arm/libraries/gd32_drivers/drv_usartX.c
@@ -0,0 +1,848 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2009-01-05 Bernard the first version
+ * 2010-03-29 Bernard remove interrupt Tx and DMA Rx mode
+ * 2012-02-08 aozima update for F4.
+ * 2012-07-28 aozima update for ART board.
+ * 2016-05-28 armink add DMA Rx mode
+ * 2022-06-09 THEWON first version for serialX
+ */
+
+#include <gd32f4xx.h>
+#include <drv_usartX.h>
+#include <board.h>
+
+#ifdef RT_USING_SERIAL
+
+#if !defined(BSP_USING_UART0) && !defined(BSP_USING_UART1) && \
+ !defined(BSP_USING_UART2) && !defined(BSP_USING_UART3) && \
+ !defined(BSP_USING_UART4) && !defined(BSP_USING_UART5) && \
+ !defined(BSP_USING_UART6) && !defined(BSP_USING_UART7)
+#error "Please define at least one UARTx"
+
+#endif
+
+enum
+{
+#ifdef BSP_USING_UART0
+ UART0_INDEX,
+#endif
+#ifdef BSP_USING_UART1
+ UART1_INDEX,
+#endif
+#ifdef BSP_USING_UART2
+ UART2_INDEX,
+#endif
+#ifdef BSP_USING_UART3
+ UART3_INDEX,
+#endif
+#ifdef BSP_USING_UART4
+ UART4_INDEX,
+#endif
+#ifdef BSP_USING_UART5
+ UART5_INDEX,
+#endif
+#ifdef BSP_USING_UART6
+ UART6_INDEX,
+#endif
+#ifdef BSP_USING_UART7
+ UART7_INDEX,
+#endif
+};
+
+/* GD32 uart driver */
+
+static void uart_isr(struct rt_serial_device *serial);
+
+#ifdef RT_SERIAL_USING_DMA
+static void DMA_RX_Configuration(struct rt_serial_device *serial);
+static void DMA_TX_Configuration(struct rt_serial_device *serial);
+#endif
+
+static struct gd32_uart uarts[] = {
+ #ifdef BSP_USING_UART0
+ {
+ .uart_periph = USART0, // uart peripheral index
+ .uart_config = {
+ .name = "uart0",
+ .irqn = USART0_IRQn, // uart iqrn
+ RCU_USART0, RCU_GPIOA, RCU_GPIOA, // periph clock, tx gpio clock, rt gpio clock
+ GPIOA, GPIO_AF_7, GPIO_PIN_9, // tx port, tx alternate, tx pin
+ GPIOA, GPIO_AF_7, GPIO_PIN_10, // rx port, rx alternate, rx pin
+ },
+#ifdef RT_SERIAL_USING_DMA
+ .dmaTxing = RT_FALSE,
+ .dma_rx = {
+ .dma_periph = DMA1,
+ .dma_channel = DMA_CH2,
+ .dma_subperi = DMA_SUBPERI4,
+ .dma_irq = DMA1_Channel2_IRQn,
+ },
+ .dma_tx = {
+ .dma_periph = DMA1,
+ .dma_channel = DMA_CH7,
+ .dma_subperi = DMA_SUBPERI4,
+ .dma_irq = DMA1_Channel7_IRQn,
+ },
+#endif
+ },
+ #endif
+
+ #ifdef BSP_USING_UART1
+ {
+ .uart_periph = USART1, // uart peripheral index
+ .uart_config = {
+ .name = "uart1",
+ .irqn = USART1_IRQn, // uart iqrn
+ RCU_USART1, RCU_GPIOA, RCU_GPIOA, // periph clock, tx gpio clock, rt gpio clock
+ GPIOA, GPIO_AF_7, GPIO_PIN_2, // tx port, tx alternate, tx pin
+ GPIOA, GPIO_AF_7, GPIO_PIN_3, // rx port, rx alternate, rx pin
+ }
+ },
+ #endif
+
+ #ifdef BSP_USING_UART2
+ {
+ .uart_periph = USART2, // uart peripheral index
+ .uart_config = {
+ .name = "uart2",
+ .irqn = USART2_IRQn, // uart iqrn
+ RCU_USART2, RCU_GPIOB, RCU_GPIOB, // periph clock, tx gpio clock, rt gpio clock
+ GPIOB, GPIO_AF_7, GPIO_PIN_10, // tx port, tx alternate, tx pin
+ GPIOB, GPIO_AF_7, GPIO_PIN_11, // rx port, rx alternate, rx pin
+ }
+ },
+ #endif
+
+ #ifdef BSP_USING_UART3
+ {
+ .uart_periph = UART3, // uart peripheral index
+ .uart_config = {
+ .name = "uart3",
+ .irqn = UART3_IRQn, // uart iqrn
+ RCU_UART3, RCU_GPIOC, RCU_GPIOC, // periph clock, tx gpio clock, rt gpio clock
+ GPIOC, GPIO_AF_8, GPIO_PIN_10, // tx port, tx alternate, tx pin
+ GPIOC, GPIO_AF_8, GPIO_PIN_11, // rx port, rx alternate, rx pin
+ }
+ },
+ #endif
+
+ #ifdef BSP_USING_UART4
+ {
+ .uart_periph = UART4, // uart peripheral index
+ .uart_config = {
+ .name = "uart4",
+ .irqn = UART4_IRQn, // uart iqrn
+ RCU_UART4, RCU_GPIOC, RCU_GPIOD, // periph clock, tx gpio clock, rt gpio clock
+ GPIOC, GPIO_AF_8, GPIO_PIN_12, // tx port, tx alternate, tx pin
+ GPIOD, GPIO_AF_8, GPIO_PIN_2, // rx port, rx alternate, rx pin
+ }
+ },
+ #endif
+
+ #ifdef BSP_USING_UART5
+ {
+ .uart_periph = USART5, // uart peripheral index
+ .uart_config = {
+ .name = "uart5",
+ .irqn = USART5_IRQn, // uart iqrn
+ RCU_USART5, RCU_GPIOC, RCU_GPIOC, // periph clock, tx gpio clock, rt gpio clock
+ GPIOC, GPIO_AF_8, GPIO_PIN_6, // tx port, tx alternate, tx pin
+ GPIOC, GPIO_AF_8, GPIO_PIN_7, // rx port, rx alternate, rx pin
+ }
+ },
+ #endif
+
+ #ifdef BSP_USING_UART6
+ {
+ .uart_periph = UART6, // uart peripheral index
+ .uart_config = {
+ .name = "uart6",
+ .irqn = UART6_IRQn, // uart iqrn
+ RCU_UART6, RCU_GPIOE, RCU_GPIOE, // periph clock, tx gpio clock, rt gpio clock
+ GPIOE, GPIO_AF_8, GPIO_PIN_7, // tx port, tx alternate, tx pin
+ GPIOE, GPIO_AF_8, GPIO_PIN_8, // rx port, rx alternate, rx pin
+ }
+ },
+ #endif
+
+ #ifdef BSP_USING_UART7
+ {
+ .uart_periph = UART7, // uart peripheral index
+ .uart_config = {
+ .name = "uart7",
+ .irqn = UART7_IRQn, // uart iqrn
+ RCU_UART7, RCU_GPIOE, RCU_GPIOE, // periph clock, tx gpio clock, rt gpio clock
+ GPIOE, GPIO_AF_8, GPIO_PIN_0, // tx port, tx alternate, tx pin
+ GPIOE, GPIO_AF_8, GPIO_PIN_1, // rx port, rx alternate, rx pin
+ }
+ },
+ #endif
+};
+
+/**
+* @brief UART MSP Initialization
+* This function configures the hardware resources used in this example:
+* - Peripheral's clock enable
+* - Peripheral's GPIO Configuration
+* - NVIC configuration for UART interrupt request enable
+* @param huart: UART handle pointer
+* @retval None
+*/
+void gd32_uart_gpio_init(struct gd32_uart *uart)
+{
+ /* enable USART clock */
+ rcu_periph_clock_enable(uart->uart_config.tx_gpio_clk);
+ rcu_periph_clock_enable(uart->uart_config.rx_gpio_clk);
+ rcu_periph_clock_enable(uart->uart_config.per_clk);
+
+ /* connect port to USARTx_Tx */
+ gpio_af_set(uart->uart_config.tx_port, uart->uart_config.tx_af, uart->uart_config.tx_pin);
+
+ /* connect port to USARTx_Rx */
+ gpio_af_set(uart->uart_config.rx_port, uart->uart_config.rx_af, uart->uart_config.rx_pin);
+
+ /* configure USART Tx as alternate function push-pull */
+ gpio_mode_set(uart->uart_config.tx_port, GPIO_MODE_AF, GPIO_PUPD_PULLUP, uart->uart_config.tx_pin);
+ gpio_output_options_set(uart->uart_config.tx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, uart->uart_config.tx_pin);
+
+ /* configure USART Rx as alternate function push-pull */
+ gpio_mode_set(uart->uart_config.rx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, uart->uart_config.rx_pin);
+ gpio_output_options_set(uart->uart_config.rx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, uart->uart_config.rx_pin);
+}
+
+static rt_err_t gd32_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
+{
+ struct gd32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+ RT_ASSERT(cfg != RT_NULL);
+
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+
+ usart_baudrate_set(uart->uart_periph, cfg->baud_rate);
+
+ switch (cfg->data_bits)
+ {
+ case DATA_BITS_9:
+ usart_word_length_set(uart->uart_periph, USART_WL_9BIT);
+ break;
+
+ default:
+ usart_word_length_set(uart->uart_periph, USART_WL_8BIT);
+ break;
+ }
+
+ switch (cfg->stop_bits)
+ {
+ case STOP_BITS_2:
+ usart_stop_bit_set(uart->uart_periph, USART_STB_2BIT);
+ break;
+ default:
+ usart_stop_bit_set(uart->uart_periph, USART_STB_1BIT);
+ break;
+ }
+
+ switch (cfg->parity)
+ {
+ case PARITY_ODD:
+ usart_parity_config(uart->uart_periph, USART_PM_ODD);
+ break;
+ case PARITY_EVEN:
+ usart_parity_config(uart->uart_periph, USART_PM_EVEN);
+ break;
+ default:
+ usart_parity_config(uart->uart_periph, USART_PM_NONE);
+ break;
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t gd32_init(struct rt_serial_device *serial)
+{
+ struct gd32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+
+ gd32_uart_gpio_init(uart);
+
+ if (gd32_configure(serial, &serial->config) != RT_EOK)
+ {
+ return -RT_ERROR;
+ }
+
+ usart_receive_config(uart->uart_periph, USART_RECEIVE_ENABLE);
+ usart_transmit_config(uart->uart_periph, USART_TRANSMIT_ENABLE);
+
+ return RT_EOK;
+}
+
+static rt_err_t gd32_control(struct rt_serial_device *serial, int cmd, void *arg)
+{
+ struct gd32_uart *uart;
+ rt_ubase_t ctrl_arg = (rt_ubase_t)arg;
+
+ RT_ASSERT(serial != RT_NULL);
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+
+ switch (cmd) {
+ case RT_DEVICE_CTRL_OPEN:
+ usart_interrupt_disable(uart->uart_periph, USART_INT_TBE);
+ usart_interrupt_disable(uart->uart_periph, USART_INT_TC);
+ usart_flag_clear(uart->uart_periph, USART_FLAG_RBNE);
+ usart_flag_clear(uart->uart_periph, USART_FLAG_TBE);
+ usart_flag_clear(uart->uart_periph, USART_FLAG_TC);
+ /* enable rx irq */
+ NVIC_SetPriority(uart->uart_config.irqn, 0);
+ NVIC_EnableIRQ(uart->uart_config.irqn);
+ usart_enable(uart->uart_periph);
+#ifdef RT_SERIAL_USING_DMA
+ uart->dmaTxing = RT_FALSE;
+#endif
+ break;
+ case RT_DEVICE_CTRL_CLOSE:
+ NVIC_DisableIRQ(uart->uart_config.irqn);
+ usart_interrupt_disable(uart->uart_periph, USART_INT_RBNE);
+ usart_interrupt_disable(uart->uart_periph, USART_INT_TBE);
+ usart_interrupt_disable(uart->uart_periph, USART_INT_IDLE);
+ usart_interrupt_disable(uart->uart_periph, USART_INT_TC);
+ usart_disable(uart->uart_periph);
+ usart_deinit(uart->uart_periph);
+#ifdef RT_SERIAL_USING_DMA
+ NVIC_DisableIRQ(uart->dma_rx.dma_irq);
+ dma_interrupt_disable(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel, DMA_CHXCTL_HTFIE);
+ dma_interrupt_disable(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel, DMA_CHXCTL_FTFIE);
+ dma_channel_disable(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel);
+ dma_deinit(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel);
+
+ NVIC_DisableIRQ(uart->dma_tx.dma_irq);
+ dma_interrupt_disable(uart->dma_tx.dma_periph, uart->dma_tx.dma_channel, DMA_CHXCTL_FTFIE);
+ dma_channel_disable(uart->dma_tx.dma_periph, uart->dma_tx.dma_channel);
+ dma_deinit(uart->dma_tx.dma_periph, uart->dma_tx.dma_channel);
+#endif
+ break;
+ case RT_DEVICE_CTRL_CLR_INT:
+ /* disable interrupt */
+ if (ctrl_arg & RT_DEVICE_FLAG_INT_RX) {
+ usart_interrupt_disable(uart->uart_periph, USART_INT_RBNE);
+ }
+#ifdef RT_SERIAL_USING_DMA
+ /* disable DMA */
+ if (ctrl_arg & RT_DEVICE_FLAG_DMA_RX) {
+ NVIC_DisableIRQ(uart->dma_rx.dma_irq);
+ dma_interrupt_disable(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel, DMA_CHXCTL_HTFIE);
+ dma_interrupt_disable(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel, DMA_CHXCTL_FTFIE);
+ }
+ if(ctrl_arg & RT_DEVICE_FLAG_DMA_TX) {
+ NVIC_DisableIRQ(uart->dma_tx.dma_irq);
+ dma_interrupt_disable(uart->dma_tx.dma_periph, uart->dma_tx.dma_channel, DMA_CHXCTL_FTFIE);
+ }
+#endif
+ break;
+ case RT_DEVICE_CTRL_SET_INT:
+ /* enable interrupt */
+ if (ctrl_arg & RT_DEVICE_FLAG_INT_RX) {
+ usart_interrupt_enable(uart->uart_periph, USART_INT_RBNE);
+ }
+ break;
+ /* USART config */
+ case RT_DEVICE_CTRL_CONFIG :
+#ifdef RT_SERIAL_USING_DMA
+ if (ctrl_arg & RT_DEVICE_FLAG_DMA_RX) {
+ DMA_RX_Configuration(serial);
+ } else if (ctrl_arg & RT_DEVICE_FLAG_DMA_TX) {
+ DMA_TX_Configuration(serial);
+ }
+#endif
+ break;
+ default :
+ break;
+ }
+
+ return RT_EOK;
+}
+
+static int gd32_putc(struct rt_serial_device *serial, char ch)
+{
+ struct gd32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+
+ while((usart_flag_get(uart->uart_periph, USART_FLAG_TBE) == RESET));
+ usart_data_transmit(uart->uart_periph, ch);
+
+ return 1;
+}
+
+static int gd32_getc(struct rt_serial_device *serial)
+{
+ int ch;
+ struct gd32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+
+ ch = -1;
+ if (usart_flag_get(uart->uart_periph, USART_FLAG_RBNE) != RESET) {
+ ch = usart_data_receive(uart->uart_periph);
+ }
+ return ch;
+}
+
+static int gd32_flush(struct rt_serial_device *serial)
+{
+ struct gd32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+ while (!(usart_flag_get(uart->uart_periph, USART_FLAG_TBE) == SET && usart_flag_get(uart->uart_periph, USART_FLAG_TC) == SET));
+
+ return 1;
+}
+
+static void gd32_start_tx(struct rt_serial_device *serial)
+{
+ struct gd32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+ usart_interrupt_enable(uart->uart_periph, USART_INT_TBE);
+}
+
+static void gd32_stop_tx(struct rt_serial_device *serial)
+{
+ struct gd32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+ usart_interrupt_disable(uart->uart_periph, USART_INT_TBE);
+}
+
+#ifdef RT_SERIAL_USING_DMA
+static rt_bool_t gd32_is_dma_txing(struct rt_serial_device *serial)
+{
+ struct gd32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+
+ return uart->dmaTxing; //RT_FALSE;
+}
+
+static void gd32_start_dma_tx(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size)
+{
+ struct gd32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+
+ // TODO: 启用 DMA 发送
+ DMA_CHM0ADDR(uart->dma_tx.dma_periph, uart->dma_tx.dma_channel) = (uint32_t)(buf);
+ DMA_CHCNT(uart->dma_tx.dma_periph, uart->dma_tx.dma_channel) = (uint32_t)(size);
+ dma_channel_enable(uart->dma_tx.dma_periph, uart->dma_tx.dma_channel);
+
+ uart->dmaTxing = RT_TRUE;
+}
+
+static void gd32_stop_dma_tx(struct rt_serial_device *serial)
+{
+ struct gd32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+
+ // TODO: 禁用 DMA 发送
+ dma_channel_disable(uart->dma_tx.dma_periph, uart->dma_tx.dma_channel);
+ uart->dmaTxing = RT_FALSE;
+}
+#endif
+
+static void gd32_enable_interrupt(struct rt_serial_device *serial)
+{
+ struct gd32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+
+ NVIC_EnableIRQ(uart->uart_config.irqn);
+}
+
+static void gd32_disable_interrupt(struct rt_serial_device *serial)
+{
+ struct gd32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+
+ NVIC_DisableIRQ(uart->uart_config.irqn);
+}
+
+#ifdef RT_SERIAL_USING_DMA
+/**
+ * DMA receive done process. This need add to DMA receive done ISR.
+ *
+ * @param serial serial device
+ */
+static void dma_rx_done_isr(struct rt_serial_device *serial)
+{
+ struct gd32_uart *uart;
+ rt_size_t dma_cnt;
+
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+
+ dma_cnt = RT_SERIAL_DMA_BUFSZ - DMA_CHCNT(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel);
+
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (dma_cnt << 8));
+
+ dma_interrupt_flag_clear(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel, DMA_INT_FLAG_HTF);
+ dma_interrupt_flag_clear(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel, DMA_INT_FLAG_FTF);
+}
+/**
+ * DMA transmit done process. This need add to DMA transmit done ISR.
+ *
+ * @param serial serial device
+ */
+static void dma_tx_done_isr(struct rt_serial_device *serial)
+{
+ struct gd32_uart *uart;
+ rt_size_t dma_cnt;
+
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+
+ dma_cnt = DMA_CHCNT(uart->dma_tx.dma_periph, uart->dma_tx.dma_channel);
+
+ if (dma_cnt == 0)
+ {
+ rt_hw_serial_isr(&uart->serial, RT_SERIAL_EVENT_TX_DMADONE);
+ }
+ dma_interrupt_flag_clear(uart->dma_tx.dma_periph, uart->dma_tx.dma_channel, DMA_INT_FLAG_FTF);
+}
+#endif
+
+/**
+ * Uart common interrupt process. This need add to uart ISR.
+ *
+ * @param serial serial device
+ */
+static void uart_isr(struct rt_serial_device *serial)
+{
+ struct gd32_uart *uart;
+#ifdef RT_SERIAL_USING_DMA
+ rt_size_t dma_cnt;
+#endif
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+
+ /* UART in mode Receiver -------------------------------------------------*/
+ if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_RBNE) != RESET))
+ {
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+ /* Clear RXNE interrupt flag */
+ usart_interrupt_flag_clear(uart->uart_periph, USART_INT_FLAG_RBNE);
+ }
+ if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_RBNE_ORERR) != RESET))
+ {
+ usart_data_receive(uart->uart_periph);
+ }
+ if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_TBE) != RESET))
+ {
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DONE);
+ usart_interrupt_flag_clear(uart->uart_periph, USART_INT_FLAG_TBE);
+ }
+#ifdef RT_SERIAL_USING_DMA
+ if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_IDLE) != RESET))
+ {
+ usart_data_receive(uart->uart_periph);
+ dma_cnt = RT_SERIAL_DMA_BUFSZ - DMA_CHCNT(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel);
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (dma_cnt << 8));
+ }
+ if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_TC) != RESET))
+ {
+ usart_interrupt_flag_clear(uart->uart_periph, USART_INT_FLAG_TC);
+ }
+#endif
+ if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_PERR) != RESET))
+ {
+ usart_data_receive(uart->uart_periph);
+ }
+ if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_EB) != RESET))
+ {
+ usart_interrupt_flag_clear(uart->uart_periph, USART_INT_FLAG_EB);
+ }
+ if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_RT) != RESET))
+ {
+ usart_interrupt_flag_clear(uart->uart_periph, USART_INT_FLAG_RT);
+ }
+}
+
+#if defined(BSP_USING_UART0)
+
+void USART0_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ uart_isr(&uarts[UART0_INDEX].serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+
+#ifdef RT_SERIAL_USING_DMA
+void DMA1_Channel2_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ dma_rx_done_isr(&uarts[UART0_INDEX].serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+void DMA1_Channel7_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ dma_tx_done_isr(&uarts[UART0_INDEX].serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+#endif
+
+#endif /* BSP_USING_UART0 */
+
+#if defined(BSP_USING_UART1)
+
+void USART1_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ uart_isr(&uarts[UART1_INDEX].serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+
+#endif /* BSP_USING_UART1 */
+
+#if defined(BSP_USING_UART2)
+
+void USART2_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ uart_isr(&uarts[UART2_INDEX].serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+
+#endif /* BSP_USING_UART2 */
+
+#if defined(BSP_USING_UART3)
+
+void UART3_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ uart_isr(&uarts[UART3_INDEX].serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+
+#endif /* BSP_USING_UART3 */
+
+#if defined(BSP_USING_UART4)
+
+void UART4_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ uart_isr(&uarts[UART4_INDEX].serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+#endif /* BSP_USING_UART4 */
+
+#if defined(BSP_USING_UART5)
+
+void USART5_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ uart_isr(&uarts[UART5_INDEX].serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+
+#endif /* BSP_USING_UART5 */
+
+#if defined(BSP_USING_UART6)
+
+void UART6_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ uart_isr(&uarts[UART6_INDEX].serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+
+#endif /* BSP_USING_UART6 */
+
+#if defined(BSP_USING_UART7)
+
+void UART7_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ uart_isr(&uarts[UART7_INDEX].serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+
+#endif /* BSP_USING_UART7 */
+
+#ifdef RT_SERIAL_USING_DMA
+// TODO: 添加发送 DMA 配置,添加接收 DMA 配置
+static void DMA_RX_Configuration(struct rt_serial_device *serial)
+{
+ dma_single_data_parameter_struct dma_init_struct;
+ struct gd32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+
+ /* enable DMA1 */
+ rcu_periph_clock_enable(RCU_DMA1);
+
+ /* deinitialize DMA channel3(USART0 tx) */
+ dma_deinit(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel);
+ dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
+ dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
+ dma_init_struct.memory0_addr = (uint32_t)(serial->serial_dma_rx);
+ dma_init_struct.number = RT_SERIAL_DMA_BUFSZ;
+ dma_init_struct.periph_addr = (uint32_t)(uart->uart_periph + 0x04);
+ dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
+ dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
+ dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
+ dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_ENABLE;
+
+ dma_single_data_mode_init(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel, &dma_init_struct);
+ dma_channel_subperipheral_select(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel, uart->dma_rx.dma_subperi);
+
+ dma_interrupt_enable(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel, DMA_CHXCTL_HTFIE);
+ dma_interrupt_enable(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel, DMA_CHXCTL_FTFIE);
+ NVIC_SetPriority(uart->dma_rx.dma_irq, 0);
+ NVIC_EnableIRQ(uart->dma_rx.dma_irq);
+ dma_channel_enable(uart->dma_rx.dma_periph, uart->dma_rx.dma_channel);
+ usart_dma_receive_config(uart->uart_periph, USART_DENR_ENABLE);
+}
+static void DMA_TX_Configuration(struct rt_serial_device *serial)
+{
+ dma_single_data_parameter_struct dma_init_struct;
+ struct gd32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+ uart = rt_container_of(serial, struct gd32_uart, serial);
+
+ /* enable DMA1 */
+ rcu_periph_clock_enable(RCU_DMA1);
+ /* deinitialize DMA channel3(USART0 tx) */
+ dma_deinit(uart->dma_tx.dma_periph, uart->dma_tx.dma_channel);
+ dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
+ dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
+// dma_init_struct.memory0_addr = (uint32_t)tx_buffer;
+// dma_init_struct.number = ARRAYNUM(tx_buffer);
+ dma_init_struct.periph_addr = (uint32_t)(uart->uart_periph + 0x04);
+ dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
+ dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
+ dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
+ dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;
+
+ dma_single_data_mode_init(uart->dma_tx.dma_periph, uart->dma_tx.dma_channel, &dma_init_struct);
+ dma_channel_subperipheral_select(uart->dma_tx.dma_periph, uart->dma_tx.dma_channel, uart->dma_tx.dma_subperi);
+
+ dma_interrupt_enable(uart->dma_tx.dma_periph, uart->dma_tx.dma_channel, DMA_CHXCTL_FTFIE);
+ NVIC_SetPriority(uart->dma_tx.dma_irq, 0);
+ NVIC_EnableIRQ(uart->dma_tx.dma_irq);
+
+ usart_interrupt_enable(uart->uart_periph, USART_INT_IDLE);
+ usart_interrupt_enable(uart->uart_periph, USART_INT_TC);
+ usart_dma_transmit_config(uart->uart_periph, USART_DENT_ENABLE);
+}
+#endif
+static const struct rt_uart_ops gd32_uart_ops =
+{
+ .init = gd32_init,
+ .configure = gd32_configure,
+ .control = gd32_control,
+ .putc = gd32_putc,
+ .getc = gd32_getc,
+ .flush = gd32_flush,
+ .start_tx = gd32_start_tx,
+ .stop_tx = gd32_stop_tx,
+#ifdef RT_SERIAL_USING_DMA
+ .is_dma_txing = gd32_is_dma_txing,
+ .start_dma_tx = gd32_start_dma_tx,
+ .stop_dma_tx = gd32_stop_dma_tx,
+#endif
+ .enable_interrupt = gd32_enable_interrupt,
+ .disable_interrupt = gd32_disable_interrupt,
+};
+
+int rt_hw_usart_init(void)
+{
+ int i;
+
+ for (i = 0; i < sizeof(uarts) / sizeof(uarts[0]); i++)
+ {
+ uarts[i].serial.ops = &gd32_uart_ops;
+
+ /* register UART1 device */
+ rt_hw_serial_register(&uarts[i].serial,
+ uarts[i].uart_config.name,
+ RT_DEVICE_FLAG_RDWR |
+ RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX
+#ifdef RT_SERIAL_USING_DMA
+ | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX
+#endif
+ , RT_NULL);
+ }
+
+ return 0;
+}
+#endif // RT_USING_SERIAL
diff --git a/bsp/gd32/arm/libraries/gd32_drivers/drv_usartX.h b/bsp/gd32/arm/libraries/gd32_drivers/drv_usartX.h
new file mode 100644
index 0000000000..1a5a44a12d
--- /dev/null
+++ b/bsp/gd32/arm/libraries/gd32_drivers/drv_usartX.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2009-01-05 Bernard the first version
+ * 2022-06-09 THEWON first version for serialX
+ */
+
+#ifndef __DRV_USARTX_H__
+#define __DRV_USARTX_H__
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define UART_ENABLE_IRQ(n) NVIC_EnableIRQ((n))
+#define UART_DISABLE_IRQ(n) NVIC_DisableIRQ((n))
+
+/* stm32 config class */
+struct gd32_uart_config
+{
+ const char *name;
+ IRQn_Type irqn;
+
+ rcu_periph_enum per_clk;
+ rcu_periph_enum tx_gpio_clk;
+ rcu_periph_enum rx_gpio_clk;
+ uint32_t tx_port;
+ uint16_t tx_af;
+ uint16_t tx_pin;
+ uint32_t rx_port;
+ uint16_t rx_af;
+ uint16_t rx_pin;
+};
+
+struct gd32_uart_dma
+{
+ /* dma channel */
+ uint32_t dma_periph;
+ dma_channel_enum dma_channel;
+ dma_subperipheral_enum dma_subperi;
+ /* dma irq channel */
+ IRQn_Type dma_irq;
+};
+
+/* gd32 uart driver class */
+struct gd32_uart
+{
+ uint32_t uart_periph;
+ struct rt_serial_device serial;
+ struct gd32_uart_config uart_config;
+#ifdef RT_SERIAL_USING_DMA
+ rt_bool_t dmaTxing;
+ struct gd32_uart_dma dma_rx;
+ struct gd32_uart_dma dma_tx;
+#endif
+};
+
+int rt_hw_usart_init(void);
+
+#endif // __DRV_USARTX_H__
diff --git a/bsp/n32/libraries/n32_drivers/SConscript b/bsp/n32/libraries/n32_drivers/SConscript
index 107e4d1b33..8b2f3a26b7 100644
--- a/bsp/n32/libraries/n32_drivers/SConscript
+++ b/bsp/n32/libraries/n32_drivers/SConscript
@@ -14,6 +14,8 @@ if GetDepend(['RT_USING_PIN']):
if GetDepend(['RT_USING_SERIAL']):
if GetDepend(['RT_USING_SERIAL_V2']):
src += ['drv_usart_v2.c']
+ elif GetDepend(['RT_USING_SERIAL_X']):
+ src += ['drv_usartX.c']
else:
src += ['drv_usart.c']
diff --git a/bsp/n32/libraries/n32_drivers/drv_usartX.c b/bsp/n32/libraries/n32_drivers/drv_usartX.c
new file mode 100644
index 0000000000..cc025080fc
--- /dev/null
+++ b/bsp/n32/libraries/n32_drivers/drv_usartX.c
@@ -0,0 +1,839 @@
+/*
+ * File : usart.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006-2022, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2009-01-05 Bernard the first version
+ * 2010-03-29 Bernard remove interrupt Tx and DMA Rx mode
+ * 2013-05-13 aozima update for kehong-lingtai.
+ * 2015-01-31 armink make sure the serial transmit complete in putc()
+ * 2016-05-13 armink add DMA Rx mode
+ * 2017-01-19 aubr.cool add interrupt Tx mode
+ * 2017-04-13 aubr.cool correct Rx parity err
+ * 2021-08-20 breo.com first version
+ * 2022-06-01 THEWON first version for serialX
+ */
+
+#include <rtdevice.h>
+#include <rthw.h>
+#include <board.h>
+#include "drv_usartX.h"
+
+#define UART_ENABLE_IRQ(n) NVIC_EnableIRQ((n))
+#define UART_DISABLE_IRQ(n) NVIC_DisableIRQ((n))
+
+#ifdef RT_SERIAL_USING_DMA
+static void DMA_RX_Configuration(struct rt_serial_device *serial);
+static void DMA_TX_Configuration(struct rt_serial_device *serial);
+#endif
+
+static rt_err_t n32_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
+{
+ struct n32_uart *uart;
+ USART_InitType USART_InitStructure;
+
+ RT_ASSERT(serial != RT_NULL);
+ RT_ASSERT(cfg != RT_NULL);
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ USART_InitStructure.BaudRate = cfg->baud_rate;
+
+ switch (cfg->data_bits)
+ {
+ case DATA_BITS_8 :
+ USART_InitStructure.WordLength = USART_WL_8B;
+ break;
+ case DATA_BITS_9 :
+ USART_InitStructure.WordLength = USART_WL_9B;
+ break;
+ default:
+ USART_InitStructure.WordLength = USART_WL_8B;
+ break;
+ }
+
+ switch (cfg->stop_bits)
+ {
+ case STOP_BITS_1 :
+ USART_InitStructure.StopBits = USART_STPB_1;
+ break;
+ case STOP_BITS_2 :
+ USART_InitStructure.StopBits = USART_STPB_2;
+ break;
+ default:
+ USART_InitStructure.StopBits = USART_STPB_1;
+ break;
+ }
+
+ switch (cfg->parity)
+ case PARITY_NONE :
+ USART_InitStructure.Parity = USART_PE_NO;
+ break;
+ case PARITY_ODD :
+ USART_InitStructure.Parity = USART_PE_ODD;
+ break;
+ case PARITY_EVEN :
+ USART_InitStructure.Parity = USART_PE_EVEN;
+ break;
+ default:
+ USART_InitStructure.Parity = USART_PE_NO;
+ break;
+ }
+
+ USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
+ USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX;
+ USART_Init(uart->uart_device, &USART_InitStructure);
+
+ return RT_EOK;
+}
+
+static rt_err_t n32_uart_init(struct rt_serial_device *serial)
+{
+ struct n32_uart *uart;
+ USART_InitType USART_InitStructure;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ n32_msp_usart_init(uart->uart_device);
+
+ if (n32_uart_configure(serial, &serial->config) != RT_EOK)
+ {
+ return -RT_ERROR;
+ }
+
+ /* Enable USART */
+ USART_Enable(uart->uart_device, ENABLE);
+
+ USART_ClrFlag(uart->uart_device, USART_FLAG_TXDE|USART_FLAG_TXC);
+
+ return RT_EOK;
+}
+
+static rt_err_t n32_uart_control(struct rt_serial_device *serial, int cmd, void *arg)
+{
+ struct n32_uart *uart;
+ rt_uint32_t ctrl_arg = (rt_uint32_t)(arg);
+ NVIC_InitType NVIC_InitStructure;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ switch (cmd) {
+ case RT_DEVICE_CTRL_OPEN:
+ USART_ConfigInt(uart->uart_device, USART_INT_TXDE, DISABLE);
+ USART_ClrIntPendingBit(uart->uart_device, USART_INT_RXDNE);
+ USART_ClrIntPendingBit(uart->uart_device, USART_INT_TXDE);
+ USART_ClrIntPendingBit(uart->uart_device, USART_INT_TXC);
+ /* enable rx irq */
+ UART_ENABLE_IRQ(uart->irq);
+#ifdef RT_SERIAL_USING_DMA
+ uart->dmaTxing = RT_FALSE;
+#endif
+ break;
+ case RT_DEVICE_CTRL_CLOSE:
+ /* disable rx irq */
+ UART_DISABLE_IRQ(uart->irq);
+ USART_ConfigInt(uart->uart_device, USART_INT_RXDNE, DISABLE);
+ USART_ConfigInt(uart->uart_device, USART_INT_TXDE, DISABLE);
+ USART_ConfigInt(uart->uart_device, USART_INT_TXC, DISABLE);
+ USART_ClrIntPendingBit(uart->uart_device, USART_INT_RXDNE);
+ USART_ClrIntPendingBit(uart->uart_device, USART_INT_TXDE);
+ USART_ClrIntPendingBit(uart->uart_device, USART_INT_TXC);
+
+#ifdef RT_SERIAL_USING_DMA
+ NVIC_InitStructure.NVIC_IRQChannel = uart->dma_rx.dma_irq;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
+ NVIC_Init(&NVIC_InitStructure);
+ DMA_EnableChannel(uart->dma_rx.dma_ch, DISABLE);
+ DMA_ConfigInt(uart->dma_rx.dma_ch, DMA_INT_HTX, DISABLE);
+ DMA_ConfigInt(uart->dma_rx.dma_ch, DMA_INT_TXC, DISABLE);
+ DMA_DeInit(uart->dma_rx.dma_ch);
+ NVIC_InitStructure.NVIC_IRQChannel = uart->dma_tx.dma_irq;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
+ NVIC_Init(&NVIC_InitStructure);
+ DMA_EnableChannel(uart->dma_tx.dma_ch, DISABLE);
+ DMA_ConfigInt(uart->dma_tx.dma_ch, DMA_INT_TXC, DISABLE);
+ DMA_DeInit(uart->dma_tx.dma_ch);
+#endif
+ break;
+ case RT_DEVICE_CTRL_CLR_INT:
+ /* disable interrupt */
+ if (ctrl_arg & RT_DEVICE_FLAG_INT_RX) {
+ USART_ConfigInt(uart->uart_device, USART_INT_RXDNE, DISABLE);
+ }
+
+#ifdef RT_SERIAL_USING_DMA
+ /* disable DMA */
+ if (ctrl_arg & RT_DEVICE_FLAG_DMA_RX) {
+ NVIC_InitStructure.NVIC_IRQChannel = uart->dma_rx.dma_irq;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
+ NVIC_Init(&NVIC_InitStructure);
+ DMA_ConfigInt(uart->dma_rx.dma_ch, DMA_INT_HTX, DISABLE);
+ DMA_ConfigInt(uart->dma_rx.dma_ch, DMA_INT_TXC, DISABLE);
+ }
+ if(ctrl_arg & RT_DEVICE_FLAG_DMA_TX) {
+ NVIC_InitStructure.NVIC_IRQChannel = uart->dma_tx.dma_irq;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
+ NVIC_Init(&NVIC_InitStructure);
+ DMA_ConfigInt(uart->dma_tx.dma_ch, DMA_INT_TXC, DISABLE);
+ }
+#endif
+ break;
+ case RT_DEVICE_CTRL_SET_INT:
+ /* enable interrupt */
+ if (ctrl_arg & RT_DEVICE_FLAG_INT_RX) {
+ USART_ConfigInt(uart->uart_device, USART_INT_RXDNE, ENABLE);
+ }
+ break;
+ /* USART config */
+ case RT_DEVICE_CTRL_CONFIG :
+#ifdef RT_SERIAL_USING_DMA
+ if (ctrl_arg & RT_DEVICE_FLAG_DMA_RX) {
+ DMA_RX_Configuration(serial);
+ } else if (ctrl_arg & RT_DEVICE_FLAG_DMA_TX) {
+ DMA_TX_Configuration(serial);
+ }
+#endif
+ break;
+ default :
+ break;
+ }
+ return RT_EOK;
+}
+
+static int n32_uart_putc(struct rt_serial_device *serial, char c)
+{
+ struct n32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ while (!(uart->uart_device->STS & USART_FLAG_TXDE));
+ uart->uart_device->DAT = c;
+
+ return 1;
+}
+
+static int n32_uart_getc(struct rt_serial_device *serial)
+{
+ int ch;
+ struct n32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ ch = -1;
+ if (uart->uart_device->STS & USART_FLAG_RXDNE)
+ {
+ ch = uart->uart_device->DAT & 0xff;
+ }
+
+ return ch;
+}
+
+static int n32_uart_flush(struct rt_serial_device *serial)
+{
+ struct n32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+ while(!((uart->uart_device->STS & USART_FLAG_TXDE) && (uart->uart_device->STS & USART_FLAG_TXC)));
+
+ return 0;
+}
+
+static void n32_start_tx(struct rt_serial_device *serial)
+{
+ struct n32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ USART_ConfigInt(uart->uart_device, USART_INT_TXDE, ENABLE);
+}
+
+static void n32_stop_tx(struct rt_serial_device *serial)
+{
+ struct n32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ USART_ConfigInt(uart->uart_device, USART_INT_TXDE, DISABLE);
+}
+
+#ifdef RT_SERIAL_USING_DMA
+static rt_bool_t n32_is_dma_txing(struct rt_serial_device *serial)
+{
+ struct n32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+// return uart->dmaTxing; //RT_FALSE;
+ return (DMA_GetFlagStatus(uart->dma_tx.dma_flag, uart->dma_tx.dma_module) == SET);
+}
+
+static void n32_start_dma_tx(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size)
+{
+ struct n32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ // TODO: 启用 DMA 发送
+ uart->dma_tx.dma_ch->MADDR = (uint32_t)(buf);
+ uart->dma_tx.dma_ch->TXNUM = (uint32_t)(size);
+ DMA_EnableChannel(uart->dma_tx.dma_ch, ENABLE);
+
+ uart->dmaTxing = RT_TRUE;
+}
+
+static void n32_stop_dma_tx(struct rt_serial_device *serial)
+{
+ struct n32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ // TODO: 禁用 DMA 发送
+ DMA_EnableChannel(uart->dma_tx.dma_ch, DISABLE);
+ uart->dmaTxing = RT_FALSE;
+}
+#endif
+
+static void n32_enable_interrupt(struct rt_serial_device *serial)
+{
+ struct n32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ UART_ENABLE_IRQ(uart->irq);
+}
+
+static void n32_disable_interrupt(struct rt_serial_device *serial)
+{
+ struct n32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ UART_DISABLE_IRQ(uart->irq);
+}
+
+#ifdef RT_SERIAL_USING_DMA
+/**
+ * DMA receive done process. This need add to DMA receive done ISR.
+ *
+ * @param serial serial device
+ */
+static void dma_rx_done_isr(struct rt_serial_device *serial)
+{
+ struct n32_uart *uart;
+ rt_size_t dma_cnt;
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ dma_cnt = RT_SERIAL_DMA_BUFSZ - DMA_GetCurrDataCounter(uart->dma_rx.dma_ch);
+
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (dma_cnt << 8));
+
+ DMA_ClearFlag(uart->dma_rx.dma_flag, uart->dma_rx.dma_module);
+ DMA_ClrIntPendingBit(uart->dma_rx.dma_flag, uart->dma_rx.dma_module);
+}
+/**
+ * DMA transmit done process. This need add to DMA transmit done ISR.
+ *
+ * @param serial serial device
+ */
+static void dma_tx_done_isr(struct rt_serial_device *serial)
+{
+ struct n32_uart *uart;
+ rt_size_t dma_cnt;
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ dma_cnt = DMA_GetCurrDataCounter(uart->dma_tx.dma_ch);
+
+ if (dma_cnt == 0)
+ {
+ rt_hw_serial_isr(&uart->serial, RT_SERIAL_EVENT_TX_DMADONE);
+ }
+ DMA_ClrIntPendingBit(uart->dma_tx.dma_flag, uart->dma_rx.dma_module);
+}
+#endif
+
+/**
+ * Uart common interrupt process. This need add to uart ISR.
+ *
+ * @param serial serial device
+ */
+static void uart_isr(struct rt_serial_device *serial)
+{
+ struct n32_uart *uart;
+#ifdef RT_SERIAL_USING_DMA
+ rt_size_t dma_cnt;
+#endif
+
+ RT_ASSERT(uart != RT_NULL);
+
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ if(USART_GetIntStatus(uart->uart_device, USART_INT_RXDNE) != RESET)
+ {
+ if(USART_GetFlagStatus(uart->uart_device, USART_FLAG_PEF) == RESET)
+ {
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+ }
+ /* clear interrupt */
+ USART_ClrIntPendingBit(uart->uart_device, USART_INT_RXDNE);
+ }
+ if(USART_GetIntStatus(uart->uart_device, USART_INT_TXDE) != RESET)
+ {
+ if(USART_GetFlagStatus(uart->uart_device, USART_FLAG_PEF) == RESET)
+ {
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DONE);
+ }
+ /* clear interrupt */
+ USART_ClrIntPendingBit(uart->uart_device, USART_INT_TXDE);
+ }
+
+#ifdef RT_SERIAL_USING_DMA
+ if(USART_GetIntStatus(uart->uart_device, USART_INT_IDLEF) != RESET)
+ {
+ /* read a data for clear receive idle interrupt flag */
+ USART_ReceiveData(uart->uart_device);
+
+ dma_cnt = RT_SERIAL_DMA_BUFSZ - DMA_GetCurrDataCounter(uart->dma_rx.dma_ch);
+
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (dma_cnt << 8));
+ }
+#endif
+ if (USART_GetFlagStatus(uart->uart_device, USART_FLAG_OREF) == SET)
+ {
+ n32_uart_getc(serial);
+ }
+}
+
+static const struct rt_uart_ops n32_uart_ops =
+{
+ .configure = n32_uart_configure,
+ .control = n32_uart_control,
+ .putc = n32_uart_putc,
+ .getc = n32_uart_getc,
+ .flush = n32_uart_flush,
+ .start_tx = n32_start_tx,
+ .stop_tx = n32_stop_tx,
+#ifdef RT_SERIAL_USING_DMA
+ .is_dma_txing = n32_is_dma_txing,
+ .start_dma_tx = n32_start_dma_tx,
+ .stop_dma_tx = n32_stop_dma_tx,
+#endif
+ .enable_interrupt = n32_enable_interrupt,
+ .disable_interrupt = n32_disable_interrupt,
+};
+
+#if defined(BSP_USING_UART1)
+/* UART1 device driver structure */
+struct n32_uart uart1 =
+{
+ .uart_device = USART1,
+ .irq = USART1_IRQn,
+#ifdef RT_SERIAL_USING_DMA
+ .dmaTxing = RT_FALSE,
+ .dma_rx = {
+ DMA1_CH5,
+ DMA1,
+ DMA1_FLAG_TC5 | DMA1_FLAG_HT5,
+ DMA1_Channel5_IRQn,
+ },
+ .dma_tx = {
+ DMA1_CH4,
+ DMA1,
+ DMA1_FLAG_TC4,
+ DMA1_Channel4_IRQn,
+ },
+#endif
+};
+
+void USART1_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ uart_isr(&uart1.serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+
+#ifdef RT_SERIAL_USING_DMA
+void DMA1_Channel5_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ dma_rx_done_isr(&uart1.serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+void DMA1_Channel4_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ dma_tx_done_isr(&uart1.serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+#endif
+#endif /* BSP_USING_UART1 */
+
+#if defined(BSP_USING_UART2)
+/* UART2 device driver structure */
+struct n32_uart uart2 =
+{
+ .uart_device = USART2,
+ .irq = USART2_IRQn,
+#ifdef RT_SERIAL_USING_DMA
+ .dmaTxing = RT_FALSE,
+ .dma_rx = {
+ DMA1_CH6,
+ DMA1,
+ DMA1_FLAG_TC6 | DMA1_FLAG_HT6,
+ DMA1_Channel6_IRQn,
+ },
+ .dma_tx = {
+ DMA1_CH7,
+ DMA1,
+ DMA1_FLAG_TC7,
+ DMA1_Channel7_IRQn,
+ },
+#endif
+};
+
+void USART2_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ uart_isr(&uart2.serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+
+#ifdef RT_SERIAL_USING_DMA
+void DMA1_Channel6_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ dma_rx_done_isr(&uart2.serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+#endif
+#endif /* BSP_USING_UART2 */
+
+#if defined(BSP_USING_UART3)
+/* UART3 device driver structure */
+struct n32_uart uart3 =
+{
+ .uart_device = USART3,
+ .irq = USART3_IRQn,
+#ifdef RT_SERIAL_USING_DMA
+ .dmaTxing = RT_FALSE,
+ .dma_rx = {
+ DMA1_CH3,
+ DMA1,
+ DMA1_FLAG_TC3 | DMA1_FLAG_HT3,
+ DMA1_Channel3_IRQn,
+ },
+ .dma_tx = {
+ DMA1_CH2,
+ DMA1,
+ DMA1_FLAG_TC2,
+ DMA1_Channel2_IRQn,
+ },
+#endif
+};
+
+void USART3_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ uart_isr(&uart3.serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+
+#ifdef RT_SERIAL_USING_DMA
+void DMA1_Channel3_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ dma_rx_done_isr(&uart3.serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+#endif
+#endif /* BSP_USING_UART3 */
+
+#if defined(BSP_USING_UART4)
+/* UART4 device driver structure */
+struct n32_uart uart4 =
+{
+ .uart_device = UART4,
+ .irq = UART4_IRQn,
+#ifdef RT_SERIAL_USING_DMA
+ .dmaTxing = RT_FALSE,
+ .dma_rx = {
+ DMA2_CH3,
+ DMA2,
+ DMA2_FLAG_TC3 | DMA2_FLAG_HT3,
+ DMA2_Channel3_IRQn,
+ },
+ .dma_tx = {
+ DMA2_CH5,
+ DMA2,
+ DMA2_FLAG_TC5,
+ DMA2_Channel5_IRQn,
+ },
+#endif
+};
+
+void UART4_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ uart_isr(&uart4.serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+
+#ifdef RT_SERIAL_USING_DMA
+void DMA2_Channel3_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ dma_rx_done_isr(&uart4.serial);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+#endif
+#endif /* BSP_USING_UART4 */
+
+static void NVIC_Configuration(struct n32_uart *uart)
+{
+ NVIC_InitType NVIC_InitStructure;
+
+ /* Enable the USART1 Interrupt */
+ NVIC_InitStructure.NVIC_IRQChannel = uart->irq;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
+ NVIC_Init(&NVIC_InitStructure);
+}
+
+#ifdef RT_SERIAL_USING_DMA
+// TODO: 添加发送 DMA 配置,添加接收 DMA 配置
+static void DMA_RX_Configuration(struct rt_serial_device *serial)
+{
+ DMA_InitType DMA_InitStructure;
+ NVIC_InitType NVIC_InitStructure;
+ struct n32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ /* enable transmit idle interrupt */
+ USART_ConfigInt(uart->uart_device, USART_INT_IDLEF, ENABLE);
+
+ /* DMA clock enable */
+ RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA1, ENABLE);
+ RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA2, ENABLE);
+
+ /* rx dma config */
+ DMA_InitStructure.PeriphAddr = (uint32_t)&(uart->uart_device->DAT);
+ DMA_InitStructure.MemAddr = (uint32_t)(serial->serial_dma_rx);
+ DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC;
+ DMA_InitStructure.BufSize = RT_SERIAL_DMA_BUFSZ;
+ DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE;
+ DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE;
+ DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE;
+ DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_Byte;
+ DMA_InitStructure.CircularMode = DMA_MODE_CIRCULAR;
+ DMA_InitStructure.Priority = DMA_PRIORITY_HIGH;
+ DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE;
+
+ DMA_DeInit(uart->dma_rx.dma_ch);
+ DMA_Init(uart->dma_rx.dma_ch, &DMA_InitStructure);
+
+ DMA_ClearFlag(uart->dma_rx.dma_flag, uart->dma_rx.dma_module);
+ DMA_ConfigInt(uart->dma_rx.dma_ch, DMA_INT_HTX, ENABLE);
+ DMA_ConfigInt(uart->dma_rx.dma_ch, DMA_INT_TXC, ENABLE);
+
+ USART_EnableDMA(uart->uart_device, USART_DMAREQ_RX, ENABLE);
+ DMA_EnableChannel(uart->dma_rx.dma_ch, ENABLE);
+
+ /* rx dma interrupt config */
+ NVIC_InitStructure.NVIC_IRQChannel = uart->dma_rx.dma_irq;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+}
+static void DMA_TX_Configuration(struct rt_serial_device *serial)
+{
+ DMA_InitType DMA_InitStructure;
+ NVIC_InitType NVIC_InitStructure;
+ struct n32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+ uart = rt_container_of(serial, struct n32_uart, serial);
+
+ /* enable transmit idle interrupt */
+// USART_ConfigInt(uart->uart_device, USART_INT_IDLEF, ENABLE);
+
+ /* DMA clock enable */
+ RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA1, ENABLE);
+ RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA2, ENABLE);
+
+ /* tx dma config */
+ DMA_InitStructure.PeriphAddr = (uint32_t)&(uart->uart_device->DAT);
+// DMA_InitStructure.MemAddr = (uint32_t)(serial->serial_dma_tx);
+ DMA_InitStructure.Direction = DMA_DIR_PERIPH_DST;
+// DMA_InitStructure.BufSize = serial->config.bufsz;
+ DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE;
+ DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE;
+ DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE;
+ DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_Byte;
+ DMA_InitStructure.CircularMode = DMA_MODE_NORMAL;
+ DMA_InitStructure.Priority = DMA_PRIORITY_HIGH;
+ DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE;
+
+ DMA_DeInit(uart->dma_tx.dma_ch);
+ DMA_Init(uart->dma_tx.dma_ch, &DMA_InitStructure);
+
+ DMA_ClearFlag(uart->dma_tx.dma_flag, uart->dma_tx.dma_module);
+ DMA_ConfigInt(uart->dma_tx.dma_ch, DMA_INT_TXC, ENABLE);
+ USART_EnableDMA(uart->uart_device, USART_DMAREQ_TX, ENABLE);
+// DMA_EnableChannel(uart->dma_tx.dma_ch, ENABLE);
+
+ /* rx dma interrupt config */
+ NVIC_InitStructure.NVIC_IRQChannel = uart->dma_tx.dma_irq;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+}
+#endif
+
+int rt_hw_usart_init(void)
+{
+ struct n32_uart *uart;
+
+#if defined(BSP_USING_UART1)
+ uart = &uart1;
+
+ uart->serial.ops = &n32_uart_ops;
+
+ NVIC_Configuration(uart);
+
+ /* register UART1 device */
+ rt_hw_serial_register(&uart->serial, "uart1",
+ RT_DEVICE_FLAG_RDWR |
+ RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX
+#ifdef RT_SERIAL_USING_DMA
+ | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX
+#endif
+ , uart);
+#endif /* BSP_USING_UART1 */
+
+#if defined(BSP_USING_UART2)
+ uart = &uart2;
+
+ uart->serial.ops = &n32_uart_ops;
+
+ NVIC_Configuration(uart);
+
+ /* register UART2 device */
+ rt_hw_serial_register(&uart->serial, "uart2",
+ RT_DEVICE_FLAG_RDWR |
+ RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX
+#ifdef RT_SERIAL_USING_DMA
+ | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX
+#endif
+ , uart);
+#endif /* BSP_USING_UART2 */
+
+#if defined(BSP_USING_UART3)
+ uart = &uart3;
+
+ uart->serial.ops = &n32_uart_ops;
+
+ NVIC_Configuration(uart);
+
+ /* register UART3 device */
+ rt_hw_serial_register(&uart->serial, "uart3",
+ RT_DEVICE_FLAG_RDWR |
+ RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX
+#ifdef RT_SERIAL_USING_DMA
+ | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX
+#endif
+ , uart);
+#endif /* BSP_USING_UART3 */
+
+#if defined(BSP_USING_UART4)
+ uart = &uart4;
+
+ uart->serial.ops = &n32_uart_ops;
+
+ NVIC_Configuration(uart);
+
+ /* register UART4 device */
+ rt_hw_serial_register(&uart->serial, "uart4",
+ RT_DEVICE_FLAG_RDWR |
+ RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX
+#ifdef RT_SERIAL_USING_DMA
+ | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX
+#endif
+ , uart);
+#endif /* BSP_USING_UART4 */
+
+ return RT_EOK;
+}
+INIT_BOARD_EXPORT(rt_hw_usart_init);
+
diff --git a/bsp/n32/libraries/n32_drivers/drv_usartX.h b/bsp/n32/libraries/n32_drivers/drv_usartX.h
new file mode 100644
index 0000000000..c383b6d55a
--- /dev/null
+++ b/bsp/n32/libraries/n32_drivers/drv_usartX.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-06-06 THEWON first version for serialX
+ */
+
+#ifndef __DRV_USARTX_H__
+#define __DRV_USARTX_H__
+
+#include "rtdevice.h"
+
+struct n32_uart_dma
+{
+ /* dma channel */
+ DMA_ChannelType *dma_ch;
+ DMA_Module *dma_module;
+ /* dma global flag */
+ uint32_t dma_flag;
+ /* dma irq channel */
+ uint8_t dma_irq;
+};
+
+struct n32_uart
+{
+ USART_Module *uart_device;
+ struct rt_serial_device serial;
+ IRQn_Type irq;
+#ifdef RT_SERIAL_USING_DMA
+ rt_bool_t dmaTxing;
+ struct n32_uart_dma dma_rx;
+ struct n32_uart_dma dma_tx;
+#endif
+};
+
+#endif /* __DRV_USART_H__ */
diff --git a/bsp/nuvoton/libraries/nuc980/rtt_port/drv_common.c b/bsp/nuvoton/libraries/nuc980/rtt_port/drv_common.c
index 11790226e5..415ff6ca35 100644
--- a/bsp/nuvoton/libraries/nuc980/rtt_port/drv_common.c
+++ b/bsp/nuvoton/libraries/nuc980/rtt_port/drv_common.c
@@ -13,7 +13,11 @@
#include <rtthread.h>
#include <rthw.h>
#include "board.h"
+#ifdef RT_USING_SERIAL_X
+#include "drv_uartX.h"
+#else
#include "drv_uart.h"
+#endif
#include "drv_sys.h"
#if defined(BSP_USING_MMU)
diff --git a/bsp/nuvoton/libraries/nuc980/rtt_port/drv_uartX.c b/bsp/nuvoton/libraries/nuc980/rtt_port/drv_uartX.c
new file mode 100644
index 0000000000..1f17d89fbb
--- /dev/null
+++ b/bsp/nuvoton/libraries/nuc980/rtt_port/drv_uartX.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2023-02-01 THEWON first version for serialX
+ */
+
+#include <rtconfig.h>
+
+#ifdef RT_USING_SERIAL
+
+#include <rtdevice.h>
+#include "drv_uartX.h"
+#include "drv_sys.h"
+
+//#define DRV_DEBUG
+#define LOG_TAG "drv.uart"
+// #include <drv_log.h>
+
+#if !defined(BSP_USING_UART1) && !defined(BSP_USING_UART2) && !defined(BSP_USING_UART3) && \
+ !defined(BSP_USING_UART4) && !defined(BSP_USING_UART5) && !defined(BSP_USING_UART6) && \
+ !defined(BSP_USING_UART7) && !defined(BSP_USING_UART8) && !defined(BSP_USING_UART9) && \
+ !defined(BSP_USING_UARTA)
+#error "Please define at least one BSP_USING_UARTx"
+/* this driver can be disabled at menuconfig -> RT-Thread Components -> Device Drivers */
+#endif
+
+static int nu_uart_flush(struct rt_serial_device *serial);
+
+static void nu_uart_isr(int vector, void *param);
+
+static struct nu_uart nu_uart_arr[] =
+{
+#ifdef BSP_USING_UART0
+ UART0_CONFIG,
+#endif
+#ifdef BSP_USING_UART1
+ UART1_CONFIG,
+#endif
+#ifdef BSP_USING_UART2
+ UART2_CONFIG,
+#endif
+#ifdef BSP_USING_UART3
+ UART3_CONFIG,
+#endif
+#ifdef BSP_USING_UART4
+ UART4_CONFIG,
+#endif
+#ifdef BSP_USING_UART5
+ UART5_CONFIG,
+#endif
+#ifdef BSP_USING_UART6
+ UART6_CONFIG,
+#endif
+#ifdef BSP_USING_UART7
+ UART7_CONFIG,
+#endif
+#ifdef BSP_USING_UART8
+ UART8_CONFIG,
+#endif
+#ifdef BSP_USING_UART9
+ UART9_CONFIG,
+#endif
+#ifdef BSP_USING_UARTA
+ UARTA_CONFIG,
+#endif
+};
+
+// for ALL uarts
+static void nu_uart_isr(int vector, void *param)
+{
+ /* Get base address of uart register */
+ nu_uart_t serial = (nu_uart_t)param;
+ UART_T *uart_base = ((nu_uart_t)serial)->uart_base;
+
+ /* Get interrupt event */
+ uint32_t u32IntSts = uart_base->INTSTS;
+ uint32_t u32FIFOSts = uart_base->FIFOSTS;
+
+ if (u32IntSts & (UART_INTSTS_RDAINT_Msk | UART_INTSTS_RXTOINT_Msk)) { // Received Data Available interrupt
+ rt_hw_serial_isr(&serial->dev, RT_SERIAL_EVENT_RX_IND);
+ }
+
+ if (u32IntSts & UART_INTSTS_THREINT_Msk) { // Transmit Holding Register Empty interrupt
+ rt_hw_serial_isr(&serial->dev, RT_SERIAL_EVENT_TX_DONE | (16<<8));
+ }
+
+ // if (uRegISR & UART_INTSTS_MODEMINT_Msk) {
+ // uRegMSR = huart->Instance->MSR;
+ // uRegMSR |= UART_MSR_DCTSF_Msk;
+ // huart->Instance->MSR = uRegMSR;
+ // }
+
+ // if (uRegISR & UART_ISR_BUF_ERR_INT_Msk) {
+ // if (uRegFSR & (UART_FSR_TX_OVER_IF_Msk)) {
+ // huart->Instance->FSR = UART_FSR_TX_OVER_IF_Msk;
+ // }
+ // if (uRegFSR & (UART_FSR_RX_OVER_IF_Msk)) {
+ // huart->Instance->FSR = UART_FSR_RX_OVER_IF_Msk;
+ // }
+ // }
+
+ // if (uRegFSR & (UART_FSR_BIF_Msk | UART_FSR_FEF_Msk | UART_FSR_PEF_Msk | UART_FSR_RX_OVER_IF_Msk | UART_FSR_TX_OVER_IF_Msk)) {
+ // huart->Instance->FSR = (UART_FSR_BIF_Msk | UART_FSR_FEF_Msk | UART_FSR_PEF_Msk | UART_FSR_RX_OVER_IF_Msk | UART_FSR_TX_OVER_IF_Msk);
+ // }
+ uart_base->INTSTS = u32IntSts;
+ uart_base->FIFOSTS = u32FIFOSts;
+}
+
+/**
+ * Configure uart port
+ */
+static rt_err_t nu_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
+{
+ rt_err_t ret = RT_EOK;
+ uint32_t uart_word_len = 0;
+ uint32_t uart_stop_bit = 0;
+ uint32_t uart_parity = 0;
+
+ /* Get base address of uart register */
+ UART_T *uart_base = ((nu_uart_t)serial)->uart_base;
+
+ /* Check baudrate */
+ RT_ASSERT(cfg->baud_rate != 0);
+
+ /* Check word len */
+ switch (cfg->data_bits) {
+ case DATA_BITS_5:
+ uart_word_len = UART_WORD_LEN_5;
+ break;
+ case DATA_BITS_6:
+ uart_word_len = UART_WORD_LEN_6;
+ break;
+ case DATA_BITS_7:
+ uart_word_len = UART_WORD_LEN_7;
+ break;
+ case DATA_BITS_8:
+ uart_word_len = UART_WORD_LEN_8;
+ break;
+ default:
+ uart_word_len = UART_WORD_LEN_8;
+ break;
+ }
+
+ /* Check stop bit */
+ switch (cfg->stop_bits) {
+ case STOP_BITS_1:
+ uart_stop_bit = UART_STOP_BIT_1;
+ break;
+ case STOP_BITS_2:
+ uart_stop_bit = UART_STOP_BIT_2;
+ break;
+ default:
+ uart_stop_bit = UART_STOP_BIT_1;
+ break;
+ }
+
+ /* Check parity */
+ switch (cfg->parity)
+ {
+ case PARITY_NONE:
+ uart_parity = UART_PARITY_NONE;
+ break;
+ case PARITY_ODD:
+ uart_parity = UART_PARITY_ODD;
+ break;
+ case PARITY_EVEN:
+ uart_parity = UART_PARITY_EVEN;
+ break;
+ default:
+ uart_parity = UART_PARITY_NONE;
+ break;
+ }
+
+ /* Set line configuration. */
+ UART_SetLineConfig(uart_base, cfg->baud_rate, uart_word_len, uart_parity, uart_stop_bit);
+
+ return RT_EOK;
+}
+
+/**
+ * Initialize uart port
+ */
+static rt_err_t nu_uart_init(struct rt_serial_device *serial)
+{
+ /* Get base address of uart register */
+ UART_T *uart_base = ((nu_uart_t)serial)->uart_base;
+
+// nu_sys_ip_reset(((nu_uart_t)serial)->rstidx);
+
+ /* Open Uart and set UART Baudrate */
+ UART_Open(uart_base, serial->config->baud_rate);
+
+ if (nu_uart_configure(serial, &serial->config) != RT_EOK)
+ {
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t nu_uart_control(struct rt_serial_device *serial, int cmd, void *arg)
+{
+ nu_uart_t psNuUart = (nu_uart_t)serial;
+ rt_err_t result = RT_EOK;
+ rt_uint32_t flag;
+ rt_ubase_t ctrl_arg = (rt_ubase_t)arg;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ /* Get base address of uart register */
+ UART_T *uart_base = psNuUart->uart_base;
+
+ switch (cmd) {
+ case RT_DEVICE_CTRL_OPEN:
+ /* Enable interrupt. */
+ rt_hw_interrupt_umask(((nu_uart_t)serial)->irqn);
+ break;
+ case RT_DEVICE_CTRL_CLR_INT:
+ /* disable interrupt */
+ if (ctrl_arg & RT_DEVICE_FLAG_INT_TX) {
+ UART_DISABLE_INT(uart_base, UART_INTEN_THREIEN_Msk);
+ }
+ if (ctrl_arg & RT_DEVICE_FLAG_INT_RX) {
+ flag = UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk | UART_INTEN_TOCNTEN_Msk;
+ UART_DISABLE_INT(uart_base, flag);
+ }
+
+#ifdef RT_SERIAL_USING_DMA
+ /* disable DMA */
+#endif
+ break;
+ case RT_DEVICE_CTRL_SET_INT:
+ /* enable interrupt */
+ if (ctrl_arg & RT_DEVICE_FLAG_INT_TX) {
+ UART_ENABLE_INT(uart_base, UART_INTEN_THREIEN_Msk);
+ }
+ if (ctrl_arg & RT_DEVICE_FLAG_INT_RX) {
+ flag = UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk | UART_INTEN_TOCNTEN_Msk;
+ UART_ENABLE_INT(uart_base, flag);
+ }
+ break;
+ case RT_DEVICE_CTRL_CONFIG:
+#ifdef RT_SERIAL_USING_DMA
+#endif
+ break;
+ case RT_DEVICE_CTRL_CLOSE:
+ /* disable interrupt */
+ rt_hw_interrupt_mask(psNuUart->irqn);
+
+ /* Close UART port */
+ UART_Close(uart_base);
+ break;
+ default :
+ break;
+ }
+ return RT_EOK;
+}
+
+static int nu_uart_putc(struct rt_serial_device *serial, char c)
+{
+ UART_T *uart_base;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ /* Get base address of uart register */
+ uart_base = ((nu_uart_t)serial)->uart_base;
+ /* Waiting if TX-FIFO is full. */
+ while (UART_IS_TX_FULL(uart_base));
+ /* Put char into TX-FIFO */
+ UART_WRITE(uart_base, c);
+ return 1;
+}
+
+static int nu_uart_getc(struct rt_serial_device *serial)
+{
+ int ch;
+ UART_T *uart_base;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ /* Get base address of uart register */
+ uart_base = ((nu_uart_t)serial)->uart_base;
+
+ /* Return failure if RX-FIFO is empty. */
+ if (UART_GET_RX_EMPTY(uart_base)) {
+ return -1;
+ }
+ /* Get char from RX-FIFO */
+ ch = UART_READ(uart_base);
+
+ return ch;
+}
+
+static int nu_uart_flush(struct rt_serial_device *serial)
+{
+ UART_T *uart_base;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ /* Get base address of uart register */
+ uart_base = ((nu_uart_t)serial)->uart_base;
+ while(!UART_IS_TX_EMPTY(uart_base)){;}
+
+ return 1;
+}
+
+static void nu_start_tx(struct rt_serial_device *serial)
+{
+ UART_T *uart_base;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart_base = ((nu_uart_t)serial)->uart_base;
+
+ /* enable interrupt */
+ UART_ENABLE_INT(uart_base, UART_INTEN_THREIEN_Msk);
+}
+
+static void nu_stop_tx(struct rt_serial_device *serial)
+{
+ UART_T *uart_base;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart_base = ((nu_uart_t)serial)->uart_base;
+
+ /* disable interrupt */
+ UART_DISABLE_INT(uart_base, UART_INTEN_THREIEN_Msk);
+}
+
+static void nu_enable_interrupt(struct rt_serial_device *serial)
+{
+ RT_ASSERT(serial != RT_NULL);
+
+ rt_hw_interrupt_umask(((nu_uart_t)serial)->irqn);
+}
+
+static void nu_disable_interrupt(struct rt_serial_device *serial)
+{
+ RT_ASSERT(serial != RT_NULL);
+
+ rt_hw_interrupt_mask(((nu_uart_t)serial)->irqn);
+}
+
+static const struct rt_uart_ops nu_uart_ops =
+{
+ .init = nu_uart_init,
+ .configure = nu_uart_configure,
+ .control = nu_uart_control,
+ .putc = nu_uart_putc,
+ .getc = nu_uart_getc,
+ .flush = nu_uart_flush,
+ .start_tx = nu_start_tx,
+ .stop_tx = nu_stop_tx,
+ .enable_interrupt = nu_enable_interrupt,
+ .disable_interrupt = nu_disable_interrupt,
+};
+
+int rt_hw_uart_init(void)
+{
+ rt_size_t obj_num = sizeof(nu_uart_arr) / sizeof(struct nu_uart);
+ rt_err_t result = 0;
+ int i;
+
+ for (i = 0; i < obj_num; i++)
+ {
+ /* init UART object */
+ nu_uart_arr[i].dev.ops = &nu_uart_ops;
+
+ rt_hw_interrupt_install(nu_uart_arr[i].irqn, nu_uart_isr, &nu_uart_arr[i], nu_uart_arr[i].name);
+
+ nu_sys_ipclk_enable(nu_uart_arr[i].clkidx);
+
+ /* register UART device */
+ result = rt_hw_serial_register(&nu_uart_arr[i].dev, nu_uart_arr[i].name,
+ RT_DEVICE_FLAG_RDWR
+ | RT_DEVICE_FLAG_INT_RX
+ | RT_DEVICE_FLAG_INT_TX
+ , NULL);
+ RT_ASSERT(result == RT_EOK);
+ }
+
+ return result;
+}
+
+#endif /* RT_USING_SERIAL */
diff --git a/bsp/nuvoton/libraries/nuc980/rtt_port/drv_uartX.h b/bsp/nuvoton/libraries/nuc980/rtt_port/drv_uartX.h
new file mode 100644
index 0000000000..98cea487fa
--- /dev/null
+++ b/bsp/nuvoton/libraries/nuc980/rtt_port/drv_uartX.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2023-02-01 THEWON first version for serialX
+ */
+
+#ifndef __DRV_UART_H__
+#define __DRV_UART_H__
+
+#include <rtthread.h>
+#include "rtdevice.h"
+#include <rthw.h>
+#include <drv_common.h>
+#include "NuMicro.h"
+#include <drv_sys.h>
+
+typedef void(*uart_isr_cb)(int, void*);
+
+/* Private typedef --------------------------------------------------------------*/
+struct nu_uart
+{
+ struct rt_serial_device dev;
+ char *name;
+ UART_T *uart_base;
+ IRQn_Type irqn;
+ E_SYS_IPRST rstidx;
+ E_SYS_IPCLK clkidx;
+
+#if defined(RT_SERIAL_USING_DMA)
+ uint32_t dma_flag;
+ int16_t pdma_perp_tx;
+ int8_t pdma_chanid_tx;
+
+ int16_t pdma_perp_rx;
+ int8_t pdma_chanid_rx;
+ int32_t rx_write_offset;
+ int32_t rxdma_trigger_len;
+
+ nu_pdma_desc_t pdma_rx_desc;
+#endif
+
+};
+typedef struct nu_uart *nu_uart_t;
+
+#if defined(BSP_USING_UART0)
+#ifndef UART0_CONFIG
+#define UART0_CONFIG \
+ { \
+ .name = "uart0", \
+ .uart_base = UART0, \
+ .irqn = IRQ_UART0, \
+ .rstidx = UART0RST, \
+ .clkidx = UART0CKEN, \
+ }
+#endif /* UART0_CONFIG */
+
+#endif /* BSP_USING_UART0 */
+
+#if defined(BSP_USING_UART1)
+#ifndef UART1_CONFIG
+#define UART1_CONFIG \
+ { \
+ .name = "uart1", \
+ .uart_base = UART1, \
+ .irqn = IRQ_UART1, \
+ .rstidx = UART1RST, \
+ .clkidx = UART1CKEN, \
+ }
+#endif /* UART1_CONFIG */
+
+#endif /* BSP_USING_UART1 */
+
+int rt_hw_uart_init(void);
+
+#endif /* __DRV_UART_H__ */
diff --git a/bsp/renesas/libraries/HAL_Drivers/SConscript b/bsp/renesas/libraries/HAL_Drivers/SConscript
index 37e7359d95..feb5d01071 100644
--- a/bsp/renesas/libraries/HAL_Drivers/SConscript
+++ b/bsp/renesas/libraries/HAL_Drivers/SConscript
@@ -12,6 +12,8 @@ src = Split("""
if GetDepend(['BSP_USING_UART']):
if GetDepend(['RT_USING_SERIAL_V2']):
src += ['drv_usart_v2.c']
+ elif GetDepend(['RT_USING_SERIAL_X']):
+ src += ['drv_usartX.c']
else:
print("\nThe current project does not support serial-v1\n")
Return('group')
diff --git a/bsp/renesas/libraries/HAL_Drivers/drv_usartX.c b/bsp/renesas/libraries/HAL_Drivers/drv_usartX.c
new file mode 100644
index 0000000000..f620dde27e
--- /dev/null
+++ b/bsp/renesas/libraries/HAL_Drivers/drv_usartX.c
@@ -0,0 +1,625 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-07-29 KyleChan first version
+ * 2022-06-08 THEWON first version for serialX
+ */
+
+#include <drv_usartX.h>
+
+#ifdef RT_USING_SERIAL_X
+
+//#define DRV_DEBUG
+#define DBG_TAG "drv.usart"
+#ifdef DRV_DEBUG
+ #define DBG_LVL DBG_LOG
+#else
+ #define DBG_LVL DBG_INFO
+#endif /* DRV_DEBUG */
+#include <rtdbg.h>
+
+/* SCI SCR register bit masks */
+#define SCI_SCR_TEIE_MASK (0x04U) ///< Transmit End Interrupt Enable
+#define SCI_SCR_RE_MASK (0x10U) ///< Receive Enable
+#define SCI_SCR_TE_MASK (0x20U) ///< Transmit Enable
+#define SCI_SCR_RIE_MASK (0x40U) ///< Receive Interrupt Enable
+#define SCI_SCR_TIE_MASK (0x80U) ///< Transmit Interrupt Enable
+
+static struct ra_uart_config uart_config[] =
+{
+#ifdef BSP_USING_UART0
+ UART0_CONFIG,
+#endif
+
+#ifdef BSP_USING_UART1
+ UART1_CONFIG,
+#endif
+
+#ifdef BSP_USING_UART2
+ UART2_CONFIG,
+#endif
+
+#ifdef BSP_USING_UART3
+ UART3_CONFIG,
+#endif
+
+#ifdef BSP_USING_UART4
+ UART4_CONFIG,
+#endif
+
+#ifdef BSP_USING_UART5
+ UART5_CONFIG,
+#endif
+
+#ifdef BSP_USING_UART6
+ UART6_CONFIG,
+#endif
+
+#ifdef BSP_USING_UART7
+ UART7_CONFIG,
+#endif
+
+#ifdef BSP_USING_UART8
+ UART8_CONFIG,
+#endif
+
+#ifdef BSP_USING_UART9
+ UART9_CONFIG,
+#endif
+};
+
+enum
+{
+#ifdef BSP_USING_UART0
+ UART0_INDEX,
+#endif
+
+#ifdef BSP_USING_UART1
+ UART1_INDEX,
+#endif
+
+#ifdef BSP_USING_UART2
+ UART2_INDEX,
+#endif
+
+#ifdef BSP_USING_UART3
+ UART3_INDEX,
+#endif
+
+#ifdef BSP_USING_UART4
+ UART4_INDEX,
+#endif
+
+#ifdef BSP_USING_UART5
+ UART5_INDEX,
+#endif
+
+#ifdef BSP_USING_UART6
+ UART6_INDEX,
+#endif
+
+#ifdef BSP_USING_UART7
+ UART7_INDEX,
+#endif
+
+#ifdef BSP_USING_UART8
+ UART8_INDEX,
+#endif
+
+#ifdef BSP_USING_UART9
+ UART9_INDEX,
+#endif
+};
+
+static struct ra_uart uart_obj[sizeof(uart_config) / sizeof(uart_config[0])] = {0};
+
+static void ra_uart_get_config(void)
+{
+ struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
+
+#ifdef BSP_USING_UART0
+ uart_obj[UART0_INDEX].serial.config = config;
+#endif
+
+#ifdef BSP_USING_UART1
+ uart_obj[UART1_INDEX].serial.config = config;
+#endif
+
+#ifdef BSP_USING_UART2
+ uart_obj[UART2_INDEX].serial.config = config;
+#endif
+
+#ifdef BSP_USING_UART3
+ uart_obj[UART3_INDEX].serial.config = config;
+#endif
+
+#ifdef BSP_USING_UART4
+ uart_obj[UART4_INDEX].serial.config = config;
+#endif
+
+#ifdef BSP_USING_UART6
+ uart_obj[UART6_INDEX].serial.config = config;
+#endif
+
+#ifdef BSP_USING_UART7
+ uart_obj[UART7_INDEX].serial.config = config;
+ uart_config[UART7_INDEX].uart_cfg = g_uart7_cfg;
+#endif
+
+#ifdef BSP_USING_UART8
+ uart_obj[UART8_INDEX].serial.config = config;
+#endif
+
+#ifdef BSP_USING_UART9
+ uart_obj[UART9_INDEX].serial.config = config;
+#endif
+}
+
+/*
+ * UART interface
+ */
+static rt_err_t ra_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
+{
+ struct ra_uart *uart;
+ RT_ASSERT(serial != RT_NULL);
+ RT_ASSERT(cfg != RT_NULL);
+
+ fsp_err_t err = FSP_SUCCESS;
+
+ uart = rt_container_of(serial, struct ra_uart, serial);
+ RT_ASSERT(uart != RT_NULL);
+
+ if (cfg->data_bits == DATA_BITS_7)
+ {
+ uart->uart_config->uart_cfg.data_bits = UART_DATA_BITS_7;
+ }
+ else if (cfg->data_bits == DATA_BITS_8)
+ {
+ uart->uart_config->uart_cfg.data_bits = UART_DATA_BITS_8;
+ }
+ else if (cfg->data_bits == DATA_BITS_9)
+ {
+ uart->uart_config->uart_cfg.data_bits = UART_DATA_BITS_9;
+ }
+
+ if (cfg->stop_bits == STOP_BITS_1)
+ {
+ uart->uart_config->uart_cfg.stop_bits = UART_STOP_BITS_1;
+ }
+ else if (cfg->stop_bits == STOP_BITS_2)
+ {
+ uart->uart_config->uart_cfg.stop_bits = UART_STOP_BITS_2;
+ }
+
+ if (cfg->parity == PARITY_NONE)
+ {
+ uart->uart_config->uart_cfg.parity = UART_PARITY_OFF;
+ }
+ else if (cfg->parity == PARITY_ODD)
+ {
+ uart->uart_config->uart_cfg.parity = UART_PARITY_ODD;
+ }
+ else if (cfg->parity == PARITY_EVEN)
+ {
+ uart->uart_config->uart_cfg.parity = UART_PARITY_EVEN;
+ }
+
+ err = R_SCI_UART_Open(uart->uart_config->p_api_ctrl, &uart->uart_config->uart_cfg);
+ if (FSP_SUCCESS != err)
+ {
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+/*
+ * Initialize UART interface
+ */
+static rt_err_t ra_uart_init(struct rt_serial_device *serial)
+{
+ if (ra_uart_configure(serial, &serial->config) != RT_EOK)
+ {
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t ra_uart_control(struct rt_serial_device *serial, int cmd, void *arg)
+{
+ struct ra_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct ra_uart, serial);
+
+ switch (cmd) {
+ case RT_DEVICE_CTRL_OPEN:
+ uart->intTxing = RT_FALSE;
+ break;
+ case RT_DEVICE_CTRL_CLOSE:
+ R_SCI_UART_Close(uart->uart_config->p_api_ctrl);
+ break;
+ case RT_DEVICE_CTRL_CLR_INT:
+ /* disable interrupt */
+ break;
+ case RT_DEVICE_CTRL_SET_INT:
+ /* enable interrupt */
+ break;
+ /* USART config */
+ case RT_DEVICE_CTRL_CONFIG :
+ break;
+ default :
+ break;
+ }
+ return RT_EOK;
+}
+
+static int ra_uart_putc(struct rt_serial_device *serial, char c, rt_bool_t useint)
+{
+ struct ra_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct ra_uart, serial);
+
+ sci_uart_instance_ctrl_t *p_ctrl = (sci_uart_instance_ctrl_t *)uart->uart_config->p_api_ctrl;
+
+ while ((p_ctrl->p_reg->SSR_b.TDRE) == 0);
+ p_ctrl->p_reg->TDR = c;
+ if (useint) {
+ p_ctrl->p_reg->SCR |= SCI_SCR_TE_MASK;
+ p_ctrl->p_reg->SCR |= SCI_SCR_TIE_MASK;
+ }
+
+ return RT_EOK;
+}
+
+static int ra_uart_getc(struct rt_serial_device *serial)
+{
+ int ch;
+ struct ra_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct ra_uart, serial);
+
+ sci_uart_instance_ctrl_t *p_ctrl = (sci_uart_instance_ctrl_t *)uart->uart_config->p_api_ctrl;
+
+ ch = -1;
+ if ((p_ctrl->p_reg->SSR_b.RDRF) == 1) {
+ ch = p_ctrl->p_reg->RDR & 0xFF;
+ p_ctrl->p_reg->SSR_b.RDRF = 0;
+ }
+
+ return ch;
+}
+
+static int ra_uart_flush(struct rt_serial_device *serial)
+{
+ struct ra_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct ra_uart, serial);
+
+ sci_uart_instance_ctrl_t *p_ctrl = (sci_uart_instance_ctrl_t *)uart->uart_config->p_api_ctrl;
+
+ while (!((p_ctrl->p_reg->SSR_b.TEND) == 1 && (p_ctrl->p_reg->SSR_b.TDRE) == 1));
+
+ return 0;
+}
+
+rt_bool_t ra_int_txing(struct rt_serial_device *serial)
+{
+ struct ra_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct ra_uart, serial);
+
+ return uart->intTxing;
+}
+
+static void ra_start_tx(struct rt_serial_device *serial, rt_uint8_t ch)
+{
+ struct ra_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct ra_uart, serial);
+
+ sci_uart_instance_ctrl_t *p_ctrl = (sci_uart_instance_ctrl_t *)uart->uart_config->p_api_ctrl;
+
+ uart->intTxing = RT_TRUE;
+ p_ctrl->p_reg->SCR &= ~(SCI_SCR_TIE_MASK | SCI_SCR_TEIE_MASK);
+ p_ctrl->p_reg->TDR = ch;
+ p_ctrl->p_reg->SCR |= SCI_SCR_TE_MASK;
+ /* Trigger a TXI interrupt. This triggers the transfer instance or a TXI interrupt if the transfer instance is
+ * not used. */
+ p_ctrl->p_reg->SCR |= SCI_SCR_TIE_MASK;
+}
+
+static void ra_stop_tx(struct rt_serial_device *serial)
+{
+ struct ra_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct ra_uart, serial);
+
+ sci_uart_instance_ctrl_t *p_ctrl = (sci_uart_instance_ctrl_t *)uart->uart_config->p_api_ctrl;
+
+ p_ctrl->p_reg->SCR &= ~(SCI_SCR_TIE_MASK | SCI_SCR_TEIE_MASK);
+ uart->intTxing = RT_FALSE;
+}
+
+#ifdef BSP_USING_UART0
+void user_uart0_callback(uart_callback_args_t *p_args)
+{
+ rt_interrupt_enter();
+
+ struct rt_serial_device *serial = &uart_obj[UART0_INDEX].serial;
+ RT_ASSERT(serial != RT_NULL);
+
+ if (UART_EVENT_RX_CHAR == p_args->event)
+ {
+ struct rt_serial_rx_fifo *rx_fifo;
+ rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
+ RT_ASSERT(rx_fifo != RT_NULL);
+
+ rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data);
+
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+ }
+
+ rt_interrupt_leave();
+}
+#endif
+
+#ifdef BSP_USING_UART1
+void user_uart1_callback(uart_callback_args_t *p_args)
+{
+ rt_interrupt_enter();
+
+ struct rt_serial_device *serial = &uart_obj[UART1_INDEX].serial;
+ RT_ASSERT(serial != RT_NULL);
+
+ if (UART_EVENT_RX_CHAR == p_args->event)
+ {
+ struct rt_serial_rx_fifo *rx_fifo;
+ rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
+ RT_ASSERT(rx_fifo != RT_NULL);
+
+ rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data);
+
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+ }
+
+ rt_interrupt_leave();
+}
+#endif
+
+#ifdef BSP_USING_UART2
+void user_uart2_callback(uart_callback_args_t *p_args)
+{
+ rt_interrupt_enter();
+
+ struct rt_serial_device *serial = &uart_obj[UART2_INDEX].serial;
+ RT_ASSERT(serial != RT_NULL);
+
+ if (UART_EVENT_RX_CHAR == p_args->event)
+ {
+ struct rt_serial_rx_fifo *rx_fifo;
+ rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
+ RT_ASSERT(rx_fifo != RT_NULL);
+
+ rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data);
+
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+ }
+
+ rt_interrupt_leave();
+}
+#endif
+
+#ifdef BSP_USING_UART3
+void user_uart3_callback(uart_callback_args_t *p_args)
+{
+ rt_interrupt_enter();
+
+ struct rt_serial_device *serial = &uart_obj[UART3_INDEX].serial;
+ RT_ASSERT(serial != RT_NULL);
+
+ if (UART_EVENT_RX_CHAR == p_args->event)
+ {
+ struct rt_serial_rx_fifo *rx_fifo;
+ rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
+ RT_ASSERT(rx_fifo != RT_NULL);
+
+ rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data);
+
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+ }
+
+ rt_interrupt_leave();
+}
+#endif
+
+#ifdef BSP_USING_UART4
+void user_uart4_callback(uart_callback_args_t *p_args)
+{
+ rt_interrupt_enter();
+
+ struct rt_serial_device *serial = &uart_obj[UART4_INDEX].serial;
+ RT_ASSERT(serial != RT_NULL);
+
+ if (UART_EVENT_RX_CHAR == p_args->event)
+ {
+ struct rt_serial_rx_fifo *rx_fifo;
+ rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
+ RT_ASSERT(rx_fifo != RT_NULL);
+
+ rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data);
+
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+ }
+
+ rt_interrupt_leave();
+}
+#endif
+
+#ifdef BSP_USING_UART5
+void user_uart5_callback(uart_callback_args_t *p_args)
+{
+ rt_interrupt_enter();
+
+ struct rt_serial_device *serial = &uart_obj[UART5_INDEX].serial;
+ RT_ASSERT(serial != RT_NULL);
+
+ if (UART_EVENT_RX_CHAR == p_args->event)
+ {
+ struct rt_serial_rx_fifo *rx_fifo;
+ rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
+ RT_ASSERT(rx_fifo != RT_NULL);
+
+ rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data);
+
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+ }
+
+ rt_interrupt_leave();
+}
+#endif
+
+#ifdef BSP_USING_UART6
+void user_uart6_callback(uart_callback_args_t *p_args)
+{
+ rt_interrupt_enter();
+
+ struct rt_serial_device *serial = &uart_obj[UART6_INDEX].serial;
+ RT_ASSERT(serial != RT_NULL);
+
+ if (UART_EVENT_RX_CHAR == p_args->event)
+ {
+ struct rt_serial_rx_fifo *rx_fifo;
+ rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
+ RT_ASSERT(rx_fifo != RT_NULL);
+
+ rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data);
+
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+ }
+
+ rt_interrupt_leave();
+}
+#endif
+
+#ifdef BSP_USING_UART7
+void user_uart7_callback(uart_callback_args_t *p_args)
+{
+ rt_interrupt_enter();
+
+ struct rt_serial_device *serial = &uart_obj[UART7_INDEX].serial;
+ RT_ASSERT(serial != RT_NULL);
+
+ if (UART_EVENT_RX_CHAR == p_args->event)
+ {
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+ } else if (UART_EVENT_TX_COMPLETE == p_args->event) {
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DONE);
+ }
+
+ rt_interrupt_leave();
+}
+#endif
+
+#ifdef BSP_USING_UART8
+void user_uart8_callback(uart_callback_args_t *p_args)
+{
+ rt_interrupt_enter();
+
+ struct rt_serial_device *serial = &uart_obj[UART8_INDEX].serial;
+ RT_ASSERT(serial != RT_NULL);
+
+ if (UART_EVENT_RX_CHAR == p_args->event)
+ {
+ struct rt_serial_rx_fifo *rx_fifo;
+ rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
+ RT_ASSERT(rx_fifo != RT_NULL);
+
+ rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data);
+
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+ }
+
+ rt_interrupt_leave();
+}
+#endif
+
+#ifdef BSP_USING_UART9
+void user_uart9_callback(uart_callback_args_t *p_args)
+{
+ rt_interrupt_enter();
+
+ struct rt_serial_device *serial = &uart_obj[UART9_INDEX].serial;
+ RT_ASSERT(serial != RT_NULL);
+
+ if (UART_EVENT_RX_CHAR == p_args->event)
+ {
+ struct rt_serial_rx_fifo *rx_fifo;
+ rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
+ RT_ASSERT(rx_fifo != RT_NULL);
+
+ rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data);
+
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+ }
+
+ rt_interrupt_leave();
+}
+#endif
+
+static const struct rt_uart_ops ra_uart_ops =
+{
+ .init = ra_uart_init,
+ .configure = ra_uart_configure,
+ .control = ra_uart_control,
+ .putc = ra_uart_putc,
+ .getc = ra_uart_getc,
+ .flush = ra_uart_flush,
+ .is_int_txing = ra_int_txing,
+ .start_tx = ra_start_tx,
+ .stop_tx = ra_stop_tx,
+};
+
+
+int rt_hw_usart_init(void)
+{
+ rt_err_t result = 0;
+ rt_size_t obj_num = sizeof(uart_obj) / sizeof(struct ra_uart);
+
+ ra_uart_get_config();
+ for (int i = 0; i < obj_num; i++)
+ {
+ /* init UART object */
+ uart_obj[i].uart_config = &uart_config[i];
+ uart_obj[i].serial.ops = &ra_uart_ops;
+ /* register UART device */
+ result = rt_hw_serial_register(&uart_obj[i].serial,
+ uart_obj[i].uart_config->name,
+ RT_DEVICE_FLAG_RDWR |
+ RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX,
+ NULL);
+ RT_ASSERT(result == RT_EOK);
+ }
+
+ return result;
+}
+
+#endif /* RT_USING_SERIAL_X */
diff --git a/bsp/renesas/libraries/HAL_Drivers/drv_usartX.h b/bsp/renesas/libraries/HAL_Drivers/drv_usartX.h
new file mode 100644
index 0000000000..2862c5c409
--- /dev/null
+++ b/bsp/renesas/libraries/HAL_Drivers/drv_usartX.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-07-29 KyleChan first version
+ * 2022-06-08 THEWON first version for serialX
+ */
+
+#ifndef __DRV_USART_V2_H__
+#define __DRV_USART_V2_H__
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rthw.h>
+#include <drv_common.h>
+#include <drv_config.h>
+#include <hal_data.h>
+
+/* renesas config class */
+struct ra_uart_config
+{
+ const char *name;
+ uart_ctrl_t * p_api_ctrl;
+ uart_cfg_t uart_cfg;
+};
+
+struct ra_uart
+{
+ struct rt_serial_device serial;
+ struct ra_uart_config *uart_config;
+ rt_bool_t intTxing;
+};
+
+int rt_hw_usart_init(void);
+
+#endif /* __DRV_USART_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/SConscript b/bsp/stm32/libraries/HAL_Drivers/SConscript
index 7057495e6e..9b11c36808 100644
--- a/bsp/stm32/libraries/HAL_Drivers/SConscript
+++ b/bsp/stm32/libraries/HAL_Drivers/SConscript
@@ -13,6 +13,8 @@ if GetDepend(['RT_USING_PIN']):
if GetDepend(['RT_USING_SERIAL']):
if GetDepend(['RT_USING_SERIAL_V2']):
src += ['drv_usart_v2.c']
+ elif GetDepend(['RT_USING_SERIAL_X']):
+ src += ['drv_usartX.c']
else:
src += ['drv_usart.c']
diff --git a/bsp/stm32/libraries/HAL_Drivers/drv_usartX.c b/bsp/stm32/libraries/HAL_Drivers/drv_usartX.c
new file mode 100644
index 0000000000..02781d5e45
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drv_usartX.c
@@ -0,0 +1,939 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-04-10 THEWON first version for serialX
+ */
+
+#include "board.h"
+#include "drv_usartX.h"
+#include "drv_config.h"
+
+#ifdef RT_USING_SERIAL
+
+//#define DRV_DEBUG
+#define LOG_TAG "drv.usart"
+#include <drv_log.h>
+
+#if !defined(BSP_USING_UART1) && !defined(BSP_USING_UART2) && !defined(BSP_USING_UART3) && \
+ !defined(BSP_USING_UART4) && !defined(BSP_USING_UART5) && !defined(BSP_USING_UART6) && \
+ !defined(BSP_USING_UART7) && !defined(BSP_USING_UART8) && !defined(BSP_USING_LPUART1)
+#error "Please define at least one BSP_USING_UARTx"
+/* this driver can be disabled at menuconfig -> RT-Thread Components -> Device Drivers */
+#endif
+
+#ifdef RT_SERIAL_USING_DMA
+static void stm32_dma_rx_config(struct rt_serial_device *serial);
+static void stm32_dma_tx_config(struct rt_serial_device *serial);
+#endif
+
+enum
+{
+#ifdef BSP_USING_UART1
+ UART1_INDEX,
+#endif
+#ifdef BSP_USING_UART2
+ UART2_INDEX,
+#endif
+#ifdef BSP_USING_UART3
+ UART3_INDEX,
+#endif
+#ifdef BSP_USING_UART4
+ UART4_INDEX,
+#endif
+#ifdef BSP_USING_UART5
+ UART5_INDEX,
+#endif
+#ifdef BSP_USING_UART6
+ UART6_INDEX,
+#endif
+#ifdef BSP_USING_UART7
+ UART7_INDEX,
+#endif
+#ifdef BSP_USING_UART8
+ UART8_INDEX,
+#endif
+#ifdef BSP_USING_LPUART1
+ LPUART1_INDEX,
+#endif
+};
+
+static struct stm32_uart_config uart_config[] =
+{
+#ifdef BSP_USING_UART1
+ UART1_CONFIG,
+#endif
+#ifdef BSP_USING_UART2
+ UART2_CONFIG,
+#endif
+#ifdef BSP_USING_UART3
+ UART3_CONFIG,
+#endif
+#ifdef BSP_USING_UART4
+ UART4_CONFIG,
+#endif
+#ifdef BSP_USING_UART5
+ UART5_CONFIG,
+#endif
+#ifdef BSP_USING_UART6
+ UART6_CONFIG,
+#endif
+#ifdef BSP_USING_UART7
+ UART7_CONFIG,
+#endif
+#ifdef BSP_USING_UART8
+ UART8_CONFIG,
+#endif
+#ifdef BSP_USING_LPUART1
+ LPUART1_CONFIG,
+#endif
+};
+
+static struct stm32_uart uart_obj[sizeof(uart_config) / sizeof(uart_config[0])] = {0};
+
+static rt_uint32_t stm32_uart_get_mask(rt_uint32_t word_length, rt_uint32_t parity)
+{
+ rt_uint32_t mask;
+ if (word_length == UART_WORDLENGTH_8B)
+ {
+ if (parity == UART_PARITY_NONE)
+ {
+ mask = 0x00FFU ;
+ }
+ else
+ {
+ mask = 0x007FU ;
+ }
+ }
+#ifdef UART_WORDLENGTH_9B
+ else if (word_length == UART_WORDLENGTH_9B)
+ {
+ if (parity == UART_PARITY_NONE)
+ {
+ mask = 0x01FFU ;
+ }
+ else
+ {
+ mask = 0x00FFU ;
+ }
+ }
+#endif
+#ifdef UART_WORDLENGTH_7B
+ else if (word_length == UART_WORDLENGTH_7B)
+ {
+ if (parity == UART_PARITY_NONE)
+ {
+ mask = 0x007FU ;
+ }
+ else
+ {
+ mask = 0x003FU ;
+ }
+ }
+ else
+ {
+ mask = 0x0000U;
+ }
+#endif
+ return mask;
+}
+
+static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
+{
+ struct stm32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+ RT_ASSERT(cfg != RT_NULL);
+
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+ uart->handle.Instance = uart->uart_config->Instance;
+ uart->handle.Init.BaudRate = cfg->baud_rate;
+ uart->handle.Init.Mode = UART_MODE_TX_RX;
+ uart->handle.Init.OverSampling = UART_OVERSAMPLING_16;
+
+ switch (cfg->flowcontrol)
+ {
+ case RT_SERIAL_FLOWCONTROL_NONE:
+ uart->handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
+ break;
+ case RT_SERIAL_FLOWCONTROL_CTSRTS:
+ uart->handle.Init.HwFlowCtl = UART_HWCONTROL_RTS_CTS;
+ break;
+ default:
+ uart->handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
+ break;
+ }
+
+ switch (cfg->data_bits)
+ {
+ case DATA_BITS_8:
+ if (cfg->parity == PARITY_ODD || cfg->parity == PARITY_EVEN)
+ uart->handle.Init.WordLength = UART_WORDLENGTH_9B;
+ else
+ uart->handle.Init.WordLength = UART_WORDLENGTH_8B;
+ break;
+ case DATA_BITS_9:
+ uart->handle.Init.WordLength = UART_WORDLENGTH_9B;
+ break;
+ default:
+ uart->handle.Init.WordLength = UART_WORDLENGTH_8B;
+ break;
+ }
+
+ switch (cfg->stop_bits)
+ {
+ case STOP_BITS_1:
+ uart->handle.Init.StopBits = UART_STOPBITS_1;
+ break;
+ case STOP_BITS_2:
+ uart->handle.Init.StopBits = UART_STOPBITS_2;
+ break;
+ default:
+ uart->handle.Init.StopBits = UART_STOPBITS_1;
+ break;
+ }
+
+ switch (cfg->parity)
+ {
+ case PARITY_NONE:
+ uart->handle.Init.Parity = UART_PARITY_NONE;
+ break;
+ case PARITY_ODD:
+ uart->handle.Init.Parity = UART_PARITY_ODD;
+ break;
+ case PARITY_EVEN:
+ uart->handle.Init.Parity = UART_PARITY_EVEN;
+ break;
+ default:
+ uart->handle.Init.Parity = UART_PARITY_NONE;
+ break;
+ }
+
+ uart->uart_config->mask = stm32_uart_get_mask(uart->handle.Init.WordLength, uart->handle.Init.Parity);
+ if (HAL_UART_Init(&uart->handle) != HAL_OK)
+ {
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t stm32_init(struct rt_serial_device *serial)
+{
+ if (stm32_configure(serial, &serial->config) != RT_EOK)
+ {
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *arg)
+{
+ struct stm32_uart *uart;
+ rt_ubase_t ctrl_arg = (rt_ubase_t)arg;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+
+ switch (cmd) {
+ case RT_DEVICE_CTRL_OPEN:
+ __HAL_UART_DISABLE_IT(&(uart->handle), UART_IT_TXE);
+ UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_RXNE);
+ UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_TXE);
+ UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_TC);
+ /* enable interrupt */
+ HAL_NVIC_SetPriority(uart->uart_config->irq_type, 1, 0);
+ HAL_NVIC_EnableIRQ(uart->uart_config->irq_type);
+#ifdef RT_SERIAL_USING_DMA
+ uart->dmaTxing = RT_FALSE;
+#endif
+ break;
+ case RT_DEVICE_CTRL_CLOSE:
+ HAL_NVIC_DisableIRQ(uart->uart_config->irq_type);
+#ifdef RT_SERIAL_USING_DMA
+ HAL_NVIC_DisableIRQ(uart->uart_config->dma_conf_rx->dma_irq);
+ if (HAL_DMA_Abort(&(uart->dma_rx.handle)) != HAL_OK) {
+ RT_ASSERT(0);
+ }
+ if (HAL_DMA_DeInit(&(uart->dma_rx.handle)) != HAL_OK) {
+ RT_ASSERT(0);
+ }
+
+ HAL_NVIC_DisableIRQ(uart->uart_config->dma_conf_tx->dma_irq);
+ if (HAL_DMA_Abort(&(uart->dma_tx.handle)) != HAL_OK) {
+ RT_ASSERT(0);
+ }
+ if (HAL_DMA_DeInit(&(uart->dma_tx.handle)) != HAL_OK) {
+ RT_ASSERT(0);
+ }
+#endif
+ __HAL_UART_DISABLE_IT(&(uart->handle), UART_IT_RXNE);
+ __HAL_UART_DISABLE_IT(&(uart->handle), UART_IT_TXE);
+ if (HAL_UART_DeInit(&(uart->handle)) != HAL_OK ) {
+ }
+ break;
+ /* disable interrupt */
+ case RT_DEVICE_CTRL_CLR_INT:
+ /* disable interrupt */
+ if (ctrl_arg & RT_DEVICE_FLAG_INT_RX) {
+ __HAL_UART_DISABLE_IT(&(uart->handle), UART_IT_RXNE);
+ }
+
+#ifdef RT_SERIAL_USING_DMA
+ /* disable DMA */
+ if (ctrl_arg & RT_DEVICE_FLAG_DMA_RX) {
+ HAL_NVIC_DisableIRQ(uart->uart_config->dma_conf_rx->dma_irq);
+ }
+ if(ctrl_arg & RT_DEVICE_FLAG_DMA_TX) {
+ HAL_NVIC_DisableIRQ(uart->uart_config->dma_conf_tx->dma_irq);
+ }
+#endif
+ break;
+ /* enable interrupt */
+ case RT_DEVICE_CTRL_SET_INT:
+ /* enable rx irq */
+ if (ctrl_arg & RT_DEVICE_FLAG_INT_RX) {
+ __HAL_UART_ENABLE_IT(&(uart->handle), UART_IT_RXNE);
+ }
+ break;
+#ifdef RT_SERIAL_USING_DMA
+ case RT_DEVICE_CTRL_CONFIG:
+ if (ctrl_arg & RT_DEVICE_FLAG_DMA_RX) {
+ stm32_dma_rx_config(serial);
+ } else if (ctrl_arg & RT_DEVICE_FLAG_DMA_TX) {
+ stm32_dma_tx_config(serial);
+ }
+ break;
+#endif
+ default :
+ break;
+ }
+ return RT_EOK;
+}
+
+static int stm32_putc(struct rt_serial_device *serial, char c)
+{
+ struct stm32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+
+ while (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TXE) == RESET);
+ UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_TC);
+#if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32WL) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32F0) \
+ || defined(SOC_SERIES_STM32L0) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32H7) \
+ || defined(SOC_SERIES_STM32G4) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) || defined(SOC_SERIES_STM32F3)
+ uart->handle.Instance->TDR = c;
+#else
+ uart->handle.Instance->DR = c;
+#endif
+ return 1;
+}
+
+static int stm32_getc(struct rt_serial_device *serial)
+{
+ int ch = -1;
+ struct stm32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+
+ if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_RXNE) == RESET)
+ {
+ return -1;
+ }
+#if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32WL) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32F0) \
+ || defined(SOC_SERIES_STM32L0) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32H7) \
+ || defined(SOC_SERIES_STM32G4) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB)|| defined(SOC_SERIES_STM32F3)
+ ch = uart->handle.Instance->RDR & uart->uart_config->mask;
+#else
+ ch = uart->handle.Instance->DR & uart->uart_config->mask;
+#endif
+ return ch;
+}
+
+static int stm32_flush(struct rt_serial_device *serial)
+{
+ struct stm32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+ while (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC) == RESET);
+
+ return 1;
+}
+
+static void stm32_start_tx(struct rt_serial_device *serial)
+{
+ struct stm32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+ __HAL_UART_ENABLE_IT(&(uart->handle), UART_IT_TXE);
+}
+
+static void stm32_stop_tx(struct rt_serial_device *serial)
+{
+ struct stm32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+ __HAL_UART_DISABLE_IT(&(uart->handle), UART_IT_TXE);
+}
+
+#ifdef RT_SERIAL_USING_DMA
+static rt_bool_t stm32_is_dma_txing(struct rt_serial_device *serial)
+{
+ struct stm32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+
+ return uart->dmaTxing; //RT_FALSE;
+}
+
+static void stm32_start_dma_tx(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size)
+{
+ struct stm32_uart *uart;
+ HAL_StatusTypeDef status;
+ DMA_HandleTypeDef *hdma;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+
+ do { // may fallin dead loop
+ status = HAL_UART_Transmit_DMA(&uart->handle, buf, size);
+ } while (status != HAL_OK);
+ uart->dmaTxing = RT_TRUE;
+}
+
+static void stm32_stop_dma_tx(struct rt_serial_device *serial)
+{
+ struct stm32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+
+ if ((uart->dma_tx.handle.Instance->CR & DMA_SxCR_EN) == DMA_SxCR_EN) {
+ return;
+ }
+ __HAL_DMA_DISABLE(&uart->dma_tx.handle);
+ uart->dmaTxing = RT_FALSE;
+}
+#endif
+
+static void stm32_enable_interrupt(struct rt_serial_device *serial)
+{
+ struct stm32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+
+ HAL_NVIC_EnableIRQ(uart->uart_config->irq_type);
+#ifdef RT_SERIAL_USING_DMA
+ if (uart->uart_dma_flag) {
+ HAL_NVIC_EnableIRQ(uart->uart_config->dma_conf_rx->dma_irq);
+ }
+#endif
+}
+
+static void stm32_disable_interrupt(struct rt_serial_device *serial)
+{
+ struct stm32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+
+ HAL_NVIC_DisableIRQ(uart->uart_config->irq_type);
+#ifdef RT_SERIAL_USING_DMA
+ if (uart->uart_dma_flag) {
+ HAL_NVIC_DisableIRQ(uart->uart_config->dma_conf_rx->dma_irq);
+ }
+#endif
+}
+
+/**
+ * Uart common interrupt process. This need add to uart ISR.
+ *
+ * @param serial serial device
+ */
+static void uart_isr(struct rt_serial_device *serial)
+{
+ struct stm32_uart *uart;
+#ifdef RT_SERIAL_USING_DMA
+ rt_size_t dma_cnt;
+#endif
+
+ RT_ASSERT(serial != RT_NULL);
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+
+ /* UART in mode Receiver -------------------------------------------------*/
+ if ((__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_RXNE) != RESET) &&
+ (__HAL_UART_GET_IT_SOURCE(&(uart->handle), UART_IT_RXNE) != RESET))
+ {
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+ }
+ if ((__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TXE) != RESET) &&
+ (__HAL_UART_GET_IT_SOURCE(&(uart->handle), UART_IT_TXE) != RESET))
+ {
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DONE);
+ }
+#ifdef RT_SERIAL_USING_DMA
+ else if ((uart->uart_dma_flag) && (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_IDLE) != RESET)
+ && (__HAL_UART_GET_IT_SOURCE(&(uart->handle), UART_IT_IDLE) != RESET))
+ {
+ __HAL_UART_CLEAR_IDLEFLAG(&uart->handle);
+ dma_cnt = RT_SERIAL_DMA_BUFSZ - __HAL_DMA_GET_COUNTER(&(uart->dma_rx.handle));
+
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (dma_cnt << 8));
+ }
+ else if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC) &&
+ (__HAL_UART_GET_IT_SOURCE(&(uart->handle), UART_IT_TC) != RESET))
+ {
+ if ((serial->parent.open_flag & RT_DEVICE_FLAG_DMA_TX) != 0)
+ {
+ HAL_UART_IRQHandler(&(uart->handle));
+ }
+ }
+#endif
+ else
+ {
+ if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_ORE) != RESET)
+ {
+ __HAL_UART_CLEAR_OREFLAG(&uart->handle);
+ }
+ if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_NE) != RESET)
+ {
+ __HAL_UART_CLEAR_NEFLAG(&uart->handle);
+ }
+ if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_FE) != RESET)
+ {
+ __HAL_UART_CLEAR_FEFLAG(&uart->handle);
+ }
+ if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_PE) != RESET)
+ {
+ __HAL_UART_CLEAR_PEFLAG(&uart->handle);
+ }
+#if !defined(SOC_SERIES_STM32L4) && !defined(SOC_SERIES_STM32WL) && !defined(SOC_SERIES_STM32F7) && !defined(SOC_SERIES_STM32F0) \
+ && !defined(SOC_SERIES_STM32L0) && !defined(SOC_SERIES_STM32G0) && !defined(SOC_SERIES_STM32H7) \
+ && !defined(SOC_SERIES_STM32G4) && !defined(SOC_SERIES_STM32MP1) && !defined(SOC_SERIES_STM32WB)
+#ifdef SOC_SERIES_STM32F3
+ if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_LBDF) != RESET)
+ {
+ UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_LBDF);
+ }
+#else
+ if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_LBD) != RESET)
+ {
+ UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_LBD);
+ }
+#endif
+#endif
+ if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_CTS) != RESET)
+ {
+ UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_CTS);
+ }
+// if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TXE) != RESET)
+// {
+// UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_TXE);
+// }
+// if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC) != RESET)
+// {
+// UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_TC);
+// }
+// if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_RXNE) != RESET)
+// {
+// UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_RXNE);
+// }
+ }
+}
+
+#ifdef RT_SERIAL_USING_DMA
+static void dma_isr(struct rt_serial_device *serial)
+{
+ struct stm32_uart *uart;
+ rt_size_t dma_cnt;
+
+ RT_ASSERT(serial != RT_NULL);
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+
+ if ((__HAL_DMA_GET_IT_SOURCE(&(uart->dma_rx.handle), DMA_IT_TC) != RESET) ||
+ (__HAL_DMA_GET_IT_SOURCE(&(uart->dma_rx.handle), DMA_IT_HT) != RESET))
+ {
+ dma_cnt = RT_SERIAL_DMA_BUFSZ - __HAL_DMA_GET_COUNTER(&(uart->dma_rx.handle));
+
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (dma_cnt << 8));
+ }
+}
+#endif
+
+#if defined(BSP_USING_UART1)
+void USART1_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ uart_isr(&(uart_obj[UART1_INDEX].serial));
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+#if defined(RT_SERIAL_USING_DMA) && defined(BSP_UART1_RX_USING_DMA)
+void UART1_DMA_RX_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ HAL_DMA_IRQHandler(&uart_obj[UART1_INDEX].dma_rx.handle);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+#endif /* defined(RT_SERIAL_USING_DMA) && defined(BSP_UART1_RX_USING_DMA) */
+#if defined(RT_SERIAL_USING_DMA) && defined(BSP_UART1_TX_USING_DMA)
+void UART1_DMA_TX_IRQHandler(void)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ HAL_DMA_IRQHandler(&uart_obj[UART1_INDEX].dma_tx.handle);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+#endif /* defined(RT_SERIAL_USING_DMA) && defined(BSP_UART1_TX_USING_DMA) */
+#endif /* BSP_USING_UART1 */
+
+#ifdef RT_SERIAL_USING_DMA
+static void stm32_uart_get_dma_config(void)
+{
+#ifdef BSP_USING_UART1
+ uart_obj[UART1_INDEX].uart_dma_flag = 0;
+#ifdef BSP_UART1_RX_USING_DMA
+ uart_obj[UART1_INDEX].uart_dma_flag |= RT_DEVICE_FLAG_DMA_RX;
+ static struct dma_config uart1_dma_rx = UART1_DMA_RX_CONFIG;
+ uart_config[UART1_INDEX].dma_conf_rx = &uart1_dma_rx;
+#endif
+#ifdef BSP_UART1_TX_USING_DMA
+ uart_obj[UART1_INDEX].uart_dma_flag |= RT_DEVICE_FLAG_DMA_TX;
+ static struct dma_config uart1_dma_tx = UART1_DMA_TX_CONFIG;
+ uart_config[UART1_INDEX].dma_conf_tx = &uart1_dma_tx;
+#endif
+#endif
+}
+
+static void stm32_dma_rx_config(struct rt_serial_device *serial)
+{
+ DMA_HandleTypeDef *DMA_Handle;
+ struct dma_config *dma_config;
+ struct stm32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+
+ DMA_Handle = &uart->dma_rx.handle;
+ dma_config = uart->uart_config->dma_conf_rx;
+
+ LOG_D("%s dma config start", uart->uart_config->name);
+
+ {
+ rt_uint32_t tmpreg = 0x00U;
+#if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0) \
+ || defined(SOC_SERIES_STM32L0)|| defined(SOC_SERIES_STM32F3) || defined(SOC_SERIES_STM32L1)
+ /* enable DMA clock && Delay after an RCC peripheral clock enabling*/
+ SET_BIT(RCC->AHBENR, dma_config->dma_rcc);
+ tmpreg = READ_BIT(RCC->AHBENR, dma_config->dma_rcc);
+#elif defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32WL) \
+ || defined(SOC_SERIES_STM32G4)|| defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32WB)
+ /* enable DMA clock && Delay after an RCC peripheral clock enabling*/
+ SET_BIT(RCC->AHB1ENR, dma_config->dma_rcc);
+ tmpreg = READ_BIT(RCC->AHB1ENR, dma_config->dma_rcc);
+#elif defined(SOC_SERIES_STM32MP1)
+ /* enable DMA clock && Delay after an RCC peripheral clock enabling*/
+ SET_BIT(RCC->MP_AHB2ENSETR, dma_config->dma_rcc);
+ tmpreg = READ_BIT(RCC->MP_AHB2ENSETR, dma_config->dma_rcc);
+#endif
+
+#if (defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32WL) || defined(SOC_SERIES_STM32G4) || defined(SOC_SERIES_STM32WB)) && defined(DMAMUX1)
+ /* enable DMAMUX clock for L4+ and G4 */
+ __HAL_RCC_DMAMUX1_CLK_ENABLE();
+#elif defined(SOC_SERIES_STM32MP1)
+ __HAL_RCC_DMAMUX_CLK_ENABLE();
+#endif
+
+ UNUSED(tmpreg); /* To avoid compiler warnings */
+ }
+
+ __HAL_LINKDMA(&(uart->handle), hdmarx, uart->dma_rx.handle);
+
+#if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32L0)|| defined(SOC_SERIES_STM32F3) || defined(SOC_SERIES_STM32L1)
+ DMA_Handle->Instance = dma_config->Instance;
+#elif defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7)
+ DMA_Handle->Instance = dma_config->Instance;
+ DMA_Handle->Init.Channel = dma_config->channel;
+#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32WL) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32G4) || defined(SOC_SERIES_STM32WB)\
+ || defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32MP1)
+ DMA_Handle->Instance = dma_config->Instance;
+ DMA_Handle->Init.Request = dma_config->request;
+#endif
+ DMA_Handle->Init.PeriphInc = DMA_PINC_DISABLE;
+ DMA_Handle->Init.MemInc = DMA_MINC_ENABLE;
+ DMA_Handle->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
+ DMA_Handle->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
+
+ DMA_Handle->Init.Direction = DMA_PERIPH_TO_MEMORY;
+ DMA_Handle->Init.Mode = DMA_CIRCULAR;
+
+ DMA_Handle->Init.Priority = DMA_PRIORITY_MEDIUM;
+#if defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32MP1)
+ DMA_Handle->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
+#endif
+ if (HAL_DMA_DeInit(DMA_Handle) != HAL_OK)
+ {
+ RT_ASSERT(0);
+ }
+
+ if (HAL_DMA_Init(DMA_Handle) != HAL_OK)
+ {
+ RT_ASSERT(0);
+ }
+
+ /* enable interrupt */
+ /* Start DMA transfer */
+ if (HAL_UART_Receive_DMA(&(uart->handle), serial->serial_dma_rx, RT_SERIAL_DMA_BUFSZ) != HAL_OK)
+ {
+ /* Transfer error in reception process */
+ RT_ASSERT(0);
+ }
+ CLEAR_BIT(uart->handle.Instance->CR3, USART_CR3_EIE);
+ __HAL_UART_ENABLE_IT(&(uart->handle), UART_IT_IDLE);
+
+ /* DMA irq should set in DMA TX mode, or HAL_UART_TxCpltCallback function will not be called */
+ HAL_NVIC_SetPriority(dma_config->dma_irq, 0, 0);
+ HAL_NVIC_EnableIRQ(dma_config->dma_irq);
+}
+
+static void stm32_dma_tx_config(struct rt_serial_device *serial)
+{
+ DMA_HandleTypeDef *DMA_Handle;
+ struct dma_config *dma_config;
+ struct stm32_uart *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+ uart = rt_container_of(serial, struct stm32_uart, serial);
+
+ DMA_Handle = &uart->dma_tx.handle;
+ dma_config = uart->uart_config->dma_conf_tx;
+
+ LOG_D("%s dma config start", uart->uart_config->name);
+
+ {
+ rt_uint32_t tmpreg = 0x00U;
+#if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0) \
+ || defined(SOC_SERIES_STM32L0)|| defined(SOC_SERIES_STM32F3) || defined(SOC_SERIES_STM32L1)
+ /* enable DMA clock && Delay after an RCC peripheral clock enabling*/
+ SET_BIT(RCC->AHBENR, dma_config->dma_rcc);
+ tmpreg = READ_BIT(RCC->AHBENR, dma_config->dma_rcc);
+#elif defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32WL) \
+ || defined(SOC_SERIES_STM32G4)|| defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32WB)
+ /* enable DMA clock && Delay after an RCC peripheral clock enabling*/
+ SET_BIT(RCC->AHB1ENR, dma_config->dma_rcc);
+ tmpreg = READ_BIT(RCC->AHB1ENR, dma_config->dma_rcc);
+#elif defined(SOC_SERIES_STM32MP1)
+ /* enable DMA clock && Delay after an RCC peripheral clock enabling*/
+ SET_BIT(RCC->MP_AHB2ENSETR, dma_config->dma_rcc);
+ tmpreg = READ_BIT(RCC->MP_AHB2ENSETR, dma_config->dma_rcc);
+#endif
+
+#if (defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32WL) || defined(SOC_SERIES_STM32G4) || defined(SOC_SERIES_STM32WB)) && defined(DMAMUX1)
+ /* enable DMAMUX clock for L4+ and G4 */
+ __HAL_RCC_DMAMUX1_CLK_ENABLE();
+#elif defined(SOC_SERIES_STM32MP1)
+ __HAL_RCC_DMAMUX_CLK_ENABLE();
+#endif
+
+ UNUSED(tmpreg); /* To avoid compiler warnings */
+ }
+
+ __HAL_LINKDMA(&(uart->handle), hdmatx, uart->dma_tx.handle);
+
+
+#if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32L0)|| defined(SOC_SERIES_STM32F3) || defined(SOC_SERIES_STM32L1)
+ DMA_Handle->Instance = dma_config->Instance;
+#elif defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7)
+ DMA_Handle->Instance = dma_config->Instance;
+ DMA_Handle->Init.Channel = dma_config->channel;
+#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32WL) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32G4) || defined(SOC_SERIES_STM32WB)\
+ || defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32MP1)
+ DMA_Handle->Instance = dma_config->Instance;
+ DMA_Handle->Init.Request = dma_config->request;
+#endif
+ DMA_Handle->Init.PeriphInc = DMA_PINC_DISABLE;
+ DMA_Handle->Init.MemInc = DMA_MINC_ENABLE;
+ DMA_Handle->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
+ DMA_Handle->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
+
+ DMA_Handle->Init.Direction = DMA_MEMORY_TO_PERIPH;
+ DMA_Handle->Init.Mode = DMA_NORMAL;
+
+ DMA_Handle->Init.Priority = DMA_PRIORITY_MEDIUM;
+#if defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32MP1)
+ DMA_Handle->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
+#endif
+ if (HAL_DMA_DeInit(DMA_Handle) != HAL_OK)
+ {
+ RT_ASSERT(0);
+ }
+
+ if (HAL_DMA_Init(DMA_Handle) != HAL_OK)
+ {
+ RT_ASSERT(0);
+ }
+
+ /* DMA irq should set in DMA TX mode, or HAL_UART_TxCpltCallback function will not be called */
+ HAL_NVIC_SetPriority(dma_config->dma_irq, 0, 0);
+ HAL_NVIC_EnableIRQ(dma_config->dma_irq);
+}
+
+/**
+ * @brief UART error callbacks
+ * @param huart: UART handle
+ * @note This example shows a simple way to report transfer error, and you can
+ * add your own implementation.
+ * @retval None
+ */
+void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
+{
+ struct stm32_uart *uart;
+
+ RT_ASSERT(huart != NULL);
+
+ uart = (struct stm32_uart *)huart;
+ LOG_D("%s: %s %d\n", __FUNCTION__, uart->uart_config->name, huart->ErrorCode);
+ UNUSED(uart);
+}
+
+/**
+ * @brief Rx Transfer completed callback
+ * @param huart: UART handle
+ * @note This example shows a simple way to report end of DMA Rx transfer, and
+ * you can add your own implementation.
+ * @retval None
+ */
+void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
+{
+ struct stm32_uart *uart;
+
+ RT_ASSERT(huart != NULL);
+
+ uart = (struct stm32_uart *)huart;
+ dma_isr(&uart->serial);
+}
+
+/**
+ * @brief Rx Half transfer completed callback
+ * @param huart: UART handle
+ * @note This example shows a simple way to report end of DMA Rx Half transfer,
+ * and you can add your own implementation.
+ * @retval None
+ */
+void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
+{
+ struct stm32_uart *uart;
+
+ RT_ASSERT(huart != NULL);
+
+ uart = (struct stm32_uart *)huart;
+ dma_isr(&uart->serial);
+}
+
+/**
+ * @brief HAL_UART_TxCpltCallback
+ * @param huart: UART handle
+ * @note This callback can be called by two functions, first in UART_EndTransmit_IT when
+ * UART Tx complete and second in UART_DMATransmitCplt function in DMA Circular mode.
+ * @retval None
+ */
+void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
+{
+ struct stm32_uart *uart;
+ rt_size_t dma_cnt;
+
+ RT_ASSERT(huart != NULL);
+
+ uart = (struct stm32_uart *)huart;
+
+ dma_cnt = __HAL_DMA_GET_COUNTER(&(uart->dma_tx.handle));
+
+ if (dma_cnt == 0)
+ {
+ rt_hw_serial_isr(&uart->serial, RT_SERIAL_EVENT_TX_DMADONE);
+ }
+}
+#endif /* RT_SERIAL_USING_DMA */
+
+static const struct rt_uart_ops stm32_uart_ops =
+{
+ .init = stm32_init,
+ .configure = stm32_configure,
+ .control = stm32_control,
+ .putc = stm32_putc,
+ .getc = stm32_getc,
+ .flush = stm32_flush,
+ .start_tx = stm32_start_tx,
+ .stop_tx = stm32_stop_tx,
+#ifdef RT_SERIAL_USING_DMA
+ .is_dma_txing = stm32_is_dma_txing,
+ .start_dma_tx = stm32_start_dma_tx,
+ .stop_dma_tx = stm32_stop_dma_tx,
+#endif
+ .enable_interrupt = stm32_enable_interrupt,
+ .disable_interrupt = stm32_disable_interrupt,
+};
+
+int rt_hw_usart_init(void)
+{
+ rt_size_t obj_num = sizeof(uart_obj) / sizeof(struct stm32_uart);
+ rt_err_t result = 0;
+
+#ifdef RT_SERIAL_USING_DMA
+ stm32_uart_get_dma_config();
+#endif
+
+ for (int i = 0; i < obj_num; i++)
+ {
+ /* init UART object */
+ uart_obj[i].uart_config = &uart_config[i];
+ uart_obj[i].serial.ops = &stm32_uart_ops;
+
+ /* register UART device */
+ result = rt_hw_serial_register(&uart_obj[i].serial, uart_obj[i].uart_config->name,
+ RT_DEVICE_FLAG_RDWR
+ | RT_DEVICE_FLAG_INT_RX
+ | RT_DEVICE_FLAG_INT_TX
+#ifdef RT_SERIAL_USING_DMA
+ | uart_obj[i].uart_dma_flag
+#endif
+ , NULL);
+ RT_ASSERT(result == RT_EOK);
+ }
+
+ return result;
+}
+
+#endif /* RT_USING_SERIAL */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drv_usartX.h b/bsp/stm32/libraries/HAL_Drivers/drv_usartX.h
new file mode 100644
index 0000000000..9e698477be
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drv_usartX.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-04-10 THEWON first version for serialX
+ */
+
+#ifndef __DRV_USARTX_H__
+#define __DRV_USARTX_H__
+
+#include <rtthread.h>
+#include "rtdevice.h"
+#include <rthw.h>
+#include <drv_common.h>
+#include "drv_dma.h"
+
+int rt_hw_usart_init(void);
+
+#if defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32WL) \
+ || defined(SOC_SERIES_STM32L0) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32G4) || defined(SOC_SERIES_STM32WB)|| defined(SOC_SERIES_STM32F3)
+#define DMA_INSTANCE_TYPE DMA_Channel_TypeDef
+#elif defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) \
+ || defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32MP1)
+#define DMA_INSTANCE_TYPE DMA_Stream_TypeDef
+#endif /* defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32WL) */
+
+#if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32WL) || defined(SOC_SERIES_STM32F2) \
+ || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32L0) || defined(SOC_SERIES_STM32G0) \
+ || defined(SOC_SERIES_STM32G4) || defined(SOC_SERIES_STM32WB)|| defined(SOC_SERIES_STM32F3)
+#define UART_INSTANCE_CLEAR_FUNCTION __HAL_UART_CLEAR_FLAG
+#elif defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32H7) \
+ || defined(SOC_SERIES_STM32MP1)
+#define UART_INSTANCE_CLEAR_FUNCTION __HAL_UART_CLEAR_IT
+#endif
+
+/* stm32 config class */
+struct stm32_uart_config
+{
+ const char *name;
+ USART_TypeDef *Instance;
+ IRQn_Type irq_type;
+ rt_uint32_t mask;
+#ifdef RT_SERIAL_USING_DMA
+ struct dma_config *dma_conf_rx;
+ struct dma_config *dma_conf_tx;
+#endif
+};
+
+/* stm32 uart driver class */
+struct stm32_uart
+{
+ UART_HandleTypeDef handle;
+ struct rt_serial_device serial;
+ struct stm32_uart_config *uart_config;
+
+#ifdef RT_SERIAL_USING_DMA
+ rt_bool_t dmaTxing;
+ struct
+ {
+ DMA_HandleTypeDef handle;
+ } dma_rx;
+ struct
+ {
+ DMA_HandleTypeDef handle;
+ } dma_tx;
+ rt_uint16_t uart_dma_flag;
+#endif
+};
+
+#endif /* __DRV_USART_H__ */
diff --git a/bsp/stm32/stm32f429-armfly-v6/board/Kconfig b/bsp/stm32/stm32f429-armfly-v6/board/Kconfig
index 0aa90398d8..1a6bb75370 100644
--- a/bsp/stm32/stm32f429-armfly-v6/board/Kconfig
+++ b/bsp/stm32/stm32f429-armfly-v6/board/Kconfig
@@ -93,6 +93,11 @@ menu "On-chip Peripheral Drivers"
bool "Enable UART1"
default y
+ config BSP_UART1_TX_USING_DMA
+ bool "Enable UART1 TX DMA"
+ depends on BSP_USING_UART1 && RT_SERIAL_USING_DMA
+ default n
+
config BSP_UART1_RX_USING_DMA
bool "Enable UART1 RX DMA"
depends on BSP_USING_UART1 && RT_SERIAL_USING_DMA
diff --git a/bsp/stm32/stm32f429-atk-apollo/board/Kconfig b/bsp/stm32/stm32f429-atk-apollo/board/Kconfig
index 0e2fa4d833..36be2e532c 100644
--- a/bsp/stm32/stm32f429-atk-apollo/board/Kconfig
+++ b/bsp/stm32/stm32f429-atk-apollo/board/Kconfig
@@ -99,6 +99,11 @@ menu "On-chip Peripheral Drivers"
bool "Enable UART1"
default y
+ config BSP_UART1_TX_USING_DMA
+ bool "Enable UART1 TX DMA"
+ depends on BSP_USING_UART1 && RT_SERIAL_USING_DMA
+ default n
+
config BSP_UART1_RX_USING_DMA
bool "Enable UART1 RX DMA"
depends on BSP_USING_UART1 && RT_SERIAL_USING_DMA
@@ -108,6 +113,11 @@ menu "On-chip Peripheral Drivers"
bool "Enable UART2"
default n
+ config BSP_UART2_TX_USING_DMA
+ bool "Enable UART2 TX DMA"
+ depends on BSP_USING_UART2 && RT_SERIAL_USING_DMA
+ default n
+
config BSP_UART2_RX_USING_DMA
bool "Enable UART2 RX DMA"
depends on BSP_USING_UART2 && RT_SERIAL_USING_DMA
@@ -116,7 +126,12 @@ menu "On-chip Peripheral Drivers"
config BSP_USING_UART3
bool "Enable UART3"
default n
+
+ config BSP_UART3_TX_USING_DMA
+ bool "Enable UART3 TX DMA"
+ depends on BSP_USING_UART3 && RT_SERIAL_USING_DMA
depends on !BSP_USING_ETH
+ default n
config BSP_UART3_RX_USING_DMA
bool "Enable UART3 RX DMA"
diff --git a/bsp/stm32/stm32f429-fire-challenger/board/Kconfig b/bsp/stm32/stm32f429-fire-challenger/board/Kconfig
index 36af05fe92..8c5873c395 100644
--- a/bsp/stm32/stm32f429-fire-challenger/board/Kconfig
+++ b/bsp/stm32/stm32f429-fire-challenger/board/Kconfig
@@ -97,6 +97,11 @@ menu "On-chip Peripheral Drivers"
bool "Enable UART1"
default y
+ config BSP_UART1_TX_USING_DMA
+ bool "Enable UART1 TX DMA"
+ depends on BSP_USING_UART1 && RT_SERIAL_USING_DMA
+ default n
+
config BSP_UART1_RX_USING_DMA
bool "Enable UART1 RX DMA"
depends on BSP_USING_UART1 && RT_SERIAL_USING_DMA
@@ -106,6 +111,11 @@ menu "On-chip Peripheral Drivers"
bool "Enable UART2"
default n
+ config BSP_UART2_TX_USING_DMA
+ bool "Enable UART2 TX DMA"
+ depends on BSP_USING_UART2 && RT_SERIAL_USING_DMA
+ default n
+
config BSP_UART2_RX_USING_DMA
bool "Enable UART2 RX DMA"
depends on BSP_USING_UART2 && RT_SERIAL_USING_DMA
diff --git a/bsp/stm32/stm32f429-st-disco/board/Kconfig b/bsp/stm32/stm32f429-st-disco/board/Kconfig
index fddfaa9616..6934a0b4e5 100644
--- a/bsp/stm32/stm32f429-st-disco/board/Kconfig
+++ b/bsp/stm32/stm32f429-st-disco/board/Kconfig
@@ -32,6 +32,11 @@ menu "On-chip Peripheral Drivers"
bool "Enable UART1"
default y
+ config BSP_UART1_TX_USING_DMA
+ bool "Enable UART1 TX DMA"
+ depends on BSP_USING_UART1 && RT_SERIAL_USING_DMA
+ default n
+
config BSP_UART1_RX_USING_DMA
bool "Enable UART1 RX DMA"
depends on BSP_USING_UART1 && RT_SERIAL_USING_DMA
@@ -41,6 +46,11 @@ menu "On-chip Peripheral Drivers"
bool "Enable UART2"
default n
+ config BSP_UART2_TX_USING_DMA
+ bool "Enable UART2 TX DMA"
+ depends on BSP_USING_UART2 && RT_SERIAL_USING_DMA
+ default n
+
config BSP_UART2_RX_USING_DMA
bool "Enable UART2 RX DMA"
depends on BSP_USING_UART2 && RT_SERIAL_USING_DMA
diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig
index 1b6fc17ebf..b0a5d70ef1 100755
--- a/components/drivers/Kconfig
+++ b/components/drivers/Kconfig
@@ -38,6 +38,10 @@ menuconfig RT_USING_SERIAL
bool "RT_USING_SERIAL_V1"
config RT_USING_SERIAL_V2
bool "RT_USING_SERIAL_V2"
+ config RT_USING_SERIAL_X
+ bool "RT_USING_SERIAL_X"
+ help
+ A serial driver that supporting True NonBlock.
endchoice
config RT_SERIAL_USING_DMA
bool "Enable serial DMA mode"
@@ -45,8 +49,36 @@ menuconfig RT_USING_SERIAL
config RT_SERIAL_RB_BUFSZ
int "Set RX buffer size"
- depends on !RT_USING_SERIAL_V2
+ depends on RT_USING_SERIAL_V1
default 64
+
+ if RT_USING_SERIAL_X
+ config RT_SERIAL_FIFO_BUFSZ
+ int "Set SerialX FIFO buffer size"
+ default 128
+ help
+ suggestion: RT_SERIAL_FIFO_BUFSZ == 2^N
+ and RT_SERIAL_FIFO_BUFSZ >= 2*RT_SERIAL_DMA_BUFSZ
+
+ config RT_SERIAL_DMA_BUFSZ
+ int "Set SerialX DMA buffer size"
+ depends on RT_SERIAL_USING_DMA
+ default 64
+ help
+ suggestion: RT_SERIAL_DMA_BUFSZ == 2^N
+ and RT_SERIAL_FIFO_BUFSZ >= 2*RT_SERIAL_DMA_BUFSZ
+
+ config RT_SERIAL_HARD_FIFO
+ bool "Using Hard FIFO"
+ default n
+ help
+ Useful only if the chip supported
+ eg: NUC970 N9H30 serial chips
+ The UART1/2/4/6/8/10 is built-in with a 64-byte transmitter FIFO (TX_FIFO)
+ and a 64-byte receiver FIFO (RX_FIFO),
+ and the UART0/3/5/7/9 are equipped 16-byte transmitter FIFO (TX_FIFO)
+ and 16-byte receiver FIFO (RX_FIFO).
+ endif
endif
config RT_USING_TTY
diff --git a/components/drivers/include/drivers/serialX.h b/components/drivers/include/drivers/serialX.h
new file mode 100644
index 0000000000..75f34794f3
--- /dev/null
+++ b/components/drivers/include/drivers/serialX.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-04-10 THEWON serialX first version
+ * 2022-06-08 THEWON add No TX Empty interrupt support
+ * 2023-02-15 THEWON add init ops
+ */
+
+#ifndef __SERIALX_H__
+#define __SERIALX_H__
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define BAUD_RATE_2400 2400
+#define BAUD_RATE_4800 4800
+#define BAUD_RATE_9600 9600
+#define BAUD_RATE_19200 19200
+#define BAUD_RATE_38400 38400
+#define BAUD_RATE_57600 57600
+#define BAUD_RATE_115200 115200
+#define BAUD_RATE_230400 230400
+#define BAUD_RATE_460800 460800
+#define BAUD_RATE_921600 921600
+#define BAUD_RATE_2000000 2000000
+#define BAUD_RATE_3000000 3000000
+
+#define DATA_BITS_5 5
+#define DATA_BITS_6 6
+#define DATA_BITS_7 7
+#define DATA_BITS_8 8
+#define DATA_BITS_9 9
+
+#define STOP_BITS_1 0
+#define STOP_BITS_2 1
+#define STOP_BITS_3 2
+#define STOP_BITS_4 3
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#define PARITY_NONE 0
+#define PARITY_ODD 1
+#define PARITY_EVEN 2
+#endif
+
+#define BIT_ORDER_LSB 0
+#define BIT_ORDER_MSB 1
+
+#define NRZ_NORMAL 0 /* Non Return to Zero : normal mode */
+#define NRZ_INVERTED 1 /* Non Return to Zero : inverted mode */
+
+#ifndef RT_SERIAL_FIFO_BUFSZ
+#define RT_SERIAL_FIFO_BUFSZ 128
+#endif
+
+#ifndef RT_SERIAL_DMA_BUFSZ
+#define RT_SERIAL_DMA_BUFSZ 32
+#endif
+
+#if RT_SERIAL_DMA_BUFSZ < 32
+#define RT_SERIAL_DMA_BUFSZ 32
+#endif
+
+#if RT_SERIAL_FIFO_BUFSZ < (RT_SERIAL_DMA_BUFSZ*2)
+#define RT_SERIAL_FIFO_BUFSZ RT_SERIAL_DMA_BUFSZ*2
+#endif
+
+
+#define RT_SERIAL_EVENT_RX_IND 0x01 /* Rx indication */
+#define RT_SERIAL_EVENT_TX_DONE 0x02 /* Tx complete */
+#define RT_SERIAL_EVENT_RX_DMADONE 0x03 /* Rx DMA transfer done */
+#define RT_SERIAL_EVENT_TX_DMADONE 0x04 /* Tx DMA transfer done */
+#define RT_SERIAL_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */
+
+#define RT_SERIAL_DMA_RX 0x01
+#define RT_SERIAL_DMA_TX 0x02
+
+#define RT_SERIAL_RX_INT 0x01
+#define RT_SERIAL_TX_INT 0x02
+
+#define RT_SERIAL_ERR_OVERRUN 0x01
+#define RT_SERIAL_ERR_FRAMING 0x02
+#define RT_SERIAL_ERR_PARITY 0x03
+
+#define RT_SERIAL_TX_DATAQUEUE_SIZE 2048
+#define RT_SERIAL_TX_DATAQUEUE_LWM 30
+
+#define RT_SERIAL_FLOWCONTROL_CTSRTS 1
+#define RT_SERIAL_FLOWCONTROL_NONE 0
+
+/* Default config for serial_configure structure */
+#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_FIFO_BUFSZ, /* Buffer size */ \
+ RT_SERIAL_FLOWCONTROL_NONE, /* Off flowcontrol */ \
+ 0 \
+}
+
+#define RT_SERIAL_EVENT_TXDONE (1 << 0)
+#define RT_SERIAL_EVENT_RXDONE (1 << 1)
+
+//#define RT_SERIAL_USE_EVENT // Just for test, maybe using event in the future
+
+struct rt_serial_device;
+
+typedef int (*cb_serial_tx)(struct rt_serial_device *serial, const rt_uint8_t *data, int length);
+typedef int (*cb_serial_rx)(struct rt_serial_device *serial, rt_uint8_t *data, int length);
+
+struct serial_configure
+{
+ rt_uint32_t baud_rate;
+
+ rt_uint32_t data_bits :4;
+ rt_uint32_t stop_bits :2;
+ rt_uint32_t parity :2;
+ rt_uint32_t bit_order :1;
+ rt_uint32_t invert :1;
+ rt_uint32_t bufsz :16; // unused, move it to struct rt_serial_device
+ rt_uint32_t flowcontrol :1;
+ rt_uint32_t reserved :5;
+};
+
+/*
+ * Serial FIFO mode
+ */
+struct rt_serial_fifo
+{
+ rt_uint32_t buf_sz;
+ /* software fifo */
+ rt_uint8_t *buffer;
+
+ rt_uint16_t put_index, get_index;
+
+ rt_bool_t is_full;
+};
+
+struct rt_serial_device
+{
+ struct rt_device parent;
+
+ const struct rt_uart_ops *ops;
+ struct serial_configure config;
+ rt_uint32_t bufsz;
+
+ void *serial_rx;
+ void *serial_tx;
+
+#ifdef RT_SERIAL_USING_DMA
+ rt_size_t dma_idx_rx;
+ rt_uint8_t serial_dma_rx[RT_SERIAL_DMA_BUFSZ];
+ rt_uint8_t serial_dma_tx[RT_SERIAL_DMA_BUFSZ];
+#endif
+
+ cb_serial_rx _cb_rx;
+ cb_serial_tx _cb_tx;
+#ifndef RT_SERIAL_USE_EVENT
+ struct rt_completion completion_rx;
+ struct rt_completion completion_tx;
+#else
+ rt_event_t rx_done;
+ rt_event_t tx_done;
+#endif
+};
+typedef struct rt_serial_device rt_serial_t;
+
+/**
+ * uart operators
+ */
+struct rt_uart_ops
+{
+ int (*init)(struct rt_serial_device *serial);
+
+ rt_err_t (*configure)(struct rt_serial_device *serial, struct serial_configure *cfg);
+ rt_err_t (*control)(struct rt_serial_device *serial, int cmd, void *arg);
+
+ int (*putc)(struct rt_serial_device *serial, char c);
+ int (*getc)(struct rt_serial_device *serial);
+ int (*flush)(struct rt_serial_device *serial);
+
+#if defined (RT_SERIAL_NO_TXEIT)
+ rt_bool_t (*is_int_txing)(struct rt_serial_device *serial);
+ void (*start_tx)(struct rt_serial_device *serial, rt_uint8_t ch);
+#else
+ void (*start_tx)(struct rt_serial_device *serial);
+#endif
+ void (*stop_tx)(struct rt_serial_device *serial);
+
+#ifdef RT_SERIAL_USING_DMA
+ rt_bool_t (*is_dma_txing)(struct rt_serial_device *serial);
+ void (*start_dma_tx)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size);
+ void (*stop_dma_tx)(struct rt_serial_device *serial);
+#endif
+
+ void (*enable_interrupt)(struct rt_serial_device *serial);
+ void (*disable_interrupt)(struct rt_serial_device *serial);
+};
+
+void rt_hw_serial_isr(struct rt_serial_device *serial, int event);
+
+rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
+ const char *name,
+ rt_uint32_t flag,
+ void *data);
+
+#endif
diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h
index 92b2211243..5b1530dbc6 100644
--- a/components/drivers/include/rtdevice.h
+++ b/components/drivers/include/rtdevice.h
@@ -7,6 +7,7 @@
* Date Author Notes
* 2012-01-08 bernard first version.
* 2014-07-12 bernard Add workqueue implementation.
+ * 2022-04-10 THEWON add serialX
*/
#ifndef __RT_DEVICE_H__
@@ -57,7 +58,9 @@ extern "C" {
#endif /* RT_USING_USB_HOST */
#ifdef RT_USING_SERIAL
-#ifdef RT_USING_SERIAL_V2
+#ifdef RT_USING_SERIAL_X
+#include "drivers/serialX.h"
+#elif defined RT_USING_SERIAL_V2
#include "drivers/serial_v2.h"
#else
#include "drivers/serial.h"
diff --git a/components/drivers/serial/SConscript b/components/drivers/serial/SConscript
index 81d791803a..6eaa27a468 100644
--- a/components/drivers/serial/SConscript
+++ b/components/drivers/serial/SConscript
@@ -7,6 +7,9 @@ if GetDepend(['RT_USING_SERIAL']):
if GetDepend(['RT_USING_SERIAL_V2']):
src = Glob('serial_v2.c')
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SERIAL_V2'], CPPPATH = CPPPATH)
+ elif GetDepend(['RT_USING_SERIAL_X']):
+ src = Glob('serialX.c')
+ group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SERIAL_X'], CPPPATH = CPPPATH)
else:
src = Glob('serial.c')
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SERIAL'], CPPPATH = CPPPATH)
diff --git a/components/drivers/serial/serialX-doc/serialX User Manual.md b/components/drivers/serial/serialX-doc/serialX User Manual.md
new file mode 100644
index 0000000000..dad536d919
--- /dev/null
+++ b/components/drivers/serial/serialX-doc/serialX User Manual.md
@@ -0,0 +1,124 @@
+## serialX User Manual
+
+serialX 驱动框架在尽量延续 v1 版使用方法的前提下,增加阻塞和非阻塞操作,同时对 DMA 收发缓冲机制进行了调整。
+
+RT-Thread 论坛上有几篇介绍和讲解 serialX 的文章,使用 serialX 前请先了解它。
+
+如果用分层理论解释 serialX ,那么它可以划分成应用层、中间驱动框架层、底层硬件层。这三层各有分工,又相互影响。
+
+硬件是千变万化的,驱动的一个职责就是把千变万化的硬件进行包装,把共性的行为固化出来,交给应用层使用。
+
+
+### 串口驱动框架和硬件底层接口功能定义详解
+
+```
+struct rt_uart_ops
+{
+ // 配置外设寄存器设置默认波特率等;外设时钟配置、引脚功能复用(如果还没配置过);启用外设等等
+ int (*init)(struct rt_serial_device *serial);
+ // 仅仅用于配置外设波特率、数据位数、停止位等等
+ rt_err_t (*configure)(struct rt_serial_device *serial, struct serial_configure *cfg);
+ // 用于使能禁用中断,初始配置 DMA
+ rt_err_t (*control)(struct rt_serial_device *serial, int cmd, void *arg);
+ // 串口外设“写数据寄存器”*为空*,把数据放入“写数据寄存器”。*不为空*,死等
+ int (*putc)(struct rt_serial_device *serial, char c);
+ // 串口外设“读数据寄存器”*不为空*,读出“读数据寄存器”的值。*为空*,返回 -1
+ int (*getc)(struct rt_serial_device *serial);
+
+ // 启动发送,多数是使能串口外设“发送寄存器”*空*中断
+ void (*start_tx)(struct rt_serial_device *serial);
+ // 结束发送,多数是禁止串口外设“发送寄存器”*空*中断
+ void (*stop_tx)(struct rt_serial_device *serial);
+
+#ifdef RT_SERIAL_USING_DMA
+ // 判断 DMA 是否在发送过程中,必须有效检测 DMA 是否在发送数据中,有些芯片有寄存器位标志,可以用标志位判断,如果没有,使用变量标志。
+ rt_bool_t (*is_dma_txing)(struct rt_serial_device *serial);
+ // 启动 DMA 发送,数据缓存首地址和数据长度由驱动框架提供。(最后置位 DMA tx 标志)
+ void (*start_dma_tx)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size);
+ // 停止 DMA 发送,停用 DMA 发送,(最后复位 DMA tx 标志)
+ void (*stop_dma_tx)(struct rt_serial_device *serial);
+#endif
+ // 使能串口外设中断,添加这个的初衷是减少全局中断开关操作。目前这部分代码已被注释并使用 rt_hw_interrupt_enable
+ void (*enable_interrupt)(struct rt_serial_device *serial);
+ // 禁用串口外设中断,添加这个的初衷是减少全局中断开关操作。目前这部分代码已被注释并使用 rt_hw_interrupt_disable
+ void (*disable_interrupt)(struct rt_serial_device *serial);
+};
+```
+
+其中,`control` 是一个多功能扩展接口,目前支持的 `cmd` 包括:
+- `RT_DEVICE_CTRL_OPEN`: 先清理一些可能出现的中断,最后配置并使能外设中断
+- `RT_DEVICE_CTRL_CLOSE`: 禁止外设中断,清理中断,卸载外设
+- `RT_DEVICE_CTRL_CLR_INT`: 定向禁止中断,包括接收中断,接收通道 DMA 中断,发送通道 DMA 中断
+- `RT_DEVICE_CTRL_SET_INT`: 定向使能中断,包括接收中断,接收通道 DMA 中断,发送通道 DMA 中断
+- `RT_DEVICE_CTRL_CONFIG`: 这部分主要是初始化配置接收通道 DMA 和发送通道 DMA。
+
+`enable_interrupt` `disable_interrupt` 两个接口是一组很细腻的操作,但是有些外设如果用中断方式,有些用 DMA 方式。这时候需要区别当前外设是否使用了 DMA ,是否需要操作 DMA 中断。(某外设 “是否支持 DMA 收发” 和外设 “使用了 DMA 收发” 是两个概念)
+
+PS: `control` 好像是无所不能的,有了它,为什么还要添加 `init` `start_tx` `stop_tx` `enable_interrupt` `disable_interrupt`?
+
+#### `rt_hw_serial_isr` 中断回调函数怎么调用?
+
+在 serialX 里只关心五种中断,
+1. “接收寄存器不空” `rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DONE);`
+2. “发送寄存器空” `rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);`
+3. “接收通道空闲” `rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (dma_cnt << 8));`
+4. “接收通道 DMA 半/全中断” `rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (dma_cnt << 8));`
+5. “发送通道 DMA 发送完成中断” `rt_hw_serial_isr(&uart->serial, RT_SERIAL_EVENT_TX_DMADONE);`
+
+其中,dma_cnt 是 DMA 接收缓存中已接收数据字节数。
+
+前两个用于中断收发,后三个用于 DMA 收发。
+
+> 注:其它异常错误中断,或者清理掉,或者转入其它流程,这些不在 serialX 驱动考虑范围内。
+
+### 重新定义 `rt_serial_device` 定义:
+
+```
+struct rt_serial_device
+{
+ struct rt_device parent;
+
+ const struct rt_uart_ops *ops;
+ struct serial_configure config;
+ rt_uint32_t bufsz; // 驱动层收发缓存容量大小
+
+ void *serial_rx; // 串口接收缓存
+ void *serial_tx; // 串口发送缓存
+
+#ifdef RT_SERIAL_USING_DMA // 串口收发缓存和 DMA 使用的二级缓存分开
+ rt_size_t dma_idx_rx;
+ rt_uint8_t serial_dma_rx[RT_SERIAL_DMA_BUFSZ]; // DMA 接收缓存
+ rt_uint8_t serial_dma_tx[RT_SERIAL_DMA_BUFSZ]; // DMA 发送缓存
+#endif
+
+ cb_serial_tx _cb_tx; // 写过程回调函数指针
+ cb_serial_rx _cb_rx; // 读过程回调函数指针
+
+ struct rt_completion completion_tx; // 发送完成
+ struct rt_completion completion_rx; // 接收到新数据
+};
+typedef struct rt_serial_device rt_serial_t;
+```
+
+在最近的一次修改中,把 `struct serial_configure` 中的 `bufsz` 成员挪到了 `struct rt_serial_device` 。就是为了 open 了设备之后还能修改波特率,而且,修改缓存大小的功能可以挪到 `control` 里,达到 open 设备之后还能修改缓存大小的目地。
+
+### 之前写过的文章汇总
+
+#### 理论类
+
+- [rt-thread 驱动篇 之 串口驱动框架剖析及性能提升](https://club.rt-thread.org/ask/article/0ee3da5b6a9c347d.html) 这里是 serialX 的理论基础,之后的所有工作都是这些想法的实现。
+- [rt-thread 驱动篇 之 serialX 全网公测](https://club.rt-thread.org/ask/article/bfd92159ba11aef6.html) 这是第一次在 stm32 上实现并进行的测试,内含测试代码。 `struct rt_uart_ops` 结构体接口定义有很详细的注释,在新的芯片上写底层驱动时,这些注释说明很重要,一定严格按照这些接口定义的功能进行实现。
+
+#### 实践类
+
+- [rt-thread 驱动篇(五)serialX 小试牛刀](http://www.elecfans.com/d/1849301.html) 这是在控制台串口上使用 serialX 的实践。
+以及,[rt-thread 驱动篇(六)serialX弊端及解决方法](https://www.elecfans.com/d/1850548.html) 会告诉你在控制台上使用**中断/DMA**收发模式时,可能遇到的尴尬问题以及怎么去避免它们。
+- [测试 serialX 的 posix 支持](https://club.rt-thread.org/ask/article/e7b067264f6badfe.html) 这里是 posix 接口测试。内含测试代码
+- [基于 serialX 串口驱动移植 libmodbus](https://club.rt-thread.org/ask/article/91437d9031d4ac5a.html) 这篇是使用 serialX 驱动跑的 libmodbus 。开启了 posix 之后,serialX 驱动和 libmodbus 配合的还是蛮好的。
+
+### 仓库
+
+最后,serialX 的[源码仓库](https://gitee.com/thewon/serialX) ,里面有一份儿移植说明文档,以及两个测试程序。我们可以从测试程序里看到所有的用法。
+
+目前已经实现了几种芯片底层驱动,想移植到其它芯片上,可以参考。
+
diff --git a/components/drivers/serial/serialX.c b/components/drivers/serial/serialX.c
new file mode 100644
index 0000000000..8c602255e5
--- /dev/null
+++ b/components/drivers/serial/serialX.c
@@ -0,0 +1,1637 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2006-03-13 bernard first version
+ * 2012-05-15 lgnq modified according bernard's implementation.
+ * 2012-05-28 bernard code cleanup
+ * 2012-11-23 bernard fix compiler warning.
+ * 2013-02-20 bernard use RT_SERIAL_RB_BUFSZ to define
+ * the size of ring buffer.
+ * 2014-07-10 bernard rewrite serial framework
+ * 2014-12-31 bernard use open_flag for poll_tx stream mode.
+ * 2015-05-19 Quintin fix DMA tx mod tx_dma->activated flag !=RT_FALSE BUG
+ * in open function.
+ * 2015-11-10 bernard fix the poll rx issue when there is no data.
+ * 2016-05-10 armink add fifo mode to DMA rx when serial->config.bufsz != 0.
+ * 2017-01-19 aubr.cool prevent change serial rx bufsz when serial is opened.
+ * 2017-11-07 JasonJia fix data bits error issue when using tcsetattr.
+ * 2017-11-15 JasonJia fix poll rx issue when data is full.
+ * add TCFLSH and FIONREAD support.
+ * 2018-12-08 Ernest Chen add DMA choice
+ * 2020-09-14 WillianChan add a line feed to the carriage return character
+ * when using interrupt tx
+ * 2020-12-14 Meco Man implement function of setting window's size(TIOCSWINSZ)
+ * 2021-08-22 Meco Man implement function of getting window's size(TIOCGWINSZ)
+ * 2022-04-10 THEWON serialX first version
+ * 2022-06-08 THEWON add No TX Empty interrupt support
+ * 2023-02-15 THEWON add init ops
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#ifdef RT_USING_SERIAL
+
+#define DBG_TAG "UART"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#ifdef RT_USING_POSIX_STDIO
+#if RTTHREAD_VERSION <= RT_VERSION_CHECK(4, 0, 3)
+#include <dfs_posix.h>
+#include <dfs_poll.h>
+#else
+#include <dfs_file.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#endif
+
+#ifdef RT_USING_POSIX_TERMIOS
+#if RTTHREAD_VERSION <= RT_VERSION_CHECK(4, 0, 3)
+#include <posix_termios.h>
+#else
+#include <termios.h>
+#endif
+#endif
+
+/* it's possible the 'getc/putc' is defined by stdio.h in gcc/newlib. */
+#ifdef getc
+#undef getc
+#endif
+
+#ifdef putc
+#undef putc
+#endif
+
+static rt_err_t serial_fops_rx_ind(rt_device_t dev, rt_size_t size)
+{
+ rt_wqueue_wakeup(&(dev->wait_queue), (void*)POLLIN);
+
+ return RT_EOK;
+}
+
+/* fops for serial */
+static int serial_fops_open(struct dfs_fd *fd)
+{
+ rt_err_t ret = 0;
+ rt_uint16_t flags = 0;
+ rt_device_t device;
+
+ device = (rt_device_t)fd->data;
+ RT_ASSERT(device != RT_NULL);
+
+ switch (fd->flags & O_ACCMODE)
+ {
+ case O_RDONLY:
+ LOG_D("fops open: O_RDONLY!");
+ flags = RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_RDONLY;
+ break;
+ case O_WRONLY:
+ LOG_D("fops open: O_WRONLY!");
+ flags = RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_WRONLY;
+ break;
+ case O_RDWR:
+ LOG_D("fops open: O_RDWR!");
+ flags = RT_DEVICE_FLAG_RDWR
+ | RT_DEVICE_FLAG_INT_RX
+ | RT_DEVICE_FLAG_INT_TX;
+ break;
+ default:
+ LOG_E("fops open: unknown mode - %d!", fd->flags & O_ACCMODE);
+ break;
+ }
+
+ if ((fd->flags & O_NONBLOCK) != 0) {
+ flags |= RT_DEVICE_OFLAG_NONBLOCKING;
+ }
+
+ ret = rt_device_open(device, flags);
+ if (ret == RT_EOK) {
+ if ((fd->flags & O_ACCMODE) != O_WRONLY) {
+ rt_device_set_rx_indicate(device, serial_fops_rx_ind);
+ }
+ return 0;
+ }
+
+ return ret;
+}
+
+static int serial_fops_close(struct dfs_fd *fd)
+{
+ rt_device_t device;
+
+ device = (rt_device_t)fd->data;
+
+ rt_device_close(device);
+
+ return 0;
+}
+
+static int serial_fops_ioctl(struct dfs_fd *fd, int cmd, void *args)
+{
+ rt_device_t device;
+
+ device = (rt_device_t)fd->data;
+ switch (cmd)
+ {
+ case FIONREAD:
+ break;
+ case FIONWRITE:
+ break;
+ }
+
+ return rt_device_control(device, cmd, args);
+}
+
+static int serial_fops_read(struct dfs_fd *fd, void *buf, size_t count)
+{
+ int size = 0;
+ int flags = 0;
+ rt_device_t device;
+
+ flags = fd->flags & O_ACCMODE;
+ if (flags == O_WRONLY) {
+ return -EIO;
+ }
+
+ device = (rt_device_t)fd->data;
+
+ do
+ {
+ size = rt_device_read(device, -1, buf, count);
+ if (size <= 0)
+ {
+ if (fd->flags & O_NONBLOCK)
+ {
+ size = -EAGAIN;
+ break;
+ }
+
+ rt_wqueue_wait(&(device->wait_queue), 0, RT_WAITING_FOREVER);
+ }
+ }while (size <= 0);
+
+ return size;
+}
+
+static int serial_fops_write(struct dfs_fd *fd, const void *buf, size_t count)
+{
+ int flags = 0;
+ rt_device_t device;
+
+ flags = fd->flags & O_ACCMODE;
+ if (flags == O_RDONLY) {
+ return -EIO;
+ }
+
+ device = (rt_device_t)fd->data;
+ return rt_device_write(device, -1, buf, count);
+}
+
+static int serial_fops_flush(struct dfs_fd *fd)
+{
+ rt_device_t device;
+
+ device = (rt_device_t)fd->data;
+ return rt_device_flush(device);
+}
+
+static int serial_fops_poll(struct dfs_fd *fd, struct rt_pollreq *req)
+{
+ int mask = 0;
+ int flags = 0;
+ rt_device_t device;
+ struct rt_serial_device *serial;
+
+ device = (rt_device_t)fd->data;
+ RT_ASSERT(device != RT_NULL);
+
+ serial = (struct rt_serial_device *)device;
+
+ /* only support POLLIN */
+ flags = fd->flags & O_ACCMODE;
+ if (flags == O_RDONLY || flags == O_RDWR)
+ {
+ rt_base_t level;
+ struct rt_serial_fifo* rx_fifo;
+
+ rt_poll_add(&(device->wait_queue), req);
+
+ rx_fifo = (struct rt_serial_fifo*) serial->serial_rx;
+
+ level = rt_hw_interrupt_disable();
+ if ((rx_fifo->get_index != rx_fifo->put_index) || (rx_fifo->get_index == rx_fifo->put_index && rx_fifo->is_full == RT_TRUE))
+ {
+ mask |= POLLIN;
+ }
+ rt_hw_interrupt_enable(level);
+ }
+
+ return mask;
+}
+
+const static struct dfs_file_ops _serial_fops =
+{
+ serial_fops_open,
+ serial_fops_close,
+ serial_fops_ioctl,
+ serial_fops_read,
+ serial_fops_write,
+ serial_fops_flush, /* flush */
+ RT_NULL, /* lseek */
+ RT_NULL, /* getdents */
+ serial_fops_poll,
+};
+#endif
+
+/**
+ * Calculate fifo data length.
+ *
+ * @param fifo the data fifo of serial device
+ *
+ * @return length
+ */
+rt_inline rt_ssize_t _serial_fifo_calc_data_len(struct rt_serial_fifo *fifo)
+{
+ rt_ssize_t size;
+ if (fifo->put_index == fifo->get_index) {
+ size = (fifo->is_full == RT_FALSE) ? 0 : fifo->buf_sz;
+ } else if (fifo->put_index > fifo->get_index) {
+ size = fifo->put_index - fifo->get_index;
+ } else {
+ size = fifo->buf_sz - (fifo->get_index - fifo->put_index);
+ }
+
+ return size;
+}
+
+rt_inline void _serial_fifo_push_data(struct rt_serial_fifo *fifo, rt_uint8_t ch)
+{
+ fifo->buffer[fifo->put_index] = ch;
+ fifo->put_index += 1;
+ if (fifo->put_index >= fifo->buf_sz) fifo->put_index = 0;
+}
+
+rt_inline rt_uint8_t _serial_fifo_pop_data(struct rt_serial_fifo *fifo)
+{
+ rt_uint8_t ch;
+
+ ch = fifo->buffer[fifo->get_index];
+ fifo->get_index += 1;
+ if (fifo->get_index >= fifo->buf_sz) fifo->get_index = 0;
+
+ return ch;
+}
+
+/*
+ * Serial poll routines
+ */
+rt_inline int _serial_poll_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
+{
+ int ch;
+ int size;
+
+ RT_ASSERT(serial != RT_NULL);
+ size = length;
+
+ while (length)
+ {
+ ch = serial->ops->getc(serial);
+ if (ch == -1) break;
+
+ *data = ch;
+ data++; length--;
+ }
+
+ return size - length;
+}
+
+rt_inline int _serial_poll_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length)
+{
+ int size;
+ rt_uint8_t last_char = 0;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ size = length;
+ while (length)
+ {
+ /*
+ * to be polite with serial console add a line feed
+ * to the carriage return character
+ */
+ if (*data == '\n' &&
+ (serial->parent.open_flag & RT_DEVICE_FLAG_STREAM) == RT_DEVICE_FLAG_STREAM &&
+ last_char != '\r')
+ {
+ serial->ops->putc(serial, '\r');
+
+ last_char = 0;
+ } else if (*data == '\r') {
+ last_char = '\r';
+ } else {
+ last_char = 0;
+ }
+
+ serial->ops->putc(serial, *data);
+
+ data++; length--;
+ }
+
+ return size - length;
+}
+
+/*
+ * Serial interrupt routines
+ */
+rt_inline int _serial_fifo_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
+{
+ rt_size_t len, size;
+ struct rt_serial_fifo* rx_fifo;
+ rt_base_t level;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ if (length == 0) return 0;
+
+ rx_fifo = (struct rt_serial_fifo*) serial->serial_rx;
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+// serial->ops->disable_interrupt(serial);
+
+ len = _serial_fifo_calc_data_len(rx_fifo);
+
+ if ((len == 0) && // non-blocking io mode
+ (serial->parent.open_flag & RT_DEVICE_OFLAG_NONBLOCKING) == RT_DEVICE_OFLAG_NONBLOCKING) {
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+// serial->ops->enable_interrupt(serial);
+ return 0;
+ }
+ if ((len == 0) && // blocking io mode
+ (serial->parent.open_flag & RT_DEVICE_OFLAG_NONBLOCKING) != RT_DEVICE_OFLAG_NONBLOCKING) {
+ rt_err_t ret;
+ do {
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+// serial->ops->enable_interrupt(serial);
+
+#ifndef RT_SERIAL_USE_EVENT
+ ret = rt_completion_wait(&(serial->completion_rx), RT_WAITING_FOREVER);
+#else
+ ret = rt_event_recv(serial->rx_done, RT_SERIAL_EVENT_RXDONE, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, RT_NULL);
+#endif
+ if (ret == RT_EOK || ret == -RT_ETIMEOUT) {
+ } else {
+ return 0;
+ }
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+// serial->ops->disable_interrupt(serial);
+
+ len = _serial_fifo_calc_data_len(rx_fifo);
+ } while(len == 0);
+ }
+
+ if (len > length) {
+ len = length;
+ }
+
+ /* read from software FIFO */
+ for (size = 0; size < len; size++) {
+ /* otherwise there's the data: */
+ *data = _serial_fifo_pop_data(rx_fifo);
+ data++;
+ }
+
+ rx_fifo->is_full = RT_FALSE;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+// serial->ops->enable_interrupt(serial);
+
+ return size;
+}
+
+rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length)
+{
+ rt_size_t len, length_t, size;
+ struct rt_serial_fifo *tx_fifo;
+ rt_base_t level;
+ rt_uint8_t ch = 0;
+ static rt_uint8_t last_char = 0;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ if (length == 0) return 0;
+
+ tx_fifo = (struct rt_serial_fifo*) serial->serial_tx;
+
+ size = 0;
+ do {
+ length_t = length - size;
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+// serial->ops->disable_interrupt(serial);
+
+ len = tx_fifo->buf_sz - _serial_fifo_calc_data_len(tx_fifo);
+
+ if ((len == 0) && // non-blocking io mode
+ (serial->parent.open_flag & RT_DEVICE_OFLAG_NONBLOCKING) == RT_DEVICE_OFLAG_NONBLOCKING) {
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+// serial->ops->enable_interrupt(serial);
+ break;
+ }
+
+ if ((len == 0) && // blocking io mode
+ (serial->parent.open_flag & RT_DEVICE_OFLAG_NONBLOCKING) != RT_DEVICE_OFLAG_NONBLOCKING) {
+ rt_err_t ret;
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+// serial->ops->enable_interrupt(serial);
+#ifndef RT_SERIAL_USE_EVENT
+ ret = rt_completion_wait(&(serial->completion_tx), RT_WAITING_FOREVER);
+#else
+ ret = rt_event_recv(serial->tx_done, RT_SERIAL_EVENT_TXDONE, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, RT_NULL);
+#endif
+ if (ret == RT_EOK || ret == -RT_ETIMEOUT) {
+ continue;
+ } else {
+ return size;
+ }
+ }
+
+ if (len > length_t) {
+ len = length_t;
+ }
+ /* copy to software FIFO */
+ while (len > 0) {
+ /*
+ * to be polite with serial console add a line feed
+ * to the carriage return character
+ */
+ if (*data == '\n' &&
+ (serial->parent.open_flag & RT_DEVICE_FLAG_STREAM) == RT_DEVICE_FLAG_STREAM &&
+ last_char != '\r') {
+ _serial_fifo_push_data(tx_fifo, '\r');
+
+ last_char = '\r';
+ if (len == 1) {
+ break;
+ } else {
+ len--;
+ }
+ } else if (*data == '\r') {
+ last_char = '\r';
+ } else {
+ last_char = 0;
+ }
+
+ _serial_fifo_push_data(tx_fifo, *data);
+
+ data++; len--; size++;
+ }
+
+ /* if the next position is read index, discard this 'read char' */
+ if (tx_fifo->put_index == tx_fifo->get_index) {
+ tx_fifo->is_full = RT_TRUE;
+ }
+
+ // TODO: start tx
+#if defined (RT_SERIAL_NO_TXEIT)
+ if (serial->ops->is_int_txing != RT_NULL && serial->ops->is_int_txing(serial) == RT_FALSE) {
+ ch = _serial_fifo_pop_data(tx_fifo);
+ serial->ops->start_tx(serial, ch);
+ }
+#else
+ serial->ops->start_tx(serial);
+#endif
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+// serial->ops->enable_interrupt(serial);
+ } while(size < length);
+
+ return size;
+}
+
+#ifdef RT_SERIAL_USING_DMA
+/*
+ * Serial DMA routines
+ */
+rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length)
+{
+ rt_size_t len, length_t, size, i;
+ struct rt_serial_fifo *tx_fifo;
+ rt_base_t level;
+ rt_uint8_t ch;
+ static rt_uint8_t last_char = 0;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ if (length == 0) return 0;
+
+ tx_fifo = (struct rt_serial_fifo*) serial->serial_tx;
+
+ size = 0;
+ do {
+ length_t = length - size;
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+// serial->ops->disable_interrupt(serial);
+
+ len = tx_fifo->buf_sz - _serial_fifo_calc_data_len(tx_fifo);
+
+ if ((len == 0) && // non-blocking io mode
+ (serial->parent.open_flag & RT_DEVICE_OFLAG_NONBLOCKING) == RT_DEVICE_OFLAG_NONBLOCKING) {
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+// serial->ops->enable_interrupt(serial);
+ break;
+ }
+
+ if ((len == 0) && // blocking io mode
+ (serial->parent.open_flag & RT_DEVICE_OFLAG_NONBLOCKING) != RT_DEVICE_OFLAG_NONBLOCKING) {
+ rt_err_t ret;
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+// serial->ops->enable_interrupt(serial);
+
+#ifndef RT_SERIAL_USE_EVENT
+ ret = rt_completion_wait(&(serial->completion_tx), RT_WAITING_FOREVER);
+#else
+ ret = rt_event_recv(serial->tx_done, RT_SERIAL_EVENT_TXDONE, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, RT_NULL);
+#endif
+ if (ret == RT_EOK || ret == -RT_ETIMEOUT) {
+ continue;
+ } else {
+ return size;
+ }
+ }
+
+ if (len > length_t) {
+ len = length_t;
+ }
+ /* copy to software FIFO */
+ while (len > 0) {
+ /*
+ * to be polite with serial console add a line feed
+ * to the carriage return character
+ */
+ if (*data == '\n' &&
+ (serial->parent.open_flag & RT_DEVICE_FLAG_STREAM) == RT_DEVICE_FLAG_STREAM &&
+ last_char != '\r') {
+ _serial_fifo_push_data(tx_fifo, '\r');
+
+ last_char = '\r';
+ if (len == 1) {
+ break;
+ } else {
+ len--;
+ }
+ } else if (*data == '\r') {
+ last_char = '\r';
+ } else {
+ last_char = 0;
+ }
+
+ _serial_fifo_push_data(tx_fifo, *data);
+
+ data++; len--; size++;
+ }
+
+ /* if the next position is read index, discard this 'read char' */
+ if (tx_fifo->put_index == tx_fifo->get_index) {
+ tx_fifo->is_full = RT_TRUE;
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+// serial->ops->enable_interrupt(serial);
+
+ // TODO: start tx
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+// serial->ops->disable_interrupt(serial);
+ if (serial->ops->is_dma_txing(serial) == RT_FALSE) {
+ /* calucate fifo data size */
+ len = _serial_fifo_calc_data_len(tx_fifo);
+
+ if (len > RT_SERIAL_DMA_BUFSZ) {
+ len = RT_SERIAL_DMA_BUFSZ;
+ }
+ /* read from software FIFO */
+ for (i = 0; i < len; i++) {
+ /* pop one byte data */
+ ch = _serial_fifo_pop_data(tx_fifo);
+
+ serial->serial_dma_tx[i] = ch;
+ }
+ tx_fifo->is_full = RT_FALSE;
+ serial->ops->start_dma_tx(serial, serial->serial_dma_tx, len);
+
+ }
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+// serial->ops->enable_interrupt(serial);
+ } while(size < length);
+
+ return size;
+}
+#endif /* RT_SERIAL_USING_DMA */
+
+/* RT-Thread Device Interface */
+/*
+ * This function initializes serial device.
+ */
+static rt_err_t rt_serial_init(struct rt_device *dev)
+{
+ rt_err_t result = RT_EOK;
+ struct rt_serial_device *serial;
+
+ RT_ASSERT(dev != RT_NULL);
+ serial = (struct rt_serial_device *)dev;
+
+ /* initialize rx/tx */
+ serial->serial_rx = RT_NULL;
+ serial->serial_tx = RT_NULL;
+
+ /* initialize hardware */
+ if (serial->ops->init)
+ result = serial->ops->init(serial);
+
+ return result;
+}
+
+static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
+{
+ rt_uint16_t stream_flag = 0;
+ struct rt_serial_device *serial;
+
+ RT_ASSERT(dev != RT_NULL);
+ serial = (struct rt_serial_device *)dev;
+
+ LOG_D("open serial device: 0x%08x with open flag: 0x%04x",
+ dev, oflag);
+ /* check device flag with the open flag */
+ if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX))
+ return -RT_EIO;
+ if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX))
+ return -RT_EIO;
+ if ((oflag & RT_DEVICE_FLAG_INT_RX) && !(dev->flag & RT_DEVICE_FLAG_INT_RX))
+ return -RT_EIO;
+ if ((oflag & RT_DEVICE_FLAG_INT_TX) && !(dev->flag & RT_DEVICE_FLAG_INT_TX))
+ return -RT_EIO;
+
+ /* keep steam flag */
+ if ((oflag & RT_DEVICE_FLAG_STREAM) || (dev->open_flag & RT_DEVICE_FLAG_STREAM))
+ stream_flag = RT_DEVICE_FLAG_STREAM;
+
+ /* get open flags */
+ dev->open_flag = oflag & 0xff;
+
+ if (oflag & RT_DEVICE_FLAG_INT_RX)
+ {
+ /* initialize the Rx/Tx structure according to open flag */
+ if (serial->serial_rx == RT_NULL)
+ {
+ struct rt_serial_fifo* rx_fifo;
+
+ rx_fifo = (struct rt_serial_fifo*)rt_malloc(sizeof(struct rt_serial_fifo) +
+ serial->bufsz);
+ RT_ASSERT(rx_fifo != RT_NULL);
+ rx_fifo->buf_sz = serial->bufsz;
+ rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
+ rt_memset(rx_fifo->buffer, 0, rx_fifo->buf_sz);
+ rx_fifo->put_index = 0;
+ rx_fifo->get_index = 0;
+ rx_fifo->is_full = RT_FALSE;
+
+ serial->serial_rx = rx_fifo;
+ }
+ dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
+
+ serial->_cb_rx = _serial_fifo_rx;
+#ifndef RT_SERIAL_USE_EVENT
+ rt_completion_init(&(serial->completion_rx));
+#else
+ serial->rx_done = rt_event_create("rx_done", RT_IPC_FLAG_PRIO);
+#endif
+ /* configure low level device */
+ serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
+ }
+#ifdef RT_SERIAL_USING_DMA
+ else if (oflag & RT_DEVICE_FLAG_DMA_RX)
+ {
+ /* initialize the Rx/Tx structure according to open flag */
+ if (serial->serial_rx == RT_NULL)
+ {
+ struct rt_serial_fifo* rx_fifo;
+
+ rx_fifo = (struct rt_serial_fifo*)rt_malloc(sizeof(struct rt_serial_fifo) +
+ serial->bufsz);
+ RT_ASSERT(rx_fifo != RT_NULL);
+ rx_fifo->buf_sz = serial->bufsz;
+ rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
+ rt_memset(rx_fifo->buffer, 0, rx_fifo->buf_sz);
+ rx_fifo->put_index = 0;
+ rx_fifo->get_index = 0;
+ rx_fifo->is_full = RT_FALSE;
+
+ serial->serial_rx = rx_fifo;
+ }
+ dev->open_flag |= RT_DEVICE_FLAG_DMA_RX;
+
+ serial->dma_idx_rx = 0;
+ serial->_cb_rx = _serial_fifo_rx;
+
+#ifndef RT_SERIAL_USE_EVENT
+ rt_completion_init(&(serial->completion_rx));
+#else
+ serial->rx_done = rt_event_create("rx_done", RT_IPC_FLAG_PRIO);
+#endif
+ /* configure fifo address and length to low level device */
+ serial->ops->control(serial, RT_DEVICE_CTRL_CONFIG, (void *) RT_DEVICE_FLAG_DMA_RX);
+ }
+#endif /* RT_SERIAL_USING_DMA */
+ else
+ {
+ serial->serial_rx = RT_NULL;
+ serial->_cb_rx = _serial_poll_rx;
+ }
+
+ if (oflag & RT_DEVICE_FLAG_INT_TX)
+ {
+ if (serial->serial_tx == RT_NULL)
+ {
+ struct rt_serial_fifo *tx_fifo;
+
+ tx_fifo = (struct rt_serial_fifo*)rt_malloc(sizeof(struct rt_serial_fifo) +
+ serial->bufsz);
+ RT_ASSERT(tx_fifo != RT_NULL);
+ tx_fifo->buf_sz = serial->bufsz;
+ tx_fifo->buffer = (rt_uint8_t*) (tx_fifo + 1);
+ rt_memset(tx_fifo->buffer, 0, tx_fifo->buf_sz);
+ tx_fifo->put_index = 0;
+ tx_fifo->get_index = 0;
+ tx_fifo->is_full = RT_FALSE;
+#ifndef RT_SERIAL_USE_EVENT
+ rt_completion_init(&(serial->completion_tx));
+#else
+ serial->tx_done = rt_event_create("tx_done", RT_IPC_FLAG_PRIO);
+#endif
+ serial->serial_tx = tx_fifo;
+ }
+ dev->open_flag |= RT_DEVICE_FLAG_INT_TX;
+ /* configure low level device */
+// serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX);
+
+ serial->_cb_tx = _serial_int_tx;
+ }
+#ifdef RT_SERIAL_USING_DMA
+ else if (oflag & RT_DEVICE_FLAG_DMA_TX)
+ {
+ if (serial->serial_tx == RT_NULL)
+ {
+ struct rt_serial_fifo *tx_fifo;
+
+ tx_fifo = (struct rt_serial_fifo*)rt_malloc(sizeof(struct rt_serial_fifo) +
+ serial->bufsz);
+ RT_ASSERT(tx_fifo != RT_NULL);
+ tx_fifo->buf_sz = serial->bufsz;
+ tx_fifo->buffer = (rt_uint8_t*) (tx_fifo + 1);
+ rt_memset(tx_fifo->buffer, 0, tx_fifo->buf_sz);
+ tx_fifo->put_index = 0;
+ tx_fifo->get_index = 0;
+ tx_fifo->is_full = RT_FALSE;
+
+#ifndef RT_SERIAL_USE_EVENT
+ rt_completion_init(&(serial->completion_tx));
+#else
+ serial->tx_done = rt_event_create("tx_done", RT_IPC_FLAG_PRIO);
+#endif
+
+ serial->serial_tx = tx_fifo;
+ }
+ dev->open_flag |= RT_DEVICE_FLAG_DMA_TX;
+
+ serial->_cb_tx = _serial_dma_tx;
+ /* configure low level device */
+ serial->ops->control(serial, RT_DEVICE_CTRL_CONFIG, (void *)RT_DEVICE_FLAG_DMA_TX);
+ }
+#endif /* RT_SERIAL_USING_DMA */
+ else
+ {
+ serial->serial_tx = RT_NULL;
+ serial->_cb_tx = _serial_poll_tx;
+ }
+
+ serial->ops->control(serial, RT_DEVICE_CTRL_OPEN, (void *)0);
+
+ /* set stream flag */
+ dev->open_flag |= stream_flag;
+
+ return RT_EOK;
+}
+
+static rt_err_t rt_serial_close(struct rt_device *dev)
+{
+ struct rt_serial_device *serial;
+
+ RT_ASSERT(dev != RT_NULL);
+ serial = (struct rt_serial_device *)dev;
+
+ serial->ops->control(serial, RT_DEVICE_CTRL_CLOSE, RT_NULL);
+
+ if (dev->open_flag & RT_DEVICE_FLAG_INT_RX)
+ {
+ struct rt_serial_fifo *rx_fifo;
+
+ /* configure low level device */
+ serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX);
+
+ dev->open_flag &= ~RT_DEVICE_FLAG_INT_RX;
+
+ rx_fifo = (struct rt_serial_fifo *)serial->serial_rx;
+ rt_free(rx_fifo);
+
+ serial->serial_rx = RT_NULL;
+#ifndef RT_SERIAL_USE_EVENT
+ rt_completion_init(&(serial->completion_rx));
+#else
+ rt_event_delete(serial->rx_done);
+#endif
+ }
+#ifdef RT_SERIAL_USING_DMA
+ else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
+ {
+ struct rt_serial_fifo *rx_fifo;
+
+ /* configure low level device */
+ serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *) RT_DEVICE_FLAG_DMA_RX);
+
+ dev->open_flag &= ~RT_DEVICE_FLAG_DMA_RX;
+
+ rx_fifo = (struct rt_serial_fifo *)serial->serial_rx;
+ rt_free(rx_fifo);
+
+ serial->serial_rx = RT_NULL;
+#ifndef RT_SERIAL_USE_EVENT
+ rt_completion_init(&(serial->completion_rx));
+#else
+ rt_event_delete(serial->rx_done);
+#endif
+ }
+#endif /* RT_SERIAL_USING_DMA */
+
+ if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
+ {
+ struct rt_serial_fifo *tx_fifo;
+
+ /* configure low level device */
+ serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_TX);
+
+ dev->open_flag &= ~RT_DEVICE_FLAG_INT_TX;
+
+ tx_fifo = (struct rt_serial_fifo *)serial->serial_tx;
+ rt_free(tx_fifo);
+
+ serial->serial_tx = RT_NULL;
+#ifndef RT_SERIAL_USE_EVENT
+ rt_completion_init(&(serial->completion_tx));
+#else
+ rt_event_delete(serial->tx_done);
+#endif
+ }
+#ifdef RT_SERIAL_USING_DMA
+ else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
+ {
+ struct rt_serial_fifo *tx_fifo;
+
+ /* configure low level device */
+ serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *) RT_DEVICE_FLAG_DMA_TX);
+
+ dev->open_flag &= ~RT_DEVICE_FLAG_DMA_TX;
+
+ tx_fifo = (struct rt_serial_fifo *)serial->serial_tx;
+ rt_free(tx_fifo);
+
+ serial->serial_tx = RT_NULL;
+#ifndef RT_SERIAL_USE_EVENT
+ rt_completion_init(&(serial->completion_tx));
+#else
+ rt_event_delete(serial->tx_done);
+#endif
+ }
+#endif /* RT_SERIAL_USING_DMA */
+
+ dev->flag &= ~RT_DEVICE_FLAG_ACTIVATED;
+
+ return RT_EOK;
+}
+
+static rt_ssize_t rt_serial_read(struct rt_device *dev,
+ rt_off_t pos,
+ void *buffer,
+ rt_size_t size)
+{
+ struct rt_serial_device *serial;
+
+ RT_ASSERT(dev != RT_NULL);
+ if (size == 0) return 0;
+
+ serial = (struct rt_serial_device *)dev;
+
+ return serial->_cb_rx(serial, (rt_uint8_t *)buffer, size);
+}
+
+static rt_ssize_t rt_serial_write(struct rt_device *dev,
+ rt_off_t pos,
+ const void *buffer,
+ rt_size_t size)
+{
+ struct rt_serial_device *serial;
+
+ RT_ASSERT(dev != RT_NULL);
+ if (size == 0) return 0;
+
+ serial = (struct rt_serial_device *)dev;
+
+ return serial->_cb_tx(serial, (const rt_uint8_t *)buffer, size);
+}
+
+static rt_err_t rt_serial_flush(struct rt_device *dev)
+{
+ struct rt_serial_device *serial;
+ rt_size_t len;
+ struct rt_serial_fifo *tx_fifo, *rx_fifo;
+ rt_base_t level;
+
+ RT_ASSERT(dev != RT_NULL);
+
+ serial = (struct rt_serial_device *)dev;
+
+ if((dev->open_flag & RT_DEVICE_FLAG_INT_RX)
+#ifdef RT_SERIAL_USING_DMA
+ || (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
+#endif /* RT_SERIAL_USING_DMA */
+ ) {
+ rx_fifo = (struct rt_serial_fifo*) serial->serial_rx;
+ level = rt_hw_interrupt_disable();
+ rx_fifo->get_index = rx_fifo->put_index = 0;
+ rx_fifo->is_full = RT_FALSE;
+ rt_hw_interrupt_enable(level);
+ }
+
+ if ((dev->open_flag & RT_DEVICE_FLAG_INT_TX)
+#ifdef RT_SERIAL_USING_DMA
+ || (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
+#endif /* RT_SERIAL_USING_DMA */
+ ) {
+ tx_fifo = (struct rt_serial_fifo*) serial->serial_tx;
+
+ while(1) {
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+ // serial->ops->disable_interrupt(serial);
+
+ len = _serial_fifo_calc_data_len(tx_fifo);
+
+ if (len == 0) {
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+ // serial->ops->enable_interrupt(serial);
+ break;
+ } else {
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+ // serial->ops->enable_interrupt(serial);
+#ifndef RT_SERIAL_USE_EVENT
+ rt_completion_wait(&(serial->completion_tx), RT_WAITING_FOREVER);
+#else
+ rt_event_recv(serial->tx_done, RT_SERIAL_EVENT_TXDONE, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, RT_NULL);
+#endif
+ }
+ }
+
+ if (dev->open_flag & RT_DEVICE_FLAG_INT_TX) {
+ serial->ops->flush(serial);
+ }
+#ifdef RT_SERIAL_USING_DMA
+ else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX) {
+ while (serial->ops->is_dma_txing(serial) == RT_TRUE);
+ }
+#endif /* RT_SERIAL_USING_DMA */
+ } else {
+ serial->ops->flush(serial);
+ }
+
+ return RT_EOK;
+}
+
+#ifdef RT_USING_POSIX_TERMIOS
+struct speed_baudrate_item
+{
+ speed_t speed;
+ int baudrate;
+};
+
+const static struct speed_baudrate_item _tbl[] =
+{
+ {B2400, BAUD_RATE_2400},
+ {B4800, BAUD_RATE_4800},
+ {B9600, BAUD_RATE_9600},
+ {B19200, BAUD_RATE_19200},
+ {B38400, BAUD_RATE_38400},
+ {B57600, BAUD_RATE_57600},
+ {B115200, BAUD_RATE_115200},
+ {B230400, BAUD_RATE_230400},
+ {B460800, BAUD_RATE_460800},
+ {B921600, BAUD_RATE_921600},
+ {B2000000, BAUD_RATE_2000000},
+ {B3000000, BAUD_RATE_3000000},
+};
+
+static speed_t _get_speed(int baudrate)
+{
+ int index;
+
+ for (index = 0; index < sizeof(_tbl)/sizeof(_tbl[0]); index ++)
+ {
+ if (_tbl[index].baudrate == baudrate)
+ return _tbl[index].speed;
+ }
+
+ return B0;
+}
+
+static int _get_baudrate(speed_t speed)
+{
+ int index;
+
+ for (index = 0; index < sizeof(_tbl)/sizeof(_tbl[0]); index ++)
+ {
+ if (_tbl[index].speed == speed)
+ return _tbl[index].baudrate;
+ }
+
+ return 0;
+}
+
+static void _tc_flush(struct rt_serial_device *serial, int queue)
+{
+ rt_base_t level;
+ int ch = -1;
+ struct rt_serial_fifo *rx_fifo = RT_NULL;
+ struct rt_device *device = RT_NULL;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ device = &(serial->parent);
+ rx_fifo = (struct rt_serial_fifo *) serial->serial_rx;
+
+ switch(queue)
+ {
+ case TCIFLUSH:
+ case TCIOFLUSH:
+
+ RT_ASSERT(rx_fifo != RT_NULL);
+
+ if((device->open_flag & RT_DEVICE_FLAG_INT_RX) || (device->open_flag & RT_DEVICE_FLAG_DMA_RX))
+ {
+ RT_ASSERT(RT_NULL != rx_fifo);
+ level = rt_hw_interrupt_disable();
+ rx_fifo->get_index = rx_fifo->put_index;
+ rx_fifo->is_full = RT_FALSE;
+ rt_hw_interrupt_enable(level);
+ }
+ else
+ {
+ while (1)
+ {
+ ch = serial->ops->getc(serial);
+ if (ch == -1) break;
+ }
+ }
+
+ break;
+
+ case TCOFLUSH:
+ break;
+ }
+
+}
+
+#endif
+
+static rt_err_t rt_serial_control(struct rt_device *dev,
+ int cmd,
+ void *args)
+{
+ rt_err_t ret = RT_EOK;
+ struct rt_serial_device *serial;
+
+ RT_ASSERT(dev != RT_NULL);
+ serial = (struct rt_serial_device *)dev;
+
+ switch (cmd)
+ {
+ case RT_DEVICE_CTRL_SUSPEND:
+ /* suspend device */
+ dev->flag |= RT_DEVICE_FLAG_SUSPENDED;
+ break;
+ case RT_DEVICE_CTRL_RESUME:
+ /* resume device */
+ dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED;
+ break;
+ case RT_DEVICE_CTRL_BLOCKING:
+ if (((rt_uint32_t)args & RT_DEVICE_OFLAG_NONBLOCKING) == RT_DEVICE_OFLAG_NONBLOCKING) {
+ dev->open_flag |= RT_DEVICE_OFLAG_NONBLOCKING;
+ } else {
+ dev->open_flag &= ~RT_DEVICE_OFLAG_NONBLOCKING;
+ }
+ break;
+ case RT_DEVICE_CTRL_CONFIG:
+ if (args)
+ {
+ struct serial_configure *pconfig = (struct serial_configure *) args;
+
+ /* serial device has been opened, to configure it */
+ ret = serial->ops->configure(serial, pconfig);
+ if (ret == RT_EOK) {
+ /* set serial configure */
+ serial->config = *pconfig;
+ }
+ }
+ break;
+#ifdef RT_USING_POSIX_STDIO
+#ifdef RT_USING_POSIX_TERMIOS
+ case TCGETA:
+ {
+ struct termios *tio = (struct termios*)args;
+ if (tio == RT_NULL) return -RT_EINVAL;
+
+ tio->c_iflag = 0;
+ tio->c_oflag = 0;
+ tio->c_lflag = 0;
+
+ /* update oflag for console device */
+ if (rt_console_get_device() == dev)
+ tio->c_oflag = OPOST | ONLCR;
+
+ /* set cflag */
+ tio->c_cflag = 0;
+ if (serial->config.data_bits == DATA_BITS_5)
+ tio->c_cflag = CS5;
+ else if (serial->config.data_bits == DATA_BITS_6)
+ tio->c_cflag = CS6;
+ else if (serial->config.data_bits == DATA_BITS_7)
+ tio->c_cflag = CS7;
+ else if (serial->config.data_bits == DATA_BITS_8)
+ tio->c_cflag = CS8;
+
+ if (serial->config.stop_bits == STOP_BITS_2)
+ tio->c_cflag |= CSTOPB;
+
+ if (serial->config.parity == PARITY_EVEN)
+ tio->c_cflag |= PARENB;
+ else if (serial->config.parity == PARITY_ODD)
+ tio->c_cflag |= (PARODD | PARENB);
+
+ cfsetospeed(tio, _get_speed(serial->config.baud_rate));
+ }
+ break;
+
+ case TCSETAW:
+ case TCSETAF:
+ case TCSETA:
+ {
+ int baudrate;
+ struct serial_configure config;
+
+ struct termios *tio = (struct termios*)args;
+ if (tio == RT_NULL) return -RT_EINVAL;
+
+ config = serial->config;
+
+ baudrate = _get_baudrate(cfgetospeed(tio));
+ config.baud_rate = baudrate;
+
+ switch (tio->c_cflag & CSIZE)
+ {
+ case CS5:
+ config.data_bits = DATA_BITS_5;
+ break;
+ case CS6:
+ config.data_bits = DATA_BITS_6;
+ break;
+ case CS7:
+ config.data_bits = DATA_BITS_7;
+ break;
+ default:
+ config.data_bits = DATA_BITS_8;
+ break;
+ }
+
+ if (tio->c_cflag & CSTOPB) config.stop_bits = STOP_BITS_2;
+ else config.stop_bits = STOP_BITS_1;
+
+ if (tio->c_cflag & PARENB)
+ {
+ if (tio->c_cflag & PARODD) config.parity = PARITY_ODD;
+ else config.parity = PARITY_EVEN;
+ }
+ else config.parity = PARITY_NONE;
+
+ serial->ops->configure(serial, &config);
+ }
+ break;
+ case TCFLSH:
+ {
+ int queue = (int)args;
+
+ _tc_flush(serial, queue);
+ }
+
+ break;
+ case TCXONC:
+ break;
+#endif /*RT_USING_POSIX_TERMIOS*/
+ case TIOCSWINSZ:
+ {
+ struct winsize* p_winsize;
+
+ p_winsize = (struct winsize*)args;
+ rt_kprintf("\x1b[8;%d;%dt", p_winsize->ws_col, p_winsize->ws_row);
+ }
+ break;
+ case TIOCGWINSZ:
+ {
+ struct winsize* p_winsize;
+ p_winsize = (struct winsize*)args;
+
+ if(rt_thread_self() != rt_thread_find("tshell"))
+ {
+ /* only can be used in tshell thread; otherwise, return default size */
+ p_winsize->ws_col = 80;
+ p_winsize->ws_row = 24;
+ }
+ else
+ {
+ #define _TIO_BUFLEN 20
+ char _tio_buf[_TIO_BUFLEN];
+ unsigned char cnt1, cnt2, cnt3, i;
+ char row_s[4], col_s[4];
+ char *p;
+
+ rt_memset(_tio_buf, 0, _TIO_BUFLEN);
+
+ /* send the command to terminal for getting the window size of the terminal */
+ rt_kprintf("\033[18t");
+
+ /* waiting for the response from the terminal */
+ i = 0;
+ while(i < _TIO_BUFLEN)
+ {
+ _tio_buf[i] = getchar();
+ if(_tio_buf[i] != 't')
+ {
+ i ++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if(i == _TIO_BUFLEN)
+ {
+ /* buffer overloaded, and return default size */
+ p_winsize->ws_col = 80;
+ p_winsize->ws_row = 24;
+ break;
+ }
+
+ /* interpreting data eg: "\033[8;1;15t" which means row is 1 and col is 15 (unit: size of ONE character) */
+ rt_memset(row_s,0,4);
+ rt_memset(col_s,0,4);
+ cnt1 = 0;
+ while(_tio_buf[cnt1] != ';' && cnt1 < _TIO_BUFLEN)
+ {
+ cnt1++;
+ }
+ cnt2 = ++cnt1;
+ while(_tio_buf[cnt2] != ';' && cnt2 < _TIO_BUFLEN)
+ {
+ cnt2++;
+ }
+ p = row_s;
+ while(cnt1 < cnt2)
+ {
+ *p++ = _tio_buf[cnt1++];
+ }
+ p = col_s;
+ cnt2++;
+ cnt3 = rt_strlen(_tio_buf) - 1;
+ while(cnt2 < cnt3)
+ {
+ *p++ = _tio_buf[cnt2++];
+ }
+
+ /* load the window size date */
+ p_winsize->ws_col = atoi(col_s);
+ p_winsize->ws_row = atoi(row_s);
+ #undef _TIO_BUFLEN
+ }
+
+ p_winsize->ws_xpixel = 0;/* unused */
+ p_winsize->ws_ypixel = 0;/* unused */
+ }
+ break;
+ case FIONREAD:
+ {
+ rt_size_t recved = 0;
+ rt_base_t level;
+
+ level = rt_hw_interrupt_disable();
+ recved = _serial_fifo_calc_data_len(serial->serial_rx);
+ rt_hw_interrupt_enable(level);
+
+ *(rt_size_t *)args = recved;
+ }
+ break;
+#endif /*RT_USING_POSIX_STDIO*/
+ default :
+ /* control device */
+ ret = serial->ops->control(serial, cmd, args);
+ break;
+ }
+
+ return ret;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops serial_ops =
+{
+ .init = rt_serial_init,
+ .open = rt_serial_open,
+ .close = rt_serial_close,
+ .read = rt_serial_read,
+ .write = rt_serial_write,
+ .flush = rt_serial_flush,
+ .control = rt_serial_control
+};
+#endif
+
+/*
+ * serial register
+ */
+rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
+ const char *name,
+ rt_uint32_t flag,
+ void *data)
+{
+ rt_err_t ret;
+ struct rt_device *device;
+ RT_ASSERT(serial != RT_NULL);
+
+ serial->config = RT_SERIAL_CONFIG_DEFAULT;
+ serial->bufsz = RT_SERIAL_FIFO_BUFSZ;
+
+ device = &(serial->parent);
+
+ device->type = RT_Device_Class_Char;
+ device->rx_indicate = RT_NULL;
+ device->tx_complete = RT_NULL;
+
+#ifdef RT_USING_DEVICE_OPS
+ device->ops = &serial_ops;
+#else
+ device->init = rt_serial_init;
+ device->open = rt_serial_open;
+ device->close = rt_serial_close;
+ device->read = rt_serial_read;
+ device->write = rt_serial_write;
+ device->flush = rt_serial_flush;
+ device->control = rt_serial_control;
+#endif
+ device->user_data = data;
+
+ /* register a character device */
+ ret = rt_device_register(device, name, flag);
+
+#if defined(RT_USING_POSIX_STDIO)
+ /* set fops */
+ device->fops = &_serial_fops;
+#endif
+
+ return ret;
+}
+
+/* ISR for serial interrupt */
+void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
+{
+ switch (event & 0xff)
+ {
+ case RT_SERIAL_EVENT_RX_IND:
+ {
+ int ch = -1;
+ struct rt_serial_fifo* rx_fifo;
+
+ /* interrupt mode receive */
+ rx_fifo = (struct rt_serial_fifo*)serial->serial_rx;
+
+#if defined(RT_SERIAL_HARD_FIFO)
+ while (1)
+#endif
+ {
+ ch = serial->ops->getc(serial);
+#if defined(RT_SERIAL_HARD_FIFO)
+ if (ch == -1) break;
+#endif
+
+ /* if fifo is full, discard one byte first */
+ if (rx_fifo->is_full == RT_TRUE) {
+ rx_fifo->get_index += 1;
+ if (rx_fifo->get_index >= rx_fifo->buf_sz) rx_fifo->get_index = 0;
+ }
+ /* push a new data */
+ _serial_fifo_push_data(rx_fifo, ch);
+
+ /* if put index equal to read index, fifo is full */
+ if (rx_fifo->put_index == rx_fifo->get_index)
+ {
+ rx_fifo->is_full = RT_TRUE;
+ }
+ }
+#ifndef RT_SERIAL_USE_EVENT
+ rt_completion_done(&(serial->completion_rx));
+#else
+ rt_event_send(serial->rx_done, RT_SERIAL_EVENT_RXDONE);
+#endif
+ /* invoke callback */
+ if (serial->parent.rx_indicate != RT_NULL) {
+ rt_size_t rx_length;
+
+ /* get rx length */
+ rx_length = _serial_fifo_calc_data_len(rx_fifo);
+ if (rx_length) {
+ serial->parent.rx_indicate(&serial->parent, rx_length);
+ }
+ }
+ }
+ break;
+ case RT_SERIAL_EVENT_TX_DONE:
+ {
+#if defined(RT_SERIAL_HARD_FIFO)
+ rt_size_t fifo_sz;
+#endif
+ rt_size_t len;
+ rt_uint8_t ch = 0;
+ struct rt_serial_fifo *tx_fifo;
+
+ tx_fifo = (struct rt_serial_fifo*) serial->serial_tx;
+
+ /* calucate fifo data size */
+ len = _serial_fifo_calc_data_len(tx_fifo);
+ if (len == 0) {
+ // TODO: stop tx
+ serial->ops->stop_tx(serial);
+#ifndef RT_SERIAL_USE_EVENT
+ rt_completion_done(&(serial->completion_tx));
+#else
+ rt_event_send(serial->tx_done, RT_SERIAL_EVENT_TXDONE);
+#endif
+ /* invoke callback */
+ if (serial->parent.tx_complete != RT_NULL) {
+ serial->parent.tx_complete(&serial->parent, (void*)len);
+ }
+ break;
+ }
+#if defined(RT_SERIAL_HARD_FIFO)
+ fifo_sz = event >> 8;
+ if (len > fifo_sz) {
+ len = fifo_sz;
+ }
+ /* read from software FIFO */
+ while (len > 0) {
+ /* pop one byte data */
+ ch = _serial_fifo_pop_data(tx_fifo);
+
+ serial->ops->putc(serial, ch);
+ len--;
+ }
+#else
+ /* pop one byte data */
+ ch = _serial_fifo_pop_data(tx_fifo);
+
+ serial->ops->putc(serial, ch);
+#endif
+ tx_fifo->is_full = RT_FALSE;
+ }
+ break;
+#ifdef RT_SERIAL_USING_DMA
+ case RT_SERIAL_EVENT_RX_DMADONE:
+ {
+ int dma_idx, ch = -1;
+ struct rt_serial_fifo* rx_fifo;
+
+ dma_idx = event >> 8;
+
+ if (serial->dma_idx_rx == dma_idx) break;
+
+ rx_fifo = (struct rt_serial_fifo*)serial->serial_rx;
+
+ while (serial->dma_idx_rx != dma_idx) {
+ ch = serial->serial_dma_rx[serial->dma_idx_rx];
+
+ /* if fifo is full, discard one byte first */
+ if (rx_fifo->is_full == RT_TRUE) {
+ rx_fifo->get_index += 1;
+ if (rx_fifo->get_index >= rx_fifo->buf_sz) rx_fifo->get_index = 0;
+ }
+ /* push a new data */
+ _serial_fifo_push_data(rx_fifo, ch);
+
+ /* if put index equal to read index, fifo is full */
+ if (rx_fifo->put_index == rx_fifo->get_index)
+ {
+ rx_fifo->is_full = RT_TRUE;
+ }
+ serial->dma_idx_rx++;
+ if (serial->dma_idx_rx == RT_SERIAL_DMA_BUFSZ) {
+ serial->dma_idx_rx = 0;
+ }
+ }
+ serial->dma_idx_rx = dma_idx;
+#ifndef RT_SERIAL_USE_EVENT
+ rt_completion_done(&(serial->completion_rx));
+#else
+ rt_event_send(serial->rx_done, RT_SERIAL_EVENT_RXDONE);
+#endif
+
+ /* invoke callback */
+ if (serial->parent.rx_indicate != RT_NULL) {
+ rt_size_t rx_length;
+
+ /* get rx length */
+ rx_length = _serial_fifo_calc_data_len(rx_fifo);
+ if (rx_length) {
+ serial->parent.rx_indicate(&serial->parent, rx_length);
+ }
+ }
+ }
+ break;
+ case RT_SERIAL_EVENT_TX_DMADONE:
+ {
+ int i;
+ rt_size_t len;
+ rt_uint8_t ch = 0;
+ struct rt_serial_fifo *tx_fifo;
+
+ tx_fifo = (struct rt_serial_fifo*) serial->serial_tx;
+
+ /* calucate fifo data size */
+ len = _serial_fifo_calc_data_len(tx_fifo);
+ if (len == 0) {
+ // TODO: stop tx
+ serial->ops->stop_dma_tx(serial);
+#ifndef RT_SERIAL_USE_EVENT
+ rt_completion_done(&(serial->completion_tx));
+#else
+ rt_event_send(serial->tx_done, RT_SERIAL_EVENT_TXDONE);
+#endif
+ /* invoke callback */
+ if (serial->parent.tx_complete != RT_NULL) {
+ serial->parent.tx_complete(&serial->parent, (void*)len);
+ }
+ break;
+ }
+
+ if (len > RT_SERIAL_DMA_BUFSZ) {
+ len = RT_SERIAL_DMA_BUFSZ;
+ }
+ /* read from software FIFO */
+ for (i = 0; i < len; i++) {
+ /* pop one byte data */
+ ch = _serial_fifo_pop_data(tx_fifo);
+
+ serial->serial_dma_tx[i] = ch;
+ }
+ tx_fifo->is_full = RT_FALSE;
+ serial->ops->start_dma_tx(serial, serial->serial_dma_tx, len);
+ }
+ break;
+#endif /* RT_SERIAL_USING_DMA */
+ }
+}
+#endif /* RT_USING_SERIAL */
diff --git a/include/rtdef.h b/include/rtdef.h
index e72f9226fa..3e239fda4f 100644
--- a/include/rtdef.h
+++ b/include/rtdef.h
@@ -41,6 +41,7 @@
* 2022-01-01 Gabriel improve hooking method
* 2022-01-07 Gabriel move some __on_rt_xxxxx_hook to dedicated c source files
* 2022-01-12 Meco Man remove RT_THREAD_BLOCK
+ * 2022-04-10 THEWON add flush for device & some device flags
* 2022-04-20 Meco Man change version number to v4.1.1
* 2022-04-21 THEWON add macro RT_VERSION_CHECK
* 2022-06-29 Meco Man add RT_USING_LIBC and standard libc headers
@@ -1165,6 +1166,10 @@ enum rt_device_class_type
#define RT_DEVICE_OFLAG_WRONLY 0x002 /**< write only access */
#define RT_DEVICE_OFLAG_RDWR 0x003 /**< read and write */
#define RT_DEVICE_OFLAG_OPEN 0x008 /**< device is opened */
+
+#define RT_DEVICE_OFLAG_BLOCKING 0x000 /**< blocking io mode */
+#define RT_DEVICE_OFLAG_NONBLOCKING 0x004 /**< non-blocking io mode */
+
#define RT_DEVICE_OFLAG_MASK 0xf0f /**< mask of open flag */
/**
@@ -1182,6 +1187,8 @@ enum rt_device_class_type
#define RT_DEVICE_CTRL_CLR_INT 0x07 /**< clear interrupt */
#define RT_DEVICE_CTRL_GET_INT 0x08 /**< get interrupt status */
#define RT_DEVICE_CTRL_CONSOLE_OFLAG 0x09 /**< get console open flag */
+#define RT_DEVICE_CTRL_OPEN 0x0A /**< open device */
+#define RT_DEVICE_CTRL_BLOCKING 0x0B /**< blocking io */
#define RT_DEVICE_CTRL_MASK 0x1f /**< mask for contrl commands */
/**
@@ -1220,6 +1227,7 @@ struct rt_device_ops
rt_ssize_t (*read) (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_ssize_t (*write) (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
rt_err_t (*control)(rt_device_t dev, int cmd, void *args);
+ rt_err_t (*flush) (rt_device_t dev);
};
#endif /* RT_USING_DEVICE_OPS */
@@ -1264,6 +1272,7 @@ struct rt_device
rt_ssize_t (*read) (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_ssize_t (*write) (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
rt_err_t (*control)(rt_device_t dev, int cmd, void *args);
+ rt_err_t (*flush) (rt_device_t dev);
#endif /* RT_USING_DEVICE_OPS */
#ifdef RT_USING_POSIX_DEVIO
diff --git a/include/rtthread.h b/include/rtthread.h
index 5cfa3c26b1..961993c0ef 100644
--- a/include/rtthread.h
+++ b/include/rtthread.h
@@ -569,6 +569,7 @@ rt_ssize_t rt_device_write(rt_device_t dev,
const void *buffer,
rt_size_t size);
rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg);
+rt_err_t rt_device_flush(rt_device_t dev);
#ifdef RT_USING_DM
rt_err_t rt_device_bind_driver(rt_device_t device, rt_driver_t driver, void *node);
rt_device_t rt_device_create_since_driver(rt_driver_t drv,int device_id);
diff --git a/src/device.c b/src/device.c
index 9665788c77..4eafb4e3ba 100644
--- a/src/device.c
+++ b/src/device.c
@@ -13,6 +13,7 @@
* 2013-07-09 Grissiom add ref_count support
* 2016-04-02 Bernard fix the open_flag initialization issue.
* 2021-03-19 Meco Man remove rt_device_init_all()
+ * 2022-04-10 THEWON add flush for device
*/
#include <rtthread.h>
@@ -28,6 +29,7 @@
#define device_close (dev->ops->close)
#define device_read (dev->ops->read)
#define device_write (dev->ops->write)
+#define device_flush (dev->ops->flush)
#define device_control (dev->ops->control)
#else
#define device_init (dev->init)
@@ -35,6 +37,7 @@
#define device_close (dev->close)
#define device_read (dev->read)
#define device_write (dev->write)
+#define device_flush (dev->flush)
#define device_control (dev->control)
#endif /* RT_USING_DEVICE_OPS */
@@ -290,7 +293,11 @@ rt_err_t rt_device_close(rt_device_t dev)
/* set open flag */
if (result == RT_EOK || result == -RT_ENOSYS)
+ {
dev->open_flag = RT_DEVICE_OFLAG_CLOSE;
+ dev->rx_indicate = RT_NULL;
+ dev->tx_complete = RT_NULL;
+ }
return result;
}
@@ -383,6 +390,33 @@ rt_ssize_t rt_device_write(rt_device_t dev,
RTM_EXPORT(rt_device_write);
/**
+ * @brief This function will flush a device's buffers.
+ *
+ * @param dev is the pointer of device driver structure.
+ *
+ * @return the result, RT_EOK on successfully.
+ */
+rt_err_t rt_device_flush(rt_device_t dev)
+{
+ RT_ASSERT(dev != RT_NULL);
+ RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
+
+ if (dev->ref_count == 0)
+ {
+ return -RT_ERROR;
+ }
+
+ /* call device_write interface */
+ if (device_flush != RT_NULL)
+ {
+ return device_flush(dev);
+ }
+
+ return -RT_ENOSYS;
+}
+RTM_EXPORT(rt_device_flush);
+
+/**
* @brief This function will perform a variety of control functions on devices.
*
* @param dev is the pointer of device driver structure.
@@ -475,13 +509,13 @@ rt_err_t rt_device_bind_driver(rt_device_t device, rt_driver_t driver, void *nod
}
device->drv = driver;
-#ifdef RT_USING_DEVICE_OPS
+#ifdef RT_USING_DEVICE_OPS
device->ops = driver->dev_ops;
-#endif
+#endif
device->dtb_node = node;
return RT_EOK;
-}
+}
RTM_EXPORT(rt_device_bind_driver);
/**