sdk-ameba-v4.0c_180328/component/common/mbed/targets/hal/rtl8711b/serial_api.c

1521 lines
43 KiB
C
Raw Permalink Normal View History

2019-04-02 08:34:25 +00:00
/** mbed Microcontroller Library
******************************************************************************
* @file serial_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for UART.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "objects.h"
#include "serial_api.h"
#include "serial_ex_api.h"
#include "pinmap.h"
#include <string.h>
typedef VOID (*UARTCB_FUN)(VOID *);
typedef struct {
int TxCount; // how many byte to TX
int RxCount; // how many bytes to RX
u8 *pTxBuf;
u8 *pRxBuf;
u8 UartIndex;
GDMA_InitTypeDef UARTTxGdmaInitStruct;
GDMA_InitTypeDef UARTRxGdmaInitStruct;
UART_InitTypeDef UART_InitStruct;
UART_TypeDef* UARTx;
IRQn_Type IrqNum;
/* for rx DMA timeout */
u32 last_dma_addr;
VOID (*TxCompCallback)(VOID *para); // User Tx complete callback function
VOID (*RxCompCallback)(VOID *para); // User Rx complete callback function
VOID *TxCompCbPara; // the pointer argument for TxCompCbPara
VOID *RxCompCbPara; // the pointer argument for RxCompCallback
}MBED_UART_ADAPTER, *PMBED_UART_ADAPTER;
#define UART_NUM (3)
#define SERIAL_TX_IRQ_EN 0x01
#define SERIAL_RX_IRQ_EN 0x02
#define SERIAL_TX_DMA_EN 0x01
#define SERIAL_RX_DMA_EN 0x02
//#define UART_USE_GTIMER_TO 1
#define UART_TIMER_ID 1
#define UART_TIMER_TO 5000
static uint32_t serial_irq_ids[UART_NUM] = {0, 0, 0};
static uart_irq_handler irq_handler[UART_NUM];
static uint32_t serial_irq_en[UART_NUM]={0, 0, 0};
#ifdef CONFIG_GDMA_EN
static uint32_t serial_dma_en[UART_NUM] = {0, 0, 0};
#endif
MBED_UART_ADAPTER uart_adapter[MAX_UART_INDEX+1];
#ifdef CONFIG_MBED_ENABLED
int stdio_uart_inited = 0;
serial_t stdio_uart;
#endif
int uart1_inited = 0;
int uart0_inited = 0;
#ifdef UART_USE_GTIMER_TO
static void uart_gtimer_deinit(void);
#endif
static const PinMap PinMap_UART_TX[] = {
{PA_4, UART_0, PIN_DATA(PullUp, PINMUX_FUNCTION_UART)},
{PA_23, UART_0, PIN_DATA(PullUp, PINMUX_FUNCTION_UART)},
{PA_26, UART_1, PIN_DATA(PullUp, PINMUX_FUNCTION_UART)},
{PA_17, UART_2, PIN_DATA(PullUp, PINMUX_FUNCTION_UART)},
{PA_30, UART_2, PIN_DATA(PullUp, PINMUX_FUNCTION_UART)},
{NC, NC, 0}
};
static const PinMap PinMap_UART_RX[] = {
{PA_1, UART_0, PIN_DATA(PullUp, PINMUX_FUNCTION_UART)},
{PA_18, UART_0, PIN_DATA(PullUp, PINMUX_FUNCTION_UART)},
{PA_25, UART_1, PIN_DATA(PullUp, PINMUX_FUNCTION_UART)},
{PA_16, UART_2, PIN_DATA(PullUp, PINMUX_FUNCTION_UART)},
{PA_29, UART_2, PIN_DATA(PullUp, PINMUX_FUNCTION_UART)},
{NC, NC, 0}
};
static u32
uart_index_get(PinName tx)
{
if ((tx == _PA_4) || (tx == _PA_23)) {
return 0;
} else if (tx == _PA_26) {
return 1;
} else if ((tx == _PA_17) || (tx == _PA_30)) {
return 2;
} else {
assert_param(0);
}
return 3;
}
static u32
uart_dmasend_complete(
IN VOID *Data
)
{
PMBED_UART_ADAPTER puart_adapter = (PMBED_UART_ADAPTER) Data;
PGDMA_InitTypeDef GDMA_InitStruct;
u8 IsrTypeMap;
puart_adapter->TxCount = 0;
GDMA_InitStruct = &puart_adapter->UARTTxGdmaInitStruct;
// Clean Auto Reload Bit
GDMA_ChCleanAutoReload(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, CLEAN_RELOAD_DST);
// Clear Pending ISR
IsrTypeMap = GDMA_ClearINT(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
/*disable UART TX DMA*/
UART_TXDMACmd(puart_adapter->UARTx, DISABLE);
GDMA_Cmd(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, DISABLE);
GDMA_ChnlFree(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
UART_SetTxFlag(puart_adapter->UartIndex, 0);
// Call user TX complete callback
if (NULL != puart_adapter->TxCompCallback) {
puart_adapter->TxCompCallback(puart_adapter->TxCompCbPara);
}
return 0;
}
static u32
uart_dmarecv_complete(
IN VOID *Data
)
{
PMBED_UART_ADAPTER puart_adapter = (PMBED_UART_ADAPTER) Data;
PGDMA_InitTypeDef GDMA_InitStruct;
u8 IsrTypeMap;
u8 LineStatus;
GDMA_InitStruct = &puart_adapter->UARTRxGdmaInitStruct;
#ifdef UART_USE_GTIMER_TO
RTIM_Cmd(TIMx[UART_TIMER_ID], DISABLE);
uart_gtimer_deinit();
#endif
// Clean Auto Reload Bit
GDMA_ChCleanAutoReload(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, CLEAN_RELOAD_SRC);
// Clear Pending ISR
IsrTypeMap = GDMA_ClearINT(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
/*disable UART RX DMA*/
UART_RXDMACmd(puart_adapter->UARTx, DISABLE);
GDMA_Cmd(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, DISABLE);
GDMA_ChnlFree(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
// Check the Line Status
LineStatus = (u8)UART_LineStatusGet(puart_adapter->UARTx);
UART_SetRxFlag(puart_adapter->UartIndex, 0);
/* close time out */
UART_INTConfig(puart_adapter->UARTx, RUART_IER_ERBI | RUART_IER_ELSI |RUART_IER_ETOI, DISABLE);
// Call User Rx complete callback
if (puart_adapter->RxCompCallback != NULL) {
puart_adapter->RxCompCallback (puart_adapter->RxCompCbPara);
}
return 0;
}
static u32
uart_dmarecv_irqhandler(
IN VOID *Data
)
{
PMBED_UART_ADAPTER puart_adapter = (PMBED_UART_ADAPTER) Data;
puart_adapter->RxCount = 0;
uart_dmarecv_complete(puart_adapter);
return 0;
}
static void uart_txdone_callback(VOID *pAdapter)
{
PMBED_UART_ADAPTER puart_adapter = pAdapter;
u8 uart_idx = puart_adapter->UartIndex;
// Mask UART TX FIFI empty
UART_INTConfig(puart_adapter->UARTx, RUART_IER_ETBEI, DISABLE);
if (irq_handler[uart_idx] != NULL) {
irq_handler[uart_idx](serial_irq_ids[uart_idx], TxIrq);
}
}
static void uart_rxdone_callback(VOID *pAdapter)
{
PMBED_UART_ADAPTER puart_adapter = pAdapter;
u8 uart_idx = puart_adapter->UartIndex;
if (irq_handler[uart_idx] != NULL) {
irq_handler[uart_idx](serial_irq_ids[uart_idx], RxIrq);
}
}
static VOID
uart_intrecv_complete(
IN PMBED_UART_ADAPTER puart_adapter
)
{
volatile u8 LineStatus;
// Disable RX Interrupt
UART_INTConfig(puart_adapter->UARTx, (RUART_IER_ERBI | RUART_IER_ELSI | RUART_IER_ETOI), DISABLE);
// Check the Line Status
LineStatus = (u8)UART_LineStatusGet(puart_adapter->UARTx);
UART_SetRxFlag(puart_adapter->UartIndex, 0);
// Call User Rx complete callback
if (puart_adapter->RxCompCallback != NULL) {
puart_adapter->RxCompCallback (puart_adapter->RxCompCbPara);
}
}
static VOID
uart_intsend_complete(
IN PMBED_UART_ADAPTER puart_adapter
)
{
// Disable Tx FIFO empty interrupt
UART_INTConfig(puart_adapter->UARTx, RUART_IER_ETBEI, DISABLE);
UART_SetTxFlag(puart_adapter->UartIndex, 0);
// Call user TX complete callback
if (NULL != puart_adapter->TxCompCallback) {
puart_adapter->TxCompCallback(puart_adapter->TxCompCbPara);
}
}
static u32
uart_irqhandler(
IN VOID *Data
)
{
volatile u8 reg_iir;
u8 IntId;
u32 RegValue;
PMBED_UART_ADAPTER puart_adapter = (PMBED_UART_ADAPTER) Data;
reg_iir = UART_IntStatus(puart_adapter->UARTx);
if ((reg_iir & RUART_IIR_INT_PEND) != 0) {
// No pending IRQ
return 0;
}
IntId = (reg_iir & RUART_IIR_INT_ID) >> 1;
switch (IntId) {
case RUART_LP_RX_MONITOR_DONE:
RegValue = UART_LPRxMonitorSatusGet(puart_adapter->UARTx);
break;
case RUART_MODEM_STATUS:
RegValue = UART_ModemStatusGet(puart_adapter->UARTx);
break;
case RUART_RECEIVE_LINE_STATUS:
RegValue = UART_LineStatusGet(puart_adapter->UARTx);
break;
case RUART_TX_FIFO_EMPTY:
if (UART_GetTxFlag(puart_adapter->UartIndex)) {
u32 TransCnt = UART_SendDataTO(puart_adapter->UARTx, puart_adapter->pTxBuf,
puart_adapter->TxCount, 1);
puart_adapter->TxCount -= TransCnt;
puart_adapter->pTxBuf += TransCnt;
if (0 == puart_adapter->TxCount) {
uart_intsend_complete(puart_adapter);
}
} else {
// Call Tx done callback
uart_txdone_callback(puart_adapter);
}
break;
case RUART_RECEIVER_DATA_AVAILABLE:
case RUART_TIME_OUT_INDICATION:
if (UART_GetRxFlag(puart_adapter->UartIndex) == STATERX_INT) {
u32 TransCnt = 0;
TransCnt = UART_ReceiveDataTO(puart_adapter->UARTx, puart_adapter->pRxBuf,
puart_adapter->RxCount, 1);
puart_adapter->RxCount -= TransCnt;
puart_adapter->pRxBuf += TransCnt;
if (puart_adapter->RxCount == 0) {
uart_intrecv_complete(puart_adapter);
}
} else {
// Call Rx data ready callback
RegValue = (UART_LineStatusGet(puart_adapter->UARTx));
if (RegValue & RUART_LINE_STATUS_REG_DR) {
uart_rxdone_callback(puart_adapter);
}
}
break;
default:
DBG_PRINTF(MODULE_UART, LEVEL_ERROR, "Unknown Interrupt \n");
break;
}
return 0;
}
#ifdef UART_USE_GTIMER_TO
static void
uart_gtimer_handle(
IN VOID *Data
)
{
PMBED_UART_ADAPTER puart_adapter = (PMBED_UART_ADAPTER) Data;
PGDMA_InitTypeDef GDMA_InitStruct;
u32 TransCnt = 0;
GDMA_InitStruct = &puart_adapter->UARTRxGdmaInitStruct;
RTIM_INTClear(TIMx[UART_TIMER_ID]);
if (UART_GetRxFlag(puart_adapter->UartIndex) == STATERX_DMA) {
u32 Current_Addr = GDMA_GetDstAddr(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
u32 data_in_fifo = UART_Readable(puart_adapter->UARTx);
/* have Rx some data */
if ((Current_Addr != (u32)(puart_adapter->pRxBuf)) || data_in_fifo) {
/* not increase for 5ms */
if (puart_adapter->last_dma_addr == Current_Addr) {
/* rx stop 5ms, packet complete */
RTIM_Cmd(TIMx[UART_TIMER_ID], DISABLE);
//DBG_8195A("%s:UART DMA TO Current_Addr:%x start_addr:%x RxCount: %d\n",
// __func__, Current_Addr, puart_adapter->pRxBuf, puart_adapter->RxCount);
puart_adapter->RxCount = puart_adapter->RxCount - (Current_Addr - (u32)puart_adapter->pRxBuf);
puart_adapter->pRxBuf = (u8*)Current_Addr;
TransCnt = UART_ReceiveDataTO(puart_adapter->UARTx, puart_adapter->pRxBuf,
puart_adapter->RxCount, 1);
puart_adapter->RxCount -= TransCnt;
puart_adapter->pRxBuf += TransCnt;
uart_dmarecv_complete(puart_adapter);
GDMA_Cmd(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, DISABLE);
//DBG_8195A("UART DMA TO RxCount: %d\n", puart_adapter->RxCount);
} else {
puart_adapter->last_dma_addr = Current_Addr;
}
} else { /* rx not start */
puart_adapter->last_dma_addr = (u32)(puart_adapter->pRxBuf);
}
}
}
/**
* @brief Initialize the timer used for the Uart Rx Dma time out.
* @param puart_adapter: a PRUART_VERIFY_PARAMETER pointer.
* @param Period: the desired timeout value (Unit: microsecond).
*
* @retval none
*/
static void
uart_gtimer_init(PMBED_UART_ADAPTER puart_adapter, u32 PeriodUs)
{
RTIM_TimeBaseInitTypeDef TIM_InitStructTmp;
RTIM_TimeBaseStructInit(&TIM_InitStructTmp);
TIM_InitStructTmp.TIM_Idx = UART_TIMER_ID;
TIM_InitStructTmp.TIM_Prescaler = 0x00;
TIM_InitStructTmp.TIM_Period = (PeriodUs / 31 - 1);
TIM_InitStructTmp.TIM_UpdateEvent = ENABLE; /* UEV enable */
TIM_InitStructTmp.TIM_UpdateSource = TIM_UpdateSource_Overflow;
TIM_InitStructTmp.TIM_ARRProtection = DISABLE;
RTIM_TimeBaseInit(TIMx[UART_TIMER_ID], &TIM_InitStructTmp,
TIMx_irq[UART_TIMER_ID], (IRQ_FUN) uart_gtimer_handle,
(u32)puart_adapter);
RTIM_INTConfig(TIMx[UART_TIMER_ID], TIM_IT_Update, ENABLE);
}
static void
uart_gtimer_deinit(void)
{
InterruptDis(TIMx_irq[UART_TIMER_ID]);
InterruptUnRegister(TIMx_irq[UART_TIMER_ID]);
RTIM_DeInit(TIMx[UART_TIMER_ID]);
}
#endif
/**
* @brief Initializes the UART device, include clock/function/interrupt/UART registers.
* @param obj: uart object define in application software.
* @param tx: Tx PinName according to pinmux spec.
* @param rx: Rx PinName according to pinmux spec.
* @retval none
*/
void serial_init(serial_t *obj, PinName tx, PinName rx)
{
uint8_t uart_idx = uart_index_get(tx);
UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX);
UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX);
UARTName UARTx = (UARTName)pinmap_merge(uart_tx, uart_rx);
PMBED_UART_ADAPTER puart_adapter = NULL;
assert_param(UARTx != (UARTName)NC);
obj->uart_idx = uart_idx;
puart_adapter = &(uart_adapter[obj->uart_idx]);
puart_adapter->UartIndex = uart_idx;
puart_adapter->UARTx = UART_DEV_TABLE[uart_idx].UARTx;
puart_adapter->IrqNum = UART_DEV_TABLE[uart_idx].IrqNum;
InterruptRegister((IRQ_FUN)uart_irqhandler, puart_adapter->IrqNum, (u32)puart_adapter, 10);
InterruptEn(puart_adapter->IrqNum, 10);
/*Enable Uart Ip Clock*/
switch (puart_adapter->UartIndex) {
case 0:
/* UART 0 */
RCC_PeriphClockCmd(APBPeriph_UART0, APBPeriph_UART0_CLOCK, ENABLE);
break;
case 1:
/* UART 1 */
RCC_PeriphClockCmd(APBPeriph_UART1, APBPeriph_UART1_CLOCK, ENABLE);
break;
default:
break;
}
/* Configure the UART pins */
pinmap_pinout(tx, PinMap_UART_TX);
pinmap_pinout(rx, PinMap_UART_RX);
UART_StructInit(&puart_adapter->UART_InitStruct);
UART_Init(puart_adapter->UARTx, &puart_adapter->UART_InitStruct);
#ifdef CONFIG_MBED_ENABLED
// For stdio management
if (uart_idx == STDIO_UART) {
stdio_uart_inited = 1;
memcpy(&stdio_uart, obj, sizeof(serial_t));
}
#endif
if (uart_idx == 0)
uart0_inited = 1;
if (uart_idx == 1)
uart1_inited = 1;
}
/**
* @brief Deinitializes the UART device, include clock/function/interrupt/UART registers.
* @param obj: uart object define in application software.
* @retval none
*/
void serial_free(serial_t *obj)
{
PMBED_UART_ADAPTER puart_adapter = &(uart_adapter[obj->uart_idx]);
UART_DeInit(puart_adapter->UARTx);
InterruptDis(puart_adapter->IrqNum);
InterruptUnRegister(puart_adapter->IrqNum);
#ifdef UART_USE_GTIMER_TO
uart_gtimer_deinit();
#endif
#ifdef CONFIG_GDMA_EN
if (serial_dma_en[obj->uart_idx] & SERIAL_RX_DMA_EN) {
GDMA_ChnlFree(puart_adapter->UARTRxGdmaInitStruct.GDMA_Index,
puart_adapter->UARTRxGdmaInitStruct.GDMA_ChNum);
serial_dma_en[obj->uart_idx] &= ~SERIAL_RX_DMA_EN;
}
if (serial_dma_en[obj->uart_idx] & SERIAL_TX_DMA_EN) {
GDMA_ChnlFree(puart_adapter->UARTTxGdmaInitStruct.GDMA_Index,
puart_adapter->UARTTxGdmaInitStruct.GDMA_ChNum);
serial_dma_en[obj->uart_idx] &= ~SERIAL_TX_DMA_EN;
}
#endif
if (obj->uart_idx == 0)
uart0_inited = 0;
if (obj->uart_idx == 1)
uart1_inited = 0;
// TODO: recovery Pin Mux
}
/**
* @brief Set UART device baudrate.
* @param obj: uart object define in application software.
* @param baudrate: Baud Rate Val, like 115200 (unit is HZ).
* @retval none
*/
void serial_baud(serial_t *obj, int baudrate)
{
PMBED_UART_ADAPTER puart_adapter = &(uart_adapter[obj->uart_idx]);
UART_SetBaud(puart_adapter->UARTx, baudrate);
UART_RxCmd(puart_adapter->UARTx, ENABLE);
if (baudrate <= 500000) {
if (uart_config[obj->uart_idx].LOW_POWER_RX_ENABLE) {
LPUART_InitTypeDef LPUART_InitStruct;
UART_LPRxpathSet(puart_adapter->UARTx, ENABLE);
UART_LPRxIPClockSet(puart_adapter->UARTx, UART_RX_CLK_OSC_8M);
UART_LPRxStructInit(&LPUART_InitStruct);
UART_LPRxInit(puart_adapter->UARTx, &LPUART_InitStruct);
UART_LPRxMonitorCmd(puart_adapter->UARTx, ENABLE);
UART_LPRxBaudSet(puart_adapter->UARTx, baudrate, OSC8M_CLOCK);
UART_LPRxCmd(puart_adapter->UARTx, ENABLE);
}else{
UART_LPRxpathSet(puart_adapter->UARTx, DISABLE);
UART_LPRxIPClockSet(puart_adapter->UARTx, UART_RX_CLK_XTAL_40M);
}
}
}
/**
* @brief Set UART format.
* @param obj: uart object define in application software.
* @param data_bits: data bits, this parameter can be one of the following values:
* @arg 7
* @arg 8
* @param parity: this parameter can be one of the following values:
* @arg ParityNone
* @arg ParityOdd
* @arg ParityEven
* @arg ParityForced1: same action with ParityOdd
* @arg ParityForced0: same action with ParityEven
* @param stop_bits: this parameter can be one of the following values:
* @arg 2
* @arg 1
* @retval none
*/
void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits)
{
PMBED_UART_ADAPTER puart_adapter = &(uart_adapter[obj->uart_idx]);
UART_TypeDef* UARTx = UART_DEV_TABLE[obj->uart_idx].UARTx;
UART_RxCmd(puart_adapter->UARTx, DISABLE);
if (data_bits == 8) {
puart_adapter->UART_InitStruct.WordLen = RUART_WLS_8BITS;
} else {
puart_adapter->UART_InitStruct.WordLen = RUART_WLS_7BITS;
}
switch (parity) {
case ParityOdd:
case ParityForced0:
puart_adapter->UART_InitStruct.Parity = RUART_PARITY_ENABLE;
puart_adapter->UART_InitStruct.ParityType = RUART_ODD_PARITY;
break;
case ParityEven:
case ParityForced1:
puart_adapter->UART_InitStruct.Parity = RUART_PARITY_ENABLE;
puart_adapter->UART_InitStruct.ParityType = RUART_EVEN_PARITY;
break;
default: // ParityNone
puart_adapter->UART_InitStruct.Parity = RUART_PARITY_DISABLE;
break;
}
if (stop_bits == 2) {
puart_adapter->UART_InitStruct.StopBit = RUART_STOP_BIT_2;
} else {
puart_adapter->UART_InitStruct.StopBit = RUART_STOP_BIT_1;
}
UARTx->LCR = ((puart_adapter->UART_InitStruct.WordLen) |
(puart_adapter->UART_InitStruct.StopBit << 2) |
(puart_adapter->UART_InitStruct.Parity << 3) |
(puart_adapter->UART_InitStruct.ParityType << 4) |
(puart_adapter->UART_InitStruct.StickParity << 5));
UART_RxCmd(puart_adapter->UARTx, ENABLE);
}
/**
* @brief Set UART interrupt hander if needed.
* @param obj: uart object define in application software.
* @param handler: interrupt callback function
* @param handler: interrupt callback parameter
* @retval none
*/
void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
{
PMBED_UART_ADAPTER puart_adapter;
u8 uart_idx;
puart_adapter = &(uart_adapter[obj->uart_idx]);
uart_idx = puart_adapter->UartIndex;
irq_handler[uart_idx] = handler;
serial_irq_ids[uart_idx] = id;
}
/**
* @brief Enable/Disable UART interrupt.
* @param obj: uart object define in application software.
* @param irq: Tx or Rx interrupt, this parameter can be one of the following values:
* @arg RxIrq
* @arg TxIrq
* @param enable:, this parameter can be one of the following values:
* @arg 0 disable
* @arg 1 enable
* @retval none
*/
void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
{
PMBED_UART_ADAPTER puart_adapter;
u8 uart_idx;
puart_adapter = &(uart_adapter[obj->uart_idx]);
uart_idx = puart_adapter->UartIndex;
if (enable) {
if (irq == RxIrq) {
serial_irq_en[uart_idx] |= SERIAL_RX_IRQ_EN;
UART_INTConfig(puart_adapter->UARTx, RUART_IER_ERBI | RUART_IER_ELSI | RUART_IER_ETOI, ENABLE);
}
else {
serial_irq_en[uart_idx] |= SERIAL_TX_IRQ_EN;
}
}
else { // disable
if (irq == RxIrq) {
serial_irq_en[uart_idx] &= ~SERIAL_RX_IRQ_EN;
UART_INTConfig(puart_adapter->UARTx, (RUART_IER_ERBI | RUART_IER_ELSI | RUART_IER_ETOI), DISABLE);
}
else {
serial_irq_en[uart_idx] &= ~SERIAL_TX_IRQ_EN;
UART_INTConfig(puart_adapter->UARTx, RUART_IER_ETBEI, DISABLE);
}
}
}
/**
* @brief get one byte from UART.
* @param obj: uart object define in application software.
* @retval received data
* @note this function is asynchronous API.
*/
int serial_getc(serial_t *obj)
{
PMBED_UART_ADAPTER puart_adapter=&(uart_adapter[obj->uart_idx]);
u8 RxByte = 0;
while (!serial_readable(obj));
UART_CharGet(puart_adapter->UARTx, &RxByte);
return (int)RxByte;
}
/**
* @brief send one byte use UART.
* @param obj: uart object define in application software.
* @param c: the data to transmit.
* @retval none
* @note this function is asynchronous API.
*/
void serial_putc(serial_t *obj, int c)
{
PMBED_UART_ADAPTER puart_adapter=&(uart_adapter[obj->uart_idx]);
while (!serial_writable(obj));
UART_CharPut(puart_adapter->UARTx, (c & 0xFF));
if (serial_irq_en[obj->uart_idx] & SERIAL_TX_IRQ_EN) {
// UnMask TX FIFO empty IRQ
UART_INTConfig(puart_adapter->UARTx, RUART_IER_ETBEI, ENABLE);
}
}
/**
* @brief check if there is data in rx fifo.
* @param obj: uart object define in application software.
* @retval status value:
* - 1: TRUE
* - 0: FALSE
*/
int serial_readable(serial_t *obj)
{
PMBED_UART_ADAPTER puart_adapter=&(uart_adapter[obj->uart_idx]);
if (UART_Readable(puart_adapter->UARTx)) {
return 1;
} else {
return 0;
}
}
/**
* @brief check if write data to tx fifo is permitted.
* @param obj: uart object define in application software.
* @retval status value:
* - 1: TRUE
* - 0: FALSE
*/
int serial_writable(serial_t *obj)
{
PMBED_UART_ADAPTER puart_adapter=&(uart_adapter[obj->uart_idx]);
if (UART_Writable(puart_adapter->UARTx)) {
return 1;
} else {
return 0;
}
}
/**
* @brief Clear Rx fifo.
* @param obj: uart object define in application software.
*/
void serial_clear(serial_t *obj)
{
PMBED_UART_ADAPTER puart_adapter;
puart_adapter = &(uart_adapter[obj->uart_idx]);
UART_ClearRxFifo(puart_adapter->UARTx);
}
/**
* @brief set tx pinmux.
* @param tx: Tx PinName according to pinmux spec.
*/
void serial_pinout_tx(PinName tx)
{
Pinmux_Config(tx, PINMUX_FUNCTION_UART);
}
/**
* @brief enable UART break contol function.
* @param obj: uart object define in application software.
*/
void serial_break_set(serial_t *obj)
{
PMBED_UART_ADAPTER puart_adapter=&(uart_adapter[obj->uart_idx]);
UART_BreakCtl(puart_adapter->UARTx, 1);
}
/**
* @brief disable UART break contol function.
* @param obj: uart object define in application software.
*/
void serial_break_clear(serial_t *obj)
{
PMBED_UART_ADAPTER puart_adapter=&(uart_adapter[obj->uart_idx]);
UART_BreakCtl(puart_adapter->UARTx, 0);
}
/**
* @brief set TX complete handler.
* @param obj: uart object define in application software.
* @param handler: TX complete callback function.
* @param id: TX complete callback function parameter.
* @retval none
* @note this function is used when asynchronous API is used.
*/
void serial_send_comp_handler(serial_t *obj, void *handler, uint32_t id)
{
PMBED_UART_ADAPTER puart_adapter;
puart_adapter = &(uart_adapter[obj->uart_idx]);
puart_adapter->TxCompCallback = (UARTCB_FUN)handler;
puart_adapter->TxCompCbPara = (void*)id;
}
/**
* @brief set RX complete handler.
* @param obj: uart object define in application software.
* @param handler: RX complete callback function.
* @param id: RX complete callback function parameter.
* @retval none
* @note this function is used when asynchronous API is used.
*/
void serial_recv_comp_handler(serial_t *obj, void *handler, uint32_t id)
{
PMBED_UART_ADAPTER puart_adapter;
puart_adapter = &(uart_adapter[obj->uart_idx]);
puart_adapter->RxCompCallback = (UARTCB_FUN)handler;
puart_adapter->RxCompCbPara = (void*)id;
}
/**
* @brief recv target length data use interrupt mode.
* @param obj: uart object define in application software.
* @param prxbuf: buffer to save data read from UART FIFO.
* @param len: number of data to be read.
* @retval HAL_Status
* @note this function is asynchronous API.
*/
int32_t serial_recv_stream (serial_t *obj, char *prxbuf, uint32_t len)
{
PMBED_UART_ADAPTER puart_adapter=&(uart_adapter[obj->uart_idx]);
int ret = HAL_OK;
u32 TransCnt = 0;
assert_param(prxbuf != NULL);
assert_param(len != 0);
if (UART_GetRxFlag(puart_adapter->UartIndex)) {
DBG_PRINTF(MODULE_UART, LEVEL_WARN, "uart int rx: busy\n");
return HAL_BUSY;
}
obj->rx_len = len;
puart_adapter->pRxBuf = (uint8_t*)prxbuf;
puart_adapter->RxCount = len;
UART_SetRxFlag(puart_adapter->UartIndex, STATERX_INT);
// Could be the RX FIFO has some data already
TransCnt = UART_ReceiveDataTO(puart_adapter->UARTx, puart_adapter->pRxBuf,
puart_adapter->RxCount, 1);
puart_adapter->RxCount -= TransCnt;
puart_adapter->pRxBuf += TransCnt;
if (puart_adapter->RxCount == 0) {
uart_intrecv_complete(puart_adapter);
} else {
// Enable RX Interrupt
UART_INTConfig(puart_adapter->UARTx, RUART_IER_ERBI | RUART_IER_ELSI | RUART_IER_ETOI, ENABLE);
}
return (ret);
}
/**
* @brief send target length data use interrupt mode.
* @param obj: uart object define in application software.
* @param ptxbuf: buffer to be written to Tx FIFO.
* @param len: number of data to be send.
* @retval HAL_Status
* @note this function is asynchronous API.
*/
int32_t serial_send_stream (serial_t *obj, char *ptxbuf, uint32_t len)
{
PMBED_UART_ADAPTER puart_adapter=&(uart_adapter[obj->uart_idx]);
int ret = 0;
u32 TransCnt = 0;
assert_param(ptxbuf != NULL);
assert_param(len != 0);
if (UART_GetTxFlag(puart_adapter->UartIndex)) {
DBG_PRINTF(MODULE_UART, LEVEL_WARN, "uart int tx: busy\n");
return HAL_BUSY;
}
obj->tx_len = len;
puart_adapter->pTxBuf = (uint8_t*)ptxbuf;
puart_adapter->TxCount = len;
UART_SetTxFlag(puart_adapter->UartIndex, STATETX_INT);
TransCnt = UART_SendDataTO(puart_adapter->UARTx, puart_adapter->pTxBuf,
puart_adapter->TxCount, 1);
puart_adapter->TxCount -= TransCnt;
puart_adapter->pTxBuf += TransCnt;
if (0 == puart_adapter->TxCount) {
uart_intsend_complete(puart_adapter);
} else {
// Enable Tx FIFO empty interrupt
UART_INTConfig(puart_adapter->UARTx, RUART_IER_ETBEI, ENABLE);
}
return (ret);
}
/**
* @brief recv target length data use DMA mode.
* @param obj: uart object define in application software.
* @param prxbuf: buffer to save data read from UART FIFO.
* @param len: number of data to be read.
* @retval HAL_Status
* @note this function is asynchronous API.
*/
int32_t serial_recv_stream_dma (serial_t *obj, char *prxbuf, uint32_t len)
{
PMBED_UART_ADAPTER puart_adapter=&(uart_adapter[obj->uart_idx]);
HAL_Status ret = HAL_OK;
u32 ret1;
if (uart_config[obj->uart_idx].LOW_POWER_RX_ENABLE) {
return serial_recv_stream (obj, prxbuf, len);
}
//ret = HalRuartRecv(puart_adapter, (u8*)prxbuf, len, DMA_BASED);
assert_param(prxbuf != NULL);
assert_param(len != 0);
if (UART_GetRxFlag(puart_adapter->UartIndex)) {
DBG_PRINTF(MODULE_UART, LEVEL_WARN, "uart dma rx: busy\n");
return HAL_BUSY;
}
obj->rx_len = len;
puart_adapter->pRxBuf = (uint8_t*)prxbuf;
puart_adapter->RxCount = len;
puart_adapter->last_dma_addr = (u32)prxbuf;
UART_SetRxFlag(puart_adapter->UartIndex, STATERX_DMA);
// Disable Rx interrupt
UART_INTConfig(puart_adapter->UARTx, (RUART_IER_ERBI | RUART_IER_ELSI | RUART_IER_ETOI), DISABLE);
UART_RXDMAConfig(puart_adapter->UARTx, 4);
UART_RXDMACmd(puart_adapter->UARTx, ENABLE);
ret1 = UART_RXGDMA_Init(puart_adapter->UartIndex, &puart_adapter->UARTRxGdmaInitStruct,
puart_adapter, uart_dmarecv_irqhandler,
puart_adapter->pRxBuf, puart_adapter->RxCount);
NVIC_SetPriority(GDMA_IrqNum[0][puart_adapter->UARTRxGdmaInitStruct.GDMA_ChNum], 12);
if ((serial_dma_en[obj->uart_idx] & SERIAL_RX_DMA_EN)==0) {
if(ret1 == _TRUE) {
serial_dma_en[obj->uart_idx] |= SERIAL_RX_DMA_EN;
} else {
return HAL_BUSY;
}
}
#ifdef UART_USE_GTIMER_TO
uart_gtimer_init(puart_adapter, UART_TIMER_TO);
RTIM_Cmd(TIMx[UART_TIMER_ID], ENABLE);
#endif
return (ret);
}
/**
* @brief send target length data use DMA mode.
* @param obj: uart object define in application software.
* @param ptxbuf: buffer to be written to Tx FIFO.
* @param len: number of data to be send.
* @retval HAL_Status
* @note this function is asynchronous API.
*/
int32_t serial_send_stream_dma (serial_t *obj, char *ptxbuf, uint32_t len)
{
PMBED_UART_ADAPTER puart_adapter=&(uart_adapter[obj->uart_idx]);
int32_t ret = HAL_OK;
u32 ret1;
if (uart_config[obj->uart_idx].LOW_POWER_RX_ENABLE) {
return serial_send_stream (obj, ptxbuf, len);
}
assert_param(ptxbuf != NULL);
assert_param(len != 0);
if (UART_GetTxFlag(puart_adapter->UartIndex)) {
DBG_PRINTF(MODULE_UART, LEVEL_WARN, "uart dma tx: busy\n");
return HAL_BUSY;
}
obj->tx_len = len;
puart_adapter->pTxBuf = (uint8_t*)ptxbuf;
puart_adapter->TxCount = len;
UART_SetTxFlag(puart_adapter->UartIndex, STATETX_DMA);
UART_TXDMAConfig(puart_adapter->UARTx, 8);
UART_TXDMACmd(puart_adapter->UARTx, ENABLE);
ret1 = UART_TXGDMA_Init(puart_adapter->UartIndex, &puart_adapter->UARTTxGdmaInitStruct,
puart_adapter, uart_dmasend_complete,
puart_adapter->pTxBuf, puart_adapter->TxCount);
NVIC_SetPriority(GDMA_IrqNum[0][puart_adapter->UARTTxGdmaInitStruct.GDMA_ChNum], 12);
if ((serial_dma_en[obj->uart_idx] & SERIAL_TX_DMA_EN)==0) {
if(ret1 == _TRUE) {
serial_dma_en[obj->uart_idx] |= SERIAL_TX_DMA_EN;
} else {
return HAL_BUSY;
}
}
return (ret);
}
/**
* @brief stop the sream or steam_dma RX.
* @param obj: uart object define in application software.
*/
int32_t serial_send_stream_abort (serial_t *obj)
{
PMBED_UART_ADAPTER puart_adapter=&(uart_adapter[obj->uart_idx]);
int ret = 0;
if (!UART_GetTxFlag(puart_adapter->UartIndex)) {
//DBG_PRINTF(MODULE_UART, LEVEL_WARN, "uart tx abort: Not in TX state \n");
return HAL_OK;
}
// Disable Tx FIFO empty interrupt
UART_INTConfig(puart_adapter->UARTx, RUART_IER_ETBEI, DISABLE);
if(UART_GetTxFlag(puart_adapter->UartIndex) == STATERX_DMA) {
if (uart_config[obj->uart_idx].LOW_POWER_RX_ENABLE == DISABLE) {
u32 Current_Addr;
PGDMA_InitTypeDef GDMA_InitStruct = &puart_adapter->UARTTxGdmaInitStruct;
u8 IsrTypeMap;
Current_Addr = GDMA_GetSrcAddr(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
GDMA_Cmd(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, DISABLE);
puart_adapter->TxCount = puart_adapter->TxCount - (Current_Addr - (u32)puart_adapter->pTxBuf);
puart_adapter->pTxBuf = (u8*)Current_Addr;
// Clean Auto Reload Bit
GDMA_ChCleanAutoReload(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, CLEAN_RELOAD_DST);
// Clear Pending ISR
IsrTypeMap = GDMA_ClearINT(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
//GDMA_Cmd(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, DISABLE);
GDMA_ChnlFree(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
UART_TXDMACmd(puart_adapter->UARTx, DISABLE);
}
}
UART_SetTxFlag(puart_adapter->UartIndex, 0);
UART_ClearTxFifo(puart_adapter->UARTx);
ret = obj->tx_len - puart_adapter->TxCount;
return (ret);
}
/**
* @brief stop the sream or steam_dma TX.
* @param obj: uart object define in application software.
*/
int32_t serial_recv_stream_abort (serial_t *obj)
{
PMBED_UART_ADAPTER puart_adapter=&(uart_adapter[obj->uart_idx]);
int ret = 0;
if (!UART_GetRxFlag(puart_adapter->UartIndex)) {
//DBG_PRINTF(MODULE_UART, LEVEL_WARN, "uart rx abort: Not in TX state \n");
return HAL_OK;
}
// Disable Rx interrupt
UART_INTConfig(puart_adapter->UARTx, (RUART_IER_ERBI | RUART_IER_ELSI | RUART_IER_ETOI), DISABLE);
if(UART_GetRxFlag(puart_adapter->UartIndex) == STATERX_DMA) {
if (uart_config[obj->uart_idx].LOW_POWER_RX_ENABLE == DISABLE) {
u32 Current_Addr;
u32 TransCnt;
PGDMA_InitTypeDef GDMA_InitStruct = &puart_adapter->UARTRxGdmaInitStruct;
u8 IsrTypeMap;
/*when stream DMA mode used, some data may be in uart rx fifo, get it if transmission aborted*/
Current_Addr = GDMA_GetDstAddr(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
GDMA_Cmd(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, DISABLE);
puart_adapter->RxCount = puart_adapter->RxCount - (Current_Addr - (u32)puart_adapter->pRxBuf);
puart_adapter->pRxBuf = (u8*)Current_Addr;
TransCnt = UART_ReceiveDataTO(puart_adapter->UARTx, puart_adapter->pRxBuf,
puart_adapter->RxCount, 1);
puart_adapter->RxCount -= TransCnt;
puart_adapter->pRxBuf += TransCnt;
// Clean Auto Reload Bit
GDMA_ChCleanAutoReload(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, CLEAN_RELOAD_DST);
// Clear Pending ISR
IsrTypeMap = GDMA_ClearINT(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
//GDMA_Cmd(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, DISABLE);
GDMA_ChnlFree(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
UART_RXDMACmd(puart_adapter->UARTx, DISABLE);
}
}
UART_SetRxFlag(puart_adapter->UartIndex, 0);
UART_ClearRxFifo(puart_adapter->UARTx);
ret = obj->rx_len - puart_adapter->RxCount;
return (ret);
}
/**
* @brief Clear TX fifo.
* @param obj: uart object define in application software.
*/
void serial_clear_tx(serial_t *obj)
{
UART_TypeDef* UARTx = UART_DEV_TABLE[obj->uart_idx].UARTx;
UART_ClearTxFifo(UARTx);
}
/**
* @brief Clear RX fifo.
* @param obj: uart object define in application software.
*/
void serial_clear_rx(serial_t *obj)
{
UART_TypeDef* UARTx = UART_DEV_TABLE[obj->uart_idx].UARTx;
UART_ClearRxFifo(UARTx);
}
/**
* @brief recv target length data use poll mode, with time out.
* @param obj: uart object define in application software.
* @param ptxbuf: buffer to be written to Tx FIFO.
* @param len: number of data to be recv.
* @param timeout_ms: polling time before timeout.
* @retval return received bytes count
* @note this function is synchronous API.
*/
int32_t serial_recv_blocked (serial_t *obj, char *prxbuf, uint32_t len, uint32_t timeout_ms)
{
UART_TypeDef* UARTx = UART_DEV_TABLE[obj->uart_idx].UARTx;
uint32_t cnt = 0;
uint32_t startcount = SYSTIMER_TickGet();
obj->rx_len = len;
while (1) {
while (!serial_readable(obj));
UART_CharGet(UARTx, prxbuf);
prxbuf++;
cnt++;
if (cnt == len) {
break;
}
if (SYSTIMER_GetPassTime(startcount) > timeout_ms) {
break;
}
}
return cnt;
}
/**
* @brief send target length data use poll mode, with time out.
* @param obj: uart object define in application software.
* @param ptxbuf: buffer to be written to Tx FIFO.
* @param len: number of data to be send.
* @param timeout_ms: polling time before timeout.
* @retval transmitted bytes count
* @note this function is synchronous API.
*/
int32_t serial_send_blocked (serial_t *obj, char *ptxbuf, uint32_t len, uint32_t timeout_ms)
{
UART_TypeDef* UARTx = UART_DEV_TABLE[obj->uart_idx].UARTx;
uint32_t cnt = 0;
uint32_t startcount = SYSTIMER_TickGet();
obj->tx_len = len;
while (1) {
while (!serial_writable(obj));
UART_CharPut(UARTx, *ptxbuf);
ptxbuf++;
cnt++;
if (cnt == len) {
break;
}
if (SYSTIMER_GetPassTime(startcount) > timeout_ms) {
break;
}
}
return cnt;
}
/**
* @brief disable uart clock and function.
* @retval none
*/
void serial_disable (serial_t *obj)
{
switch (obj->uart_idx) {
case 0:
/* UART 0 */
RCC_PeriphClockCmd(APBPeriph_UART0, APBPeriph_UART0_CLOCK, DISABLE);
break;
case 1:
/* UART 1 */
RCC_PeriphClockCmd(APBPeriph_UART1, APBPeriph_UART1_CLOCK, DISABLE);
break;
default:
break;
}
}
/**
* @brief enable uart clock and function.
* @retval none
*/
void serial_enable (serial_t *obj)
{
switch (obj->uart_idx) {
case 0:
/* UART 0 */
RCC_PeriphClockCmd(APBPeriph_UART0, APBPeriph_UART0_CLOCK, ENABLE);
break;
case 1:
/* UART 1 */
RCC_PeriphClockCmd(APBPeriph_UART1, APBPeriph_UART1_CLOCK, ENABLE);
break;
default:
break;
}
}
/**
* @brief send target length data use interrupt mode.
* @param obj: uart object define in application software.
* @param ptxbuf: buffer to be written to Tx FIFO.
* @param len: number of data to be recv.
* @retval the byte count received before timeout, or error(<0)
* @note this function is asynchronous API.
*/
int32_t serial_recv_stream_timeout (serial_t *obj,
char *prxbuf,
uint32_t len,
uint32_t timeout_ms,
void *force_cs)
{
UART_TypeDef* UARTx = UART_DEV_TABLE[obj->uart_idx].UARTx;
PMBED_UART_ADAPTER puart_adapter=&(uart_adapter[obj->uart_idx]);
u32 TransCnt = 0;
void (*task_yield)(void);
uint32_t startcount = SYSTIMER_TickGet();
assert_param(prxbuf != NULL);
assert_param(len != 0);
assert_param(timeout_ms > 0);
//ret = HalRuartRecv(puart_adapter, (u8*)prxbuf, len, INT_BASED);
if (UART_GetRxFlag(obj->uart_idx)) {
DBG_PRINTF(MODULE_UART, LEVEL_WARN, "uart int rx: busy\n");
return -1;
}
puart_adapter->pRxBuf = (uint8_t*)prxbuf;
puart_adapter->RxCount = len;
UART_SetRxFlag(obj->uart_idx, STATERX_INT);
// Could be the RX FIFO has some data already
TransCnt = UART_ReceiveDataTO(UARTx, puart_adapter->pRxBuf,
puart_adapter->RxCount, 1);
puart_adapter->RxCount -= TransCnt;
puart_adapter->pRxBuf += TransCnt;
if (puart_adapter->RxCount == 0) {
uart_intrecv_complete(puart_adapter);
return len;
} else {
// Enable RX Interrupt
UART_INTConfig(UARTx, RUART_IER_ERBI | RUART_IER_ELSI | RUART_IER_ETOI, ENABLE);
}
if (puart_adapter->RxCount > 0) {
task_yield = (void (*)(void))force_cs;
while (1) {
/* complete */
if (UART_GetRxFlag(obj->uart_idx) != STATERX_INT) {
break;
}
/* time out */
if (SYSTIMER_GetPassTime(startcount) > timeout_ms) {
serial_recv_stream_abort(obj);
}
if (NULL != task_yield) {
task_yield();
}
}
}
return (len - puart_adapter->RxCount);
}
/**
* @brief send target length data use DMA mode.
* @param obj: uart object define in application software.
* @param ptxbuf: buffer to be written to Tx FIFO.
* @param len: number of data to be recv.
* @retval the byte count received before timeout, or error(<0)
* @note this function is asynchronous API.
*/
int32_t serial_recv_stream_dma_timeout (serial_t *obj,
char *prxbuf,
uint32_t len,
uint32_t timeout_ms,
void *force_cs)
{
UART_TypeDef* UARTx = UART_DEV_TABLE[obj->uart_idx].UARTx;
PMBED_UART_ADAPTER puart_adapter=&(uart_adapter[obj->uart_idx]);
void (*task_yield)(void);
uint32_t startcount = SYSTIMER_TickGet();
u32 ret1;
if (uart_config[obj->uart_idx].LOW_POWER_RX_ENABLE) {
return serial_recv_stream_timeout (obj, prxbuf, len, timeout_ms, force_cs);
}
assert_param(prxbuf != NULL);
assert_param(len != 0);
assert_param(timeout_ms > 0);
if (UART_GetRxFlag(puart_adapter->UartIndex)) {
DBG_PRINTF(MODULE_UART, LEVEL_WARN, "uart dma rx: busy\n");
return -1;
}
puart_adapter->pRxBuf = (u8*)prxbuf;
puart_adapter->RxCount = len;
puart_adapter->last_dma_addr = (u32)prxbuf;
UART_SetRxFlag(puart_adapter->UartIndex, STATERX_DMA);
// Disable Rx interrupt
UART_INTConfig(puart_adapter->UARTx, (RUART_IER_ERBI | RUART_IER_ELSI | RUART_IER_ETOI), DISABLE);
UART_RXDMAConfig(puart_adapter->UARTx, 4);
UART_RXDMACmd(puart_adapter->UARTx, ENABLE);
ret1 = UART_RXGDMA_Init(puart_adapter->UartIndex, &puart_adapter->UARTRxGdmaInitStruct,
puart_adapter, uart_dmarecv_irqhandler,
puart_adapter->pRxBuf, puart_adapter->RxCount);
if ((serial_dma_en[obj->uart_idx] & SERIAL_RX_DMA_EN)==0) {
if(ret1 == _TRUE) {
serial_dma_en[obj->uart_idx] |= SERIAL_RX_DMA_EN;
} else {
return -1;
}
}
if (puart_adapter->RxCount > 0) {
task_yield = (void (*)(void))force_cs;
while (1) {
/* complete */
if (UART_GetRxFlag(obj->uart_idx) != STATERX_DMA) {
break;
}
/* time out */
if (SYSTIMER_GetPassTime(startcount) > timeout_ms) {
uint32_t current_dst_addr = GDMA_GetDstAddr(puart_adapter->UARTRxGdmaInitStruct.GDMA_Index,
puart_adapter->UARTRxGdmaInitStruct.GDMA_ChNum);
uint32_t data_in_fifo = UART_Readable(puart_adapter->UARTx);
uint32_t trans_cnt = 0;
/* have Rx some data */
if ((current_dst_addr != (u32)(puart_adapter->pRxBuf)) || data_in_fifo) {
puart_adapter->RxCount = puart_adapter->RxCount - (current_dst_addr - (u32)puart_adapter->pRxBuf);
puart_adapter->pRxBuf = (u8*)current_dst_addr;
trans_cnt = UART_ReceiveDataTO(puart_adapter->UARTx, puart_adapter->pRxBuf,
puart_adapter->RxCount, 1);
puart_adapter->RxCount -= trans_cnt;
puart_adapter->pRxBuf += trans_cnt;
}
uart_dmarecv_complete(puart_adapter);
break;
}
if (NULL != task_yield) {
task_yield();
}
}
}
return (len - puart_adapter->RxCount);
}
/**
* @brief set uart rx fifo trigger level.
* @param obj: uart object define in application software.
* @param FifoLv: FIFO level enum index.
* @retval none
*/
void serial_rx_fifo_level(serial_t *obj, SerialFifoLevel FifoLv)
{
UART_TypeDef* UARTx = UART_DEV_TABLE[obj->uart_idx].UARTx;
u32 Temp;
switch(FifoLv) {
case FifoLv1Byte:
Temp = UART_RX_FIFOTRIG_LEVEL_1BYTES;
break;
case FifoLvQuarter:
Temp = UART_RX_FIFOTRIG_LEVEL_4BYTES;
break;
case FifoLvHalf:
Temp = UART_RX_FIFOTRIG_LEVEL_8BYTES;
break;
case FifoLvFull:
Temp = UART_RX_FIFOTRIG_LEVEL_14BYTES;
break;
default:
assert_param(0);
break;
}
/*set rx fifo level*/
UART_SetRxLevel(UARTx, Temp);
}
/**
* @brief uart autoflow contol setting.
* @param obj: uart object define in application software.
* @param type: autoflow control type.
* @param rxflow: RTS pin.
* @param txflow: CTS pin.
* @retval none
*/
void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow)
{
UART_TypeDef* UARTx = UART_DEV_TABLE[obj->uart_idx].UARTx;
/*Only UART0 supports auto flow control in AmebaZ*/
assert_param(obj->uart_idx == 0);
/*autoflow control configuration*/
if(type != FlowControlNone) {
/*config UART0 pinmux*/
if(rxflow == PA_3) {
/*UART0 "S0" */
Pinmux_Config(_PA_3, PINMUX_FUNCTION_UART); /*RTS*/
Pinmux_Config(_PA_2, PINMUX_FUNCTION_UART); /*CTS*/
} else if (rxflow == PA_22) {
/*UART0 "S1" */
Pinmux_Config(_PA_22, PINMUX_FUNCTION_UART); /*RTS*/
Pinmux_Config(_PA_19, PINMUX_FUNCTION_UART); /*CTS*/
} else {
assert_param(0);
}
/*enable auto flow control*/
UARTx->MCR |= BIT(5);
} else {
/*disable auto flow control*/
UARTx->MCR &= ~ BIT(5);
}
/*no matter auto flow control is enabled or disabled,
RTS pin should be always Low, and thus peer can send data*/
UARTx->MCR |= BIT(1);
}
/******************* (C) COPYRIGHT 2016 Realtek Semiconductor *****END OF FILE****/