517 lines
14 KiB
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;
|
||
|
}
|