1618 lines
57 KiB
C
1618 lines
57 KiB
C
/*
|
|
* Copyright 2017-2019 NXP
|
|
* All rights reserved.
|
|
*
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "fsl_usart.h"
|
|
|
|
/* Component ID definition, used by tools. */
|
|
#ifndef FSL_COMPONENT_ID
|
|
#define FSL_COMPONENT_ID "platform.drivers.vusart"
|
|
#endif
|
|
|
|
enum _usart_transfer_states
|
|
{
|
|
kUSART_TxIdle, /* TX idle. */
|
|
kUSART_TxBusy, /* TX busy. */
|
|
kUSART_RxIdle, /* RX idle. */
|
|
kUSART_RxBusy /* RX busy. */
|
|
};
|
|
|
|
/*******************************************************************************
|
|
* Variables
|
|
******************************************************************************/
|
|
/* Array of USART handle. */
|
|
static usart_handle_t *s_usartHandle[FSL_FEATURE_SOC_USART_COUNT];
|
|
|
|
/*! @brief IRQ name array */
|
|
static const IRQn_Type s_usartIRQ[] = USART_IRQS;
|
|
|
|
/*! @brief Array to map USART instance number to base address. */
|
|
static const uint32_t s_usartBaseAddrs[FSL_FEATURE_SOC_USART_COUNT] = USART_BASE_ADDRS;
|
|
|
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
|
/* @brief Array to map USART instance number to CLOCK names */
|
|
static const clock_ip_name_t s_usartClock[] = USART_CLOCKS;
|
|
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
|
|
|
#if !(defined(FSL_FEATURE_USART_HAS_NO_RESET) && FSL_FEATURE_USART_HAS_NO_RESET)
|
|
/* Reset the USART module */
|
|
static const reset_ip_name_t s_usartResets[] = USART_RSTS;
|
|
#endif
|
|
|
|
/* Typedef for interrupt handler. */
|
|
typedef void (*usart_isr_t)(USART_Type *base, usart_handle_t *handle);
|
|
|
|
/* USART ISR for transactional APIs. */
|
|
static usart_isr_t s_usartIsr;
|
|
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
|
|
/* Get the index corresponding to the USART */
|
|
/*! brief Returns instance number for USART peripheral base address. */
|
|
uint32_t USART_GetInstance(USART_Type *base)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < FSL_FEATURE_SOC_USART_COUNT; i++)
|
|
{
|
|
if ((uint32_t)base == s_usartBaseAddrs[i])
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
assert(false);
|
|
return 0;
|
|
}
|
|
/* Write one byte to TX register. */
|
|
/*!
|
|
* brief Writes to the FIFO TXDATUSART register or TXDAT register.
|
|
*
|
|
* This function will writes data to the txFIFO register or TXDAT automatly, which depend
|
|
* on if the system FIFO is enabled.The upper layer must ensure
|
|
* that txFIFO has space for data to write before calling this function.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param data The byte to write.
|
|
*/
|
|
void USART_WriteByte(USART_Type *base, uint8_t data)
|
|
{
|
|
uint32_t instance = USART_GetInstance(base);
|
|
if (USART_IsTxFifoEnable(base))
|
|
{
|
|
VFIFO->USART[instance].TXDATUSART = data;
|
|
}
|
|
else
|
|
{
|
|
base->TXDAT = data;
|
|
}
|
|
}
|
|
|
|
/* Read one byte from RX register. */
|
|
/*!
|
|
* brief Reads the FIFO RXDATUSART register or RXDAT directly.
|
|
*
|
|
* This function reads data from the FIFO RXDATUSART register or RXDAT automatly. which depend
|
|
* on if the system FIFO is enabled for USART. The upper layer must
|
|
* ensure that the rxFIFO is not empty before calling this function.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* return The byte read from USART data register.
|
|
*/
|
|
uint8_t USART_ReadByte(USART_Type *base)
|
|
{
|
|
uint32_t instance = USART_GetInstance(base);
|
|
return ((USART_IsRxFifoEnable(base)) ? (VFIFO->USART[instance].RXDATUSART) : (base->RXDAT & 0x000000FFU));
|
|
}
|
|
|
|
/* Get system FIFO USART status flags. */
|
|
/*!
|
|
* brief Get system FIFO status flags for USART.
|
|
*
|
|
* This function get all system FIFO status flags for USART, the flags are returned as the logical
|
|
* OR value of the enumerators ref _usart_fifo_flags. To check a specific status,
|
|
* compare the return value with enumerators in ref _usart_fifo_flags.
|
|
* For example, to check whether the TX FIFO is empty:
|
|
* code
|
|
* if (kUSART_TxFifoEmptyFlag & USART_GetFifoStatusFlags(USART1))
|
|
* {
|
|
* ...
|
|
* }
|
|
* endcode
|
|
*
|
|
* param base USART peripheral base address.
|
|
* return USART status flags which are ORed by the enumerators in the _usart_fifo_flags.
|
|
*/
|
|
uint32_t USART_GetFifoStatusFlags(USART_Type *base)
|
|
{
|
|
uint32_t instance = USART_GetInstance(base);
|
|
return (VFIFO->USART[instance].STATUSART);
|
|
}
|
|
|
|
/* Clear system FIFO USART status flag. */
|
|
/*!
|
|
* brief Clear FIFO status flag for USART.
|
|
*
|
|
* This function clear supported USART status flags
|
|
* Flags that can be cleared or set are:
|
|
* kUSART_FifoBusErrorFlag
|
|
* For example:
|
|
* code
|
|
* USART_ClearFifoStatusFlags(USART0, kUSART_FifoBusErrorFlag)
|
|
* endcode
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param mask status flags to be cleared.
|
|
*/
|
|
void USART_ClearFifoStatusFlags(USART_Type *base, uint32_t mask)
|
|
{
|
|
uint32_t instance = USART_GetInstance(base);
|
|
VFIFO->USART[instance].STATUSART |= mask;
|
|
}
|
|
|
|
/* Enable system FIFO interrupts for USART. */
|
|
/*!
|
|
* brief Enables FIFO interrupts for USART according to the provided mask.
|
|
*
|
|
* This function enables the USART FIFO interrupts according to the provided mask. The mask
|
|
* is a logical OR of enumeration members. See ref _usart_interrupt_enable.
|
|
* For example, to enable TX threshold interrupt and RX threshold interrupt:
|
|
* code
|
|
* USART_EnableInterrupts(USART0, kUSART_RxFifoThresholdInterruptEnable | kUSART_RxFifoThresholdInterruptEnable);
|
|
* endcode
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param mask The interrupts to enable. Logical OR of ref _usart_interrupt_enable.
|
|
*/
|
|
void USART_EnableFifoInterrupts(USART_Type *base, uint32_t mask)
|
|
{
|
|
uint32_t instance = USART_GetInstance(base);
|
|
VFIFO->USART[instance].CTLSETUSART |= mask;
|
|
}
|
|
|
|
/* Disable FIFO interrupts for USART. */
|
|
/*!
|
|
* brief Disables FIFO interrupts for USART according to a provided mask.
|
|
*
|
|
* This function disables the USART FIFO interrupts according to a provided mask. The mask
|
|
* is a logical OR of enumeration members. See ref _usart_interrupt_enable.
|
|
* This example shows how to disable the TX threshold interrupt and RX threshold interrupt:
|
|
* code
|
|
* USART_DisableInterrupts(USART1, kUSART_RxFifoThresholdInterruptEnable | kUSART_RxFifoThresholdInterruptEnable);
|
|
* endcode
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param mask The interrupts to disable. Logical OR of ref _usart_fifo_interrupt_enable.
|
|
*/
|
|
void USART_DisableFifoInterrupts(USART_Type *base, uint32_t mask)
|
|
{
|
|
uint32_t instance = USART_GetInstance(base);
|
|
VFIFO->USART[instance].CTLCLRUSART |= mask;
|
|
}
|
|
|
|
/* Get enabled interrupt of FIFO for USART. */
|
|
/*!
|
|
* brief Returns enabled USART FIFO interrupts.
|
|
*
|
|
* This function returns the enabled USART FIFO interrupts.
|
|
*
|
|
* param base USART peripheral base address.
|
|
*/
|
|
uint32_t USART_GetEnabledFifoInterrupts(USART_Type *base)
|
|
{
|
|
uint32_t instance = USART_GetInstance(base);
|
|
return (VFIFO->USART[instance].CTLSETUSART);
|
|
}
|
|
|
|
/* Flush the FIFO for USART transfer. */
|
|
/*!
|
|
* brief Flush the FIFO buffer.
|
|
*
|
|
* This function will Flush tHE fifo buffer.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param direction the fifo direction need to flushed, Tx FIFO or Rx FIFO.
|
|
*/
|
|
void USART_FifoFlush(USART_Type *base, uint32_t direction)
|
|
{
|
|
uint32_t instance = USART_GetInstance(base);
|
|
|
|
if (kUSART_FifoTx & direction)
|
|
{
|
|
VFIFO->USART[instance].CTLSETUSART |= VFIFO_USART_CTLSETUSART_TXFLUSH_MASK;
|
|
VFIFO->USART[instance].CTLCLRUSART |= VFIFO_USART_CTLCLRUSART_TXFLUSHCLR_MASK;
|
|
}
|
|
|
|
if (kUSART_FifoRx & direction)
|
|
{
|
|
VFIFO->USART[instance].CTLSETUSART |= VFIFO_USART_CTLSETUSART_RXFLUSH_MASK;
|
|
VFIFO->USART[instance].CTLCLRUSART |= VFIFO_USART_CTLCLRUSART_RXFLUSHCLR_MASK;
|
|
}
|
|
}
|
|
|
|
/* Enable USART FIFO function. */
|
|
/*!
|
|
* brief Enable FIFO.
|
|
*
|
|
* This function will configure the FIFOs according to the config struct.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param config Pointer to user-defined configuration structure.
|
|
*/
|
|
void USART_EnableFifo(USART_Type *base, const usart_fifo_config_t *config)
|
|
{
|
|
uint32_t instance = 0U;
|
|
|
|
instance = USART_GetInstance(base);
|
|
|
|
/* Enable the system FIFO clock. */
|
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
|
/* Enable the clock. */
|
|
CLOCK_EnableClock(kCLOCK_Fifo);
|
|
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
|
|
|
/* Enable the TX/RX FIFO mode. */
|
|
switch (instance)
|
|
{
|
|
case 0:
|
|
SYSCON->FIFOCTRL &= ~(SYSCON_FIFOCTRL_U0TXFIFOEN_MASK | SYSCON_FIFOCTRL_U0RXFIFOEN_MASK);
|
|
SYSCON->FIFOCTRL |=
|
|
SYSCON_FIFOCTRL_U0TXFIFOEN(config->enableTxFifo) | SYSCON_FIFOCTRL_U0RXFIFOEN(config->enableRxFifo);
|
|
break;
|
|
case 1:
|
|
SYSCON->FIFOCTRL &= ~(SYSCON_FIFOCTRL_U1TXFIFOEN_MASK | SYSCON_FIFOCTRL_U1RXFIFOEN_MASK);
|
|
SYSCON->FIFOCTRL |=
|
|
SYSCON_FIFOCTRL_U1TXFIFOEN(config->enableTxFifo) | SYSCON_FIFOCTRL_U1RXFIFOEN(config->enableRxFifo);
|
|
break;
|
|
case 2:
|
|
SYSCON->FIFOCTRL &= ~(SYSCON_FIFOCTRL_U2TXFIFOEN_MASK | SYSCON_FIFOCTRL_U2RXFIFOEN_MASK);
|
|
SYSCON->FIFOCTRL |=
|
|
SYSCON_FIFOCTRL_U2TXFIFOEN(config->enableTxFifo) | SYSCON_FIFOCTRL_U2RXFIFOEN(config->enableRxFifo);
|
|
break;
|
|
case 3:
|
|
SYSCON->FIFOCTRL &= ~(SYSCON_FIFOCTRL_U3TXFIFOEN_MASK | SYSCON_FIFOCTRL_U3RXFIFOEN_MASK);
|
|
SYSCON->FIFOCTRL |=
|
|
SYSCON_FIFOCTRL_U3TXFIFOEN(config->enableTxFifo) | SYSCON_FIFOCTRL_U3RXFIFOEN(config->enableRxFifo);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
/* Pause the USART FIFO for setting. */
|
|
while (!((VFIFO->FIFOCTLUSART & VFIFO_FIFOCTLUSART_RXPAUSED_MASK) &&
|
|
(VFIFO->FIFOCTLUSART & VFIFO_FIFOCTLUSART_TXPAUSED_MASK)))
|
|
{
|
|
VFIFO->FIFOCTLUSART |= (VFIFO_FIFOCTLUSART_RXPAUSE_MASK | VFIFO_FIFOCTLUSART_TXPAUSE_MASK);
|
|
}
|
|
/* Flush the TX and RX FIFO buffer. */
|
|
USART_FifoFlush(base, kUSART_FifoTx | kUSART_FifoRx);
|
|
/* Set the TX and RX FIFO size. */
|
|
VFIFO->FIFOCFGUSART[instance] =
|
|
VFIFO_FIFOCFGUSART_RXSIZE(config->rxFifoSize) | VFIFO_FIFOCFGUSART_TXSIZE(config->txFifoSize);
|
|
/* Set the TX and RX FIFO threshold size. */
|
|
VFIFO->USART[instance].CFGUSART &= ~(VFIFO_USART_CFGUSART_RXTHRESHOLD_MASK | VFIFO_USART_CFGUSART_TXTHRESHOLD_MASK);
|
|
VFIFO->USART[instance].CFGUSART |= VFIFO_USART_CFGUSART_RXTHRESHOLD(config->rxFifoThreshold) |
|
|
VFIFO_USART_CFGUSART_TXTHRESHOLD(config->txFifoThreshold);
|
|
/* Update all the TX and RX fifo size. */
|
|
VFIFO->FIFOUPDATEUSART |=
|
|
VFIFO_FIFOUPDATEUSART_USART0RXUPDATESIZE_MASK | VFIFO_FIFOUPDATEUSART_USART1RXUPDATESIZE_MASK |
|
|
VFIFO_FIFOUPDATEUSART_USART2RXUPDATESIZE_MASK | VFIFO_FIFOUPDATEUSART_USART3RXUPDATESIZE_MASK |
|
|
VFIFO_FIFOUPDATEUSART_USART0TXUPDATESIZE_MASK | VFIFO_FIFOUPDATEUSART_USART1TXUPDATESIZE_MASK |
|
|
VFIFO_FIFOUPDATEUSART_USART2TXUPDATESIZE_MASK | VFIFO_FIFOUPDATEUSART_USART3TXUPDATESIZE_MASK;
|
|
/* Unpause the system FIFO for transfer. */
|
|
VFIFO->FIFOCTLUSART &= ~(VFIFO_FIFOCTLUSART_RXPAUSE_MASK | VFIFO_FIFOCTLUSART_TXPAUSE_MASK);
|
|
}
|
|
|
|
/*!
|
|
* brief Disable FIFO.
|
|
*
|
|
* This function will disable the FIFO.
|
|
*
|
|
* param base USART peripheral base address.
|
|
*/
|
|
void USART_DisableFifo(USART_Type *base)
|
|
{
|
|
assert(NULL != base);
|
|
uint32_t instance = 0U;
|
|
|
|
instance = USART_GetInstance(base);
|
|
|
|
/* Pause the USART FIFO for setting. */
|
|
while (!((VFIFO->FIFOCTLUSART & VFIFO_FIFOCTLUSART_RXPAUSED_MASK) &&
|
|
(VFIFO->FIFOCTLUSART & VFIFO_FIFOCTLUSART_TXPAUSED_MASK)))
|
|
{
|
|
VFIFO->FIFOCTLUSART |= (VFIFO_FIFOCTLUSART_RXPAUSE_MASK | VFIFO_FIFOCTLUSART_TXPAUSE_MASK);
|
|
}
|
|
/* Flush the TX and RX FIFO buffer. */
|
|
USART_FifoFlush(base, kUSART_FifoTx | kUSART_FifoRx);
|
|
/* Set the TX and RX FIFO size. */
|
|
VFIFO->FIFOCFGUSART[instance] = VFIFO_FIFOCFGUSART_RXSIZE(0U) | VFIFO_FIFOCFGUSART_TXSIZE(0U);
|
|
/* Set the TX and RX FIFO threshold size. */
|
|
VFIFO->USART[instance].CFGUSART &= ~(VFIFO_USART_CFGUSART_RXTHRESHOLD_MASK | VFIFO_USART_CFGUSART_TXTHRESHOLD_MASK);
|
|
/* Disable all FIFO interrupts. */
|
|
USART_DisableFifoInterrupts(base, kUSART_FifoAllinterruptEnable);
|
|
/* Clear all FIFO status flags, only receive timeout and bus error flag can be cleared. */
|
|
USART_ClearFifoStatusFlags(base, kUSART_RxFifoTimeOutFlag | kUSART_FifoBusErrorFlag);
|
|
|
|
/* Unpause the system FIFO for transfer. */
|
|
VFIFO->FIFOCTLUSART &= ~(VFIFO_FIFOCTLUSART_RXPAUSE_MASK | VFIFO_FIFOCTLUSART_TXPAUSE_MASK);
|
|
|
|
/* Disable the TX/RX FIFO mode. */
|
|
switch (instance)
|
|
{
|
|
case 0:
|
|
SYSCON->FIFOCTRL &= ~(SYSCON_FIFOCTRL_U0TXFIFOEN_MASK | SYSCON_FIFOCTRL_U0RXFIFOEN_MASK);
|
|
break;
|
|
case 1:
|
|
SYSCON->FIFOCTRL &= ~(SYSCON_FIFOCTRL_U1TXFIFOEN_MASK | SYSCON_FIFOCTRL_U1RXFIFOEN_MASK);
|
|
break;
|
|
case 2:
|
|
SYSCON->FIFOCTRL &= ~(SYSCON_FIFOCTRL_U2TXFIFOEN_MASK | SYSCON_FIFOCTRL_U2RXFIFOEN_MASK);
|
|
break;
|
|
case 3:
|
|
SYSCON->FIFOCTRL &= ~(SYSCON_FIFOCTRL_U3TXFIFOEN_MASK | SYSCON_FIFOCTRL_U3RXFIFOEN_MASK);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Check if TX FIFO enabled. */
|
|
/*!
|
|
* brief Is TX FIFO enabled.
|
|
*
|
|
* This function will return status if the transmit fifo is enabled. true for enabled and false for not enabled.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param direction the fifo direction need to be check, Tx FIFO or Rx FIFO.
|
|
* return true for enabled and false for not enabled.
|
|
*/
|
|
bool USART_IsTxFifoEnable(USART_Type *base)
|
|
{
|
|
uint32_t instance = USART_GetInstance(base);
|
|
uint32_t fifosize = VFIFO->FIFOCFGUSART[instance];
|
|
bool status = false;
|
|
|
|
/* Check if system FIFO control TX is enabled. */
|
|
switch (instance)
|
|
{
|
|
case 0:
|
|
if (SYSCON->FIFOCTRL & SYSCON_FIFOCTRL_U0TXFIFOEN_MASK)
|
|
{
|
|
status = true;
|
|
}
|
|
break;
|
|
case 1:
|
|
if (SYSCON->FIFOCTRL & SYSCON_FIFOCTRL_U1TXFIFOEN_MASK)
|
|
{
|
|
status = true;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (SYSCON->FIFOCTRL & SYSCON_FIFOCTRL_U2TXFIFOEN_MASK)
|
|
{
|
|
status = true;
|
|
}
|
|
break;
|
|
case 3:
|
|
if (SYSCON->FIFOCTRL & SYSCON_FIFOCTRL_U3TXFIFOEN_MASK)
|
|
{
|
|
status = true;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (true != status)
|
|
{
|
|
return status;
|
|
}
|
|
/* Check if TX FIFO size is available. */
|
|
return (fifosize & VFIFO_FIFOCFGUSART_TXSIZE_MASK) ? (true) : (false);
|
|
}
|
|
|
|
/* Check if RX FIFO enabled. */
|
|
/*!
|
|
* brief Is RX FIFO enabled.
|
|
*
|
|
* This function will return status if the receive fifo is enabled. true for enabled and false for not enabled.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param direction the fifo direction need to be check, Tx FIFO or Rx FIFK.
|
|
* return true for enabled and false for not enabled.
|
|
*/
|
|
bool USART_IsRxFifoEnable(USART_Type *base)
|
|
{
|
|
uint32_t instance = USART_GetInstance(base);
|
|
uint32_t fifosize = VFIFO->FIFOCFGUSART[instance];
|
|
bool status = false;
|
|
|
|
/* Check if system FIFO control RX is enabled. */
|
|
switch (instance)
|
|
{
|
|
case 0:
|
|
if (SYSCON->FIFOCTRL & SYSCON_FIFOCTRL_U0RXFIFOEN_MASK)
|
|
{
|
|
status = true;
|
|
}
|
|
break;
|
|
case 1:
|
|
if (SYSCON->FIFOCTRL & SYSCON_FIFOCTRL_U1RXFIFOEN_MASK)
|
|
{
|
|
status = true;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (SYSCON->FIFOCTRL & SYSCON_FIFOCTRL_U2RXFIFOEN_MASK)
|
|
{
|
|
status = true;
|
|
}
|
|
break;
|
|
case 3:
|
|
if (SYSCON->FIFOCTRL & SYSCON_FIFOCTRL_U3RXFIFOEN_MASK)
|
|
{
|
|
status = true;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (true != status)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
/* Check if RX FIFO size is available. */
|
|
return (fifosize & VFIFO_FIFOCFGUSART_RXSIZE_MASK) ? (true) : (false);
|
|
}
|
|
|
|
/*!
|
|
* brief Get the length of received data in RX ring buffer.
|
|
*
|
|
* param handle USART handle pointer.
|
|
* return Length of received data in RX ring buffer.
|
|
*/
|
|
size_t USART_TransferGetRxRingBufferLength(usart_handle_t *handle)
|
|
{
|
|
size_t size = 0U;
|
|
|
|
/* Check arguments */
|
|
assert(NULL != handle);
|
|
|
|
if (handle->rxRingBufferTail > handle->rxRingBufferHead)
|
|
{
|
|
size = (size_t)(handle->rxRingBufferHead + handle->rxRingBufferSize - handle->rxRingBufferTail);
|
|
}
|
|
else
|
|
{
|
|
size = (size_t)(handle->rxRingBufferHead - handle->rxRingBufferTail);
|
|
}
|
|
return size;
|
|
}
|
|
|
|
static bool USART_TransferIsRxRingBufferFull(usart_handle_t *handle)
|
|
{
|
|
bool full = 0U;
|
|
|
|
/* Check arguments */
|
|
assert(NULL != handle);
|
|
|
|
if (USART_TransferGetRxRingBufferLength(handle) == (handle->rxRingBufferSize - 1U))
|
|
{
|
|
full = true;
|
|
}
|
|
else
|
|
{
|
|
full = false;
|
|
}
|
|
return full;
|
|
}
|
|
|
|
/*!
|
|
* brief Sets up the RX ring buffer.
|
|
*
|
|
* This function sets up the RX ring buffer to a specific USART handle.
|
|
*
|
|
* When the RX ring buffer is used, data received are stored into the ring buffer even when the
|
|
* user doesn't call the USART_TransferReceiveNonBlocking() API. If there is already data received
|
|
* in the ring buffer, the user can get the received data from the ring buffer directly.
|
|
*
|
|
* note When using the RX ring buffer, one byte is reserved for internal use. In other
|
|
* words, if p ringBufferSize is 32, then only 31 bytes are used for saving data.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param handle USART handle pointer.
|
|
* param ringBuffer Start address of the ring buffer for background receiving. Pass NULL to disable the ring buffer.
|
|
* param ringBufferSize size of the ring buffer.
|
|
*/
|
|
void USART_TransferStartRingBuffer(USART_Type *base, usart_handle_t *handle, uint8_t *ringBuffer, size_t ringBufferSize)
|
|
{
|
|
/* Check arguments */
|
|
assert(NULL != base);
|
|
assert(NULL != handle);
|
|
assert(NULL != ringBuffer);
|
|
|
|
/* Setup the ringbuffer address */
|
|
handle->rxRingBuffer = ringBuffer;
|
|
handle->rxRingBufferSize = ringBufferSize;
|
|
handle->rxRingBufferHead = 0U;
|
|
handle->rxRingBufferTail = 0U;
|
|
|
|
/* Ring buffer is ready we can start receiving data */
|
|
if (handle->isRxFifoEnabled)
|
|
{
|
|
/* Start RX threshold interrupt for ring buffer to receive data. */
|
|
USART_EnableFifoInterrupts(base, kUSART_RxFifoThresholdInterruptEnable);
|
|
}
|
|
else
|
|
{
|
|
/* Start receive data read interrupt and reveive overrun interrupt. */
|
|
USART_EnableInterrupts(base, kUSART_RxReadyInterruptEnable | kUSART_HardwareOverRunInterruptEnable);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* brief Aborts the background transfer and uninstalls the ring buffer.
|
|
*
|
|
* This function aborts the background transfer and uninstalls the ring buffer.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param handle USART handle pointer.
|
|
*/
|
|
void USART_TransferStopRingBuffer(USART_Type *base, usart_handle_t *handle)
|
|
{
|
|
/* Check arguments */
|
|
assert(NULL != base);
|
|
assert(NULL != handle);
|
|
|
|
/* If USART is in idle state, dsiable the interrupts for ring buffer. */
|
|
if (handle->rxState == kUSART_RxIdle)
|
|
{
|
|
if (handle->isRxFifoEnabled)
|
|
{
|
|
/* Disable FIFO RX threshold interrupt. */
|
|
USART_DisableFifoInterrupts(base, kUSART_RxFifoThresholdInterruptEnable);
|
|
}
|
|
else
|
|
{
|
|
USART_DisableInterrupts(base, kUSART_RxReadyInterruptEnable | kUSART_HardwareOverRunInterruptEnable);
|
|
}
|
|
}
|
|
handle->rxRingBuffer = NULL;
|
|
handle->rxRingBufferSize = 0U;
|
|
handle->rxRingBufferHead = 0U;
|
|
handle->rxRingBufferTail = 0U;
|
|
}
|
|
|
|
/*!
|
|
* brief Initializes a USART instance with user configuration structure and peripheral clock.
|
|
*
|
|
* This function configures the USART module with the user-defined settings. The user can configure the configuration
|
|
* structure and also get the default configuration by using the USART_GetDefaultConfig() function.
|
|
* Example below shows how to use this API to configure USART.
|
|
* code
|
|
* usart_config_t usartConfig;
|
|
* usartConfig.baudRate_Bps = 115200U;
|
|
* usartConfig.parityMode = kUSART_ParityDisabled;
|
|
* usartConfig.stopBitCount = kUSART_OneStopBit;
|
|
* USART_Init(USART1, &usartConfig, 20000000U);
|
|
* endcode
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param config Pointer to user-defined configuration structure.
|
|
* param srcClock_Hz USART clock source frequency in HZ.
|
|
* retval kStatus_USART_BaudrateNotSupport Baudrate is not support in current clock source.
|
|
* retval kStatus_InvalidArgument USART base address is not valid
|
|
* retval kStatus_Success Status USART initialize succeed
|
|
*/
|
|
status_t USART_Init(USART_Type *base, const usart_config_t *config, uint32_t srcClock_Hz)
|
|
{
|
|
int result = 0U;
|
|
|
|
/* Check arguments */
|
|
assert(!((NULL == base) || (NULL == config) || (0 == srcClock_Hz)));
|
|
if ((NULL == base) || (NULL == config) || (0 == srcClock_Hz))
|
|
{
|
|
return kStatus_InvalidArgument;
|
|
}
|
|
|
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
|
/* Enable usart clock and FRG clock */
|
|
CLOCK_EnableClock(s_usartClock[USART_GetInstance(base)]);
|
|
|
|
#if !(defined(FSL_FEATURE_USART_HAS_NO_RESET) && FSL_FEATURE_USART_HAS_NO_RESET)
|
|
/* Reset the USART module */
|
|
RESET_PeripheralReset(s_usartResets[USART_GetInstance(base)]);
|
|
#endif
|
|
|
|
CLOCK_EnableClock(kCLOCK_Frg);
|
|
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
|
|
|
/* Setup configuration and enable USART to configure other register. */
|
|
base->CFG = USART_CFG_PARITYSEL(config->parityMode) | USART_CFG_STOPLEN(config->stopBitCount) |
|
|
USART_CFG_DATALEN(config->bitCountPerChar) | USART_CFG_LOOP(config->loopback) |
|
|
USART_CFG_SYNCEN(config->syncMode >> 1) | USART_CFG_SYNCMST(config->syncMode) |
|
|
USART_CFG_CLKPOL(config->clockPolarity) | USART_CFG_ENABLE_MASK;
|
|
|
|
/* Setup baudrate */
|
|
result = USART_SetBaudRate(base, config->baudRate_Bps, srcClock_Hz);
|
|
if (kStatus_Success != result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
/* Setting continuous Clock configuration. used for synchronous mode. */
|
|
USART_EnableContinuousSCLK(base, config->enableContinuousSCLK);
|
|
|
|
/* Check if FIFO is enabled from extern configuration. */
|
|
if ((config->fifoConfig.enableTxFifo) || (config->fifoConfig.enableRxFifo))
|
|
{
|
|
USART_EnableFifo(base, &config->fifoConfig);
|
|
}
|
|
/* Setup the USART transmit and receive. */
|
|
USART_EnableTx(base, config->enableTx);
|
|
USART_EnableRx(base, config->enableRx);
|
|
|
|
return kStatus_Success;
|
|
}
|
|
|
|
/*!
|
|
* brief Deinitializes a USART instance.
|
|
*
|
|
* This function waits for TX complete, disables USART and FIFO if used, and disables the USART clock and FIFO clock if
|
|
* used.
|
|
*
|
|
* param base USART peripheral base address.
|
|
*/
|
|
void USART_Deinit(USART_Type *base)
|
|
{
|
|
/* Check arguments */
|
|
assert(NULL != base);
|
|
/* Wait for data transmit complete. */
|
|
while (!(base->STAT & USART_STAT_TXIDLE_MASK))
|
|
{
|
|
}
|
|
if ((USART_IsTxFifoEnable(base)) || (USART_IsRxFifoEnable(base)))
|
|
{
|
|
USART_DisableFifo(base);
|
|
}
|
|
/* Disable the USART module. */
|
|
base->CFG &= ~(USART_CFG_ENABLE_MASK);
|
|
|
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
|
/* Disable the clock. */
|
|
CLOCK_DisableClock(s_usartClock[USART_GetInstance(base)]);
|
|
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
|
}
|
|
|
|
/*!
|
|
* brief Gets the default configuration structure.
|
|
*
|
|
* This function initializes the USART configuration structure to a default value. The default
|
|
* values are:
|
|
* usartConfig->baudRate_Bps = 115200U;
|
|
* usartConfig->parityMode = kUSART_ParityDisabled;
|
|
* usartConfig->stopBitCount = kUSART_OneStopBit;
|
|
* usartConfig->bitCountPerChar = kUSART_8BitsPerChar;
|
|
* usartConfig->loopback = false;
|
|
* usartConfig->enableTx = false;
|
|
* usartConfig->enableRx = false;
|
|
* ...
|
|
* param config Pointer to configuration structure.
|
|
*/
|
|
void USART_GetDefaultConfig(usart_config_t *config)
|
|
{
|
|
/* Check arguments */
|
|
assert(NULL != config);
|
|
|
|
/* Initializes the configure structure to zero. */
|
|
memset(config, 0, sizeof(*config));
|
|
|
|
/* Set always all members ! */
|
|
config->baudRate_Bps = 115200U;
|
|
config->parityMode = kUSART_ParityDisabled;
|
|
config->stopBitCount = kUSART_OneStopBit;
|
|
config->bitCountPerChar = kUSART_8BitsPerChar;
|
|
config->loopback = false;
|
|
config->enableRx = false;
|
|
config->enableTx = false;
|
|
config->fifoConfig.enableTxFifo = false;
|
|
config->fifoConfig.enableRxFifo = false;
|
|
config->fifoConfig.rxFifoSize = 16U;
|
|
config->fifoConfig.txFifoSize = 16U;
|
|
config->fifoConfig.txFifoThreshold = 0U;
|
|
config->fifoConfig.rxFifoThreshold = 0U;
|
|
config->syncMode = kUSART_SyncModeDisabled;
|
|
config->enableContinuousSCLK = false;
|
|
config->clockPolarity = kUSART_RxSampleOnFallingEdge;
|
|
}
|
|
|
|
/*!
|
|
* brief Sets the USART instance baud rate.
|
|
*
|
|
* This function configures the USART module baud rate. This function is used to update
|
|
* the USART module baud rate after the USART module is initialized by the USART_Init.
|
|
* code
|
|
* USART_SetBaudRate(USART1, 115200U, 20000000U);
|
|
* endcode
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param baudrate_Bps USART baudrate to be set.
|
|
* param srcClock_Hz USART clock source frequency in HZ.
|
|
* retval kStatus_USART_BaudrateNotSupport Baudrate is not support in current clock source.
|
|
* retval kStatus_Success Set baudrate succeed.
|
|
* retval kStatus_InvalidArgument One or more arguments are invalid.
|
|
*/
|
|
status_t USART_SetBaudRate(USART_Type *base, uint32_t baudrate_Bps, uint32_t srcClock_Hz)
|
|
{
|
|
uint32_t best_diff = (uint32_t)-1, best_osrval = 0xf, best_brgval = (uint32_t)-1;
|
|
uint32_t osrval, brgval, diff, baudrate;
|
|
|
|
/* check arguments */
|
|
assert(!((NULL == base) || (0 == baudrate_Bps) || (0 == srcClock_Hz)));
|
|
if ((NULL == base) || (0 == baudrate_Bps) || (0 == srcClock_Hz))
|
|
{
|
|
return kStatus_InvalidArgument;
|
|
}
|
|
|
|
/* If synchronous master mode is enabled, only configure the BRG value. */
|
|
if (base->CFG & USART_CFG_SYNCEN_MASK)
|
|
{
|
|
if (base->CFG & USART_CFG_SYNCMST_MASK)
|
|
{
|
|
brgval = srcClock_Hz / baudrate_Bps;
|
|
base->BRG = brgval - 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Smaller values of OSR can make the sampling position within a data bit less accurate and may
|
|
* potentially cause more noise errors or incorrect data.
|
|
*/
|
|
for (osrval = best_osrval; osrval >= 8; osrval--)
|
|
{
|
|
brgval = (srcClock_Hz / ((osrval + 1) * baudrate_Bps)) - 1;
|
|
if (brgval > 0xFFFF)
|
|
{
|
|
continue;
|
|
}
|
|
baudrate = srcClock_Hz / ((osrval + 1) * (brgval + 1));
|
|
diff = baudrate_Bps < baudrate ? baudrate - baudrate_Bps : baudrate_Bps - baudrate;
|
|
if (diff < best_diff)
|
|
{
|
|
best_diff = diff;
|
|
best_osrval = osrval;
|
|
best_brgval = brgval;
|
|
}
|
|
}
|
|
|
|
/* value over range */
|
|
if (best_brgval > 0xFFFF)
|
|
{
|
|
return kStatus_USART_BaudrateNotSupport;
|
|
}
|
|
|
|
base->OSR = best_osrval;
|
|
base->BRG = best_brgval;
|
|
}
|
|
|
|
return kStatus_Success;
|
|
}
|
|
|
|
/*!
|
|
* brief Writes to the TX register using a blocking method.
|
|
*
|
|
* This function polls the TX register, waits for the TX register to be empty or for the TX FIFO
|
|
* to have room and writes data to the TX buffer.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param data Start address of the data to write.
|
|
* param length Size of the data to write.
|
|
*/
|
|
void USART_WriteBlocking(USART_Type *base, const uint8_t *data, size_t length)
|
|
{
|
|
uint32_t instance = 0U;
|
|
/* Check arguments */
|
|
assert(!((NULL == base) || (NULL == data)));
|
|
if ((NULL == base) || (NULL == data))
|
|
{
|
|
return;
|
|
}
|
|
|
|
instance = USART_GetInstance(base);
|
|
|
|
for (; length > 0; length--)
|
|
{
|
|
if (USART_IsTxFifoEnable(base))
|
|
{
|
|
/* Loop until TX FIFO is empty for new data */
|
|
while (!(VFIFO->USART[instance].STATUSART & VFIFO_USART_STATUSART_TXEMPTY_MASK))
|
|
{
|
|
}
|
|
VFIFO->USART[instance].TXDATUSART = *data;
|
|
}
|
|
else
|
|
{
|
|
/* Wait for TX is ready to transmit new data. */
|
|
while (!(base->STAT & USART_STAT_TXRDY_MASK))
|
|
{
|
|
}
|
|
base->TXDAT = *data;
|
|
}
|
|
data++;
|
|
}
|
|
/* Wait to finish transfer */
|
|
while (!(base->STAT & USART_STAT_TXIDLE_MASK))
|
|
{
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* brief Read RX data register using a blocking method.
|
|
*
|
|
* This function polls the RX register, waits for the RX register to be full or for RX FIFO to
|
|
* have data and read data from the TX register.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param data Start address of the buffer to store the received data.
|
|
* param length Size of the buffer.
|
|
* retval kStatus_USART_FramingError Receiver overrun happened while receiving data.
|
|
* retval kStatus_USART_ParityError Noise error happened while receiving data.
|
|
* retval kStatus_USART_NoiseError Framing error happened while receiving data.
|
|
* retval kStatus_USART_RxError Overflow or underflow rxFIFO happened.
|
|
* retval kStatus_Success Successfully received all data.
|
|
*/
|
|
status_t USART_ReadBlocking(USART_Type *base, uint8_t *data, size_t length)
|
|
{
|
|
uint32_t status;
|
|
uint32_t instance = 0U;
|
|
|
|
/* Check arguments */
|
|
assert(!((NULL == base) || (NULL == data)));
|
|
if ((NULL == base) || (NULL == data))
|
|
{
|
|
return kStatus_InvalidArgument;
|
|
}
|
|
|
|
instance = USART_GetInstance(base);
|
|
|
|
for (; length > 0; length--)
|
|
{
|
|
if (USART_IsRxFifoEnable(base))
|
|
{
|
|
/* Wait for RX FIFO is not empty. */
|
|
while ((VFIFO->USART[instance].STATUSART & VFIFO_USART_STATUSART_RXEMPTY_MASK))
|
|
{
|
|
}
|
|
/* Check FIFO receive status. */
|
|
status = VFIFO->USART[instance].STATUSART;
|
|
if (status & VFIFO_USART_STATUSART_BUSERR_MASK)
|
|
{
|
|
return kStatus_USART_FifoBusError;
|
|
}
|
|
status = VFIFO->USART[instance].RXDATSTATUSART;
|
|
if (status & VFIFO_USART_RXDATSTATUSART_FRAMERR_MASK)
|
|
{
|
|
return kStatus_USART_FramingError;
|
|
}
|
|
if (status & VFIFO_USART_RXDATSTATUSART_PARITYERR_MASK)
|
|
{
|
|
return kStatus_USART_ParityError;
|
|
}
|
|
if (status & VFIFO_USART_RXDATSTATUSART_RXNOISE_MASK)
|
|
{
|
|
return kStatus_USART_NoiseError;
|
|
}
|
|
*data = (status & VFIFO_USART_RXDATSTATUSART_RXDAT_MASK);
|
|
}
|
|
else
|
|
{
|
|
/* loop until receive is ready to read */
|
|
while (!(base->STAT & USART_STAT_RXRDY_MASK))
|
|
{
|
|
}
|
|
|
|
/* Check receive status */
|
|
status = base->STAT;
|
|
|
|
if (status & USART_STAT_FRAMERRINT_MASK)
|
|
{
|
|
base->STAT |= USART_STAT_FRAMERRINT_MASK;
|
|
return kStatus_USART_FramingError;
|
|
}
|
|
if (status & USART_STAT_PARITYERRINT_MASK)
|
|
{
|
|
base->STAT |= USART_STAT_PARITYERRINT_MASK;
|
|
return kStatus_USART_ParityError;
|
|
}
|
|
if (status & USART_STAT_RXNOISEINT_MASK)
|
|
{
|
|
base->STAT |= USART_STAT_RXNOISEINT_MASK;
|
|
return kStatus_USART_NoiseError;
|
|
}
|
|
if (base->STAT & USART_STAT_OVERRUNINT_MASK)
|
|
{
|
|
base->STAT |= USART_STAT_OVERRUNINT_MASK;
|
|
return kStatus_USART_HardwareOverrun;
|
|
}
|
|
*data = base->RXDAT;
|
|
}
|
|
data++;
|
|
}
|
|
return kStatus_Success;
|
|
}
|
|
|
|
/*!
|
|
* brief Initializes the USART handle.
|
|
*
|
|
* This function initializes the USART handle which can be used for other USART
|
|
* transactional APIs. Usually, for a specified USART instance,
|
|
* call this API once to get the initialized handle.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param handle USART handle pointer.
|
|
* param callback The callback function.
|
|
* param userData The parameter of the callback function.
|
|
*/
|
|
status_t USART_TransferCreateHandle(USART_Type *base,
|
|
usart_handle_t *handle,
|
|
usart_transfer_callback_t callback,
|
|
void *userData)
|
|
{
|
|
int32_t instance = 0;
|
|
|
|
/* Check 'base' */
|
|
assert(!((NULL == base) || (NULL == handle)));
|
|
if ((NULL == base) || (NULL == handle))
|
|
{
|
|
return kStatus_InvalidArgument;
|
|
}
|
|
|
|
instance = USART_GetInstance(base);
|
|
|
|
memset(handle, 0, sizeof(*handle));
|
|
/* Set the TX/RX state. */
|
|
handle->rxState = kUSART_RxIdle;
|
|
handle->txState = kUSART_TxIdle;
|
|
/* Set the callback and user data. */
|
|
handle->callback = callback;
|
|
handle->userData = userData;
|
|
/* Check if TX/RX FIFO are enabled. */
|
|
handle->isTxFifoEnabled = USART_IsTxFifoEnable(base);
|
|
handle->isRxFifoEnabled = USART_IsRxFifoEnable(base);
|
|
if ((handle->isTxFifoEnabled) || (handle->isRxFifoEnabled))
|
|
{
|
|
handle->rxFifoThreshold = (VFIFO->USART[instance].CFGUSART & VFIFO_USART_CFGUSART_RXTHRESHOLD_MASK) >>
|
|
VFIFO_USART_CFGUSART_RXTHRESHOLD_SHIFT;
|
|
handle->txFifoThreshold = (VFIFO->USART[instance].CFGUSART & VFIFO_USART_CFGUSART_TXTHRESHOLD_MASK) >>
|
|
VFIFO_USART_CFGUSART_TXTHRESHOLD_SHIFT;
|
|
}
|
|
/* Store the handle data to global variables. */
|
|
s_usartHandle[instance] = handle;
|
|
/* Mapping the interrupt function. */
|
|
s_usartIsr = USART_TransferHandleIRQ;
|
|
|
|
/* Enable interrupt in NVIC. */
|
|
EnableIRQ(s_usartIRQ[instance]);
|
|
|
|
return kStatus_Success;
|
|
}
|
|
|
|
/*!
|
|
* brief Transmits a buffer of data using the interrupt method.
|
|
*
|
|
* This function sends data using an interrupt method. This is a non-blocking function, which
|
|
* returns directly without waiting for all data to be written to the TX register. When
|
|
* all data is written to the TX register in the IRQ handler, the USART driver calls the callback
|
|
* function and passes the ref kStatus_USART_TxIdle as status parameter.
|
|
*
|
|
* note The kStatus_USART_TxIdle is passed to the upper layer when all data is written
|
|
* to the TX register. However it does not ensure that all data are sent out. Before disabling the TX,
|
|
* check the kUSART_TransmissionCompleteFlag to ensure that the TX is finished.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param handle USART handle pointer.
|
|
* param xfer USART transfer structure. See #usart_transfer_t.
|
|
* retval kStatus_Success Successfully start the data transmission.
|
|
* retval kStatus_USART_TxBusy Previous transmission still not finished, data not all written to TX register yet.
|
|
* retval kStatus_InvalidArgument Invalid argument.
|
|
*/
|
|
status_t USART_TransferSendNonBlocking(USART_Type *base, usart_handle_t *handle, usart_transfer_t *xfer)
|
|
{
|
|
/* Check arguments */
|
|
assert(!((NULL == base) || (NULL == handle) || (NULL == xfer)));
|
|
if ((NULL == base) || (NULL == handle) || (NULL == xfer))
|
|
{
|
|
return kStatus_InvalidArgument;
|
|
}
|
|
/* Check xfer members */
|
|
assert(!((0 == xfer->dataSize) || (NULL == xfer->data)));
|
|
if ((0 == xfer->dataSize) || (NULL == xfer->data))
|
|
{
|
|
return kStatus_InvalidArgument;
|
|
}
|
|
uint32_t instance = USART_GetInstance(base);
|
|
|
|
/* Return error if current TX busy. */
|
|
if (kUSART_TxBusy == handle->txState)
|
|
{
|
|
return kStatus_USART_TxBusy;
|
|
}
|
|
else
|
|
{
|
|
handle->txData = xfer->data;
|
|
handle->txDataSize = xfer->dataSize;
|
|
handle->txDataSizeAll = xfer->dataSize;
|
|
handle->txState = kUSART_TxBusy;
|
|
/* Check if TX/RX FIFO are enabled. */
|
|
handle->isTxFifoEnabled = USART_IsTxFifoEnable(base);
|
|
handle->isRxFifoEnabled = USART_IsRxFifoEnable(base);
|
|
if ((handle->isTxFifoEnabled) || (handle->isRxFifoEnabled))
|
|
{
|
|
handle->rxFifoThreshold = (VFIFO->USART[instance].CFGUSART & VFIFO_USART_CFGUSART_RXTHRESHOLD_MASK) >>
|
|
VFIFO_USART_CFGUSART_RXTHRESHOLD_SHIFT;
|
|
handle->txFifoThreshold = (VFIFO->USART[instance].CFGUSART & VFIFO_USART_CFGUSART_TXTHRESHOLD_MASK) >>
|
|
VFIFO_USART_CFGUSART_TXTHRESHOLD_SHIFT;
|
|
}
|
|
/* Enable transmiter interrupt. */
|
|
if (handle->isTxFifoEnabled)
|
|
{
|
|
/* Start system fifo usart tx threshold interrupt. */
|
|
USART_EnableFifoInterrupts(base, kUSART_TxFifoThresholdInterruptEnable);
|
|
}
|
|
else
|
|
{
|
|
USART_EnableInterrupts(base, kUSART_TxReadyInterruptEnable);
|
|
/* Clear transmit disable bit. */
|
|
base->CTL &= ~USART_CTL_TXDIS_MASK;
|
|
}
|
|
}
|
|
return kStatus_Success;
|
|
}
|
|
|
|
/*!
|
|
* brief Aborts the interrupt-driven data transmit.
|
|
*
|
|
* This function aborts the interrupt driven data sending. The user can get the remainBtyes to find out
|
|
* how many bytes are still not sent out.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param handle USART handle pointer.
|
|
*/
|
|
void USART_TransferAbortSend(USART_Type *base, usart_handle_t *handle)
|
|
{
|
|
assert(NULL != handle);
|
|
|
|
/* Disable interrupts */
|
|
if (handle->isTxFifoEnabled)
|
|
{
|
|
/* Disable system fifo usart tx threshold interrupt. */
|
|
USART_DisableFifoInterrupts(base, kUSART_TxFifoThresholdInterruptEnable);
|
|
}
|
|
else
|
|
{
|
|
USART_DisableInterrupts(base, kUSART_TxReadyInterruptEnable);
|
|
}
|
|
/* Disable transmit after data being transmitted. */
|
|
USART_EnableTx(base, false);
|
|
|
|
handle->txDataSize = 0;
|
|
handle->txState = kUSART_TxIdle;
|
|
}
|
|
|
|
/*!
|
|
* brief Get the number of bytes that have been written to USART TX register.
|
|
*
|
|
* This function gets the number of bytes that have been written to USART TX
|
|
* register by interrupt method.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param handle USART handle pointer.
|
|
* param count Send bytes count.
|
|
* retval kStatus_NoTransferInProgress No send in progress.
|
|
* retval kStatus_InvalidArgument Parameter is invalid.
|
|
* retval kStatus_Success Get successfully through the parameter \p count;
|
|
*/
|
|
status_t USART_TransferGetSendCount(USART_Type *base, usart_handle_t *handle, uint32_t *count)
|
|
{
|
|
assert(NULL != handle);
|
|
assert(NULL != count);
|
|
|
|
if (kUSART_TxIdle == handle->txState)
|
|
{
|
|
return kStatus_NoTransferInProgress;
|
|
}
|
|
|
|
*count = handle->txDataSizeAll - handle->txDataSize;
|
|
|
|
return kStatus_Success;
|
|
}
|
|
|
|
/*!
|
|
* brief Receives a buffer of data using an interrupt method.
|
|
*
|
|
* This function receives data using an interrupt method. This is a non-blocking function, which
|
|
* returns without waiting for all data to be received.
|
|
* If the RX ring buffer is used and not empty, the data in the ring buffer is copied and
|
|
* the parameter p receivedBytes shows how many bytes are copied from the ring buffer.
|
|
* After copying, if the data in the ring buffer is not enough to read, the receive
|
|
* request is saved by the USART driver. When the new data arrives, the receive request
|
|
* is serviced first. When all data is received, the USART driver notifies the upper layer
|
|
* through a callback function and passes the status parameter ref kStatus_USART_RxIdle.
|
|
* For example, the upper layer needs 10 bytes but there are only 5 bytes in the ring buffer.
|
|
* The 5 bytes are copied to the xfer->data and this function returns with the
|
|
* parameter p receivedBytes set to 5. For the left 5 bytes, newly arrived data is
|
|
* saved from the xfer->data[5]. When 5 bytes are received, the USART driver notifies the upper layer.
|
|
* If the RX ring buffer is not enabled, this function enables the RX and RX interrupt
|
|
* to receive data to the xfer->data. When all data is received, the upper layer is notified.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param handle USART handle pointer.
|
|
* param xfer USART transfer structure, see #usart_transfer_t.
|
|
* param receivedBytes Bytes received from the ring buffer directly.
|
|
* retval kStatus_Success Successfully queue the transfer into transmit queue.
|
|
* retval kStatus_USART_RxBusy Previous receive request is not finished.
|
|
* retval kStatus_InvalidArgument Invalid argument.
|
|
*/
|
|
status_t USART_TransferReceiveNonBlocking(USART_Type *base,
|
|
usart_handle_t *handle,
|
|
usart_transfer_t *xfer,
|
|
size_t *receivedBytes)
|
|
{
|
|
uint32_t i;
|
|
/* How many bytes to copy from ring buffer to user memory. */
|
|
size_t bytesToCopy = 0U;
|
|
/* How many bytes to receive. */
|
|
size_t bytesToReceive;
|
|
/* How many bytes currently have received. */
|
|
size_t bytesCurrentReceived;
|
|
uint32_t instance = USART_GetInstance(base);
|
|
|
|
/* Check arguments */
|
|
assert(!((NULL == base) || (NULL == handle) || (NULL == xfer)));
|
|
if ((NULL == base) || (NULL == handle) || (NULL == xfer))
|
|
{
|
|
return kStatus_InvalidArgument;
|
|
}
|
|
/* Check xfer members */
|
|
assert(!((0 == xfer->dataSize) || (NULL == xfer->data)));
|
|
if ((0 == xfer->dataSize) || (NULL == xfer->data))
|
|
{
|
|
return kStatus_InvalidArgument;
|
|
}
|
|
|
|
/* How to get data:
|
|
1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize
|
|
to uart handle, enable interrupt to store received data to xfer->data. When
|
|
all data received, trigger callback.
|
|
2. If RX ring buffer is enabled and not empty, get data from ring buffer first.
|
|
If there are enough data in ring buffer, copy them to xfer->data and return.
|
|
If there are not enough data in ring buffer, copy all of them to xfer->data,
|
|
save the xfer->data remained empty space to uart handle, receive data
|
|
to this empty space and trigger callback when finished. */
|
|
if (kUSART_RxBusy == handle->rxState)
|
|
{
|
|
return kStatus_USART_RxBusy;
|
|
}
|
|
else
|
|
{
|
|
/* Check if TX/RX FIFO are enabled. */
|
|
handle->isTxFifoEnabled = USART_IsTxFifoEnable(base);
|
|
handle->isRxFifoEnabled = USART_IsRxFifoEnable(base);
|
|
if ((handle->isTxFifoEnabled) || (handle->isRxFifoEnabled))
|
|
{
|
|
handle->rxFifoThreshold = (VFIFO->USART[instance].CFGUSART & VFIFO_USART_CFGUSART_RXTHRESHOLD_MASK) >>
|
|
VFIFO_USART_CFGUSART_RXTHRESHOLD_SHIFT;
|
|
handle->txFifoThreshold = (VFIFO->USART[instance].CFGUSART & VFIFO_USART_CFGUSART_TXTHRESHOLD_MASK) >>
|
|
VFIFO_USART_CFGUSART_TXTHRESHOLD_SHIFT;
|
|
}
|
|
|
|
bytesToReceive = xfer->dataSize;
|
|
bytesCurrentReceived = 0U;
|
|
/* If RX ring buffer is used. */
|
|
if (handle->rxRingBuffer)
|
|
{
|
|
/* Disable USART receive IRQ, protect ring buffer. */
|
|
if (handle->isRxFifoEnabled)
|
|
{
|
|
/* Disable system fifo usart rx threshold interrupt. */
|
|
USART_DisableFifoInterrupts(base, kUSART_RxFifoThresholdInterruptEnable);
|
|
}
|
|
else
|
|
{
|
|
USART_DisableInterrupts(base, kUSART_RxReadyInterruptEnable);
|
|
}
|
|
/* How many bytes in RX ring buffer currently. */
|
|
bytesToCopy = USART_TransferGetRxRingBufferLength(handle);
|
|
if (bytesToCopy)
|
|
{
|
|
bytesToCopy = MIN(bytesToReceive, bytesToCopy);
|
|
bytesToReceive -= bytesToCopy;
|
|
/* Copy data from ring buffer to user memory. */
|
|
for (i = 0U; i < bytesToCopy; i++)
|
|
{
|
|
xfer->data[bytesCurrentReceived++] = handle->rxRingBuffer[handle->rxRingBufferTail];
|
|
/* Wrap to 0. Not use modulo (%) because it might be large and slow. */
|
|
if (handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
|
|
{
|
|
handle->rxRingBufferTail = 0U;
|
|
}
|
|
else
|
|
{
|
|
handle->rxRingBufferTail++;
|
|
}
|
|
}
|
|
}
|
|
/* If ring buffer does not have enough data, still need to read more data. */
|
|
if (bytesToReceive)
|
|
{
|
|
/* No data in ring buffer, save the request to UART handle. */
|
|
handle->rxData = xfer->data + bytesCurrentReceived;
|
|
handle->rxDataSize = bytesToReceive;
|
|
handle->rxDataSizeAll = bytesToReceive;
|
|
handle->rxState = kUSART_RxBusy;
|
|
}
|
|
/* Enable USART receive interrupt for next transfer. */
|
|
if (handle->isRxFifoEnabled)
|
|
{
|
|
/* Enable system fifo usart rx threshold interrupt. */
|
|
USART_EnableFifoInterrupts(base, kUSART_RxFifoThresholdInterruptEnable);
|
|
}
|
|
else
|
|
{
|
|
USART_EnableInterrupts(base, kUSART_RxReadyInterruptEnable);
|
|
}
|
|
/* Call user callback since all data are received. */
|
|
if (0 == bytesToReceive)
|
|
{
|
|
if (handle->callback)
|
|
{
|
|
handle->callback(base, handle, kStatus_USART_RxIdle, handle->userData);
|
|
}
|
|
}
|
|
}
|
|
/* Ring buffer not used. */
|
|
else
|
|
{
|
|
handle->rxData = xfer->data + bytesCurrentReceived;
|
|
handle->rxDataSize = bytesToReceive;
|
|
handle->rxDataSizeAll = bytesToReceive;
|
|
handle->rxState = kUSART_RxBusy;
|
|
|
|
/* Enable RX interrupt. */
|
|
if (handle->isRxFifoEnabled)
|
|
{
|
|
USART_EnableFifoInterrupts(base, kUSART_RxFifoThresholdInterruptEnable);
|
|
}
|
|
else
|
|
{
|
|
USART_EnableInterrupts(base, kUSART_RxReadyInterruptEnable | kUSART_HardwareOverRunInterruptEnable);
|
|
}
|
|
}
|
|
/* Return the how many bytes have read. */
|
|
if (receivedBytes)
|
|
{
|
|
*receivedBytes = bytesCurrentReceived;
|
|
}
|
|
}
|
|
return kStatus_Success;
|
|
}
|
|
|
|
/*!
|
|
* brief Aborts the interrupt-driven data receiving.
|
|
*
|
|
* This function aborts the interrupt-driven data receiving. The user can get the remainBytes to find out
|
|
* how many bytes not received yet.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param handle USART handle pointer.
|
|
*/
|
|
void USART_TransferAbortReceive(USART_Type *base, usart_handle_t *handle)
|
|
{
|
|
assert(NULL != handle);
|
|
|
|
/* Only abort the receive to handle->rxData, the RX ring buffer is still working. */
|
|
if (!handle->rxRingBuffer)
|
|
{
|
|
/* Disable interrupts */
|
|
if (handle->isRxFifoEnabled)
|
|
{
|
|
USART_DisableFifoInterrupts(base, kUSART_RxFifoThresholdInterruptEnable);
|
|
}
|
|
else
|
|
{
|
|
USART_DisableInterrupts(base, kUSART_RxReadyInterruptEnable | kUSART_HardwareOverRunInterruptEnable);
|
|
}
|
|
}
|
|
|
|
handle->rxDataSize = 0U;
|
|
handle->rxState = kUSART_RxIdle;
|
|
}
|
|
|
|
/*!
|
|
* brief Get the number of bytes that have been received.
|
|
*
|
|
* This function gets the number of bytes that have been received.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param handle USART handle pointer.
|
|
* param count Receive bytes count.
|
|
* retval kStatus_NoTransferInProgress No receive in progress.
|
|
* retval kStatus_InvalidArgument Parameter is invalid.
|
|
* retval kStatus_Success Get successfully through the parameter \p count;
|
|
*/
|
|
status_t USART_TransferGetReceiveCount(USART_Type *base, usart_handle_t *handle, uint32_t *count)
|
|
{
|
|
assert(NULL != handle);
|
|
assert(NULL != count);
|
|
|
|
if (kUSART_RxIdle == handle->rxState)
|
|
{
|
|
return kStatus_NoTransferInProgress;
|
|
}
|
|
|
|
*count = handle->rxDataSizeAll - handle->rxDataSize;
|
|
|
|
return kStatus_Success;
|
|
}
|
|
|
|
/*!
|
|
* brief USART IRQ handle function.
|
|
*
|
|
* This function handles the USART transmit and receive IRQ request.
|
|
*
|
|
* param base USART peripheral base address.
|
|
* param handle USART handle pointer.
|
|
*/
|
|
void USART_TransferHandleIRQ(USART_Type *base, usart_handle_t *handle)
|
|
{
|
|
/* Check arguments */
|
|
assert((NULL != base) && (NULL != handle));
|
|
|
|
bool receiveEnabled = (handle->rxDataSize) || (handle->rxRingBuffer);
|
|
bool sendEnabled = handle->txDataSize;
|
|
uint32_t instance = USART_GetInstance(base);
|
|
|
|
/* If RX overrun. */
|
|
if (base->STAT & USART_STAT_OVERRUNINT_MASK)
|
|
{
|
|
/* Clear rx error state. */
|
|
base->STAT |= USART_STAT_OVERRUNINT_MASK;
|
|
/* Trigger callback. */
|
|
if (handle->callback)
|
|
{
|
|
handle->callback(base, handle, kStatus_USART_RxError, handle->userData);
|
|
}
|
|
}
|
|
if ((receiveEnabled &&
|
|
((handle->isRxFifoEnabled) ? (VFIFO->USART[instance].INTSTATUSART & VFIFO_USART_INTSTATUSART_RXTH_MASK) :
|
|
(base->STAT & USART_STAT_RXRDY_MASK))) ||
|
|
(sendEnabled &&
|
|
((handle->isTxFifoEnabled) ? (VFIFO->USART[instance].INTSTATUSART & VFIFO_USART_INTSTATUSART_TXTH_MASK) :
|
|
(base->STAT & USART_STAT_TXRDY_MASK))))
|
|
{
|
|
/* Receive data */
|
|
if ((receiveEnabled) &&
|
|
((handle->isRxFifoEnabled) ? (VFIFO->USART[instance].INTSTATUSART & VFIFO_USART_INTSTATUSART_RXTH_MASK) :
|
|
(base->STAT & USART_STAT_RXRDY_MASK)))
|
|
{
|
|
/* Receive to app bufffer if app buffer is present */
|
|
if ((handle->rxDataSize))
|
|
{
|
|
if (handle->isRxFifoEnabled)
|
|
{
|
|
uint8_t dataToReceive = handle->rxFifoThreshold + 1;
|
|
do
|
|
{
|
|
*handle->rxData = VFIFO->USART[instance].RXDATUSART;
|
|
handle->rxDataSize--;
|
|
handle->rxData++;
|
|
receiveEnabled = ((handle->rxDataSize != 0) || (handle->rxRingBuffer));
|
|
} while ((--dataToReceive) && (handle->rxDataSize));
|
|
}
|
|
else
|
|
{
|
|
*handle->rxData = base->RXDAT;
|
|
handle->rxDataSize--;
|
|
handle->rxData++;
|
|
receiveEnabled = ((handle->rxDataSize != 0) || (handle->rxRingBuffer));
|
|
}
|
|
|
|
if (!handle->rxDataSize)
|
|
{
|
|
if (!handle->rxRingBuffer)
|
|
{
|
|
/* If system FIFO enabled. */
|
|
if (handle->isRxFifoEnabled)
|
|
{
|
|
/* Disable system fifo usart rx threshold interrupt. */
|
|
USART_DisableFifoInterrupts(base, kUSART_RxFifoThresholdInterruptEnable);
|
|
}
|
|
else
|
|
{
|
|
USART_DisableInterrupts(
|
|
base, kUSART_RxReadyInterruptEnable | kUSART_HardwareOverRunInterruptEnable);
|
|
}
|
|
}
|
|
handle->rxState = kUSART_RxIdle;
|
|
if (handle->callback)
|
|
{
|
|
handle->callback(base, handle, kStatus_USART_RxIdle, handle->userData);
|
|
}
|
|
}
|
|
}
|
|
/* Otherwise receive to ring buffer if ring buffer is present */
|
|
else
|
|
{
|
|
if (handle->rxRingBuffer)
|
|
{
|
|
uint8_t count = (handle->isRxFifoEnabled) ? (handle->rxFifoThreshold + 1) : (1U);
|
|
/* If RX ring buffer is full, trigger callback to notify over run. */
|
|
while (count--)
|
|
{
|
|
if (USART_TransferIsRxRingBufferFull(handle))
|
|
{
|
|
if (handle->callback)
|
|
{
|
|
handle->callback(base, handle, kStatus_USART_RxRingBufferOverrun, handle->userData);
|
|
}
|
|
}
|
|
/* If ring buffer is still full after callback function, the oldest data is overridden. */
|
|
if (USART_TransferIsRxRingBufferFull(handle))
|
|
{
|
|
/* Increase handle->rxRingBufferTail to make room for new data. */
|
|
if (handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
|
|
{
|
|
handle->rxRingBufferTail = 0U;
|
|
}
|
|
else
|
|
{
|
|
handle->rxRingBufferTail++;
|
|
}
|
|
}
|
|
/* Read data. */
|
|
if (handle->isRxFifoEnabled)
|
|
{
|
|
handle->rxRingBuffer[handle->rxRingBufferHead] = VFIFO->USART[instance].RXDATUSART;
|
|
}
|
|
else
|
|
{
|
|
handle->rxRingBuffer[handle->rxRingBufferHead] = base->RXDAT;
|
|
}
|
|
/* Increase handle->rxRingBufferHead. */
|
|
if (handle->rxRingBufferHead + 1U == handle->rxRingBufferSize)
|
|
{
|
|
handle->rxRingBufferHead = 0U;
|
|
}
|
|
else
|
|
{
|
|
handle->rxRingBufferHead++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* Send data */
|
|
if (sendEnabled &&
|
|
((handle->isTxFifoEnabled) ? (VFIFO->USART[instance].INTSTATUSART & VFIFO_USART_INTSTATUSART_TXTH_MASK) :
|
|
(base->STAT & USART_STAT_TXRDY_MASK)))
|
|
{
|
|
/* Send data. */
|
|
if (handle->isTxFifoEnabled)
|
|
{
|
|
uint8_t dataToSend = (handle->txFifoThreshold) ? (handle->txFifoThreshold) : (1U);
|
|
do
|
|
{
|
|
VFIFO->USART[instance].TXDATUSART = *handle->txData;
|
|
handle->txDataSize--;
|
|
handle->txData++;
|
|
sendEnabled = handle->txDataSize;
|
|
} while ((--dataToSend) && (sendEnabled));
|
|
}
|
|
else
|
|
{
|
|
base->TXDAT = *handle->txData;
|
|
handle->txDataSize--;
|
|
handle->txData++;
|
|
sendEnabled = handle->txDataSize != 0;
|
|
}
|
|
|
|
if (!sendEnabled)
|
|
{
|
|
/* Disable interrupts */
|
|
if (handle->isTxFifoEnabled)
|
|
{
|
|
USART_DisableFifoInterrupts(base, kUSART_TxFifoThresholdInterruptEnable);
|
|
}
|
|
else
|
|
{
|
|
USART_DisableInterrupts(base, kUSART_TxReadyInterruptEnable);
|
|
}
|
|
handle->txState = kUSART_TxIdle;
|
|
if (handle->callback)
|
|
{
|
|
handle->callback(base, handle, kStatus_USART_TxIdle, handle->userData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Ring buffer is not used */
|
|
if ((NULL == handle->rxRingBuffer) && (handle->isRxFifoEnabled))
|
|
{
|
|
/* Restore if rx transfer ends and rxLevel is different from default value */
|
|
if ((handle->rxDataSize == 0) && (((VFIFO->USART[instance].CFGUSART & VFIFO_USART_CFGUSART_RXTHRESHOLD_MASK) >>
|
|
VFIFO_USART_CFGUSART_RXTHRESHOLD_SHIFT) != handle->rxFifoThreshold))
|
|
{
|
|
VFIFO->USART[instance].CFGUSART =
|
|
((VFIFO->USART[instance].CFGUSART & (~VFIFO_USART_CFGUSART_RXTHRESHOLD_MASK)) |
|
|
VFIFO_USART_CFGUSART_RXTHRESHOLD(handle->rxFifoThreshold));
|
|
}
|
|
/* Decrease level if rx transfer is bellow */
|
|
if ((handle->rxDataSize != 0) &&
|
|
(handle->rxDataSize <= (VFIFO->USART[instance].CFGUSART & VFIFO_USART_CFGUSART_RXTHRESHOLD_MASK) >>
|
|
VFIFO_USART_CFGUSART_RXTHRESHOLD_SHIFT))
|
|
{
|
|
VFIFO->USART[instance].CFGUSART =
|
|
((VFIFO->USART[instance].CFGUSART & (~VFIFO_USART_CFGUSART_RXTHRESHOLD_MASK)) |
|
|
VFIFO_USART_CFGUSART_RXTHRESHOLD(handle->rxDataSize - 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(USART0)
|
|
void USART0_DriverIRQHandler(void)
|
|
{
|
|
s_usartIsr(USART0, s_usartHandle[0]);
|
|
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
|
|
exception return operation might vector to incorrect interrupt */
|
|
#if defined __CORTEX_M && (__CORTEX_M == 4U)
|
|
__DSB();
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#if defined(USART1)
|
|
void USART1_DriverIRQHandler(void)
|
|
{
|
|
s_usartIsr(USART1, s_usartHandle[1]);
|
|
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
|
|
exception return operation might vector to incorrect interrupt */
|
|
#if defined __CORTEX_M && (__CORTEX_M == 4U)
|
|
__DSB();
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#if defined(USART2)
|
|
void USART2_DriverIRQHandler(void)
|
|
{
|
|
s_usartIsr(USART2, s_usartHandle[2]);
|
|
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
|
|
exception return operation might vector to incorrect interrupt */
|
|
#if defined __CORTEX_M && (__CORTEX_M == 4U)
|
|
__DSB();
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#if defined(USART3)
|
|
void USART3_DriverIRQHandler(void)
|
|
{
|
|
s_usartIsr(USART3, s_usartHandle[3]);
|
|
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
|
|
exception return operation might vector to incorrect interrupt */
|
|
#if defined __CORTEX_M && (__CORTEX_M == 4U)
|
|
__DSB();
|
|
#endif
|
|
}
|
|
#endif
|