1142 lines
29 KiB
C
1142 lines
29 KiB
C
/*
|
|
* Copyright (C) 2017-2019 Alibaba Group Holding Limited
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2020-08-20 zx.chen CSI Source File for usart Driver
|
|
*/
|
|
|
|
#include <csi_config.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <drv_irq.h>
|
|
#include <drv_usart.h>
|
|
#include <ck_usart.h>
|
|
#include <soc.h>
|
|
#include <csi_core.h>
|
|
|
|
#define ERR_USART(errno) (CSI_DRV_ERRNO_USART_BASE | errno)
|
|
|
|
/*
|
|
* setting config may be accessed when the USART is not
|
|
* busy(USR[0]=0) and the DLAB bit(LCR[7]) is set.
|
|
*/
|
|
|
|
#define WAIT_USART_IDLE(addr)\
|
|
do { \
|
|
int32_t timecount = 0; \
|
|
while ((addr->USR & USR_UART_BUSY) && (timecount < UART_BUSY_TIMEOUT)) {\
|
|
timecount++;\
|
|
}\
|
|
if (timecount >= UART_BUSY_TIMEOUT) {\
|
|
return ERR_USART(DRV_ERROR_TIMEOUT);\
|
|
} \
|
|
} while(0)
|
|
|
|
#define USART_NULL_PARAM_CHK(para) HANDLE_PARAM_CHK(para, ERR_USART(DRV_ERROR_PARAMETER))
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t base;
|
|
uint32_t irq;
|
|
usart_event_cb_t cb_event; ///< Event callback
|
|
uint32_t rx_total_num;
|
|
uint32_t tx_total_num;
|
|
uint8_t *rx_buf;
|
|
uint8_t *tx_buf;
|
|
volatile uint32_t rx_cnt;
|
|
volatile uint32_t tx_cnt;
|
|
volatile uint32_t tx_busy;
|
|
volatile uint32_t rx_busy;
|
|
uint32_t last_tx_num;
|
|
uint32_t last_rx_num;
|
|
int32_t idx;
|
|
} ck_usart_priv_t;
|
|
|
|
extern int32_t target_usart_init(int32_t idx, uint32_t *base, uint32_t *irq, void **handler);
|
|
|
|
static ck_usart_priv_t usart_instance[CONFIG_USART_NUM];
|
|
|
|
static const usart_capabilities_t usart_capabilities =
|
|
{
|
|
.asynchronous = 1, /* supports USART (Asynchronous) mode */
|
|
.synchronous_master = 0, /* supports Synchronous Master mode */
|
|
.synchronous_slave = 0, /* supports Synchronous Slave mode */
|
|
.single_wire = 0, /* supports USART Single-wire mode */
|
|
.event_tx_complete = 1, /* Transmit completed event */
|
|
.event_rx_timeout = 0, /* Signal receive character timeout event */
|
|
};
|
|
|
|
/**
|
|
\brief set the bautrate of usart.
|
|
\param[in] addr usart base to operate.
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_config_baudrate(usart_handle_t handle, uint32_t baud)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
|
|
|
|
WAIT_USART_IDLE(addr);
|
|
|
|
/* baudrate=(seriak clock freq)/(16*divisor); algorithm :rounding*/
|
|
uint32_t divisor = ((drv_get_usart_freq(usart_priv->idx) * 10) / baud) >> 4;
|
|
|
|
if ((divisor % 10) >= 5)
|
|
{
|
|
divisor = (divisor / 10) + 1;
|
|
} else
|
|
{
|
|
divisor = divisor / 10;
|
|
}
|
|
|
|
addr->LCR |= LCR_SET_DLAB;
|
|
/* DLL and DLH is lower 8-bits and higher 8-bits of divisor.*/
|
|
addr->DLL = divisor & 0xff;
|
|
addr->DLH = (divisor >> 8) & 0xff;
|
|
/*
|
|
* The DLAB must be cleared after the baudrate is setted
|
|
* to access other registers.
|
|
*/
|
|
addr->LCR &= (~LCR_SET_DLAB);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
\brief config usart mode.
|
|
\param[in] handle usart handle to operate.
|
|
\param[in] mode \ref usart_mode_e
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_config_mode(usart_handle_t handle, usart_mode_e mode)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
|
|
if (mode == USART_MODE_ASYNCHRONOUS)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return ERR_USART(USART_ERROR_MODE);
|
|
}
|
|
|
|
/**
|
|
\brief config usart parity.
|
|
\param[in] handle usart handle to operate.
|
|
\param[in] parity \ref usart_parity_e
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_config_parity(usart_handle_t handle, usart_parity_e parity)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
|
|
WAIT_USART_IDLE(addr);
|
|
|
|
switch (parity)
|
|
{
|
|
case USART_PARITY_NONE:
|
|
/*CLear the PEN bit(LCR[3]) to disable parity.*/
|
|
addr->LCR &= (~LCR_PARITY_ENABLE);
|
|
break;
|
|
|
|
case USART_PARITY_ODD:
|
|
/* Set PEN and clear EPS(LCR[4]) to set the ODD parity. */
|
|
addr->LCR |= LCR_PARITY_ENABLE;
|
|
addr->LCR &= LCR_PARITY_ODD;
|
|
break;
|
|
|
|
case USART_PARITY_EVEN:
|
|
/* Set PEN and EPS(LCR[4]) to set the EVEN parity.*/
|
|
addr->LCR |= LCR_PARITY_ENABLE;
|
|
addr->LCR |= LCR_PARITY_EVEN;
|
|
break;
|
|
|
|
default:
|
|
return ERR_USART(USART_ERROR_PARITY);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
\brief config usart stop bit number.
|
|
\param[in] handle usart handle to operate.
|
|
\param[in] stopbits \ref usart_stop_bits_e
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_config_stopbits(usart_handle_t handle, usart_stop_bits_e stopbit)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
|
|
WAIT_USART_IDLE(addr);
|
|
|
|
switch (stopbit)
|
|
{
|
|
case USART_STOP_BITS_1:
|
|
/* Clear the STOP bit to set 1 stop bit*/
|
|
addr->LCR &= LCR_STOP_BIT1;
|
|
break;
|
|
|
|
case USART_STOP_BITS_2:
|
|
/*
|
|
* If the STOP bit is set "1",we'd gotten 1.5 stop
|
|
* bits when DLS(LCR[1:0]) is zero, else 2 stop bits.
|
|
*/
|
|
addr->LCR |= LCR_STOP_BIT2;
|
|
break;
|
|
|
|
default:
|
|
return ERR_USART(USART_ERROR_STOP_BITS);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
\brief config usart data length.
|
|
\param[in] handle usart handle to operate.
|
|
\param[in] databits \ref usart_data_bits_e
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_config_databits(usart_handle_t handle, usart_data_bits_e databits)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
|
|
WAIT_USART_IDLE(addr);
|
|
/* The word size decides by the DLS bits(LCR[1:0]), and the
|
|
* corresponding relationship between them is:
|
|
* DLS word size
|
|
* 00 -- 5 bits
|
|
* 01 -- 6 bits
|
|
* 10 -- 7 bits
|
|
* 11 -- 8 bits
|
|
*/
|
|
|
|
switch (databits)
|
|
{
|
|
case USART_DATA_BITS_5:
|
|
addr->LCR &= LCR_WORD_SIZE_5;
|
|
break;
|
|
|
|
case USART_DATA_BITS_6:
|
|
addr->LCR &= 0xfd;
|
|
addr->LCR |= LCR_WORD_SIZE_6;
|
|
break;
|
|
|
|
case USART_DATA_BITS_7:
|
|
addr->LCR &= 0xfe;
|
|
addr->LCR |= LCR_WORD_SIZE_7;
|
|
break;
|
|
|
|
case USART_DATA_BITS_8:
|
|
addr->LCR |= LCR_WORD_SIZE_8;
|
|
break;
|
|
|
|
default:
|
|
return ERR_USART(USART_ERROR_DATA_BITS);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int32_t ck_usart_set_int_flag(usart_handle_t handle,uint32_t flag)
|
|
{
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
|
|
addr->IER |= flag;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t ck_usart_clr_int_flag(usart_handle_t handle,uint32_t flag)
|
|
{
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
|
|
addr->IER &= ~flag;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
\brief get character in query mode.
|
|
\param[in] instance usart instance to operate.
|
|
\param[in] the pointer to the recieve charater.
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_getchar(usart_handle_t handle, uint8_t *ch)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
USART_NULL_PARAM_CHK(ch);
|
|
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
|
|
while (!(addr->LSR & LSR_DATA_READY));
|
|
|
|
*ch = addr->RBR;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
\brief get character in query mode.
|
|
\param[in] instance usart instance to operate.
|
|
\param[in] the pointer to the recieve charater.
|
|
\return error code
|
|
*/
|
|
int csi_uart_getchar(usart_handle_t handle)
|
|
{
|
|
volatile int ch;
|
|
USART_NULL_PARAM_CHK(handle);
|
|
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
|
|
ch = -1;
|
|
|
|
if (addr->LSR & LSR_DATA_READY)
|
|
{
|
|
ch = addr->RBR & 0xff;
|
|
}
|
|
|
|
return ch;
|
|
}
|
|
|
|
|
|
/**
|
|
\brief transmit character in query mode.
|
|
\param[in] instance usart instance to operate.
|
|
\param[in] ch the input charater
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_putchar(usart_handle_t handle, uint8_t ch)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
uint32_t timecount = 0;
|
|
|
|
while ((!(addr->LSR & DW_LSR_TRANS_EMPTY)))
|
|
{
|
|
timecount++;
|
|
|
|
if (timecount >= UART_BUSY_TIMEOUT)
|
|
{
|
|
return ERR_USART(DRV_ERROR_TIMEOUT);
|
|
}
|
|
}
|
|
|
|
addr->THR = ch;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/**
|
|
\brief interrupt service function for transmitter holding register empty.
|
|
\param[in] usart_priv usart private to operate.
|
|
*/
|
|
void ck_usart_intr_threshold_empty(int32_t idx, ck_usart_priv_t *usart_priv)
|
|
{
|
|
if (usart_priv->tx_total_num == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
volatile int i = 500;
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
|
|
if (usart_priv->tx_cnt >= usart_priv->tx_total_num)
|
|
{
|
|
addr->IER &= (~IER_THRE_INT_ENABLE);
|
|
usart_priv->last_tx_num = usart_priv->tx_total_num;
|
|
|
|
/* fix hardware bug */
|
|
while (addr->USR & USR_UART_BUSY);
|
|
|
|
i = 500;
|
|
|
|
while (i--);
|
|
|
|
usart_priv->tx_cnt = 0;
|
|
usart_priv->tx_busy = 0;
|
|
usart_priv->tx_buf = NULL;
|
|
usart_priv->tx_total_num = 0;
|
|
|
|
if (usart_priv->cb_event)
|
|
{
|
|
usart_priv->cb_event(idx, USART_EVENT_SEND_COMPLETE);
|
|
}
|
|
} else
|
|
{
|
|
/* fix hardware bug */
|
|
while (addr->USR & USR_UART_BUSY);
|
|
|
|
i = 500;
|
|
|
|
while (i--);
|
|
|
|
addr->THR = *((uint8_t *)usart_priv->tx_buf);
|
|
usart_priv->tx_cnt++;
|
|
usart_priv->tx_buf++;
|
|
}
|
|
}
|
|
|
|
/**
|
|
\brief interrupt service function for receiver data available.
|
|
\param[in] usart_priv usart private to operate.
|
|
*/
|
|
static void ck_usart_intr_recv_data(int32_t idx, ck_usart_priv_t *usart_priv)
|
|
{
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
uint8_t data = addr->RBR;
|
|
|
|
*((uint8_t *)usart_priv->rx_buf) = data;
|
|
usart_priv->rx_cnt++;
|
|
usart_priv->rx_buf++;
|
|
|
|
if (usart_priv->rx_cnt >= usart_priv->rx_total_num)
|
|
{
|
|
usart_priv->last_rx_num = usart_priv->rx_total_num;
|
|
usart_priv->rx_cnt = 0;
|
|
usart_priv->rx_buf = NULL;
|
|
usart_priv->rx_busy = 0;
|
|
usart_priv->rx_total_num = 0;
|
|
|
|
if (usart_priv->cb_event)
|
|
{
|
|
usart_priv->cb_event(idx, USART_EVENT_RECEIVE_COMPLETE);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
\brief interrupt service function for receiver line.
|
|
\param[in] usart_priv usart private to operate.
|
|
*/
|
|
static void ck_usart_intr_recv_line(int32_t idx, ck_usart_priv_t *usart_priv)
|
|
{
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
uint32_t lsr_stat = addr->LSR;
|
|
|
|
addr->IER &= (~IER_THRE_INT_ENABLE);
|
|
|
|
uint32_t timecount = 0;
|
|
|
|
while (addr->LSR & 0x1)
|
|
{
|
|
addr->RBR;
|
|
timecount++;
|
|
|
|
if (timecount >= UART_BUSY_TIMEOUT)
|
|
{
|
|
if (usart_priv->cb_event)
|
|
{
|
|
usart_priv->cb_event(idx, USART_EVENT_RX_TIMEOUT);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/** Break Interrupt bit. This is used to indicate the detection of a
|
|
* break sequence on the serial input data.
|
|
*/
|
|
if (lsr_stat & DW_LSR_BI)
|
|
{
|
|
if (usart_priv->cb_event)
|
|
{
|
|
usart_priv->cb_event(idx, USART_EVENT_RX_BREAK);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/** Framing Error bit. This is used to indicate the occurrence of a
|
|
* framing error in the receiver. A framing error occurs when the receiver
|
|
* does not detect a valid STOP bit in the received data.
|
|
*/
|
|
if (lsr_stat & DW_LSR_FE)
|
|
{
|
|
if (usart_priv->cb_event)
|
|
{
|
|
usart_priv->cb_event(idx, USART_EVENT_RX_FRAMING_ERROR);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/** Framing Error bit. This is used to indicate the occurrence of a
|
|
* framing error in the receiver. A framing error occurs when the
|
|
* receiver does not detect a valid STOP bit in the received data.
|
|
*/
|
|
if (lsr_stat & DW_LSR_PE)
|
|
{
|
|
if (usart_priv->cb_event)
|
|
{
|
|
usart_priv->cb_event(idx, USART_EVENT_RX_PARITY_ERROR);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/** Overrun error bit. This is used to indicate the occurrence of an overrun error.
|
|
* This occurs if a new data character was received before the previous data was read.
|
|
*/
|
|
if (lsr_stat & DW_LSR_OE)
|
|
{
|
|
if (usart_priv->cb_event)
|
|
{
|
|
usart_priv->cb_event(idx, USART_EVENT_RX_OVERFLOW);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
/**
|
|
\brief interrupt service function for character timeout.
|
|
\param[in] usart_priv usart private to operate.
|
|
*/
|
|
static void ck_usart_intr_char_timeout(int32_t idx, ck_usart_priv_t *usart_priv)
|
|
{
|
|
if ((usart_priv->rx_total_num != 0) && (usart_priv->rx_buf != NULL))
|
|
{
|
|
ck_usart_intr_recv_data(idx, usart_priv);
|
|
return;
|
|
}
|
|
|
|
if (usart_priv->cb_event)
|
|
{
|
|
usart_priv->cb_event(idx, USART_EVENT_RECEIVED);
|
|
} else
|
|
{
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
|
|
uint32_t timecount = 0;
|
|
|
|
while (addr->LSR & 0x1)
|
|
{
|
|
addr->RBR;
|
|
timecount++;
|
|
|
|
if (timecount >= UART_BUSY_TIMEOUT)
|
|
{
|
|
if (usart_priv->cb_event)
|
|
{
|
|
usart_priv->cb_event(idx, USART_EVENT_RX_TIMEOUT);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
\brief the interrupt service function.
|
|
\param[in] index of usart instance.
|
|
*/
|
|
void ck_usart_irqhandler(int32_t idx)
|
|
{
|
|
ck_usart_priv_t *usart_priv = &usart_instance[idx];
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
|
|
uint8_t intr_state = addr->IIR & 0xf;
|
|
|
|
switch (intr_state)
|
|
{
|
|
case DW_IIR_THR_EMPTY: /* interrupt source:transmitter holding register empty */
|
|
ck_usart_intr_threshold_empty(idx, usart_priv);
|
|
break;
|
|
|
|
case DW_IIR_RECV_DATA: /* interrupt source:receiver data available or receiver fifo trigger level reached */
|
|
ck_usart_intr_char_timeout(idx, usart_priv);
|
|
//ck_usart_intr_recv_data(idx, usart_priv);
|
|
break;
|
|
|
|
case DW_IIR_RECV_LINE:
|
|
ck_usart_intr_recv_line(idx, usart_priv);
|
|
break;
|
|
|
|
case DW_IIR_CHAR_TIMEOUT:
|
|
ck_usart_intr_char_timeout(idx, usart_priv);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
\brief Get driver capabilities.
|
|
\param[in] idx usart index
|
|
\return \ref usart_capabilities_t
|
|
*/
|
|
usart_capabilities_t csi_usart_get_capabilities(int32_t idx)
|
|
{
|
|
if (idx < 0 || idx >= CONFIG_USART_NUM)
|
|
{
|
|
usart_capabilities_t ret;
|
|
memset(&ret, 0, sizeof(usart_capabilities_t));
|
|
return ret;
|
|
}
|
|
|
|
return usart_capabilities;
|
|
}
|
|
|
|
/**
|
|
\brief Initialize USART Interface. 1. Initializes the resources needed for the USART interface 2.registers event callback function
|
|
\param[in] idx usart index
|
|
\param[in] cb_event Pointer to \ref usart_event_cb_t
|
|
\return return usart handle if success
|
|
*/
|
|
usart_handle_t csi_usart_initialize(int32_t idx, usart_event_cb_t cb_event)
|
|
{
|
|
uint32_t base = 0u;
|
|
uint32_t irq = 0u;
|
|
void *handler;
|
|
|
|
int32_t ret = target_usart_init(idx, &base, &irq, &handler);
|
|
|
|
if (ret < 0 || ret >= CONFIG_USART_NUM)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ck_usart_priv_t *usart_priv = &usart_instance[idx];
|
|
usart_priv->base = base;
|
|
usart_priv->irq = irq;
|
|
usart_priv->cb_event = cb_event;
|
|
usart_priv->idx = idx;
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
|
|
/* enable received data available */
|
|
addr->IER = IER_RDA_INT_ENABLE | IIR_RECV_LINE_ENABLE;
|
|
drv_irq_register(usart_priv->irq, handler);
|
|
drv_irq_enable(usart_priv->irq);
|
|
|
|
return usart_priv;
|
|
}
|
|
|
|
/**
|
|
\brief De-initialize UART Interface. stops operation and releases the software resources used by the interface
|
|
\param[in] handle usart handle to operate.
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_uninitialize(usart_handle_t handle)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
|
|
drv_irq_disable(usart_priv->irq);
|
|
drv_irq_unregister(usart_priv->irq);
|
|
usart_priv->cb_event = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
\brief config usart mode.
|
|
\param[in] handle usart handle to operate.
|
|
\param[in] baud baud rate
|
|
\param[in] mode \ref usart_mode_e
|
|
\param[in] parity \ref usart_parity_e
|
|
\param[in] stopbits \ref usart_stop_bits_e
|
|
\param[in] bits \ref usart_data_bits_e
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_config(usart_handle_t handle,
|
|
uint32_t baud,
|
|
usart_mode_e mode,
|
|
usart_parity_e parity,
|
|
usart_stop_bits_e stopbits,
|
|
usart_data_bits_e bits)
|
|
{
|
|
int32_t ret;
|
|
|
|
/* control the data_bit of the usart*/
|
|
ret = csi_usart_config_baudrate(handle, baud);
|
|
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
/* control mode of the usart*/
|
|
ret = csi_usart_config_mode(handle, mode);
|
|
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
/* control the parity of the usart*/
|
|
ret = csi_usart_config_parity(handle, parity);
|
|
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
/* control the stopbit of the usart*/
|
|
ret = csi_usart_config_stopbits(handle, stopbits);
|
|
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = csi_usart_config_databits(handle, bits);
|
|
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
\brief Start sending data to UART transmitter,(received data is ignored).
|
|
The function is non-blocking,UART_EVENT_TRANSFER_COMPLETE is signaled when transfer completes.
|
|
csi_usart_get_status can indicates if transmission is still in progress or pending
|
|
\param[in] handle usart handle to operate.
|
|
\param[in] data Pointer to buffer with data to send to UART transmitter. data_type is : uint8_t for 1..8 data bits, uint16_t for 9..16 data bits,uint32_t for 17..32 data bits,
|
|
\param[in] num Number of data items to send
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_send(usart_handle_t handle, const void *data, uint32_t num)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
USART_NULL_PARAM_CHK(data);
|
|
|
|
if (num == 0)
|
|
{
|
|
return ERR_USART(DRV_ERROR_PARAMETER);
|
|
}
|
|
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
|
|
usart_priv->tx_buf = (uint8_t *)data;
|
|
usart_priv->tx_total_num = num;
|
|
usart_priv->tx_cnt = 0;
|
|
usart_priv->tx_busy = 1;
|
|
usart_priv->last_tx_num = 0;
|
|
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
ck_usart_intr_threshold_empty(usart_priv->idx, usart_priv);
|
|
/* enable the interrupt*/
|
|
addr->IER |= IER_THRE_INT_ENABLE;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
\brief Abort Send data to UART transmitter
|
|
\param[in] handle usart handle to operate.
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_abort_send(usart_handle_t handle)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
addr->IER &= (~IER_THRE_INT_ENABLE);
|
|
|
|
usart_priv->tx_cnt = usart_priv->tx_total_num;
|
|
usart_priv->tx_cnt = 0;
|
|
usart_priv->tx_busy = 0;
|
|
usart_priv->tx_buf = NULL;
|
|
usart_priv->tx_total_num = 0;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
\brief Start receiving data from UART receiver.transmits the default value as specified by csi_usart_set_default_tx_value
|
|
\param[in] handle usart handle to operate.
|
|
\param[out] data Pointer to buffer for data to receive from UART receiver
|
|
\param[in] num Number of data items to receive
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_receive(usart_handle_t handle, void *data, uint32_t num)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
USART_NULL_PARAM_CHK(data);
|
|
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
|
|
usart_priv->rx_buf = (uint8_t *)data; // Save receive buffer usart
|
|
usart_priv->rx_total_num = num; // Save number of data to be received
|
|
usart_priv->rx_cnt = 0;
|
|
usart_priv->rx_busy = 1;
|
|
usart_priv->last_rx_num = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/**
|
|
\brief query data from UART receiver FIFO.
|
|
\param[in] handle usart handle to operate.
|
|
\param[out] data Pointer to buffer for data to receive from UART receiver
|
|
\param[in] num Number of data items to receive
|
|
\return receive fifo data num
|
|
*/
|
|
int32_t csi_usart_receive_query(usart_handle_t handle, void *data, uint32_t num)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
USART_NULL_PARAM_CHK(data);
|
|
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
int32_t recv_num = 0;
|
|
uint8_t *dest = (uint8_t *)data;
|
|
|
|
while (addr->LSR & 0x1)
|
|
{
|
|
*dest++ = addr->RBR;
|
|
recv_num++;
|
|
|
|
if (recv_num >= num)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return recv_num;
|
|
|
|
}
|
|
|
|
/**
|
|
\brief Abort Receive data from UART receiver
|
|
\param[in] handle usart handle to operate.
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_abort_receive(usart_handle_t handle)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
|
|
usart_priv->rx_cnt = usart_priv->rx_total_num;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
\brief Start sending/receiving data to/from UART transmitter/receiver.
|
|
\param[in] handle usart handle to operate.
|
|
\param[in] data_out Pointer to buffer with data to send to USART transmitter
|
|
\param[out] data_in Pointer to buffer for data to receive from USART receiver
|
|
\param[in] num Number of data items to transfer
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_transfer(usart_handle_t handle, const void *data_out, void *data_in, uint32_t num)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
return ERR_USART(DRV_ERROR_UNSUPPORTED);
|
|
}
|
|
|
|
/**
|
|
\brief abort sending/receiving data to/from USART transmitter/receiver.
|
|
\param[in] handle usart handle to operate.
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_abort_transfer(usart_handle_t handle)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
return ERR_USART(DRV_ERROR_UNSUPPORTED);
|
|
}
|
|
|
|
/**
|
|
\brief Get USART status.
|
|
\param[in] handle usart handle to operate.
|
|
\return USART status \ref usart_status_t
|
|
*/
|
|
usart_status_t csi_usart_get_status(usart_handle_t handle)
|
|
{
|
|
usart_status_t usart_status;
|
|
|
|
memset(&usart_status, 0, sizeof(usart_status_t));
|
|
|
|
if (handle == NULL)
|
|
{
|
|
return usart_status;
|
|
}
|
|
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
uint32_t line_status_reg = addr->LSR;
|
|
|
|
usart_status.tx_busy = usart_priv->tx_busy;
|
|
usart_status.rx_busy = usart_priv->rx_busy;
|
|
|
|
if (line_status_reg & DW_LSR_BI)
|
|
{
|
|
usart_status.rx_break = 1;
|
|
}
|
|
|
|
if (line_status_reg & DW_LSR_FE)
|
|
{
|
|
usart_status.rx_framing_error = 1;
|
|
}
|
|
|
|
if (line_status_reg & DW_LSR_PE)
|
|
{
|
|
usart_status.rx_parity_error = 1;
|
|
}
|
|
|
|
usart_status.tx_enable = 1;
|
|
usart_status.rx_enable = 1;
|
|
|
|
return usart_status;
|
|
}
|
|
|
|
/**
|
|
\brief control the transmit.
|
|
\param[in] handle usart handle to operate.
|
|
\param[in] 1 - enable the transmitter. 0 - disable the transmitter
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_control_tx(usart_handle_t handle, uint32_t enable)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
\brief control the receive.
|
|
\param[in] handle usart handle to operate.
|
|
\param[in] 1 - enable the receiver. 0 - disable the receiver
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_control_rx(usart_handle_t handle, uint32_t enable)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
\brief control the break.
|
|
\param[in] handle usart handle to operate.
|
|
\param[in] 1- Enable continuous Break transmission,0 - disable continuous Break transmission
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_control_break(usart_handle_t handle, uint32_t enable)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
return ERR_USART(DRV_ERROR_UNSUPPORTED);
|
|
}
|
|
|
|
/**
|
|
\brief flush receive/send data.
|
|
\param[in] handle usart handle to operate.
|
|
\param[in] type \ref usart_flush_type_e.
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_flush(usart_handle_t handle, usart_flush_type_e type)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
|
|
uint32_t timecount = 0;
|
|
|
|
if (type == USART_FLUSH_WRITE) {
|
|
while ((!(addr->LSR & DW_LSR_TEMT)))
|
|
{
|
|
timecount++;
|
|
|
|
if (timecount >= UART_BUSY_TIMEOUT)
|
|
{
|
|
return ERR_USART(DRV_ERROR_TIMEOUT);
|
|
}
|
|
}
|
|
} else if (type == USART_FLUSH_READ)
|
|
{
|
|
while (addr->LSR & 0x1) {
|
|
timecount++;
|
|
|
|
if (timecount >= UART_BUSY_TIMEOUT)
|
|
{
|
|
return ERR_USART(DRV_ERROR_TIMEOUT);
|
|
}
|
|
}
|
|
} else
|
|
{
|
|
return ERR_USART(DRV_ERROR_PARAMETER);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
\brief set interrupt mode.
|
|
\param[in] handle usart handle to operate.
|
|
\param[in] type \ref usart_intr_type_e.
|
|
\param[in] flag 0-OFF, 1-ON.
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_set_interrupt(usart_handle_t handle, usart_intr_type_e type, int32_t flag)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
ck_usart_reg_t *addr = (ck_usart_reg_t *)(usart_priv->base);
|
|
|
|
switch (type)
|
|
{
|
|
case USART_INTR_WRITE:
|
|
if (flag == 0)
|
|
{
|
|
addr->IER &= ~IER_THRE_INT_ENABLE;
|
|
} else if (flag == 1)
|
|
{
|
|
addr->IER |= IER_THRE_INT_ENABLE;
|
|
} else
|
|
{
|
|
return ERR_USART(DRV_ERROR_PARAMETER);
|
|
}
|
|
|
|
break;
|
|
|
|
case USART_INTR_READ:
|
|
if (flag == 0)
|
|
{
|
|
addr->IER &= ~IER_RDA_INT_ENABLE;
|
|
} else if (flag == 1)
|
|
{
|
|
addr->IER |= IER_RDA_INT_ENABLE;
|
|
} else
|
|
{
|
|
return ERR_USART(DRV_ERROR_PARAMETER);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
return ERR_USART(DRV_ERROR_PARAMETER);
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
\brief Get usart send data count.
|
|
\param[in] handle usart handle to operate.
|
|
\return number of currently transmitted data bytes
|
|
*/
|
|
uint32_t csi_usart_get_tx_count(usart_handle_t handle)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
|
|
if (usart_priv->tx_busy)
|
|
{
|
|
return usart_priv->tx_cnt;
|
|
} else
|
|
{
|
|
return usart_priv->last_tx_num;
|
|
}
|
|
}
|
|
|
|
/**
|
|
\brief Get usart receive data count.
|
|
\param[in] handle usart handle to operate.
|
|
\return number of currently received data bytes
|
|
*/
|
|
uint32_t csi_usart_get_rx_count(usart_handle_t handle)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
ck_usart_priv_t *usart_priv = handle;
|
|
|
|
if (usart_priv->rx_busy)
|
|
{
|
|
return usart_priv->rx_cnt;
|
|
} else
|
|
{
|
|
return usart_priv->last_rx_num;
|
|
}
|
|
}
|
|
|
|
/**
|
|
\brief control usart power.
|
|
\param[in] handle usart handle to operate.
|
|
\param[in] state power state.\ref csi_power_stat_e.
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_power_control(usart_handle_t handle, csi_power_stat_e state)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
return ERR_USART(DRV_ERROR_UNSUPPORTED);
|
|
}
|
|
|
|
/**
|
|
\brief config usart flow control type.
|
|
\param[in] handle usart handle to operate.
|
|
\param[in] flowctrl_type flow control type.\ref usart_flowctrl_type_e.
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_config_flowctrl(usart_handle_t handle,
|
|
usart_flowctrl_type_e flowctrl_type)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
|
|
switch (flowctrl_type)
|
|
{
|
|
case USART_FLOWCTRL_CTS:
|
|
return ERR_USART(DRV_ERROR_UNSUPPORTED);
|
|
|
|
case USART_FLOWCTRL_RTS:
|
|
return ERR_USART(DRV_ERROR_UNSUPPORTED);
|
|
|
|
case USART_FLOWCTRL_CTS_RTS:
|
|
return ERR_USART(DRV_ERROR_UNSUPPORTED);
|
|
break;
|
|
|
|
case USART_FLOWCTRL_NONE:
|
|
return ERR_USART(DRV_ERROR_UNSUPPORTED);
|
|
break;
|
|
|
|
default:
|
|
return ERR_USART(DRV_ERROR_UNSUPPORTED);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
\brief config usart clock Polarity and Phase.
|
|
\param[in] handle usart handle to operate.
|
|
\param[in] cpol Clock Polarity.\ref usart_cpol_e.
|
|
\param[in] cpha Clock Phase.\ref usart_cpha_e.
|
|
\return error code
|
|
*/
|
|
int32_t csi_usart_config_clock(usart_handle_t handle, usart_cpol_e cpol, usart_cpha_e cpha)
|
|
{
|
|
USART_NULL_PARAM_CHK(handle);
|
|
return ERR_USART(DRV_ERROR_UNSUPPORTED);
|
|
}
|
|
|