Files
TencentOS-tiny/board/EVB_LN882x/BSP/Src/serial_hw.c
supowang 875a14aaf0 add EVB_LN822x iot exporer demo
add EVB_LN822x  iot exporer demo
2020-06-19 11:10:17 +08:00

416 lines
13 KiB
C

#include "proj_config.h"
#include "ln88xx.h"
#include "serial/serial.h"
#include "hal/hal_syscon.h"
#include "hal/hal_uart.h"
//#include "hal/hal_sleep.h"
#include "utils/debug/art_assert.h"
#define UART0_TX_BUF_SIZE CFG_UART0_TX_BUF_SIZE
#define UART0_RX_BUF_SIZE CFG_UART0_RX_BUF_SIZE
#define UART1_TX_BUF_SIZE CFG_UART1_TX_BUF_SIZE
#define UART1_RX_BUF_SIZE CFG_UART1_RX_BUF_SIZE
/* From the high-level serial driver */
extern Serial_t serial_handles[SER_PORT_NUM];
/* TX and RX buffers */
unsigned char uart0_txbuffer[UART0_TX_BUF_SIZE];
unsigned char uart0_rxbuffer[UART0_RX_BUF_SIZE];
unsigned char uart1_txbuffer[UART1_TX_BUF_SIZE];
unsigned char uart1_rxbuffer[UART1_RX_BUF_SIZE];
/* UART device*/
UART_DevTypeDef g_huart0,g_huart1;
/**
* Internal state structure
*/
struct ARTSerial
{
struct SerialHardware Hardware;
struct Serial *serial;
};
struct ARTSerial UARTDescs[SER_PORT_NUM];
static void uart0_SendDataIrqCallback(uint8_t *ch);
static void uart0_RecvDataIrqCallback(uint8_t *ch);
static void uart1_SendDataIrqCallback(uint8_t *ch);
static void uart1_RecvDataIrqCallback(uint8_t *ch);
/*
* ***************************** Port IO Config ******************************
*/
static void uart_io_pin_request(struct Serial *serial)
{
int en = 1;
ART_ASSERT(serial);
if(serial->port_id == SER_PORT_UART0){
#if defined (LN881x)
HAL_SYSCON_FuncIOSet(GPIO_AF_UART0_RX, GPIO_AF_IO_0, en);
HAL_SYSCON_FuncIOSet(GPIO_AF_UART0_TX, GPIO_AF_IO_1, en);
#elif defined (LN882x)
HAL_SYSCON_FuncIOSet(GPIO_AF_UART0_RX, GPIO_AF_IO_18, en); //LN882x: GPIO_A[8], FULL_MUX_18, PAD24 [rom_uart0 RX]
HAL_SYSCON_FuncIOSet(GPIO_AF_UART0_TX, GPIO_AF_IO_19, en); //LN882x: GPIO_A[9], FULL_MUX_19, PAD25 [rom_uart0 TX]
#else
#error Add your bord type!!!
#endif
}else if(serial->port_id == SER_PORT_UART1){
#if defined (LN881x)
// EVB V2 引脚更改了
HAL_SYSCON_FuncIOSet(GPIO_AF_UART1_RX, GPIO_AF_IO_2, en);
HAL_SYSCON_FuncIOSet(GPIO_AF_UART1_TX, GPIO_AF_IO_4, en);
#elif defined (LN882x)
//TODO:待最终demo板确认
//HAL_SYSCON_FuncIOSet(GPIO_AF_UART1_RX, GPIO_AF_IO_15, en);//LN882x FPGA: GPIO_1[5], FULL_MUX_15, PAD21
//HAL_SYSCON_FuncIOSet(GPIO_AF_UART1_TX, GPIO_AF_IO_16, en);//LN882x FPGA: GPIO_1[6], FULL_MUX_16, PAD22
#if 0//LN8826CT
HAL_SYSCON_FuncIOSet(GPIO_AF_UART1_RX, GPIO_AF_IO_8, en);//LN8826CT EVB: GPIOA8 GPIO_0[8], FULL_MUX_08, PAD08
HAL_SYSCON_FuncIOSet(GPIO_AF_UART1_TX, GPIO_AF_IO_9, en);//LN8826CT EVB: GPIOA9 GPIO_0[9], FULL_MUX_09, PAD09
#else //LN8820 or LN8825
HAL_SYSCON_FuncIOSet(GPIO_AF_UART1_RX, GPIO_AF_IO_16, en);//LN8820 (LN8825) &BLE EVB: GPIOB6, FULL_MUX_16, Pin31
HAL_SYSCON_FuncIOSet(GPIO_AF_UART1_TX, GPIO_AF_IO_17, en);//LN8820 (LN8825) &BLE EVB: GPIOB7, FULL_MUX_17, Pin32
#endif
#else
#error Add your bord type!!!
#endif
}
}
static void uart_io_pin_release(struct Serial *serial)
{
int en = 0;
ART_ASSERT(serial);
if(serial->port_id == SER_PORT_UART0){
#if defined (LN881x)
HAL_SYSCON_FuncIOSet(GPIO_AF_UART0_RX, GPIO_AF_IO_0, en);
HAL_SYSCON_FuncIOSet(GPIO_AF_UART0_TX, GPIO_AF_IO_1, en);
#elif defined (LN882x)
HAL_SYSCON_FuncIOSet(GPIO_AF_UART0_RX, GPIO_AF_IO_18, en);//LN882x: GPIO_1[8], FULL_MUX_18, PAD24 [rom_uart0 RX]
HAL_SYSCON_FuncIOSet(GPIO_AF_UART0_TX, GPIO_AF_IO_19, en);//LN882x: GPIO_1[9], FULL_MUX_19, PAD25 [rom_uart0 TX]
#else
#error Add your bord type!!!
#endif
}else if(serial->port_id == SER_PORT_UART1){
#if defined (LN881x)
// EVB V2 引脚更改了
HAL_SYSCON_FuncIOSet(GPIO_AF_UART1_RX, GPIO_AF_IO_2, en);
HAL_SYSCON_FuncIOSet(GPIO_AF_UART1_TX, GPIO_AF_IO_4, en);
#elif defined (LN882x)
//TODO:待最终demo板确认
HAL_SYSCON_FuncIOSet(GPIO_AF_UART1_RX, GPIO_AF_IO_15, en);//LN882x: GPIO_1[5], FULL_MUX_15, PAD21
HAL_SYSCON_FuncIOSet(GPIO_AF_UART1_TX, GPIO_AF_IO_16, en);//LN882x: GPIO_1[6], FULL_MUX_16, PAD22
#else
#error Add your bord type!!!
#endif
}
}
/*
* ***************************** Device Init ******************************
*/
static void hw_uart0_init(struct SerialHardware *_hw, struct Serial *serial, uint32_t baudrate)
{
struct ARTSerial *hw = NULL;
ART_ASSERT(_hw && serial);
hw = (struct ARTSerial *)_hw;
hw->serial = serial;
g_huart0.Instance = UART0;
g_huart0.Config.BaudRate = baudrate;//115200 921600 2000000
g_huart0.Config.DataLength = UART_DATALEN_8BIT;
g_huart0.Config.Parity = UART_PARITY_NONE;
g_huart0.Config.StopBits = UART_STOP_BIT_1;
g_huart0.Config.FlowControl = UART_FLOW_CONTROL_SOFTWARE;
//request pin for uart
uart_io_pin_request(hw->serial);
//init uart hardware
HAL_UART_Init(&g_huart0);
//config tx/rx trigger
HAL_UART_FIFOControl(&g_huart0, UART_TX_EMPTY_TRIGGER_FIFO_EMPTY, UART_RCVR_TRIGGER_FIFO_HAS_ONE_CHARACTER, UART_DMA_MODE0);
//enable RX interrupt if necessary
HAL_UART_INT_Switch_RecvDataAvailable(&g_huart0, 1);
//enable TX interrupt if necessary
// hal_uart_xfer_data_interrupt(_hw->hw_addr, 1);
//Enable Receiver Line Status Interrupt if necessary
HAL_UART_INT_Switch_RecvLineStatus(&g_huart0, 1);
//Enable Modem Status Interrupt if necessary
//hal_uart_modem_status_interrupt(_hw->hw_addr, 1);
//Enable Programmable THRE Interrupt if necessary
// hal_uart_thre_interrupt(_hw->hw_addr, 1);
HAL_UART_SetIsrRecvCharCallback(g_huart0.Instance, uart0_RecvDataIrqCallback);
HAL_UART_SetIsrSendCharCallback(g_huart0.Instance, uart0_SendDataIrqCallback);
//enable uart master switch
NVIC_EnableIRQ(UART0_IRQn);
/*
* Register with the sleep module to ensure that the serial port can be used during Light sleep
*/
// hal_sleep_register(MOD_UART0, NULL, NULL, NULL);
}
static void hw_uart1_init(struct SerialHardware *_hw, struct Serial *serial, uint32_t baudrate)
{
struct ARTSerial *hw = NULL;
ART_ASSERT(_hw && serial);
hw = (struct ARTSerial *)_hw;
hw->serial = serial;
g_huart1.Instance = UART1;
g_huart1.Config.BaudRate = baudrate;//115200, 921600
g_huart1.Config.DataLength = UART_DATALEN_8BIT;
g_huart1.Config.Parity = UART_PARITY_NONE;
g_huart1.Config.StopBits = UART_STOP_BIT_1;
g_huart1.Config.FlowControl = UART_FLOW_CONTROL_SOFTWARE;
//request pin for uart
uart_io_pin_request(hw->serial);
//init uart hardware
HAL_UART_Init(&g_huart1);
//config tx/rx trigger
HAL_UART_FIFOControl(&g_huart1, UART_TX_EMPTY_TRIGGER_FIFO_EMPTY, UART_RCVR_TRIGGER_FIFO_HAS_ONE_CHARACTER, UART_DMA_MODE0);
//enable RX interrupt if necessary
HAL_UART_INT_Switch_RecvDataAvailable(&g_huart1, 1);
HAL_UART_SetIsrRecvCharCallback(g_huart1.Instance, uart1_RecvDataIrqCallback);
HAL_UART_SetIsrSendCharCallback(g_huart1.Instance, uart1_SendDataIrqCallback);
//enable uart master switch
NVIC_EnableIRQ(UART1_IRQn);
/*
* Register with the sleep module to ensure that the serial port can be used during Light sleep
*/
// hal_sleep_register(MOD_UART1, NULL, NULL, NULL);
}
/*
* ***************************** Device Cleanup ******************************
*/
static void hw_uart_cleanup(struct SerialHardware *_hw)
{
struct ARTSerial *hw = NULL;
ART_ASSERT(_hw);
hw = (struct ARTSerial *)_hw;
HAL_UART_Deinit(hw->Hardware.hw_device);
uart_io_pin_release(hw->serial);
hw->serial = NULL;
}
/*
* ***************************** Device txStart ******************************
*/
//txStart polling mode.
static void hw_uart_txStartPolling(struct SerialHardware * _hw)
{
uint8_t ch;
struct ARTSerial *hw = NULL;
UART_DevTypeDef * pUartDev;
ART_ASSERT(_hw);
hw = (struct ARTSerial *)_hw;
while(!fifo_isempty(&hw->serial->txfifo))
{
ch = fifo_pop(&hw->serial->txfifo);
pUartDev = (UART_DevTypeDef *)hw->Hardware.hw_device;
HAL_UART_WriteOneChar(pUartDev->Instance, &ch);
}
}
//txStart ISR mode.
static void hw_uart_txStartIsr(struct SerialHardware * _hw)
{
struct ARTSerial *hw = NULL;
ART_ASSERT(_hw);
hw = (struct ARTSerial *)_hw;
if (hw->Hardware.isSending){
return;
}
if(!fifo_isempty(&hw->serial->txfifo))
{
hw->Hardware.isSending = true;
/* Enable TX empty interrupts. */
HAL_UART_INT_Switch_TransmitHoldingRegEmpty(hw->Hardware.hw_device, 1);
}
}
/*
* ***************************** Device ixSending ******************************
*/
static bool hw_uart_txIsSending(struct SerialHardware * _hw)
{
struct ARTSerial *hw = NULL;
ART_ASSERT(_hw);
hw = (struct ARTSerial *)_hw;
return hw->Hardware.isSending;
}
/*
* ***************************** Device setBaudrate ******************************
*/
static bool hw_uart_setBaudrate(struct SerialHardware * _hw, uint32_t baudrate)
{
struct ARTSerial *hw = NULL;
UART_DevTypeDef * pUartDev;
ART_ASSERT(_hw);
hw = (struct ARTSerial *)_hw;
pUartDev = (UART_DevTypeDef *)hw->Hardware.hw_device;
if(HAL_OK == HAL_UART_BaudRateConfig(pUartDev, baudrate)){
return true;
} else {
return false;
}
}
/*
* ***************************** Register ISR Callback *****************************
*/
//send data callback in ISR mode.
static void uart0_SendDataIrqCallback(uint8_t *ch)
{
struct ARTSerial *hw = (struct ARTSerial *)&UARTDescs[SER_PORT_UART0];
uint8_t tx_char = 0;
if (fifo_isempty(&hw->serial->txfifo))
{
/* Disable TX empty interrupts if there're no more characters to transmit. */
HAL_UART_INT_Switch_TransmitHoldingRegEmpty(&g_huart0, 0);
hw->Hardware.isSending = false;
}
else
{
tx_char = fifo_pop(&hw->serial->txfifo);
HAL_UART_WriteOneChar(g_huart0.Instance, &tx_char);
}
}
//recieve data callback in ISR mode.
static void uart0_RecvDataIrqCallback(uint8_t *ch)
{
struct ARTSerial *hw = (struct ARTSerial *)&UARTDescs[SER_PORT_UART0];
while (fifo_isfull_locked(&hw->serial->rxfifo)){
serial_purgeRx(hw->serial);
}
fifo_push(&hw->serial->rxfifo, (unsigned char)*ch);
hw->serial->callback();
}
//send data callback in ISR mode.
static void uart1_SendDataIrqCallback(uint8_t *ch)
{
struct ARTSerial *hw = (struct ARTSerial *)&UARTDescs[SER_PORT_UART1];
uint8_t tx_char = 0;
if (fifo_isempty(&hw->serial->txfifo))
{
/* Disable TX empty interrupts if there're no more characters to transmit. */
HAL_UART_INT_Switch_TransmitHoldingRegEmpty(&g_huart1, 0);
hw->Hardware.isSending = false;
}
else
{
*ch = fifo_pop(&hw->serial->txfifo);
HAL_UART_WriteOneChar(g_huart1.Instance, &tx_char);
}
}
//recieve data callback in ISR mode.
static void uart1_RecvDataIrqCallback(uint8_t *ch)
{
struct ARTSerial *hw = (struct ARTSerial *)&UARTDescs[SER_PORT_UART1];
if (fifo_isfull_locked(&hw->serial->rxfifo)){
serial_purgeRx(hw->serial);
}
fifo_push(&hw->serial->rxfifo, (unsigned char)*ch);
if(*ch == '\n'){
hw->serial->callback();
}
}
/*
* High-level interface data structures.
*/
static const struct SerialHardwareVT uart0_vtable =
{
.init = hw_uart0_init,
.cleanup = hw_uart_cleanup,
.txStart = hw_uart_txStartPolling,//hw_uart_txStartPolling,hw_uart_txStartIsr
.txSending = hw_uart_txIsSending,
.setBaudrate = hw_uart_setBaudrate,
};
static const struct SerialHardwareVT uart1_vtable =
{
.init = hw_uart1_init,
.cleanup = hw_uart_cleanup,
.txStart = hw_uart_txStartPolling,//hw_uart_txStartPolling,hw_uart_txStartIsr
.txSending = hw_uart_txIsSending,
.setBaudrate = hw_uart_setBaudrate,
};
struct ARTSerial UARTDescs[SER_PORT_NUM] =
{
{
.Hardware =
{
.table = &uart0_vtable,
.txbuffer = uart0_txbuffer,
.rxbuffer = uart0_rxbuffer,
.txbuffer_size = sizeof(uart0_txbuffer),
.rxbuffer_size = sizeof(uart0_rxbuffer),
.hw_device = (void *)&g_huart0,
.isSending = false,
},
.serial = NULL,
},
{
.Hardware =
{
.table = &uart1_vtable,
.txbuffer = uart1_txbuffer,
.rxbuffer = uart1_rxbuffer,
.txbuffer_size = sizeof(uart1_txbuffer),
.rxbuffer_size = sizeof(uart1_rxbuffer),
.hw_device = (void *)&g_huart1,
.isSending = false,
},
.serial = NULL,
},
};
struct SerialHardware *serial_hw_getdesc(SerialPortID port_id)
{
ART_ASSERT(port_id < SER_PORT_NUM);
return (struct SerialHardware *)&UARTDescs[port_id].Hardware;
}