4
0
mirror of https://github.com/RT-Thread/rt-thread.git synced 2025-03-04 09:55:29 +08:00
thewon86 e98df69775
add serialX hardware driver for bluetrum gd32 n32 nuc980 renesas (#6952)
add serialX hardware driver for bluetrum gd32 n32 nuc980 renesas
2023-02-22 10:37:47 -05:00

391 lines
9.8 KiB
C

/*
* 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 */