rt-thread-official/bsp/hc32f460/drivers/drv_usart.c

528 lines
13 KiB
C

/*
* Copyright (C) 2021, lizhengyang
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-09-02 lizhengyang first version
*/
#include <rtdevice.h>
#include <rthw.h>
#include "drv_usart.h"
#include "board_config.h"
#ifdef RT_USING_SERIAL
#if !defined(BSP_USING_UART1) && !defined(BSP_USING_UART2) && !defined(BSP_USING_UART3) && !defined(BSP_USING_UART4)
#error "Please define at least one BSP_USING_UARTx"
/* UART instance can be selected at menuconfig -> Hardware Drivers Config -> On-chip Peripheral Drivers -> Enable UART */
#endif
/* HC32 config uart class */
struct hc32_uart_config
{
struct hc32_irq_config rxerr_irq_config;
struct hc32_irq_config rx_irq_config;
};
/* HC32 UART index */
struct uart_index
{
rt_uint32_t index;
M4_USART_TypeDef *Instance;
};
/* HC32 UART irq handler */
struct uart_irq_handler
{
void (*rxerr_irq_handler)(void);
void (*rx_irq_handler)(void);
};
/* HC32 uart dirver class */
struct hc32_uart
{
const char *name;
M4_USART_TypeDef *Instance;
struct hc32_uart_config config;
struct rt_serial_device serial;
};
#ifndef UART_CONFIG
#define UART_CONFIG(uart_name, USART) \
{ \
.name = uart_name, \
.Instance = M4_##USART, \
.config = { \
.rxerr_irq_config = { \
.irq = USART##_RXERR_INT_IRQn, \
.irq_prio = USART##_RXERR_INT_PRIO, \
.int_src = INT_##USART##_EI, \
}, \
.rx_irq_config = { \
.irq = USART##_RX_INT_IRQn, \
.irq_prio = USART##_RX_INT_PRIO, \
.int_src = INT_##USART##_RI, \
}, \
}, \
}
#endif /* UART_CONFIG */
enum
{
#ifdef BSP_USING_UART1
UART1_INDEX,
#endif
#ifdef BSP_USING_UART2
UART2_INDEX,
#endif
#ifdef BSP_USING_UART3
UART3_INDEX,
#endif
#ifdef BSP_USING_UART4
UART4_INDEX,
#endif
UART_INDEX_MAX,
};
static const struct uart_index uart_map[] =
{
#ifdef BSP_USING_UART1
{UART1_INDEX, M4_USART1},
#endif
#ifdef BSP_USING_UART2
{UART2_INDEX, M4_USART2},
#endif
#ifdef BSP_USING_UART3
{UART3_INDEX, M4_USART3},
#endif
#ifdef BSP_USING_UART4
{UART4_INDEX, M4_USART4},
#endif
};
static const struct uart_index uart_clock_map[] =
{
#ifdef BSP_USING_UART1
{0, M4_USART1},
#endif
#ifdef BSP_USING_UART2
{1, M4_USART2},
#endif
#ifdef BSP_USING_UART3
{2, M4_USART3},
#endif
#ifdef BSP_USING_UART4
{3, M4_USART4},
#endif
};
static struct hc32_uart uart_obj[] =
{
#ifdef BSP_USING_UART1
UART_CONFIG("uart1", USART1),
#endif
#ifdef BSP_USING_UART2
UART_CONFIG("uart2", USART2),
#endif
#ifdef BSP_USING_UART3
UART_CONFIG("uart3", USART3),
#endif
#ifdef BSP_USING_UART4
UART_CONFIG("uart4", USART4),
#endif
};
static const struct uart_irq_handler uart_irq_handlers[sizeof(uart_obj) / sizeof(uart_obj[0])];
static uint32_t hc32_get_uart_index(M4_USART_TypeDef *Instance)
{
uint32_t index = UART_INDEX_MAX;
for (uint8_t i = 0U; i < ARRAY_SZ(uart_map); i++)
{
if (uart_map[i].Instance == Instance)
{
index = uart_map[i].index;
RT_ASSERT(index < UART_INDEX_MAX)
break;
}
}
return index;
}
static uint32_t hc32_get_uart_clock_index(M4_USART_TypeDef *Instance)
{
uint32_t index = 4;
for (uint8_t i = 0U; i < ARRAY_SZ(uart_clock_map); i++)
{
if (uart_clock_map[i].Instance == Instance)
{
index = uart_clock_map[i].index;
RT_ASSERT(index < 4)
break;
}
}
return index;
}
static uint32_t hc32_get_usart_fcg(M4_USART_TypeDef *Instance)
{
return (PWC_FCG1_PERIPH_USART1 << hc32_get_uart_clock_index(Instance));
}
static rt_err_t hc32_configure(struct rt_serial_device *serial,
struct serial_configure *cfg)
{
struct hc32_uart *uart;
stc_usart_uart_init_t uart_init;
RT_ASSERT(RT_NULL != cfg);
RT_ASSERT(RT_NULL != serial);
uart = rt_container_of(serial, struct hc32_uart, serial);
RT_ASSERT(RT_NULL != uart->Instance);
/* Configure USART initialization structure */
MEM_ZERO_STRUCT(uart_init);
uart_init.enSampleMode = UsartSampleBit8;
uart_init.enSampleMode = UsartSampleBit8;
uart_init.enDetectMode = UsartStartBitFallEdge;
uart_init.enHwFlow = UsartRtsEnable;
uart_init.enClkMode = UsartIntClkCkNoOutput;
uart_init.enClkDiv = UsartClkDiv_1;
if (BIT_ORDER_LSB == cfg->bit_order)
{
uart_init.enDirection = UsartDataLsbFirst;
}
else
{
uart_init.enDirection = UsartDataMsbFirst;
}
switch (cfg->stop_bits)
{
case STOP_BITS_1:
uart_init.enStopBit = UsartOneStopBit;
break;
case STOP_BITS_2:
uart_init.enStopBit = UsartTwoStopBit;
break;
default:
uart_init.enStopBit = UsartOneStopBit;
break;
}
switch (cfg->parity)
{
case PARITY_NONE:
uart_init.enParity = UsartParityNone;
break;
case PARITY_EVEN:
uart_init.enParity = UsartParityEven;
break;
case PARITY_ODD:
uart_init.enParity = UsartParityOdd;
break;
default:
uart_init.enParity = UsartParityNone;
break;
}
switch (cfg->data_bits)
{
case DATA_BITS_8:
uart_init.enDataLength = UsartDataBits8;
break;
default:
return -RT_ERROR;
}
/* Enable USART clock */
PWC_Fcg1PeriphClockCmd(hc32_get_usart_fcg(uart->Instance), Enable);
rt_err_t rt_hw_board_uart_init(M4_USART_TypeDef * USARTx);
if (RT_EOK != rt_hw_board_uart_init(uart->Instance))
{
return -RT_ERROR;
}
USART_DeInit(uart->Instance);
if (Error == USART_UART_Init(uart->Instance, &uart_init))
{
return -RT_ERROR;
}
USART_SetBaudrate(uart->Instance, cfg->baud_rate);
if (RT_EOK != USART_SetBaudrate(uart->Instance, cfg->baud_rate))
{
return -RT_ERROR;
}
/* Register RX error interrupt */
hc32_install_irq_handler(&uart->config.rxerr_irq_config,
uart_irq_handlers[hc32_get_uart_index(uart->Instance)].rxerr_irq_handler,
RT_TRUE);
USART_FuncCmd(uart->Instance, UsartRxInt, Enable);
if ((serial->parent.flag & RT_DEVICE_FLAG_RDWR) || \
(serial->parent.flag & RT_DEVICE_FLAG_RDONLY))
{
USART_FuncCmd(uart->Instance, UsartRx, Enable);
}
if ((serial->parent.flag & RT_DEVICE_FLAG_RDWR) || \
(serial->parent.flag & RT_DEVICE_FLAG_WRONLY))
{
USART_FuncCmd(uart->Instance, UsartTx, Enable);
}
return RT_EOK;
}
static rt_err_t hc32_control(struct rt_serial_device *serial, int cmd, void *arg)
{
struct hc32_uart *uart;
uint32_t uart_index;
RT_ASSERT(RT_NULL != serial);
uart = rt_container_of(serial, struct hc32_uart, serial);
RT_ASSERT(RT_NULL != uart->Instance);
switch (cmd)
{
/* Disable interrupt */
case RT_DEVICE_CTRL_CLR_INT:
/* Disable RX irq */
NVIC_DisableIRQ(uart->config.rx_irq_config.irq);
enIrqResign(uart->config.rx_irq_config.irq);
break;
/* Enable interrupt */
case RT_DEVICE_CTRL_SET_INT:
uart_index = hc32_get_uart_index(uart->Instance);
/* Install RX irq handler */
hc32_install_irq_handler(&uart->config.rx_irq_config,
uart_irq_handlers[uart_index].rx_irq_handler,
RT_TRUE);
break;
}
return RT_EOK;
}
static int hc32_putc(struct rt_serial_device *serial, char c)
{
struct hc32_uart *uart;
RT_ASSERT(RT_NULL != serial);
uart = rt_container_of(serial, struct hc32_uart, serial);
RT_ASSERT(RT_NULL != uart->Instance);
USART_SendData(uart->Instance, c);
/* Polling mode. */
while (USART_GetStatus(uart->Instance, UsartTxEmpty) != Set);
return 1;
}
static int hc32_getc(struct rt_serial_device *serial)
{
int ch = -1;
struct hc32_uart *uart;
RT_ASSERT(RT_NULL != serial);
uart = rt_container_of(serial, struct hc32_uart, serial);
RT_ASSERT(RT_NULL != uart->Instance);
if (Set == USART_GetStatus(uart->Instance, UsartRxNoEmpty))
{
ch = (rt_uint8_t)USART_RecData(uart->Instance);
}
return ch;
}
static void hc32_uart_rx_irq_handler(struct hc32_uart *uart)
{
RT_ASSERT(RT_NULL != uart);
rt_hw_serial_isr(&uart->serial, RT_SERIAL_EVENT_RX_IND);
}
static void hc32_uart_rxerr_irq_handler(struct hc32_uart *uart)
{
RT_ASSERT(RT_NULL != uart);
RT_ASSERT(RT_NULL != uart->Instance);
if (Set == USART_GetStatus(uart->Instance, UsartParityErr) || \
Set == USART_GetStatus(uart->Instance, UsartFrameErr))
{
USART_RecData(uart->Instance);
}
USART_ClearStatus(uart->Instance, UsartParityErr);
USART_ClearStatus(uart->Instance, UsartFrameErr);
USART_ClearStatus(uart->Instance, UsartOverrunErr);
}
#if defined(BSP_USING_UART1)
static void hc32_uart1_rx_irq_handler(void)
{
/* enter interrupt */
rt_interrupt_enter();
hc32_uart_rx_irq_handler(&uart_obj[UART1_INDEX]);
/* leave interrupt */
rt_interrupt_leave();
}
static void hc32_uart1_rxerr_irq_handler(void)
{
/* enter interrupt */
rt_interrupt_enter();
hc32_uart_rxerr_irq_handler(&uart_obj[UART1_INDEX]);
/* leave interrupt */
rt_interrupt_leave();
}
#endif /* BSP_USING_UART1 */
#if defined(BSP_USING_UART2)
static void hc32_uart2_rx_irq_handler(void)
{
/* enter interrupt */
rt_interrupt_enter();
hc32_uart_rx_irq_handler(&uart_obj[UART2_INDEX]);
/* leave interrupt */
rt_interrupt_leave();
}
static void hc32_uart2_rxerr_irq_handler(void)
{
/* enter interrupt */
rt_interrupt_enter();
hc32_uart_rxerr_irq_handler(&uart_obj[UART2_INDEX]);
/* leave interrupt */
rt_interrupt_leave();
}
#endif /* BSP_USING_UART2 */
#if defined(BSP_USING_UART3)
static void hc32_uart3_rx_irq_handler(void)
{
/* enter interrupt */
rt_interrupt_enter();
hc32_uart_rx_irq_handler(&uart_obj[UART3_INDEX]);
/* leave interrupt */
rt_interrupt_leave();
}
static void hc32_uart3_rxerr_irq_handler(void)
{
/* enter interrupt */
rt_interrupt_enter();
hc32_uart_rxerr_irq_handler(&uart_obj[UART3_INDEX]);
/* leave interrupt */
rt_interrupt_leave();
}
#endif /* BSP_USING_UART3 */
#if defined(BSP_USING_UART4)
static void hc32_uart4_rx_irq_handler(void)
{
/* enter interrupt */
rt_interrupt_enter();
hc32_uart_rx_irq_handler(&uart_obj[UART4_INDEX]);
/* leave interrupt */
rt_interrupt_leave();
}
static void hc32_uart4_rxerr_irq_handler(void)
{
/* enter interrupt */
rt_interrupt_enter();
hc32_uart_rxerr_irq_handler(&uart_obj[UART4_INDEX]);
/* leave interrupt */
rt_interrupt_leave();
}
#endif /* BSP_USING_UART4 */
static const struct uart_irq_handler uart_irq_handlers[] =
{
#ifdef BSP_USING_UART1
{hc32_uart1_rxerr_irq_handler, hc32_uart1_rx_irq_handler},
#endif
#ifdef BSP_USING_UART2
{hc32_uart2_rxerr_irq_handler, hc32_uart2_rx_irq_handler},
#endif
#ifdef BSP_USING_UART3
{hc32_uart3_rxerr_irq_handler, hc32_uart3_rx_irq_handler},
#endif
#ifdef BSP_USING_UART4
{hc32_uart4_rxerr_irq_handler, hc32_uart4_rx_irq_handler},
#endif
};
static const struct rt_uart_ops hc32_uart_ops =
{
.configure = hc32_configure,
.control = hc32_control,
.putc = hc32_putc,
.getc = hc32_getc,
};
int hc32_hw_uart_init(void)
{
rt_err_t result = RT_EOK;
rt_size_t obj_num = sizeof(uart_obj) / sizeof(struct hc32_uart);
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
for (int i = 0; i < obj_num; i++)
{
/* init UART object */
uart_obj[i].serial.ops = &hc32_uart_ops;
uart_obj[i].serial.config = config;
/* register UART device */
result = rt_hw_serial_register(&uart_obj[i].serial,
uart_obj[i].name,
(RT_DEVICE_FLAG_RDWR |
RT_DEVICE_FLAG_INT_RX |
RT_DEVICE_FLAG_INT_TX),
&uart_obj[i]);
RT_ASSERT(result == RT_EOK);
}
return result;
}
INIT_BOARD_EXPORT(hc32_hw_uart_init);
#endif