769 lines
21 KiB
C
769 lines
21 KiB
C
|
/*
|
||
|
* Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
/******************************************************************************
|
||
|
* @file dw_usart.c
|
||
|
* @brief CSI Source File for usart Driver
|
||
|
* @version V1.0
|
||
|
* @date 02. June 2017
|
||
|
******************************************************************************/
|
||
|
#include <stdbool.h>
|
||
|
#include "csi_core.h"
|
||
|
#include "drv_usart.h"
|
||
|
#include "dw_usart.h"
|
||
|
#include "soc.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(EDRV_TIMEOUT);\
|
||
|
} \
|
||
|
} while(0)
|
||
|
|
||
|
#define USART_NULL_PARAM_CHK(para) \
|
||
|
do { \
|
||
|
if (para == NULL) { \
|
||
|
return ERR_USART(EDRV_PARAMETER); \
|
||
|
} \
|
||
|
} while (0)
|
||
|
|
||
|
|
||
|
typedef struct {
|
||
|
uint32_t base;
|
||
|
uint32_t irq;
|
||
|
usart_event_cb_t cb_event; ///< Event callback
|
||
|
void *cb_arg;
|
||
|
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;
|
||
|
} dw_usart_priv_t;
|
||
|
|
||
|
static dw_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.
|
||
|
\param[in] baudrate.
|
||
|
\param[in] apbfreq the frequence of the apb.
|
||
|
\return error code
|
||
|
*/
|
||
|
static int32_t dw_usart_set_baudrate(dw_usart_reg_t *addr, uint32_t baudrate, uint32_t apbfreq)
|
||
|
{
|
||
|
WAIT_USART_IDLE(addr);
|
||
|
|
||
|
/* baudrate=(seriak clock freq)/(16*divisor); algorithm :rounding*/
|
||
|
uint32_t divisor = ((apbfreq * 10) / baudrate) >> 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 enable or disable parity.
|
||
|
\param[in] addr usart base to operate.
|
||
|
\param[in] parity ODD=8, EVEN=16, or NONE=0.
|
||
|
\return error code
|
||
|
*/
|
||
|
|
||
|
static int32_t dw_usart_set_parity(dw_usart_reg_t *addr, usart_parity_e parity)
|
||
|
{
|
||
|
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(EDRV_USART_PARITY);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\brief set the stop bit.
|
||
|
\param[in] addr usart base to operate.
|
||
|
\param[in] stopbit two possible value: USART_STOP_BITS_1 and USART_STOP_BITS_2.
|
||
|
\return error code
|
||
|
*/
|
||
|
static int32_t dw_usart_set_stopbit(dw_usart_reg_t *addr, usart_stop_bits_e stopbit)
|
||
|
{
|
||
|
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(EDRV_USART_STOP_BITS);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\brief the transmit data length,and we have four choices:5, 6, 7, and 8 bits.
|
||
|
\param[in] addr usart base to operate.
|
||
|
\param[in] databits the data length that user decides.
|
||
|
\return error code
|
||
|
*/
|
||
|
static int32_t dw_usart_set_databit(dw_usart_reg_t *addr, usart_data_bits_e databits)
|
||
|
{
|
||
|
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(EDRV_USART_DATA_BITS);
|
||
|
}
|
||
|
|
||
|
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 dw_usart_getchar(usart_handle_t handle, uint8_t *ch)
|
||
|
{
|
||
|
dw_usart_priv_t *usart_priv = handle;
|
||
|
dw_usart_reg_t *addr = (dw_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
|
||
|
*/
|
||
|
int32_t dw_usart_getchar_no_poll(usart_handle_t handle, uint8_t *ch)
|
||
|
{
|
||
|
dw_usart_priv_t *usart_priv = handle;
|
||
|
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
|
||
|
|
||
|
if (addr->LSR & LSR_DATA_READY)
|
||
|
{
|
||
|
*ch = addr->RBR;
|
||
|
return 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int32_t dw_usart_set_int_flag(usart_handle_t handle,uint32_t flag)
|
||
|
{
|
||
|
dw_usart_priv_t *usart_priv = handle;
|
||
|
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
|
||
|
|
||
|
addr->IER |= flag;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int32_t dw_usart_clr_int_flag(usart_handle_t handle,uint32_t flag)
|
||
|
{
|
||
|
dw_usart_priv_t *usart_priv = handle;
|
||
|
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
|
||
|
|
||
|
addr->IER &= ~flag;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\brief transmit character in query mode.
|
||
|
\param[in] instance usart instance to operate.
|
||
|
\param[in] ch the input charater
|
||
|
\return error code
|
||
|
*/
|
||
|
int32_t dw_usart_putchar(usart_handle_t handle, uint8_t ch)
|
||
|
{
|
||
|
dw_usart_priv_t *usart_priv = handle;
|
||
|
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
|
||
|
|
||
|
while ((!(addr->LSR & DW_LSR_TRANS_EMPTY)));
|
||
|
|
||
|
if (ch == '\n')
|
||
|
{
|
||
|
addr->THR = '\r';
|
||
|
|
||
|
while ((!(addr->LSR & DW_LSR_TRANS_EMPTY))) ;
|
||
|
}
|
||
|
|
||
|
addr->THR = ch;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\brief interrupt service function for transmitter holding register empty.
|
||
|
\param[in] usart_priv usart private to operate.
|
||
|
*/
|
||
|
static void dw_usart_intr_threshold_empty(dw_usart_priv_t *usart_priv)
|
||
|
{
|
||
|
if (usart_priv->tx_total_num == 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
uint8_t remain_txdata = usart_priv->tx_total_num - usart_priv->tx_cnt;
|
||
|
|
||
|
uint8_t txdata_num = (remain_txdata > UART_MAX_FIFO) ? UART_MAX_FIFO : remain_txdata;
|
||
|
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
|
||
|
uint8_t i = 0u;
|
||
|
|
||
|
for (i = 0; i < txdata_num; i++) {
|
||
|
addr->THR = *((uint8_t *)usart_priv->tx_buf);
|
||
|
usart_priv->tx_cnt++;
|
||
|
usart_priv->tx_buf++;
|
||
|
}
|
||
|
|
||
|
if (usart_priv->tx_cnt >= usart_priv->tx_total_num) {
|
||
|
addr->IER &= (~IER_THRE_INT_ENABLE);
|
||
|
|
||
|
while ((!(addr->LSR & DW_LSR_TEMT)));
|
||
|
|
||
|
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(USART_EVENT_SEND_COMPLETE, usart_priv->cb_arg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\brief interrupt service function for receiver data available.
|
||
|
\param[in] usart_priv usart private to operate.
|
||
|
*/
|
||
|
static void dw_usart_intr_recv_data(dw_usart_priv_t *usart_priv)
|
||
|
{
|
||
|
if (usart_priv->cb_event && (usart_priv->rx_total_num == 0)) {
|
||
|
usart_priv->cb_event(USART_EVENT_RECEIVED, usart_priv->cb_arg);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
|
||
|
uint8_t data = addr->RBR;
|
||
|
|
||
|
if ((usart_priv->rx_total_num == 0) || (usart_priv->rx_buf == NULL)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
*((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->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(USART_EVENT_RECEIVE_COMPLETE, usart_priv->cb_arg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\brief the interrupt service function.
|
||
|
\param[in] index of usart instance.
|
||
|
*/
|
||
|
void dw_usart_irqhandler(int32_t idx)
|
||
|
{
|
||
|
dw_usart_priv_t *usart_priv = &usart_instance[idx];
|
||
|
dw_usart_reg_t *addr = (dw_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 */
|
||
|
dw_usart_intr_threshold_empty(usart_priv);
|
||
|
break;
|
||
|
|
||
|
case DW_IIR_RECV_DATA: /* interrupt source:receiver data available or receiver fifo trigger level reached */
|
||
|
dw_usart_intr_recv_data(usart_priv);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int32_t __attribute__((weak)) target_usart_init(pin_t tx, pin_t rx, uint32_t *base, uint32_t *irq)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\brief Get driver capabilities.
|
||
|
\param[in] handle usart handle to operate.
|
||
|
\return \ref usart_capabilities_t
|
||
|
*/
|
||
|
usart_capabilities_t csi_usart_get_capabilities(usart_handle_t handle)
|
||
|
{
|
||
|
return usart_capabilities;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\brief Initialize USART Interface. 1. Initializes the resources needed for the USART interface 2.registers event callback function
|
||
|
\param[in] usart pin of tx
|
||
|
\param[in] usart pin of rx
|
||
|
\param[in] cb_event Pointer to \ref usart_event_cb_t
|
||
|
\return return usart handle if success
|
||
|
*/
|
||
|
usart_handle_t csi_usart_initialize(pin_t tx, pin_t rx, usart_event_cb_t cb_event, void *cb_arg)
|
||
|
{
|
||
|
uint32_t base = 0u;
|
||
|
uint32_t irq = 0u;
|
||
|
|
||
|
int32_t idx = target_usart_init(tx, rx, &base, &irq);
|
||
|
|
||
|
if (idx < 0 || idx >= CONFIG_USART_NUM) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
dw_usart_priv_t *usart_priv = &usart_instance[idx];
|
||
|
usart_priv->base = base;
|
||
|
usart_priv->irq = irq;
|
||
|
usart_priv->cb_event = cb_event;
|
||
|
usart_priv->cb_arg = cb_arg;
|
||
|
|
||
|
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
|
||
|
/* FIFO enable */
|
||
|
addr->FCR = DW_FCR_FIFOE;
|
||
|
// /* enable received data available */
|
||
|
// addr->IER = IER_RDA_INT_ENABLE;
|
||
|
drv_nvic_enable_irq(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);
|
||
|
|
||
|
dw_usart_priv_t *usart_priv = handle;
|
||
|
|
||
|
drv_nvic_disable_irq(usart_priv->irq);
|
||
|
usart_priv->cb_event = NULL;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\brief config usart mode.
|
||
|
\param[in] handle usart handle to operate.
|
||
|
\param[in] sysclk configured system clock.
|
||
|
\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
|
||
|
\param[in] baud configured baud
|
||
|
\return error code
|
||
|
*/
|
||
|
int32_t csi_usart_config(usart_handle_t handle,
|
||
|
uint32_t sysclk,
|
||
|
uint32_t baud,
|
||
|
usart_mode_e mode,
|
||
|
usart_parity_e parity,
|
||
|
usart_stop_bits_e stopbits,
|
||
|
usart_data_bits_e bits)
|
||
|
{
|
||
|
USART_NULL_PARAM_CHK(handle);
|
||
|
dw_usart_priv_t *usart_priv = handle;
|
||
|
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
|
||
|
|
||
|
/* control the data_bit of the usart*/
|
||
|
int32_t ret = dw_usart_set_baudrate(addr, baud, sysclk);
|
||
|
|
||
|
if (ret < 0) {
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/* control the parity of the usart*/
|
||
|
ret = dw_usart_set_parity(addr, parity);
|
||
|
|
||
|
if (ret < 0) {
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/* control the stopbit of the usart*/
|
||
|
ret = dw_usart_set_stopbit(addr, stopbits);
|
||
|
|
||
|
if (ret < 0) {
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
ret = dw_usart_set_databit(addr, bits);
|
||
|
|
||
|
if (ret < 0) {
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
/**
|
||
|
\brief config usart default tx value. used in syn mode
|
||
|
\param[in] handle usart handle to operate.
|
||
|
\param[in] value default tx value
|
||
|
\return error code
|
||
|
*/
|
||
|
int32_t csi_usart_set_default_tx_value(usart_handle_t handle, uint32_t value)
|
||
|
{
|
||
|
USART_NULL_PARAM_CHK(handle);
|
||
|
return ERR_USART(EDRV_UNSUPPORTED);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\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(EDRV_PARAMETER);
|
||
|
}
|
||
|
|
||
|
dw_usart_priv_t *usart_priv = handle;
|
||
|
uint8_t *source = NULL;
|
||
|
source = (uint8_t *)data;
|
||
|
|
||
|
usart_priv->tx_buf = (uint8_t *)data;
|
||
|
usart_priv->tx_total_num = num;
|
||
|
usart_priv->tx_cnt = 0;
|
||
|
usart_priv->tx_busy = 1;
|
||
|
|
||
|
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
|
||
|
/* 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);
|
||
|
dw_usart_priv_t *usart_priv = handle;
|
||
|
|
||
|
usart_priv->tx_cnt = usart_priv->tx_total_num;
|
||
|
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);
|
||
|
|
||
|
uint8_t *dest = NULL;
|
||
|
dw_usart_priv_t *usart_priv = handle;
|
||
|
dest = (uint8_t *)data;
|
||
|
|
||
|
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;
|
||
|
|
||
|
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);
|
||
|
|
||
|
dw_usart_priv_t *usart_priv = handle;
|
||
|
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
|
||
|
int32_t recv_num = 0;
|
||
|
|
||
|
while (addr->LSR & 0x1) {
|
||
|
*((uint8_t *)data++) = 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);
|
||
|
dw_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(EDRV_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(EDRV_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;
|
||
|
dw_usart_priv_t *usart_priv = handle;
|
||
|
dw_usart_reg_t *addr = (dw_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;
|
||
|
}
|
||
|
|
||
|
return usart_status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\brief control the transmit.
|
||
|
\param[in] handle usart handle to operate.
|
||
|
\param[in] enable the transmitter.
|
||
|
\return error code
|
||
|
*/
|
||
|
int32_t csi_usart_control_tx(usart_handle_t handle, bool enable)
|
||
|
{
|
||
|
USART_NULL_PARAM_CHK(handle);
|
||
|
return ERR_USART(EDRV_UNSUPPORTED);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\brief control the receive.
|
||
|
\param[in] handle usart handle to operate.
|
||
|
\param[in] enable the receive.
|
||
|
\return error code
|
||
|
*/
|
||
|
int32_t csi_usart_control_rx(usart_handle_t handle, bool enable)
|
||
|
{
|
||
|
USART_NULL_PARAM_CHK(handle);
|
||
|
return ERR_USART(EDRV_UNSUPPORTED);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\brief control the break.
|
||
|
\param[in] handle usart handle to operate.
|
||
|
\param[in] enable the break.
|
||
|
\return error code
|
||
|
*/
|
||
|
int32_t csi_usart_control_break(usart_handle_t handle, bool enable)
|
||
|
{
|
||
|
USART_NULL_PARAM_CHK(handle);
|
||
|
return ERR_USART(EDRV_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);
|
||
|
|
||
|
dw_usart_priv_t *usart_priv = handle;
|
||
|
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
|
||
|
|
||
|
if (type == USART_FLUSH_WRITE) {
|
||
|
addr->FCR |= DW_FCR_XFIFOR;
|
||
|
} else if (type == USART_FLUSH_READ) {
|
||
|
addr->FCR |= DW_FCR_RFIFOR;
|
||
|
} else {
|
||
|
return ERR_USART(EDRV_PARAMETER);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|