433 lines
11 KiB
C
433 lines
11 KiB
C
/*
|
|
* Copyright (c) 2020-2022, CQ 100ask Development Team
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2022-05-29 Alen first version
|
|
*/
|
|
|
|
#include "board.h"
|
|
#include "drv_uart.h"
|
|
#include "drv_config.h"
|
|
|
|
#ifdef RT_USING_SERIAL
|
|
|
|
//#define DRV_DEBUG
|
|
#define LOG_TAG "drv.usart"
|
|
|
|
#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)
|
|
#error "Please define at least one BSP_USING_UARTx"
|
|
/* this driver can be disabled at menuconfig -> RT-Thread Components -> Device Drivers */
|
|
#endif
|
|
|
|
#define __HAL_UART_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->CSR & (__FLAG__)) == (__FLAG__))
|
|
#define __HAL_UART_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->CSR = ~(__FLAG__))
|
|
#define __HAL_UART_GET_INT_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->ISR & (__FLAG__)) == (__FLAG__))
|
|
#define __HAL_UART_CLEAR_INT_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->ICR &= (__FLAG__))
|
|
|
|
enum
|
|
{
|
|
#ifdef BSP_USING_UART1
|
|
UART1_INDEX,
|
|
#endif
|
|
#ifdef BSP_USING_UART2
|
|
UART2_INDEX,
|
|
#endif
|
|
#ifdef BSP_USING_UART3
|
|
UART3_INDEX,
|
|
#endif
|
|
#ifdef BSP_USING_UART4
|
|
UART4_INDEX,
|
|
#endif
|
|
#ifdef BSP_USING_UART5
|
|
UART5_INDEX,
|
|
#endif
|
|
#ifdef BSP_USING_UART6
|
|
UART6_INDEX,
|
|
#endif
|
|
#ifdef BSP_USING_UART7
|
|
UART7_INDEX,
|
|
#endif
|
|
#ifdef BSP_USING_UART8
|
|
UART8_INDEX,
|
|
#endif
|
|
#ifdef BSP_USING_LPUART1
|
|
LPUART1_INDEX,
|
|
#endif
|
|
};
|
|
|
|
static struct mm32_uart_config uart_config[] =
|
|
{
|
|
#ifdef BSP_USING_UART1
|
|
UART1_CONFIG,
|
|
#endif
|
|
#ifdef BSP_USING_UART2
|
|
UART2_CONFIG,
|
|
#endif
|
|
#ifdef BSP_USING_UART3
|
|
UART3_CONFIG,
|
|
#endif
|
|
#ifdef BSP_USING_UART4
|
|
UART4_CONFIG,
|
|
#endif
|
|
#ifdef BSP_USING_UART5
|
|
UART5_CONFIG,
|
|
#endif
|
|
#ifdef BSP_USING_UART6
|
|
UART6_CONFIG,
|
|
#endif
|
|
#ifdef BSP_USING_UART7
|
|
UART7_CONFIG,
|
|
#endif
|
|
#ifdef BSP_USING_UART8
|
|
UART8_CONFIG,
|
|
#endif
|
|
#ifdef BSP_USING_LPUART1
|
|
LPUART1_CONFIG,
|
|
#endif
|
|
};
|
|
|
|
static struct mm32_uart uart_obj[sizeof(uart_config) / sizeof(uart_config[0])] = {0};
|
|
|
|
static rt_err_t mm32_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
|
|
{
|
|
struct mm32_uart *uart;
|
|
RT_ASSERT(serial != RT_NULL);
|
|
RT_ASSERT(cfg != RT_NULL);
|
|
|
|
uart = rt_container_of(serial, struct mm32_uart, serial);
|
|
uart->handle.ClockFreqHz = HAL_Get_APB2_Clock();
|
|
uart->handle.BaudRate = cfg->baud_rate;
|
|
uart->handle.XferMode = UART_XferMode_RxTx;
|
|
|
|
switch (cfg->flowcontrol)
|
|
{
|
|
case RT_SERIAL_FLOWCONTROL_NONE:
|
|
uart->handle.HwFlowControl = UART_HwFlowControl_None;
|
|
break;
|
|
case RT_SERIAL_FLOWCONTROL_CTSRTS:
|
|
uart->handle.HwFlowControl = UART_HwFlowControl_RTS_CTS;
|
|
break;
|
|
default:
|
|
uart->handle.HwFlowControl = UART_HwFlowControl_None;
|
|
break;
|
|
}
|
|
|
|
switch (cfg->data_bits)
|
|
{
|
|
case DATA_BITS_5:
|
|
uart->handle.WordLength = UART_WordLength_5b;
|
|
break;
|
|
case DATA_BITS_6:
|
|
uart->handle.WordLength = UART_WordLength_6b;
|
|
break;
|
|
case DATA_BITS_7:
|
|
uart->handle.WordLength = UART_WordLength_7b;
|
|
break;
|
|
case DATA_BITS_8:
|
|
uart->handle.WordLength = UART_WordLength_8b;
|
|
break;
|
|
default:
|
|
uart->handle.WordLength = UART_WordLength_8b;
|
|
break;
|
|
}
|
|
|
|
switch (cfg->stop_bits)
|
|
{
|
|
case STOP_BITS_1:
|
|
uart->handle.StopBits = UART_StopBits_1;
|
|
break;
|
|
case STOP_BITS_2:
|
|
uart->handle.StopBits = UART_StopBits_2;
|
|
break;
|
|
default:
|
|
uart->handle.StopBits = UART_StopBits_1;
|
|
break;
|
|
}
|
|
|
|
switch (cfg->parity)
|
|
{
|
|
case PARITY_NONE:
|
|
uart->handle.Parity = UART_Parity_None;
|
|
break;
|
|
case PARITY_ODD:
|
|
uart->handle.Parity = UART_Parity_Odd;
|
|
break;
|
|
case PARITY_EVEN:
|
|
uart->handle.Parity = UART_Parity_Even;
|
|
break;
|
|
default:
|
|
uart->handle.Parity = UART_Parity_None;
|
|
break;
|
|
}
|
|
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
if (!(serial->parent.open_flag & RT_DEVICE_OFLAG_OPEN)) {
|
|
uart->dma_rx.last_index = 0;
|
|
}
|
|
#endif
|
|
extern void UART_MspInit(UART_Type *muart);
|
|
UART_MspInit(uart->config->Instance);
|
|
UART_Init(uart->config->Instance, &uart->handle);
|
|
UART_Enable(uart->config->Instance, true);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t mm32_control(struct rt_serial_device *serial, int cmd, void *arg)
|
|
{
|
|
struct mm32_uart *uart;
|
|
rt_uint32_t prioritygroup = 0x00U;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
rt_ubase_t ctrl_arg = (rt_ubase_t)arg;
|
|
#endif
|
|
|
|
RT_ASSERT(serial != RT_NULL);
|
|
uart = rt_container_of(serial, struct mm32_uart, serial);
|
|
|
|
switch (cmd)
|
|
{
|
|
/* disable interrupt */
|
|
case RT_DEVICE_CTRL_CLR_INT:
|
|
/* disable rx irq */
|
|
NVIC_DisableIRQ(uart->config->irq_type);
|
|
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
/* disable DMA */
|
|
if (ctrl_arg == RT_DEVICE_FLAG_DMA_RX)
|
|
{
|
|
|
|
}
|
|
else if(ctrl_arg == RT_DEVICE_FLAG_DMA_TX)
|
|
{
|
|
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
/* enable interrupt */
|
|
case RT_DEVICE_CTRL_SET_INT:
|
|
/* enable rx irq */
|
|
UART_EnableInterrupts(uart->config->Instance, UART_INT_RX_DONE, true);
|
|
prioritygroup = NVIC_GetPriorityGrouping();
|
|
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(prioritygroup, 1, 0));
|
|
NVIC_EnableIRQ(uart->config->irq_type);
|
|
break;
|
|
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
case RT_DEVICE_CTRL_CONFIG:
|
|
|
|
break;
|
|
#endif
|
|
|
|
case RT_DEVICE_CTRL_CLOSE:
|
|
|
|
break;
|
|
|
|
}
|
|
return RT_EOK;
|
|
}
|
|
|
|
rt_uint32_t mm32_uart_get_mask(rt_uint32_t word_length, rt_uint32_t parity)
|
|
{
|
|
rt_uint32_t mask;
|
|
if (word_length == UART_WordLength_8b)
|
|
{
|
|
if (parity == UART_Parity_None)
|
|
{
|
|
mask = 0x00FFU ;
|
|
}
|
|
else
|
|
{
|
|
mask = 0x007FU ;
|
|
}
|
|
}
|
|
|
|
#ifdef UART_WORDLENGTH_7B
|
|
else if (word_length == UART_WordLength_7b)
|
|
{
|
|
if (parity == UART_Parity_None)
|
|
{
|
|
mask = 0x007FU ;
|
|
}
|
|
else
|
|
{
|
|
mask = 0x003FU ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mask = 0x0000U;
|
|
}
|
|
#endif
|
|
return mask;
|
|
}
|
|
|
|
static int mm32_putc(struct rt_serial_device *serial, char c)
|
|
{
|
|
struct mm32_uart *uart;
|
|
RT_ASSERT(serial != RT_NULL);
|
|
|
|
uart = rt_container_of(serial, struct mm32_uart, serial);
|
|
|
|
uart->config->Instance->TDR = c;
|
|
|
|
while ( 0u == (UART_STATUS_TX_EMPTY & UART_GetStatus(uart->config->Instance)) )
|
|
{}
|
|
return 1;
|
|
}
|
|
|
|
static int mm32_getc(struct rt_serial_device *serial)
|
|
{
|
|
int ch;
|
|
struct mm32_uart *uart;
|
|
RT_ASSERT(serial != RT_NULL);
|
|
uart = rt_container_of(serial, struct mm32_uart, serial);
|
|
|
|
ch = -1;
|
|
if ((UART_STATUS_RX_DONE & UART_GetStatus(uart->config->Instance)) != 0)
|
|
{
|
|
|
|
ch = uart->config->Instance->RDR & mm32_uart_get_mask(uart->handle.WordLength, uart->handle.Parity);
|
|
}
|
|
return ch;
|
|
}
|
|
|
|
/**
|
|
* Uart common interrupt process. This need add to uart ISR.
|
|
*
|
|
* @param serial serial device
|
|
*/
|
|
static void uart_isr(struct rt_serial_device *serial)
|
|
{
|
|
struct mm32_uart *uart;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
rt_size_t recv_total_index, recv_len;
|
|
rt_base_t level;
|
|
#endif
|
|
|
|
RT_ASSERT(serial != RT_NULL);
|
|
uart = rt_container_of(serial, struct mm32_uart, serial);
|
|
|
|
/* UART in mode Receiver -------------------------------------------------*/
|
|
if ( (0u != __HAL_UART_GET_INT_FLAG(uart->config->Instance, UART_INT_RX_DONE))
|
|
&& (0u != __HAL_UART_GET_FLAG(uart->config->Instance, UART_STATUS_RX_DONE)) )
|
|
{
|
|
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
|
|
}
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
|
|
#endif
|
|
else
|
|
{
|
|
if (__HAL_UART_GET_FLAG(uart->config->Instance, UART_STATUS_RX_DONE) != 0)
|
|
{
|
|
__HAL_UART_CLEAR_FLAG(uart->config->Instance, UART_STATUS_RX_DONE);
|
|
}
|
|
if (__HAL_UART_GET_FLAG(uart->config->Instance, UART_STATUS_TX_DONE) != 0)
|
|
{
|
|
__HAL_UART_CLEAR_FLAG(uart->config->Instance, UART_STATUS_TX_DONE);
|
|
}
|
|
if (__HAL_UART_GET_FLAG(uart->config->Instance, UART_STATUS_TX_FULL) != 0)
|
|
{
|
|
__HAL_UART_CLEAR_FLAG(uart->config->Instance, UART_STATUS_TX_FULL);
|
|
}
|
|
if (__HAL_UART_GET_FLAG(uart->config->Instance, UART_STATUS_TX_EMPTY) != 0)
|
|
{
|
|
__HAL_UART_CLEAR_FLAG(uart->config->Instance, UART_STATUS_TX_EMPTY);
|
|
}
|
|
|
|
if (__HAL_UART_GET_INT_FLAG(uart->config->Instance, UART_INT_RX_DONE) != 0)
|
|
{
|
|
__HAL_UART_CLEAR_INT_FLAG(uart->config->Instance, UART_INT_RX_DONE);
|
|
}
|
|
if (__HAL_UART_GET_INT_FLAG(uart->config->Instance, UART_INT_TX_DONE) != 0)
|
|
{
|
|
__HAL_UART_CLEAR_INT_FLAG(uart->config->Instance, UART_INT_TX_DONE);
|
|
}
|
|
if (__HAL_UART_GET_INT_FLAG(uart->config->Instance, UART_INT_TX_EMPTY) != 0)
|
|
{
|
|
__HAL_UART_CLEAR_INT_FLAG(uart->config->Instance, UART_INT_TX_EMPTY);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(BSP_USING_UART1)
|
|
void UART1_IRQHandler(void)
|
|
{
|
|
/* enter interrupt */
|
|
rt_interrupt_enter();
|
|
|
|
uart_isr(&(uart_obj[UART1_INDEX].serial));
|
|
|
|
/* leave interrupt */
|
|
rt_interrupt_leave();
|
|
}
|
|
#endif
|
|
|
|
|
|
#if defined(BSP_USING_UART2)
|
|
void UART2_IRQHandler(void)
|
|
{
|
|
/* enter interrupt */
|
|
rt_interrupt_enter();
|
|
|
|
uart_isr(&(uart_obj[UART2_INDEX].serial));
|
|
|
|
/* leave interrupt */
|
|
rt_interrupt_leave();
|
|
}
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART3)
|
|
void UART3_IRQHandler(void)
|
|
{
|
|
/* enter interrupt */
|
|
rt_interrupt_enter();
|
|
|
|
uart_isr(&(uart_obj[UART3_INDEX].serial));
|
|
|
|
/* leave interrupt */
|
|
rt_interrupt_leave();
|
|
}
|
|
#endif
|
|
|
|
static const struct rt_uart_ops mm32_uart_ops =
|
|
{
|
|
.configure = mm32_configure,
|
|
.control = mm32_control,
|
|
.putc = mm32_putc,
|
|
.getc = mm32_getc,
|
|
.dma_transmit = RT_NULL
|
|
};
|
|
|
|
int rt_hw_uart_init(void)
|
|
{
|
|
rt_size_t obj_num = sizeof(uart_obj) / sizeof(struct mm32_uart);
|
|
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
|
|
rt_err_t result = 0;
|
|
|
|
for (int i = 0; i < obj_num; i++)
|
|
{
|
|
/* init UART object */
|
|
uart_obj[i].config = &uart_config[i];
|
|
uart_obj[i].serial.ops = &mm32_uart_ops;
|
|
uart_obj[i].serial.config = config;
|
|
|
|
/* register UART device */
|
|
result = rt_hw_serial_register(&uart_obj[i].serial, uart_obj[i].config->name,
|
|
RT_DEVICE_FLAG_RDWR
|
|
| RT_DEVICE_FLAG_INT_RX
|
|
| RT_DEVICE_FLAG_INT_TX
|
|
| uart_obj[i].uart_dma_flag
|
|
, NULL);
|
|
RT_ASSERT(result == RT_EOK);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#endif /* RT_USING_SERIAL */
|