319 lines
7.9 KiB
C
319 lines
7.9 KiB
C
/*
|
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2022/12/25 flyingcys first version
|
|
*/
|
|
|
|
#include <rthw.h>
|
|
#include <rtthread.h>
|
|
#include <rtdevice.h>
|
|
|
|
#include "board.h"
|
|
#include "drv_uart.h"
|
|
|
|
|
|
struct device_uart
|
|
{
|
|
struct rt_serial_device serial;
|
|
uint8_t port;
|
|
uint8_t tx_pin;
|
|
uint8_t rx_pin;
|
|
};
|
|
|
|
static void _uart_rx_irq(void *param)
|
|
{
|
|
struct device_uart *uart = (struct device_uart *)param;;
|
|
|
|
struct rt_serial_device *serial = &uart->serial;
|
|
|
|
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
|
|
}
|
|
|
|
static int uart_signal_get(uint8_t pin)
|
|
{
|
|
//TODO no magic number is allowed here
|
|
if (pin >= 12 && pin <=23) {
|
|
return (pin + 6) % 12;
|
|
} else if (pin >= 36 && pin <=45) {
|
|
return (pin + 6) % 12;
|
|
}
|
|
return (pin % 12);
|
|
}
|
|
|
|
static int uart_func_get(uint8_t id, GLB_UART_SIG_FUN_Type uartfunc)
|
|
{
|
|
switch (id) {
|
|
case 0:
|
|
return uartfunc;
|
|
case 1:
|
|
return (GLB_UART_SIG_FUN_UART1_RTS - GLB_UART_SIG_FUN_UART0_RTS) * 1 + uartfunc;
|
|
case 2:
|
|
return (GLB_UART_SIG_FUN_UART1_RTS - GLB_UART_SIG_FUN_UART0_RTS) * 1 + uartfunc;
|
|
default:
|
|
/*empty here*/
|
|
//TODO should assert here?
|
|
return uartfunc;
|
|
}
|
|
}
|
|
static void uart_gpio_demo(uint8_t id, uint8_t tx_pin, uint8_t rx_pin, uint8_t cts_pin, uint8_t rts_pin)
|
|
{
|
|
GLB_GPIO_Cfg_Type gpio_cfg;
|
|
uint8_t uart_func, uart_sig;
|
|
|
|
//FIXME SWAP set is NOT put here
|
|
GLB_UART_Sig_Swap_Set(GLB_UART_SIG_SWAP_GRP_GPIO12_GPIO23, 1);
|
|
GLB_UART_Sig_Swap_Set(GLB_UART_SIG_SWAP_GRP_GPIO36_GPIO45, 1);
|
|
|
|
//common GPIO cfg
|
|
gpio_cfg.drive = 0;
|
|
gpio_cfg.smtCtrl = 1;
|
|
gpio_cfg.gpioMode = GPIO_MODE_AF;
|
|
gpio_cfg.pullType = GPIO_PULL_UP;
|
|
gpio_cfg.gpioFun = GPIO_FUN_UART;
|
|
|
|
//cfg for UART Tx
|
|
gpio_cfg.gpioPin = GLB_GPIO_PIN_0 + tx_pin;
|
|
uart_func = uart_func_get(id, GLB_UART_SIG_FUN_UART0_TXD);
|
|
uart_sig = uart_signal_get(gpio_cfg.gpioPin);
|
|
GLB_UART_Fun_Sel((GLB_UART_SIG_Type)uart_sig, (GLB_UART_SIG_FUN_Type)uart_func);
|
|
GLB_UART_Fun_Sel((GLB_UART_SIG_Type)uart_func, (GLB_UART_SIG_FUN_Type)uart_sig);
|
|
GLB_GPIO_Init(&gpio_cfg);
|
|
|
|
//cfg for UART Rx
|
|
gpio_cfg.gpioPin = GLB_GPIO_PIN_0 + rx_pin;
|
|
uart_func = uart_func_get(id, GLB_UART_SIG_FUN_UART0_RXD);
|
|
uart_sig = uart_signal_get(gpio_cfg.gpioPin);
|
|
GLB_UART_Fun_Sel((GLB_UART_SIG_Type)uart_sig, (GLB_UART_SIG_FUN_Type)uart_func);
|
|
GLB_UART_Fun_Sel((GLB_UART_SIG_Type)uart_func, (GLB_UART_SIG_FUN_Type)uart_sig);
|
|
GLB_GPIO_Init(&gpio_cfg);
|
|
|
|
//Enable UART clock
|
|
GLB_Set_UART_CLK(1, 0, 0);
|
|
}
|
|
|
|
static rt_err_t _uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
|
|
{
|
|
struct device_uart *uart;
|
|
uint8_t id;
|
|
|
|
RT_ASSERT(serial != RT_NULL);
|
|
RT_ASSERT(cfg != RT_NULL);
|
|
|
|
uart = serial->parent.user_data;
|
|
RT_ASSERT(uart != RT_NULL);
|
|
|
|
id = uart->port;
|
|
|
|
UART_CFG_Type uart_cfg = {
|
|
80*1000*1000, /*UART clock from XTAL*/
|
|
2000000, /* baudrate */
|
|
UART_DATABITS_8, /* data bits */
|
|
UART_STOPBITS_1, /* stop bits */
|
|
UART_PARITY_NONE, /* parity */
|
|
DISABLE, /* Disable auto flow control */
|
|
DISABLE, /* Disable rx input de-glitch function */
|
|
DISABLE, /* Disable RTS output SW control mode */
|
|
DISABLE, /* Disable tx output SW control mode */
|
|
DISABLE, /* Disable tx lin mode */
|
|
DISABLE, /* Disable rx lin mode */
|
|
0, /* Tx break bit count for lin mode */
|
|
UART_LSB_FIRST, /* UART each data byte is send out LSB-first */
|
|
};
|
|
|
|
UART_FifoCfg_Type fifoCfg = {
|
|
16, /* TX FIFO threshold */
|
|
16, /* RX FIFO threshold */
|
|
DISABLE, /* Disable tx dma req/ack interface */
|
|
DISABLE /* Disable rx dma req/ack interface */
|
|
};
|
|
|
|
/* init debug uart gpio first */
|
|
uart_gpio_demo(id, uart->tx_pin, uart->rx_pin, 0xff, 0xff);
|
|
|
|
/* disable all interrupt */
|
|
UART_IntMask(id, UART_INT_ALL, MASK);
|
|
|
|
/* disable uart before config */
|
|
UART_Disable(id, UART_TXRX);
|
|
|
|
uart_cfg.baudRate = cfg->baud_rate;
|
|
|
|
switch (cfg->data_bits)
|
|
{
|
|
case DATA_BITS_5:
|
|
uart_cfg.dataBits = UART_DATABITS_5;
|
|
break;
|
|
|
|
case DATA_BITS_6:
|
|
uart_cfg.dataBits = UART_DATABITS_6;
|
|
break;
|
|
|
|
case DATA_BITS_7:
|
|
uart_cfg.dataBits = UART_DATABITS_7;
|
|
break;
|
|
|
|
case DATA_BITS_8:
|
|
uart_cfg.dataBits = UART_DATABITS_8;
|
|
break;
|
|
|
|
default:
|
|
uart_cfg.dataBits = UART_DATABITS_8;
|
|
break;
|
|
}
|
|
|
|
switch (cfg->stop_bits)
|
|
{
|
|
case STOP_BITS_1:
|
|
uart_cfg.stopBits = UART_STOPBITS_1;
|
|
break;
|
|
|
|
case STOP_BITS_2:
|
|
uart_cfg.stopBits = UART_STOPBITS_2;
|
|
break;
|
|
|
|
default:
|
|
uart_cfg.stopBits = UART_STOPBITS_1;
|
|
break;
|
|
}
|
|
|
|
switch (cfg->parity)
|
|
{
|
|
case PARITY_NONE:
|
|
uart_cfg.parity = UART_PARITY_NONE;
|
|
break;
|
|
|
|
case PARITY_ODD:
|
|
uart_cfg.parity = UART_PARITY_ODD;
|
|
break;
|
|
|
|
case PARITY_EVEN:
|
|
uart_cfg.parity = UART_PARITY_EVEN;
|
|
break;
|
|
|
|
default:
|
|
uart_cfg.parity = UART_PARITY_NONE;
|
|
break;
|
|
}
|
|
|
|
/* uart init with configuration */
|
|
UART_Init(id, &uart_cfg);
|
|
|
|
/* UART fifo configuration */
|
|
UART_FifoConfig(id, &fifoCfg);
|
|
|
|
/* Enable tx free run mode */
|
|
UART_TxFreeRun(id, ENABLE);
|
|
|
|
/* Set rx time-out value */
|
|
UART_SetRxTimeoutValue(id, UART_DEFAULT_RTO_TIMEOUT);
|
|
|
|
/* enable uart */
|
|
UART_AutoBaudDetection(id, 0);
|
|
UART_Enable(id, UART_TXRX);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t _uart_control(struct rt_serial_device *serial, int cmd, void *arg)
|
|
{
|
|
struct device_uart *uart;
|
|
|
|
RT_ASSERT(serial != RT_NULL);
|
|
|
|
uart = serial->parent.user_data;
|
|
RT_ASSERT(uart != RT_NULL);
|
|
|
|
switch (cmd)
|
|
{
|
|
/* disable interrupt */
|
|
case RT_DEVICE_CTRL_CLR_INT:
|
|
bl_uart_int_disable(uart->port);
|
|
bl_uart_int_rx_notify_unregister(uart->port, _uart_rx_irq, uart);
|
|
break;
|
|
|
|
/* enable interrupt */
|
|
case RT_DEVICE_CTRL_SET_INT:
|
|
bl_uart_int_rx_notify_register(uart->port, _uart_rx_irq, uart);
|
|
bl_uart_int_enable(uart->port);
|
|
break;
|
|
}
|
|
return RT_EOK;
|
|
}
|
|
|
|
static int _uart_putc(struct rt_serial_device *serial, char c)
|
|
{
|
|
struct device_uart *uart;
|
|
|
|
RT_ASSERT(serial != RT_NULL);
|
|
|
|
uart = serial->parent.user_data;
|
|
RT_ASSERT(uart != RT_NULL);
|
|
|
|
bl_uart_data_send(uart->port, c);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int _uart_getc(struct rt_serial_device *serial)
|
|
{
|
|
int ch = -1;
|
|
struct device_uart *uart;
|
|
|
|
RT_ASSERT(serial != RT_NULL);
|
|
uart = serial->parent.user_data;
|
|
RT_ASSERT(uart != RT_NULL);
|
|
|
|
ch = bl_uart_data_recv(uart->port);
|
|
|
|
return ch;
|
|
}
|
|
|
|
static const struct rt_uart_ops _uart_ops =
|
|
{
|
|
.configure = _uart_configure,
|
|
.control = _uart_control,
|
|
.putc = _uart_putc,
|
|
.getc = _uart_getc,
|
|
.dma_transmit = RT_NULL
|
|
};
|
|
|
|
/*
|
|
* UART Initiation
|
|
*/
|
|
int rt_hw_uart_init(void)
|
|
{
|
|
rt_err_t result = 0;
|
|
|
|
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
|
|
struct rt_serial_device *serial;
|
|
struct device_uart *uart;
|
|
|
|
#ifdef BSP_USING_UART0
|
|
static struct device_uart uart0;
|
|
|
|
serial = &uart0.serial;
|
|
uart = &uart0;
|
|
|
|
serial->ops = &_uart_ops;
|
|
serial->config = config;
|
|
serial->config.baud_rate = 2000000;
|
|
|
|
uart->port = 0;
|
|
uart->tx_pin = BSP_UART0_TXD_PIN;
|
|
uart->rx_pin = BSP_UART0_RXD_PIN;
|
|
|
|
/* register USART device */
|
|
result = rt_hw_serial_register(serial,
|
|
"uart0",
|
|
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
|
|
uart);
|
|
RT_ASSERT(result == RT_EOK);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|