1 /*----------------------------------------------------------------------------
\r
3 * Purpose: serial port handling for LPC17xx
\r
5 *----------------------------------------------------------------------------
\r
6 * This software is supplied "AS IS" without any warranties, express,
\r
7 * implied or statutory, including but not limited to the implied
\r
8 * warranties of fitness for purpose, satisfactory quality and
\r
9 * noninfringement. Keil extends you a royalty-free right to reproduce
\r
10 * and distribute executable files created using this software for use
\r
11 * on NXP Semiconductors LPC microcontroller devices only. Nothing else
\r
12 * gives you the right to use this software.
\r
14 * Copyright (c) 2009 Keil - An ARM Company. All rights reserved.
\r
15 *---------------------------------------------------------------------------*/
\r
16 #include "../LPC17xx.h" // LPC17xx definitions
\r
17 #include "lpc_types.h"
\r
21 /*----------------------------------------------------------------------------
\r
22 Defines for ring buffers
\r
23 *---------------------------------------------------------------------------*/
\r
24 #define SER_BUF_SIZE (128) // serial buffer in bytes (power 2)
\r
25 #define SER_BUF_MASK (SER_BUF_SIZE-1ul) // buffer size mask
\r
27 /* Buffer read / write macros */
\r
28 #define SER_BUF_RESET(serBuf) (serBuf.rdIdx = serBuf.wrIdx = 0)
\r
29 #define SER_BUF_WR(serBuf, dataIn) (serBuf.data[SER_BUF_MASK & serBuf.wrIdx++] = (dataIn))
\r
30 #define SER_BUF_RD(serBuf) (serBuf.data[SER_BUF_MASK & serBuf.rdIdx++])
\r
31 #define SER_BUF_EMPTY(serBuf) (serBuf.rdIdx == serBuf.wrIdx)
\r
32 #define SER_BUF_FULL(serBuf) (serBuf.rdIdx == serBuf.wrIdx+1)
\r
33 #define SER_BUF_COUNT(serBuf) (SER_BUF_MASK & (serBuf.wrIdx - serBuf.rdIdx))
\r
36 typedef struct __SER_BUF_T {
\r
37 unsigned char data[SER_BUF_SIZE];
\r
42 unsigned long ser_txRestart; // NZ if TX restart is required
\r
43 unsigned short ser_lineState; // ((msr << 8) | (lsr))
\r
44 SER_BUF_T ser_out; // Serial data buffers
\r
47 /*----------------------------------------------------------------------------
\r
48 open the serial port
\r
49 *---------------------------------------------------------------------------*/
\r
50 void ser_OpenPort (char portNum) {
\r
55 NVIC_DisableIRQ(UART0_IRQn);
\r
56 PINCON->PINSEL0 &= ~0x000000F0;
\r
57 PINCON->PINSEL0 |= 0x00000050; /* RxD0 is P0.3 and TxD0 is P0.2 */
\r
62 NVIC_DisableIRQ(UART1_IRQn);
\r
63 PINCON->PINSEL4 &= ~0x0000000F;
\r
64 PINCON->PINSEL4 |= 0x0000000A; /* Enable RxD1 P2.1, TxD1 P2.0 */
\r
69 /*----------------------------------------------------------------------------
\r
70 close the serial port
\r
71 *---------------------------------------------------------------------------*/
\r
72 void ser_ClosePort (char portNum ) {
\r
76 PINCON->PINSEL0 &= ~0x000000F0;
\r
77 /* Disable the interrupt in the VIC and UART controllers */
\r
79 NVIC_DisableIRQ(UART0_IRQn);
\r
84 PINCON->PINSEL4 &= ~0x0000000F;
\r
85 /* Disable the interrupt in the VIC and UART controllers */
\r
87 NVIC_DisableIRQ(UART1_IRQn);
\r
92 /*----------------------------------------------------------------------------
\r
93 initialize the serial port
\r
94 *---------------------------------------------------------------------------*/
\r
95 void ser_InitPort0 (unsigned long baudrate, unsigned int databits,
\r
96 unsigned int parity, unsigned int stopbits) {
\r
98 unsigned char lcr_p, lcr_s, lcr_d;
\r
100 unsigned int pclkdiv, pclk;
\r
102 switch (databits) {
\r
103 case 5: // 5 Data bits
\r
106 case 6: // 6 Data bits
\r
109 case 7: // 7 Data bits
\r
112 case 8: // 8 Data bits
\r
118 switch (stopbits) {
\r
119 case 1: // 1,5 Stop bits
\r
120 case 2: // 2 Stop bits
\r
123 case 0: // 1 Stop bit
\r
130 case 1: // Parity Odd
\r
133 case 2: // Parity Even
\r
136 case 3: // Parity Mark
\r
139 case 4: // Parity Space
\r
142 case 0: // Parity None
\r
148 SER_BUF_RESET(ser_out); // reset out buffer
\r
149 SER_BUF_RESET(ser_in); // reset in buffer
\r
151 /* Bit 6~7 is for UART0 */
\r
152 pclkdiv = (SC->PCLKSEL0 >> 6) & 0x03;
\r
158 pclk = SystemFrequency/4;
\r
161 pclk = SystemFrequency;
\r
164 pclk = SystemFrequency/2;
\r
167 pclk = SystemFrequency/8;
\r
171 dll = (pclk/16)/baudrate ; /*baud rate */
\r
172 UART0->FDR = 0; // Fractional divider not used
\r
173 UART0->LCR = 0x80 | lcr_d | lcr_p | lcr_s; // Data bits, Parity, Stop bit
\r
174 UART0->DLL = dll; // Baud Rate depending on PCLK
\r
175 UART0->DLM = (dll >> 8); // High divisor latch
\r
176 UART0->LCR = 0x00 | lcr_d | lcr_p | lcr_s; // DLAB = 0
\r
177 UART0->IER = 0x03; // Enable TX/RX interrupts
\r
179 UART0->FCR = 0x07; /* Enable and reset TX and RX FIFO. */
\r
180 ser_txRestart = 1; // TX fifo is empty
\r
182 /* Enable the UART Interrupt */
\r
183 NVIC_EnableIRQ(UART0_IRQn);
\r
187 /*----------------------------------------------------------------------------
\r
188 initialize the serial port
\r
189 *---------------------------------------------------------------------------*/
\r
190 void ser_InitPort1 (unsigned long baudrate, unsigned int databits,
\r
191 unsigned int parity, unsigned int stopbits) {
\r
193 unsigned char lcr_p, lcr_s, lcr_d;
\r
195 unsigned int pclkdiv, pclk;
\r
197 switch (databits) {
\r
198 case 5: // 5 Data bits
\r
201 case 6: // 6 Data bits
\r
204 case 7: // 7 Data bits
\r
207 case 8: // 8 Data bits
\r
213 switch (stopbits) {
\r
214 case 1: // 1,5 Stop bits
\r
215 case 2: // 2 Stop bits
\r
218 case 0: // 1 Stop bit
\r
225 case 1: // Parity Odd
\r
228 case 2: // Parity Even
\r
231 case 3: // Parity Mark
\r
234 case 4: // Parity Space
\r
237 case 0: // Parity None
\r
243 SER_BUF_RESET(ser_out); // reset out buffer
\r
244 SER_BUF_RESET(ser_in); // reset in buffer
\r
246 /* Bit 8,9 are for UART1 */
\r
247 pclkdiv = (SC->PCLKSEL0 >> 8) & 0x03;
\r
253 pclk = SystemFrequency/4;
\r
256 pclk = SystemFrequency;
\r
259 pclk = SystemFrequency/2;
\r
262 pclk = SystemFrequency/8;
\r
266 dll = (pclk/16)/baudrate ; /*baud rate */
\r
267 UART1->FDR = 0; // Fractional divider not used
\r
268 UART1->LCR = 0x80 | lcr_d | lcr_p | lcr_s; // Data bits, Parity, Stop bit
\r
269 UART1->DLL = dll; // Baud Rate depending on PCLK
\r
270 UART1->DLM = (dll >> 8); // High divisor latch
\r
271 UART1->LCR = 0x00 | lcr_d | lcr_p | lcr_s; // DLAB = 0
\r
272 UART1->IER = 0x03; // Enable TX/RX interrupts
\r
274 UART1->FCR = 0x07; /* Enable and reset TX and RX FIFO. */
\r
275 ser_txRestart = 1; // TX fifo is empty
\r
277 /* Enable the UART Interrupt */
\r
278 NVIC_EnableIRQ(UART1_IRQn);
\r
282 /*----------------------------------------------------------------------------
\r
283 read data from serial port
\r
284 *---------------------------------------------------------------------------*/
\r
285 int ser_Read (char *buffer, const int *length) {
\r
286 int bytesToRead, bytesRead;
\r
288 /* Read *length bytes, block if *bytes are not avaialable */
\r
289 bytesToRead = *length;
\r
290 bytesToRead = (bytesToRead < (*length)) ? bytesToRead : (*length);
\r
291 bytesRead = bytesToRead;
\r
293 while (bytesToRead--) {
\r
294 while (SER_BUF_EMPTY(ser_in)); // Block until data is available if none
\r
295 *buffer++ = SER_BUF_RD(ser_in);
\r
297 return (bytesRead);
\r
300 /*----------------------------------------------------------------------------
\r
301 write data to the serial port
\r
302 *---------------------------------------------------------------------------*/
\r
303 int ser_Write (char portNum, const char *buffer, int *length) {
\r
304 int bytesToWrite, bytesWritten;
\r
306 // Write *length bytes
\r
307 bytesToWrite = *length;
\r
308 bytesWritten = bytesToWrite;
\r
310 while (!SER_BUF_EMPTY(ser_out)); // Block until space is available if none
\r
311 while (bytesToWrite) {
\r
312 SER_BUF_WR(ser_out, *buffer++); // Read Rx FIFO to buffer
\r
316 if (ser_txRestart) {
\r
318 if ( portNum == 0 )
\r
320 UART0->THR = SER_BUF_RD(ser_out); // Write to the Tx Register
\r
324 UART1->THR = SER_BUF_RD(ser_out); // Write to the Tx Register
\r
328 return (bytesWritten);
\r
331 /*----------------------------------------------------------------------------
\r
332 check if character(s) are available at the serial interface
\r
333 *---------------------------------------------------------------------------*/
\r
334 void ser_AvailChar (int *availChar) {
\r
336 *availChar = SER_BUF_COUNT(ser_in);
\r
340 /*----------------------------------------------------------------------------
\r
341 read the line state of the serial port
\r
342 *---------------------------------------------------------------------------*/
\r
343 void ser_LineState (unsigned short *lineState) {
\r
345 *lineState = ser_lineState;
\r
350 /*----------------------------------------------------------------------------
\r
351 serial port 0 interrupt
\r
352 *---------------------------------------------------------------------------*/
\r
353 void UART0_IRQHandler(void)
\r
355 volatile unsigned long iir;
\r
359 if ((iir & 0x4) || (iir & 0xC)) { // RDA or CTI pending
\r
360 while (UART0->LSR & 0x01) { // Rx FIFO is not empty
\r
361 SER_BUF_WR(ser_in, UART0->RBR); // Read Rx FIFO to buffer
\r
364 if ((iir & 0x2)) { // TXMIS pending
\r
365 if (SER_BUF_COUNT(ser_out) != 0) {
\r
366 UART0->THR = SER_BUF_RD(ser_out); // Write to the Tx FIFO
\r
373 ser_lineState = UART0->LSR & 0x1E; // update linestate
\r
377 /*----------------------------------------------------------------------------
\r
378 serial port 1 interrupt
\r
379 *---------------------------------------------------------------------------*/
\r
380 void UART1_IRQHandler(void)
\r
382 volatile unsigned long iir;
\r
386 if ((iir & 0x4) || (iir & 0xC)) { // RDA or CTI pending
\r
387 while (UART1->LSR & 0x01) { // Rx FIFO is not empty
\r
388 SER_BUF_WR(ser_in, UART1->RBR); // Read Rx FIFO to buffer
\r
391 if ((iir & 0x2)) { // TXMIS pending
\r
392 if (SER_BUF_COUNT(ser_out) != 0) {
\r
393 UART1->THR = SER_BUF_RD(ser_out); // Write to the Tx FIFO
\r
400 ser_lineState = ((UART1->MSR<<8)|UART1->LSR) & 0xE01E; // update linestate
\r