438 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			438 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /****************************************************************************
 | ||
|  |  *   $Id:: uart.c 7125 2011-04-15 00:22:12Z usb01267                        $ | ||
|  |  *   Project: NXP LPC13Uxx UART example | ||
|  |  * | ||
|  |  *   Description: | ||
|  |  *     This file contains UART code example which include UART  | ||
|  |  *     initialization, UART interrupt handler, and related APIs for  | ||
|  |  *     UART access. | ||
|  |  * | ||
|  |  **************************************************************************** | ||
|  | * Software that is described herein is for illustrative purposes only | ||
|  | * which provides customers with programming information regarding the | ||
|  | * products. This software is supplied "AS IS" without any warranties. | ||
|  | * NXP Semiconductors assumes no responsibility or liability for the | ||
|  | * use of the software, conveys no license or title under any patent, | ||
|  | * copyright, or mask work right to the product. NXP Semiconductors | ||
|  | * reserves the right to make changes in the software without | ||
|  | * notification. NXP Semiconductors also make no representation or | ||
|  | * warranty that such application will be suitable for the specified | ||
|  | * use without further testing or modification. | ||
|  | * Permission to use, copy, modify, and distribute this software and its | ||
|  | * documentation is hereby granted, under NXP Semiconductors' | ||
|  | * relevant copyright 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 "LPC13Uxx.h"
 | ||
|  | #include "type.h"
 | ||
|  | #include "uart.h"
 | ||
|  | 
 | ||
|  | volatile uint32_t UARTStatus; | ||
|  | volatile uint8_t  UARTTxEmpty = 1; | ||
|  | volatile uint8_t  UARTBuffer[BUFSIZE]; | ||
|  | volatile uint32_t UARTCount = 0; | ||
|  | 
 | ||
|  | #if AUTOBAUD_ENABLE
 | ||
|  | volatile uint32_t UARTAutoBaud = 0, AutoBaudTimeout = 0; | ||
|  | #endif
 | ||
|  | 
 | ||
|  | /*****************************************************************************
 | ||
|  | ** Function name:		USART_IRQHandler | ||
|  | ** | ||
|  | ** Descriptions:		USART interrupt handler | ||
|  | ** | ||
|  | ** parameters:			None | ||
|  | ** Returned value:		None | ||
|  | **  | ||
|  | *****************************************************************************/ | ||
|  | void USART_IRQHandler(void) | ||
|  | { | ||
|  |   uint8_t IIRValue, LSRValue; | ||
|  |   uint8_t Dummy = Dummy; | ||
|  | 
 | ||
|  |   IIRValue = LPC_USART->IIR; | ||
|  |      | ||
|  |   IIRValue >>= 1;			/* skip pending bit in IIR */ | ||
|  |   IIRValue &= 0x07;			/* check bit 1~3, interrupt identification */ | ||
|  |   if (IIRValue == IIR_RLS)		/* Receive Line Status */ | ||
|  |   { | ||
|  |     LSRValue = LPC_USART->LSR; | ||
|  |     /* Receive Line Status */ | ||
|  |     if (LSRValue & (LSR_OE | LSR_PE | LSR_FE | LSR_RXFE | LSR_BI)) | ||
|  |     { | ||
|  |       /* There are errors or break interrupt */ | ||
|  |       /* Read LSR will clear the interrupt */ | ||
|  |       UARTStatus = LSRValue; | ||
|  |       Dummy = LPC_USART->RBR;	/* Dummy read on RX to clear 
 | ||
|  | 								interrupt, then bail out */ | ||
|  |       return; | ||
|  |     } | ||
|  |     if (LSRValue & LSR_RDR)	/* Receive Data Ready */			 | ||
|  |     { | ||
|  |       /* If no error on RLS, normal ready, save into the data buffer. */ | ||
|  |       /* Note: read RBR will clear the interrupt */ | ||
|  |       UARTBuffer[UARTCount++] = LPC_USART->RBR; | ||
|  |       if (UARTCount == BUFSIZE) | ||
|  |       { | ||
|  |         UARTCount = 0;		/* buffer overflow */ | ||
|  |       }	 | ||
|  |     } | ||
|  |   } | ||
|  |   else if (IIRValue == IIR_RDA)	/* Receive Data Available */ | ||
|  |   { | ||
|  |     /* Receive Data Available */ | ||
|  |     UARTBuffer[UARTCount++] = LPC_USART->RBR; | ||
|  |     if (UARTCount == BUFSIZE) | ||
|  |     { | ||
|  |       UARTCount = 0;		/* buffer overflow */ | ||
|  |     } | ||
|  |   } | ||
|  |   else if (IIRValue == IIR_CTI)	/* Character timeout indicator */ | ||
|  |   { | ||
|  |     /* Character Time-out indicator */ | ||
|  |     UARTStatus |= 0x100;		/* Bit 9 as the CTI error */ | ||
|  |   } | ||
|  |   else if (IIRValue == IIR_THRE)	/* THRE, transmit holding register empty */ | ||
|  |   { | ||
|  |     /* THRE interrupt */ | ||
|  |     LSRValue = LPC_USART->LSR;		/* Check status in the LSR to see if
 | ||
|  | 								valid data in U0THR or not */ | ||
|  |     if (LSRValue & LSR_THRE) | ||
|  |     { | ||
|  |       UARTTxEmpty = 1; | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |       UARTTxEmpty = 0; | ||
|  |     } | ||
|  |   } | ||
|  | #if AUTOBAUD_ENABLE
 | ||
|  |   if (LPC_USART->IIR & IIR_ABEO) /* End of Auto baud */ | ||
|  |   { | ||
|  | 	LPC_USART->IER &= ~IIR_ABEO; | ||
|  | 	/* clear bit ABEOInt in the IIR by set ABEOIntClr in the ACR register */ | ||
|  | 	LPC_USART->ACR |= IIR_ABEO; | ||
|  | 	UARTAutoBaud = 1; | ||
|  |   } | ||
|  |   else if (LPC_USART->IIR & IIR_ABTO)/* Auto baud time out */ | ||
|  |   { | ||
|  | 	LPC_USART->IER &= ~IIR_ABTO; | ||
|  | 	AutoBaudTimeout = 1; | ||
|  | 	/* clear bit ABTOInt in the IIR by set ABTOIntClr in the ACR register */ | ||
|  | 	LPC_USART->ACR |= IIR_ABTO; | ||
|  |   } | ||
|  | #endif
 | ||
|  |   return; | ||
|  | } | ||
|  | 
 | ||
|  | #if MODEM_TEST
 | ||
|  | /*****************************************************************************
 | ||
|  | ** Function name:		ModemInit | ||
|  | ** | ||
|  | ** Descriptions:		Initialize UART0 port as modem, setup pin select. | ||
|  | ** | ||
|  | ** parameters:			None | ||
|  | ** Returned value:		None | ||
|  | **  | ||
|  | *****************************************************************************/ | ||
|  | void ModemInit( void ) | ||
|  | { | ||
|  |    | ||
|  |   LPC_IOCON->PIO0_7 &= ~0x07;     /* UART I/O config */ | ||
|  |   LPC_IOCON->PIO0_7 |= 0x01;      /* UART CTS */ | ||
|  |   LPC_IOCON->PIO0_17 &= ~0x07;    /* UART I/O config */ | ||
|  |   LPC_IOCON->PIO0_17 |= 0x01;     /* UART RTS */ | ||
|  | #if 1
 | ||
|  |   LPC_IOCON->PIO1_13 &= ~0x07;    /* UART I/O config */ | ||
|  |   LPC_IOCON->PIO1_13 |= 0x01;     /* UART DTR */  | ||
|  |   LPC_IOCON->PIO1_14 &= ~0x07;    /* UART I/O config */ | ||
|  |   LPC_IOCON->PIO1_14 |= 0x01;     /* UART DSR */ | ||
|  |   LPC_IOCON->PIO1_15 &= ~0x07;    /* UART I/O config */ | ||
|  |   LPC_IOCON->PIO1_15 |= 0x01;     /* UART DCD */ | ||
|  |   LPC_IOCON->PIO1_16 &= ~0x07;    /* UART I/O config */ | ||
|  |   LPC_IOCON->PIO1_16 |= 0x01;     /* UART RI */ | ||
|  | 
 | ||
|  | #else
 | ||
|  |   LPC_IOCON->PIO1_19 &= ~0x07;    /* UART I/O config */ | ||
|  |   LPC_IOCON->PIO1_19 |= 0x01;     /* UART DTR */ | ||
|  |   LPC_IOCON->PIO1_20 &= ~0x07;    /* UART I/O config */ | ||
|  |   LPC_IOCON->PIO1_20 |= 0x01;     /* UART DSR */ | ||
|  |   LPC_IOCON->PIO1_21 &= ~0x07;    /* UART I/O config */ | ||
|  |   LPC_IOCON->PIO1_21 |= 0x01;     /* UART DCD */ | ||
|  |   LPC_IOCON->PIO1_22 &= ~0x07;    /* UART I/O config */ | ||
|  |   LPC_IOCON->PIO1_22 |= 0x01;     /* UART RI */ | ||
|  | #endif
 | ||
|  |   LPC_USART->MCR = 0xC0;          /* Enable Auto RTS and Auto CTS. */			 | ||
|  |   return; | ||
|  | } | ||
|  | #endif
 | ||
|  | 
 | ||
|  | /***********************************************************************
 | ||
|  |  * | ||
|  |  * Function: uart_set_divisors | ||
|  |  * | ||
|  |  * Purpose: Determines best dividers to get a target clock rate | ||
|  |  * | ||
|  |  * Processing: | ||
|  |  *     See function. | ||
|  |  * | ||
|  |  * Parameters: | ||
|  |  *     UARTClk    : UART clock | ||
|  |  *     baudrate   : Desired UART baud rate | ||
|  |  * | ||
|  |  * Outputs: | ||
|  |  *	  baudrate : Sets the estimated buadrate value in DLL, DLM, and FDR. | ||
|  |  * | ||
|  |  * Returns: Error status. | ||
|  |  * | ||
|  |  * Notes: None | ||
|  |  * | ||
|  |  **********************************************************************/ | ||
|  | uint32_t uart_set_divisors(uint32_t UARTClk, uint32_t baudrate) | ||
|  | { | ||
|  |   uint32_t uClk; | ||
|  |   uint32_t calcBaudrate = 0; | ||
|  |   uint32_t temp = 0; | ||
|  | 
 | ||
|  |   uint32_t mulFracDiv, dividerAddFracDiv; | ||
|  |   uint32_t diviser = 0 ; | ||
|  |   uint32_t mulFracDivOptimal = 1; | ||
|  |   uint32_t dividerAddOptimal = 0; | ||
|  |   uint32_t diviserOptimal = 0; | ||
|  | 
 | ||
|  |   uint32_t relativeError = 0; | ||
|  |   uint32_t relativeOptimalError = 100000; | ||
|  | 
 | ||
|  |   /* get UART block clock */ | ||
|  |   uClk = UARTClk >> 4; /* div by 16 */ | ||
|  |   /* 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 */ | ||
|  |   for (mulFracDiv = 1; mulFracDiv <= 15; mulFracDiv++) | ||
|  |   { | ||
|  |     for (dividerAddFracDiv = 0; dividerAddFracDiv <= 15; dividerAddFracDiv++) | ||
|  |     { | ||
|  |       temp = (mulFracDiv * uClk) / ((mulFracDiv + dividerAddFracDiv)); | ||
|  |       diviser = temp / baudrate; | ||
|  |       if ((temp % baudrate) > (baudrate / 2)) | ||
|  |         diviser++; | ||
|  | 
 | ||
|  |       if (diviser > 2 && diviser < 65536) | ||
|  |       { | ||
|  |         calcBaudrate = temp / diviser; | ||
|  | 
 | ||
|  |         if (calcBaudrate <= baudrate) | ||
|  |           relativeError = baudrate - calcBaudrate; | ||
|  |         else | ||
|  |           relativeError = calcBaudrate - baudrate; | ||
|  | 
 | ||
|  |         if ((relativeError < relativeOptimalError)) | ||
|  |         { | ||
|  |           mulFracDivOptimal = mulFracDiv ; | ||
|  |           dividerAddOptimal = dividerAddFracDiv; | ||
|  |           diviserOptimal = diviser; | ||
|  |           relativeOptimalError = relativeError; | ||
|  |           if (relativeError == 0) | ||
|  |             break; | ||
|  |         } | ||
|  |       } /* End of if */ | ||
|  |     } /* end of inner for loop */ | ||
|  |     if (relativeError == 0) | ||
|  |       break; | ||
|  |   } /* end of outer for loop  */ | ||
|  | 
 | ||
|  |   if (relativeOptimalError < (baudrate / 30)) | ||
|  |   { | ||
|  |     /* Set the `Divisor Latch Access Bit` and enable so the DLL/DLM access*/ | ||
|  |     /* Initialise the `Divisor latch LSB` and `Divisor latch MSB` registers */ | ||
|  |     LPC_USART->DLM = (diviserOptimal >> 8) & 0xFF; | ||
|  |     LPC_USART->DLL = diviserOptimal & 0xFF; | ||
|  | 
 | ||
|  |     /* Initialise the Fractional Divider Register */ | ||
|  |     LPC_USART->FDR = ((mulFracDivOptimal & 0xF) << 4) | (dividerAddOptimal & 0xF); | ||
|  |     return( TRUE ); | ||
|  |   } | ||
|  |   return ( FALSE ); | ||
|  | } | ||
|  | 
 | ||
|  | /*****************************************************************************
 | ||
|  | ** Function name:		UARTInit | ||
|  | ** | ||
|  | ** Descriptions:		Initialize UART0 port, setup pin select, | ||
|  | **				clock, parity, stop bits, FIFO, etc. | ||
|  | ** | ||
|  | ** parameters:			UART baudrate | ||
|  | ** Returned value:		None | ||
|  | **  | ||
|  | *****************************************************************************/ | ||
|  | void UARTInit(uint32_t baudrate) | ||
|  | { | ||
|  | #if !AUTOBAUD_ENABLE
 | ||
|  |   uint32_t Fdiv; | ||
|  | #endif
 | ||
|  |   volatile uint32_t regVal; | ||
|  | 
 | ||
|  |   UARTTxEmpty = 1; | ||
|  |   UARTCount = 0; | ||
|  |    | ||
|  |   NVIC_DisableIRQ(USART_IRQn); | ||
|  |   /* Select only one location from below. */ | ||
|  | #if 1
 | ||
|  |   LPC_IOCON->PIO0_18 &= ~0x07;    /*  UART I/O config */ | ||
|  |   LPC_IOCON->PIO0_18 |= 0x01;     /* UART RXD */ | ||
|  |   LPC_IOCON->PIO0_19 &= ~0x07;	 | ||
|  |   LPC_IOCON->PIO0_19 |= 0x01;     /* UART TXD */ | ||
|  | #endif
 | ||
|  | #if 0
 | ||
|  |   LPC_IOCON->PIO1_14 &= ~0x07;    /*  UART I/O config */ | ||
|  |   LPC_IOCON->PIO1_14 |= 0x03;     /* UART RXD */ | ||
|  |   LPC_IOCON->PIO1_13 &= ~0x07;	 | ||
|  |   LPC_IOCON->PIO1_13 |= 0x03;     /* UART TXD */ | ||
|  | #endif
 | ||
|  | #if 0
 | ||
|  |   LPC_IOCON->PIO1_17 &= ~0x07;    /*  UART I/O config */ | ||
|  |   LPC_IOCON->PIO1_17 |= 0x02;     /* UART RXD */ | ||
|  |   LPC_IOCON->PIO1_18 &= ~0x07;	 | ||
|  |   LPC_IOCON->PIO1_18 |= 0x02;     /* UART TXD */ | ||
|  | #endif
 | ||
|  | #if 0
 | ||
|  |   LPC_IOCON->PIO1_26 &= ~0x07;    /*  UART I/O config */ | ||
|  |   LPC_IOCON->PIO1_26 |= 0x02;     /* UART RXD */ | ||
|  |   LPC_IOCON->PIO1_27 &= ~0x07;	 | ||
|  |   LPC_IOCON->PIO1_27 |= 0x02;     /* UART TXD */ | ||
|  | #endif
 | ||
|  | 
 | ||
|  |   /* Enable UART clock */ | ||
|  |   LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12); | ||
|  |   LPC_SYSCON->UARTCLKDIV = 0x1;     /* divided by 1 */ | ||
|  | 
 | ||
|  |   LPC_USART->LCR = 0x83;            /* 8 bits, no Parity, 1 Stop bit */ | ||
|  | #if !AUTOBAUD_ENABLE
 | ||
|  | #if FDR_CALIBRATION
 | ||
|  | 	if ( uart_set_divisors(SystemCoreClock/LPC_SYSCON->UARTCLKDIV, baudrate) != TRUE ) | ||
|  | 	{ | ||
|  |       Fdiv = ((SystemCoreClock/LPC_SYSCON->UARTCLKDIV)/16)/baudrate ;	/*baud rate */ | ||
|  |       LPC_USART->DLM = Fdiv / 256;							 | ||
|  |       LPC_USART->DLL = Fdiv % 256; | ||
|  | 	  LPC_USART->FDR = 0x10;		/* Default */ | ||
|  | 	} | ||
|  | #else
 | ||
|  |     Fdiv = ((SystemCoreClock/LPC_SYSCON->UARTCLKDIV)/16)/baudrate ;	/*baud rate */ | ||
|  |     LPC_USART->DLM = Fdiv / 256;							 | ||
|  |     LPC_USART->DLL = Fdiv % 256; | ||
|  | 	LPC_USART->FDR = 0x10;		/* Default */ | ||
|  | #endif
 | ||
|  | #endif
 | ||
|  |   LPC_USART->LCR = 0x03;		/* DLAB = 0 */ | ||
|  |   LPC_USART->FCR = 0x07;		/* Enable and reset TX and RX FIFO. */ | ||
|  | 
 | ||
|  |   /* Read to clear the line status. */ | ||
|  |   regVal = LPC_USART->LSR; | ||
|  | 
 | ||
|  |   /* Ensure a clean start, no data in either TX or RX FIFO. */ | ||
|  |   while (( LPC_USART->LSR & (LSR_THRE|LSR_TEMT)) != (LSR_THRE|LSR_TEMT) ); | ||
|  |   while ( LPC_USART->LSR & LSR_RDR ) | ||
|  |   { | ||
|  | 	regVal = LPC_USART->RBR;	/* Dump data from RX FIFO */ | ||
|  |   } | ||
|  |   | ||
|  |   /* Enable the UART Interrupt */ | ||
|  |   NVIC_EnableIRQ(USART_IRQn); | ||
|  | 
 | ||
|  | #if TX_INTERRUPT
 | ||
|  |   LPC_USART->IER = IER_RBR | IER_THRE | IER_RLS;	/* Enable UART interrupt */ | ||
|  | #else
 | ||
|  |   LPC_USART->IER = IER_RBR | IER_RLS;	/* Enable UART interrupt */ | ||
|  | #endif
 | ||
|  | #if AUTOBAUD_ENABLE
 | ||
|  |     LPC_USART->IER |= IER_ABEO | IER_ABTO; | ||
|  | #endif
 | ||
|  |   return; | ||
|  | } | ||
|  | 
 | ||
|  | /*****************************************************************************
 | ||
|  | ** Function name:		UARTSend | ||
|  | ** | ||
|  | ** Descriptions:		Send a block of data to the UART 0 port based | ||
|  | **				on the data length | ||
|  | ** | ||
|  | ** parameters:		buffer pointer, and data length | ||
|  | ** Returned value:	None | ||
|  | **  | ||
|  | *****************************************************************************/ | ||
|  | void UARTSend(uint8_t *BufferPtr, uint32_t Length) | ||
|  | { | ||
|  |    | ||
|  |   while ( Length != 0 ) | ||
|  |   { | ||
|  | 	  /* THRE status, contain valid data */ | ||
|  | #if !TX_INTERRUPT
 | ||
|  | 	  while ( !(LPC_USART->LSR & LSR_THRE) ); | ||
|  | 	  LPC_USART->THR = *BufferPtr; | ||
|  | #else
 | ||
|  | 	  /* Below flag is set inside the interrupt handler when THRE occurs. */ | ||
|  |       while ( !(UARTTxEmpty & 0x01) ); | ||
|  | 	  LPC_USART->THR = *BufferPtr; | ||
|  |       UARTTxEmpty = 0;	/* not empty in the THR until it shifts out */ | ||
|  | #endif
 | ||
|  |       BufferPtr++; | ||
|  |       Length--; | ||
|  |   } | ||
|  |   return; | ||
|  | } | ||
|  | 
 | ||
|  | /*****************************************************************************
 | ||
|  | ** Function name:		print_string | ||
|  | ** | ||
|  | ** Descriptions:		print out string on the terminal | ||
|  | ** | ||
|  | ** parameters:			pointer to the string end with NULL char. | ||
|  | ** Returned value:		none. | ||
|  | **  | ||
|  | *****************************************************************************/ | ||
|  | void print_string( uint8_t *str_ptr ) | ||
|  | { | ||
|  |   while(*str_ptr != 0x00) | ||
|  |   { | ||
|  |     while((LPC_USART->LSR & 0x60) != 0x60); | ||
|  |     LPC_USART->THR = *str_ptr; | ||
|  |     str_ptr++; | ||
|  |   } | ||
|  |   return; | ||
|  | } | ||
|  | 
 | ||
|  | /*****************************************************************************
 | ||
|  | ** Function name:		get_key | ||
|  | ** | ||
|  | ** Descriptions:		Get a character from the terminal | ||
|  | ** | ||
|  | ** parameters:			None | ||
|  | ** Returned value:		character, zero is none. | ||
|  | **  | ||
|  | *****************************************************************************/ | ||
|  | uint8_t get_key( void ) | ||
|  | { | ||
|  |   uint8_t dummy; | ||
|  |    | ||
|  |   while ( !(LPC_USART->LSR & 0x01) );   | ||
|  |   dummy = LPC_USART->RBR; | ||
|  |   if ((dummy>=65) && (dummy<=90)) | ||
|  |   { | ||
|  | 	/* convert capital to non-capital character, A2a, B2b, C2c. */  | ||
|  | 	dummy +=32; | ||
|  |   } | ||
|  |   /* echo */ | ||
|  |   LPC_USART->THR = dummy; | ||
|  |   return(dummy); | ||
|  | } | ||
|  | 
 | ||
|  | /******************************************************************************
 | ||
|  | **                            End Of File | ||
|  | ******************************************************************************/ |