rt-thread-official/bsp/xplorer4330/libraries/lpc_ip/usart_001.c

517 lines
14 KiB
C

/*
* @brief usart registers and control functions
*
* @note
* Copyright(C) NXP Semiconductors, 2012
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#include "usart_001.h"
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Private functions
****************************************************************************/
/*****************************************************************************
* Public functions
****************************************************************************/
/* Initializes the UARTx peripheral according to the specified parameters in
the UART_ConfigStruct */
void IP_UART_Init(IP_USART_001_Type *LPC_UART, UART_ID_Type UARTPort)
{
volatile uint32_t tmp;
/* FIFOs are empty */
LPC_UART->FCR = ( UART_FCR_FIFO_EN | UART_FCR_RX_RS | UART_FCR_TX_RS);
/* Disable FIFO */
// LPC_UART->FCR = 0;
/* Dummy reading */
while (LPC_UART->LSR & UART_LSR_RDR) {
tmp = LPC_UART->RBR;
}
#if defined(CHIP_LPC177X_8X) || defined(CHIP_LPC18XX) || defined(CHIP_LPC43XX)
switch (UARTPort) {
#if defined(CHIP_LPC177X_8X)
case 4:
#else
case 0:
case 2:
case 3:
#endif
LPC_UART->TER2 = UART_TER2_TXEN;
/* Wait for current transmit complete */
while (!(LPC_UART->LSR & UART_LSR_THRE)) {}
/* Disable Tx */
LPC_UART->TER2 = 0;
break;
default:
break;
}
#else
LPC_UART->TER1 = UART_TER1_TXEN;
/* Wait for current transmit complete */
while (!(LPC_UART->LSR & UART_LSR_THRE)) {}
/* Disable Tx */
LPC_UART->TER1 = 0;
#endif
/* Disable interrupt */
LPC_UART->IER = 0;
/* Set LCR to default state */
LPC_UART->LCR = 0;
/* Set ACR to default state */
LPC_UART->ACR = 0;
#if defined(CHIP_LPC175X_6X) || defined(CHIP_LPC177X_8X)
if ((UARTPort == 1) || (UARTPort == 4)) {
/* Set RS485 control to default state */
LPC_UART->RS485CTRL = 0;
/* Set RS485 delay timer to default state */
LPC_UART->RS485DLY = 0;
/* Set RS485 addr match to default state */
LPC_UART->RS485ADRMATCH = 0;
}
#else
/* Set RS485 control to default state */
LPC_UART->RS485CTRL = 0;
/* Set RS485 delay timer to default state */
LPC_UART->RS485DLY = 0;
/* Set RS485 addr match to default state */
LPC_UART->RS485ADRMATCH = 0;
#endif
#if defined(CHIP_LPC175X_6X) || defined(CHIP_LPC177X_8X) || defined(CHIP_LPC18XX) || defined(CHIP_LPC43XX)
if (UARTPort == 1) {
#endif
/* Set Modem Control to default state */
LPC_UART->MCR = 0;
/*Dummy Reading to Clear Status */
tmp = LPC_UART->MSR;
#if defined(CHIP_LPC175X_6X) || defined(CHIP_LPC177X_8X) || defined(CHIP_LPC18XX) || defined(CHIP_LPC43XX)
}
#endif
/* Dummy reading */
tmp = LPC_UART->LSR;
/* Set Line Control register ---------------------------- */
// LPC_UART->LCR = UART_DATABIT_8 | /* Default: 8N1 */
// UART_STOPBIT_1 |
// UART_PARITY_NONE;
LPC_UART->FDR = 0x10; /* No fractional divider */
}
/* De-initializes the UARTx peripheral registers to their default reset values */
void IP_UART_DeInit(IP_USART_001_Type *LPC_UART, UART_ID_Type UARTPort)
{
/* For debug mode */
IP_UART_TxCmd(LPC_UART, UARTPort, DISABLE);
switch (UARTPort) {
default:
break;
}
}
/* Determines best dividers to get a target clock rate */
Status IP_UART_SetBaud(IP_USART_001_Type *LPC_UART, uint32_t baudrate, uint32_t uClk)
{
Status errorStatus = ERROR;
uint32_t d, m, bestd, bestm, tmp;
uint64_t best_divisor, divisor;
uint32_t current_error, best_error;
uint32_t recalcbaud;
/* In the Uart IP block, baud rate is calculated using FDR and DLL-DLM registers
* The formula is :
* BaudRate= uClk * (mulFracDiv/(mulFracDiv+dividerAddFracDiv) / (16 * (DLL)
* It involves floating point calculations. That's the reason the formulae are adjusted with
* Multiply and divide method.*/
/* The value of mulFracDiv and dividerAddFracDiv should comply to the following expressions:
* 0 < mulFracDiv <= 15, 0 <= dividerAddFracDiv <= 15 */
best_error = 0xFFFFFFFF;/* Worst case */
bestd = 0;
bestm = 0;
best_divisor = 0;
for (m = 1; m <= 15; m++) {
for (d = 0; d < m; d++) {
divisor = ((uint64_t) uClk << 28) * m / (baudrate * (m + d));
current_error = divisor & 0xFFFFFFFF;
tmp = divisor >> 32;
/* Adjust error */
if (current_error > ((uint32_t) 1 << 31)) {
current_error = -current_error;
tmp++;
}
if (( tmp < 1) || ( tmp > 65536) ) {/* Out of range */
continue;
}
if ( current_error < best_error) {
best_error = current_error;
best_divisor = tmp;
bestd = d;
bestm = m;
if (best_error == 0) {
break;
}
}
} /* end of inner for loop */
if (best_error == 0) {
break;
}
} /* end of outer for loop */
if (best_divisor == 0) {
return ERROR; /* can not find best match */
}
recalcbaud = (uClk >> 4) * bestm / (best_divisor * (bestm + bestd));
/* reuse best_error to evaluate baud error */
if (baudrate > recalcbaud) {
best_error = baudrate - recalcbaud;
}
else {best_error = recalcbaud - baudrate; }
best_error = best_error * 100 / baudrate;
if (best_error < UART_ACCEPTED_BAUDRATE_ERROR) {
LPC_UART->LCR |= UART_LCR_DLAB_EN;
LPC_UART->DLM = UART_LOAD_DLM(best_divisor);
LPC_UART->DLL = UART_LOAD_DLL(best_divisor);
/* Then reset DLAB bit */
LPC_UART->LCR &= (~UART_LCR_DLAB_EN) & UART_LCR_BITMASK;
LPC_UART->FDR = (UART_FDR_MULVAL(bestm) \
| UART_FDR_DIVADDVAL(bestd)) & UART_FDR_BITMASK;
errorStatus = SUCCESS;
}
return errorStatus;
}
/* Configure data width, parity mode and stop bits */
void IP_UART_ConfigData(IP_USART_001_Type *LPC_UART,
UART_DATABIT_Type Databits,
UART_PARITY_Type Parity,
UART_STOPBIT_Type Stopbits)
{
uint32_t tmp = (LPC_UART->LCR & (UART_LCR_DLAB_EN | UART_LCR_BREAK_EN)) & UART_LCR_BITMASK;
tmp |= (uint32_t) Databits | (uint32_t) Parity | (uint32_t) Stopbits;
LPC_UART->LCR = (uint8_t) (tmp & UART_LCR_BITMASK);
}
/* UART Send/Recieve functions -------------------------------------------------*/
/* Transmit a single data through UART peripheral */
Status IP_UART_SendByte(IP_USART_001_Type *LPC_UART, uint8_t Data)
{
if (!(LPC_UART->LSR & UART_LSR_THRE)) {
return ERROR;
}
LPC_UART->THR = Data & UART_THR_MASKBIT;
return SUCCESS;
}
/* Receive a single data from UART peripheral */
Status IP_UART_ReceiveByte(IP_USART_001_Type *LPC_UART, uint8_t *Data)
{
if (!(LPC_UART->LSR & UART_LSR_RDR)) {
return ERROR;
}
*Data = (uint8_t) (LPC_UART->RBR & UART_RBR_MASKBIT);
return SUCCESS;
}
/* Send a block of data via UART peripheral */
uint32_t IP_UART_Send(IP_USART_001_Type *LPC_UART, uint8_t *txbuf, uint32_t buflen, TRANSFER_BLOCK_Type flag)
{
uint32_t bToSend, bSent, timeOut; // , fifo_cnt;
uint8_t *pChar = txbuf;
bToSend = buflen;
/* blocking mode */
if (flag == BLOCKING) {
bSent = 0;
while (bToSend) {
timeOut = UART_BLOCKING_TIMEOUT;
/* Wait for THR empty with timeout */
while (!(IP_UART_SendByte(LPC_UART, *pChar))) {
if (timeOut == 0) {
break;
}
timeOut--;
}
/* Time out! */
if (timeOut == 0) {
break;
}
pChar++;
bToSend--;
bSent++;
}
}
/* None blocking mode */
else {
bSent = 0;
while (bToSend) {
if (!(IP_UART_SendByte(LPC_UART, *pChar))) {
break;
}
pChar++;
bToSend--;
bSent++;
}
}
return bSent;
}
/* Receive a block of data via UART peripheral */
uint32_t IP_UART_Receive(IP_USART_001_Type *LPC_UART, uint8_t *rxbuf, uint32_t buflen, TRANSFER_BLOCK_Type flag)
{
uint32_t bToRecv, bRecv, timeOut;
uint8_t *pChar = rxbuf;
bToRecv = buflen;
/* Blocking mode */
if (flag == BLOCKING) {
bRecv = 0;
while (bToRecv) {
timeOut = UART_BLOCKING_TIMEOUT;
while (!(IP_UART_ReceiveByte(LPC_UART, pChar))) {
if (timeOut == 0) {
break;
}
timeOut--;
}
/* Time out! */
if (timeOut == 0) {
break;
}
pChar++;
bToRecv--;
bRecv++;
}
}
/* None blocking mode */
else {
bRecv = 0;
while (bToRecv) {
if (!(IP_UART_ReceiveByte(LPC_UART, pChar))) {
break;
}
else {
pChar++;
bRecv++;
bToRecv--;
}
}
}
return bRecv;
}
/* Enable or disable specified UART interrupt */
void IP_UART_IntConfig(IP_USART_001_Type *LPC_UART, UART_INT_Type UARTIntCfg, FunctionalState NewState)
{
uint32_t tmp = 0;
switch (UARTIntCfg) {
case UART_INTCFG_RBR:
tmp = UART_IER_RBRINT_EN;
break;
case UART_INTCFG_THRE:
tmp = UART_IER_THREINT_EN;
break;
case UART_INTCFG_RLS:
tmp = UART_IER_RLSINT_EN;
break;
case UART_INTCFG_MS:
tmp = UART_IER_MSINT_EN;
break;
case UART_INTCFG_CTS:
tmp = UART_IER_CTSINT_EN;
break;
case UART_INTCFG_ABEO:
tmp = UART_IER_ABEOINT_EN;
break;
case UART_INTCFG_ABTO:
tmp = UART_IER_ABTOINT_EN;
break;
}
if (NewState == ENABLE) {
LPC_UART->IER |= tmp;
}
else {
LPC_UART->IER &= (~tmp) & UART_IER_BITMASK;
}
}
/* Get Source Interrupt */
uint32_t IP_UART_IntGetStatus(IP_USART_001_Type *LPC_UART)
{
return (LPC_UART->IIR) & UART_IIR_BITMASK;
}
/* Force BREAK character on UART line, output pin UARTx TXD is forced to logic 0 */
void IP_UART_ForceBreak(IP_USART_001_Type *LPC_UART)
{
LPC_UART->LCR |= UART_LCR_BREAK_EN;
}
/* Get current value of Line Status register in UART peripheral */
uint8_t IP_UART_GetLineStatus(IP_USART_001_Type *LPC_UART)
{
return (LPC_UART->LSR) & UART_LSR_BITMASK;
}
/* Check whether if UART is busy or not */
FlagStatus IP_UART_CheckBusy(IP_USART_001_Type *LPC_UART)
{
if (LPC_UART->LSR & UART_LSR_TEMT) {
return RESET;
}
else {
return SET;
}
}
/* Enable/Disable transmission on UART TxD pin */
void IP_UART_TxCmd(IP_USART_001_Type *LPC_UART, UART_ID_Type UARTPort, FunctionalState NewState)
{
if (NewState == ENABLE) {
#if defined(CHIP_LPC177X_8X) || defined(CHIP_LPC18XX) || defined(CHIP_LPC43XX)
switch (UARTPort) {
#if defined(CHIP_LPC177X_8X)
case 4:
#else
case 0:
case 2:
case 3:
#endif
LPC_UART->TER2 = UART_TER2_TXEN;
break;
default:
break;
}
#else
LPC_UART->TER1 = UART_TER1_TXEN;
#endif
}
else {
#if defined(CHIP_LPC177X_8X) || defined(CHIP_LPC18XX) || defined(CHIP_LPC43XX)
switch (UARTPort) {
#if defined(CHIP_LPC177X_8X)
case 4:
#else
case 0:
case 2:
case 3:
#endif
LPC_UART->TER2 &= (~UART_TER2_TXEN) & UART_TER2_BITMASK;
break;
default:
break;
}
#else
LPC_UART->TER1 &= (~UART_TER1_TXEN) & UART_TER1_BITMASK;
#endif
}
}
/* UART FIFO functions ----------------------------------------------------------*/
/* Configure FIFO function on selected UART peripheral */
void IP_UART_FIFOConfig(IP_USART_001_Type *LPC_UART, UART_FIFO_CFG_Type *FIFOCfg)
{
uint8_t tmp = 0;
tmp |= UART_FCR_FIFO_EN;
switch (FIFOCfg->FIFO_Level) {
case UART_FIFO_TRGLEV0:
tmp |= UART_FCR_TRG_LEV0;
break;
case UART_FIFO_TRGLEV1:
tmp |= UART_FCR_TRG_LEV1;
break;
case UART_FIFO_TRGLEV2:
tmp |= UART_FCR_TRG_LEV2;
break;
case UART_FIFO_TRGLEV3:
default:
tmp |= UART_FCR_TRG_LEV3;
break;
}
if (FIFOCfg->FIFO_ResetTxBuf == ENABLE) {
tmp |= UART_FCR_TX_RS;
}
if (FIFOCfg->FIFO_ResetRxBuf == ENABLE) {
tmp |= UART_FCR_RX_RS;
}
if (FIFOCfg->FIFO_DMAMode == ENABLE) {
tmp |= UART_FCR_DMAMODE_SEL;
}
/* write to FIFO control register */
LPC_UART->FCR = tmp & UART_FCR_BITMASK;
}
/* Fills each UART_FIFOInitStruct member with its default value */
void IP_UART_FIFOConfigStructInit(UART_FIFO_CFG_Type *UART_FIFOInitStruct)
{
UART_FIFOInitStruct->FIFO_DMAMode = DISABLE;
UART_FIFOInitStruct->FIFO_Level = UART_FIFO_TRGLEV0;
UART_FIFOInitStruct->FIFO_ResetRxBuf = ENABLE;
UART_FIFOInitStruct->FIFO_ResetTxBuf = ENABLE;
}