From e98df6977590f91fae79fd2b4a8d983ec47885d0 Mon Sep 17 00:00:00 2001 From: thewon86 Date: Wed, 22 Feb 2023 23:37:47 +0800 Subject: [PATCH] add serialX hardware driver for bluetrum gd32 n32 nuc980 renesas (#6952) add serialX hardware driver for bluetrum gd32 n32 nuc980 renesas --- bsp/bluetrum/libraries/hal_drivers/SConscript | 5 +- .../libraries/hal_drivers/drv_usartX.c | 348 +++++++ .../libraries/hal_drivers/drv_usartX.h | 40 + .../arm/libraries/gd32_drivers/SConscript | 5 +- .../arm/libraries/gd32_drivers/drv_usartX.c | 848 ++++++++++++++++++ .../arm/libraries/gd32_drivers/drv_usartX.h | 64 ++ bsp/n32/libraries/n32_drivers/SConscript | 2 + bsp/n32/libraries/n32_drivers/drv_usartX.c | 839 +++++++++++++++++ bsp/n32/libraries/n32_drivers/drv_usartX.h | 39 + .../libraries/nuc980/rtt_port/drv_common.c | 4 + .../libraries/nuc980/rtt_port/drv_uartX.c | 390 ++++++++ .../libraries/nuc980/rtt_port/drv_uartX.h | 79 ++ bsp/renesas/libraries/HAL_Drivers/SConscript | 2 + .../libraries/HAL_Drivers/drv_usartX.c | 625 +++++++++++++ .../libraries/HAL_Drivers/drv_usartX.h | 39 + src/device.c | 6 +- 16 files changed, 3330 insertions(+), 5 deletions(-) create mode 100644 bsp/bluetrum/libraries/hal_drivers/drv_usartX.c create mode 100644 bsp/bluetrum/libraries/hal_drivers/drv_usartX.h create mode 100644 bsp/gd32/arm/libraries/gd32_drivers/drv_usartX.c create mode 100644 bsp/gd32/arm/libraries/gd32_drivers/drv_usartX.h create mode 100644 bsp/n32/libraries/n32_drivers/drv_usartX.c create mode 100644 bsp/n32/libraries/n32_drivers/drv_usartX.h create mode 100644 bsp/nuvoton/libraries/nuc980/rtt_port/drv_uartX.c create mode 100644 bsp/nuvoton/libraries/nuc980/rtt_port/drv_uartX.h create mode 100644 bsp/renesas/libraries/HAL_Drivers/drv_usartX.c create mode 100644 bsp/renesas/libraries/HAL_Drivers/drv_usartX.h 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 + +#ifdef RT_USING_SERIAL + +//#define DRV_DEBUG +#define LOG_TAG "drv.usart" +#include + +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 +#include +#include + +#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 +#include +#include + +#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 +#include +#include +#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 #include #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 + +#ifdef RT_USING_SERIAL + +#include +#include "drv_uartX.h" +#include "drv_sys.h" + +//#define DRV_DEBUG +#define LOG_TAG "drv.uart" +// #include + +#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 +#include "rtdevice.h" +#include +#include +#include "NuMicro.h" +#include + +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 2c137fe107..12762f1ba3 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 + +#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 + +/* 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 +#include +#include +#include +#include +#include + +/* 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/src/device.c b/src/device.c index a0d7484aed..4eafb4e3ba 100644 --- a/src/device.c +++ b/src/device.c @@ -509,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); /**