root/Examples_CP-JR_ARM7_LPC2368/ETT_LPC2368_Examples/USB_DEMO/USBCDC/serial.c

Revision 8, 19.0 kB (checked in by phil, 16 years ago)

Added Examples etc. from CD

Line 
1 /*----------------------------------------------------------------------------
2  *      Name:    serial.c
3  *      Purpose: serial port handling for MCB2300
4  *      Version: V1.03
5  *      NOTE:    Tx is only buffered in the HW fifo (max 16 bytes)
6  *----------------------------------------------------------------------------
7  *      This file is part of the uVision/ARM development tools.
8  *      This software may only be used under the terms of a valid, current,
9  *      end user licence from KEIL for a compatible version of KEIL software
10  *      development tools. Nothing else gives you the right to use it.
11  *
12  *      Copyright (c) 2005-2007 Keil Software.
13  *---------------------------------------------------------------------------*/
14  
15 #include <LPC23xx.H>                                     // LPC23xx definitions
16 #include "serial.h"
17
18 #define UART_CLK                   (24000000UL)          // UART Clock is 24.0 MHz
19
20 #define SER_IN_BUF_SIZE            64                    // Input buffer in bytes (power 2)
21 #define SER_OUT_BUF_SIZE           0                     // Output buffer in bytes (power 2)
22
23
24 #define SER_PORTCLOSED             0
25 #define SER_PORTOPENED             1
26
27 #define SER_MINPORT                0
28 #define SER_MAXPORT                1
29
30 #define SER_OK                     1
31 #define SER_GENERAL_ERR            0
32 #define SER_PORTNOTKNOWN_ERR       (-1)
33 #define SER_PORTNOTOPENED_ERR      (-1)
34 #define SER_DEVNOTKNOWN_ERR        (-1)
35
36 /* Buffer masks */
37 #define SER_IN_MASK                (SER_IN_BUF_SIZE-1ul)
38 #define SER_OUT_MASK               (SER_OUT_BUF_SIZE-1ul)
39
40 /* Buffer read / write macros */
41 #define OUT_BUF_RESET(serDev)      (serDev->ser_out.rd_idx = serDev->ser_out.wr_idx = 0)
42 #define OUT_BUF_WR(serDev, dataIn) (serDev->ser_out.data[SER_OUT_MASK & serDev->ser_out.wr_idx++] = (dataIn))
43 #define OUT_BUF_RD(serDev)         (serDev->ser_out.data[SER_OUT_MASK & serDev->ser_out.rd_idx++])   
44 #define OUT_BUF_EMPTY(serDev)      (serDev->ser_out.rd_idx == serDev->ser_out.wr_idx)
45 #define OUT_BUF_FULL(serDev)       (serDev->ser_out.rd_idx == serDev->ser_out.wr_idx+1)
46
47 #define IN_BUF_RESET(serDev)       (serDev->ser_in.rd_idx = serDev->ser_in.wr_idx = 0)
48 #define IN_BUF_WR(serDev, dataIn)  (serDev->ser_in.data[SER_IN_MASK & serDev->ser_in.wr_idx++] = (dataIn))
49 #define IN_BUF_RD(serDev)          (serDev->ser_in.data[SER_IN_MASK & serDev->ser_in.rd_idx++])   
50 #define IN_BUF_EMPTY(serDev)       (serDev->ser_in.rd_idx == serDev->ser_in.wr_idx)
51 #define IN_BUF_FULL(serDev)        (serDev->ser_in.rd_idx == serDev->ser_in.wr_idx+1)
52 #define IN_BUF_COUNT(serDev)       (SER_IN_MASK & (serDev->ser_in.wr_idx - serDev->ser_in.rd_idx))
53
54
55 // Serial output buffer
56 #if 0 // Not implemented
57 typedef struct __ser_out_t {
58   unsigned char data[SER_OUT_BUF_SIZE];
59   unsigned int wr_idx;
60   unsigned int rd_idx;
61 } ser_out_t;
62 #endif
63
64
65 // Serial input buffer
66 typedef struct __ser_in_t {
67   unsigned char data[SER_IN_BUF_SIZE];
68   unsigned int wr_idx;
69   unsigned int rd_idx;
70 } ser_in_t;
71
72
73 /*----------------------------------------------------------------------------
74   structure to administrate the serial port
75  *---------------------------------------------------------------------------*/
76 typedef __irq void (*ser_irq_fp)(void);                  // RV irq function pointer typedef
77 static __irq void ser_irq_0 (void);                      // RV irq function prototype
78 static __irq void ser_irq_2 (void);                      // RV irq function prototype
79
80 typedef struct {
81                     int   serialDeviceNumber;            // = portNumber + 1
82            unsigned int   status;
83            unsigned long  baudRate;
84            unsigned int   dataBits;
85            unsigned int   stopBits;
86            unsigned int   parity;
87   volatile unsigned long *rbr;
88   volatile unsigned long *thr;
89   volatile unsigned long *dll;
90   volatile unsigned long *dlm;
91   volatile unsigned long *lcr;
92   volatile unsigned long *lsr;
93   volatile unsigned long *msr;
94   volatile unsigned long *fdr;
95   volatile unsigned long *fcr;
96   volatile unsigned long *iir;
97   volatile unsigned long *ier;
98   volatile unsigned long *irqAddr;
99   volatile unsigned long *irqCntl; 
100   ser_irq_fp             ser_irq;                        // Serial IRQ function
101   unsigned long          ser_irq_mask;                   // Serial IRQ enable / disable bit mask
102   unsigned short         ser_lineState;                  // ((msr << 8) | (lsr))
103   unsigned long          txFifoEmpty      :1;            // 0x000(0000000X) Indicates transmit fifo is empty and needs to be kickstarted
104   unsigned long          unused_flags     :31;           // 0xXXX(XXXXXXX0) Unused
105
106 #if 0 // Not implemented
107   ser_out_t              ser_out;                        // Serial data buffers
108 #endif
109
110   ser_in_t               ser_in;
111 } SER_INFO;
112
113 static SER_INFO ser_Dev[SER_MAXPORT + 1] = {
114   { 1,
115     SER_PORTCLOSED, 9600, 8, 0, 0,
116     (volatile unsigned long *)(UART0_BASE_ADDR + 0x00),  // RBR
117     (volatile unsigned long *)(UART0_BASE_ADDR + 0x00),  // THR
118     (volatile unsigned long *)(UART0_BASE_ADDR + 0x00),  // DLL
119     (volatile unsigned long *)(UART0_BASE_ADDR + 0x04),  // DLM
120     (volatile unsigned long *)(UART0_BASE_ADDR + 0x0C),  // LCR
121     (volatile unsigned long *)(UART0_BASE_ADDR + 0x14),  // LSR
122     (volatile unsigned long *)(UART0_BASE_ADDR + 0x14),  // MSR dummy
123     (volatile unsigned long *)(UART0_BASE_ADDR + 0x28),  // FDR
124     (volatile unsigned long *)(UART0_BASE_ADDR + 0x08),  // FCR
125     (volatile unsigned long *)(UART0_BASE_ADDR + 0x08),  // IIR
126     (volatile unsigned long *)(UART0_BASE_ADDR + 0x04),  // IER
127     (volatile unsigned long *)(VIC_BASE_ADDR + 0x118),   // IRQ Addr
128     (volatile unsigned long *)(VIC_BASE_ADDR + 0x218),   // IRQ Cntl
129     ser_irq_0,                                           // IRQ function
130     0x00000040,                                          // IRQ mask bit
131         0                                                    // ser_lineState
132   },
133   { 2,
134     SER_PORTCLOSED, 9600, 8, 0, 0,
135     (volatile unsigned long *)(UART2_BASE_ADDR + 0x00),  // RBR 
136     (volatile unsigned long *)(UART2_BASE_ADDR + 0x00),  // THR
137     (volatile unsigned long *)(UART2_BASE_ADDR + 0x00),  // DLL 
138     (volatile unsigned long *)(UART2_BASE_ADDR + 0x04),  // DLM 
139     (volatile unsigned long *)(UART2_BASE_ADDR + 0x0C),  // LCR 
140     (volatile unsigned long *)(UART2_BASE_ADDR + 0x14),  // LSR   
141     (volatile unsigned long *)(UART2_BASE_ADDR + 0x14),  // MSR dummy
142     (volatile unsigned long *)(UART2_BASE_ADDR + 0x28),  // FDR
143     (volatile unsigned long *)(UART2_BASE_ADDR + 0x08),  // FCR
144     (volatile unsigned long *)(UART2_BASE_ADDR + 0x08),  // IIR
145     (volatile unsigned long *)(UART2_BASE_ADDR + 0x04),  // IER
146     (volatile unsigned long *)(VIC_BASE_ADDR + 0x170),   // IRQ Addr
147     (volatile unsigned long *)(VIC_BASE_ADDR + 0x270),   // IRQ Cntl
148     ser_irq_2,                                           // IRQ function
149     0x10000000,                                          // IRQ mask bit
150         0                                                    // ser_lineState
151   }
152 };
153
154 /*----------------------------------------------------------------------------
155   Function Prototypes
156  *---------------------------------------------------------------------------*/
157
158
159
160 /*----------------------------------------------------------------------------
161   open the serial port
162  *---------------------------------------------------------------------------*/
163 int ser_OpenPort (int port, int *serDevNo) {
164
165   if ( (port < SER_MINPORT) ||                           // check the port number
166        (port > SER_MAXPORT)   ) {
167     return (SER_PORTNOTKNOWN_ERR);
168   }
169
170   if (port == 0)
171   {
172         PINSEL0 &= 0xFFFFFF0F;                                                                  // Reset P0.2,P0.3 Pin Config
173     PINSEL0 |= 0x00000010;                                                                      // Select P0.2 = TxD(UART0)
174     PINSEL0 |= 0x00000040;                                                                      // Select P0.3 = RxD(UART0)
175   }
176   else
177   {   
178         PINSEL0 &= 0xFF0FFFFF;                                                                  // Reset P0.10,P0.11 Pin Config
179     PINSEL0 |= 0x00100000;                                                                      // Select P0.10 = TxD(UART2)
180     PINSEL0 |= 0x00400000;                                                                      // Select P0.11 = RxD(UART2)
181         PCONP   |= 0x01000000;                                                                  // UART2 Power-ON
182   }
183
184   ser_Dev[port].status = SER_PORTOPENED;
185   *serDevNo = ser_Dev[port].serialDeviceNumber;
186
187   return (SER_OK);
188 }
189
190 /*----------------------------------------------------------------------------
191   close the serial port
192  *---------------------------------------------------------------------------*/
193 int ser_ClosePort (int serDevNo) {
194   SER_INFO *pSerDev;
195
196   if ( (serDevNo < (SER_MINPORT+1)) ||                   // check the serial device number
197        (serDevNo > (SER_MAXPORT+1))   ) {
198     return (SER_DEVNOTKNOWN_ERR);
199   }
200
201   pSerDev = &ser_Dev[(serDevNo-1)];
202
203   if ((serDevNo-1) == 0)
204   {   
205         PINSEL0 &= 0xFFFFFF0F;                                                                  // Reset P0.2,P0.3 Pin Config   
206   }
207   else
208   {   
209         PINSEL0 &= 0xFF0FFFFF;                                                                  // Reset P0.10,P0.11 Pin Config   
210         PCONP   &= ~0x01000000;                                                                 // UART2 Power-OFF
211   }
212
213   /* Disable the interrupt in the VIC and UART controllers */
214   *(pSerDev->ier) = 0x00;                                // Disable UART interrupts
215   VICIntEnClr = pSerDev->ser_irq_mask;                   // Disable VIC interrupt
216
217   pSerDev->status   = SER_PORTCLOSED;
218  
219   return (SER_OK);
220 }
221
222 /*----------------------------------------------------------------------------
223   initialize the serial port
224  *---------------------------------------------------------------------------*/
225 int ser_InitPort (int serDevNo, unsigned long baudrate, unsigned int  databits,
226                                 unsigned int  parity,   unsigned int  stopbits) {
227
228   unsigned char lcr_p, lcr_s, lcr_d;
229   unsigned long dll;
230   SER_INFO *pSerDev;
231
232   if ( (serDevNo < (SER_MINPORT+1)) ||                   // check the serial device number
233        (serDevNo > (SER_MAXPORT+1))   ) {
234     return (SER_DEVNOTKNOWN_ERR);
235   }
236
237   pSerDev = &ser_Dev[(serDevNo-1)];
238
239   switch (databits) {
240     case 5:                                              // 5 Data bits
241       lcr_d = 0x00;
242     break;
243     case 6:                                              // 6 Data bits
244       lcr_d = 0x01;
245     break;
246     case 7:                                              // 7 Data bits
247       lcr_d = 0x02;
248     break;
249     case 8:                                              // 8 Data bits
250     default:
251       lcr_d = 0x03;
252     break;
253   }
254
255   switch (stopbits) {
256     case 1:                                              // 1,5 Stop bits
257     case 2:                                              // 2   Stop bits
258       lcr_s = 0x04;
259     break;
260     case 0:                                              // 1   Stop bit
261     default:
262       lcr_s = 0x00;
263     break;
264   }
265
266   switch (parity) {
267     case 1:                                              // Parity Odd
268       lcr_p = 0x08;
269     break;
270     case 2:                                              // Parity Even
271       lcr_p = 0x18;
272     break;
273     case 3:                                              // Parity Mark
274       lcr_p = 0x28;
275     break;
276     case 4:                                              // Parity Space
277       lcr_p = 0x38;
278     break;
279     case 0:                                              // Parity None
280     default:
281       lcr_p = 0x00;
282     break;
283   }
284
285   pSerDev->baudRate = baudrate;
286   pSerDev->dataBits = databits;
287   pSerDev->stopBits = stopbits;
288   pSerDev->parity   = parity;
289  
290   //OUT_BUF_RESET(pSerDev);
291   IN_BUF_RESET(pSerDev);
292  
293   /* Note that the pclk is 24,0 MHz.  (48.0 MHz / 2)         */
294   /* 24 MHz PCLK generates also rates for 115200, 57600 baud */
295   dll = ((UART_CLK / baudrate) / 16UL);
296
297   *(pSerDev->fdr) = 0;                                   // Fractional divider not used
298   *(pSerDev->lcr) = 0x80 | lcr_d | lcr_p | lcr_s;        // Data bits, Parity,   Stop bit
299   *(pSerDev->dll) = dll;                                 // Baud Rate @ 24 MHZ PCLK
300   *(pSerDev->dlm) = (dll >> 8);                          // High divisor latch
301   *(pSerDev->lcr) = 0x00 | lcr_d | lcr_p | lcr_s;        // DLAB = 0
302   *(pSerDev->fcr) = 0x87;                                // Enable and reset FIFOs (irq=8 Chr in RxFIFO)
303   *(pSerDev->ier) = 0x03;                                // Enable TX/RX interrupts
304   pSerDev->txFifoEmpty = 1;                              // TX fifo is empty
305
306   /* Set up and enable the UART interrupt in the VIC */
307   *(pSerDev->irqAddr) = (unsigned long)pSerDev->ser_irq; // Set interrupt function
308   *(pSerDev->irqCntl) = 0x0F;                            // Set interrupt priority
309   VICIntEnable = pSerDev->ser_irq_mask;                  // Enable interrupt
310
311   return (SER_OK);
312 }
313
314 /*----------------------------------------------------------------------------
315   read data from serial port
316  *---------------------------------------------------------------------------*/
317 int ser_Read (int serDevNo, char *buffer, const int *length) {
318   SER_INFO *pSerDev;
319   int bytesToRead, bytesRead;
320  
321   if ( (serDevNo < (SER_MINPORT+1)) ||                   // check the serial device number
322        (serDevNo > (SER_MAXPORT+1))   ) {
323     return (SER_DEVNOTKNOWN_ERR);
324   }
325   pSerDev = &ser_Dev[(serDevNo-1)];
326
327   /* Read *length bytes, block if *bytes are not avaialable     */
328   bytesToRead = *length;
329   bytesToRead = (bytesToRead < (*length)) ? bytesToRead : (*length);
330   bytesRead = bytesToRead;
331
332   while (bytesToRead--) {
333     while (IN_BUF_EMPTY(pSerDev));                       // Block until data is available if none
334     *buffer++ = IN_BUF_RD(pSerDev);
335   }
336   return (bytesRead); 
337 }
338
339 /*----------------------------------------------------------------------------
340   write data to the serial port
341  *---------------------------------------------------------------------------*/
342 int ser_Write (int serDevNo, const char *buffer, int *length) {
343   SER_INFO *pSerDev;
344   int i, bytesToWrite, bytesWritten;
345
346   if ( (serDevNo < (SER_MINPORT+1)) ||                   // check the serial device number
347        (serDevNo > (SER_MAXPORT+1))   ) {
348     return (SER_DEVNOTKNOWN_ERR);
349   }
350   pSerDev = &ser_Dev[(serDevNo-1)];
351
352   // Write *length bytes
353   bytesToWrite = *length;
354   bytesWritten = bytesToWrite;
355
356   /* Lets just use the 16 byte hardware FIFO to buffer outgoing data */
357   while (bytesToWrite) {
358     if (pSerDev->txFifoEmpty) {
359       for (i=16; (bytesToWrite && i);i--) {
360         pSerDev->txFifoEmpty = 0;
361         *(pSerDev->thr) = *buffer++;                     // Write to the Tx FIFO
362         bytesToWrite--;
363       }     
364     }
365     // Else: Wait for the fifo to be empty
366   }
367
368   return (bytesWritten);
369 }
370
371 /*----------------------------------------------------------------------------
372   check if character(s) are available at the serial interface
373  *---------------------------------------------------------------------------*/
374 int ser_AvailChar (int serDevNo, int *availChar) {
375   SER_INFO *pSerDev;
376
377   if ( (serDevNo < (SER_MINPORT+1)) ||                   // check the serial device number
378        (serDevNo > (SER_MAXPORT+1))   ) {
379     return (SER_DEVNOTKNOWN_ERR);
380   }
381   pSerDev = &ser_Dev[(serDevNo-1)];
382
383   *availChar = IN_BUF_COUNT(pSerDev);
384
385   return (SER_OK);
386 }
387
388 /*----------------------------------------------------------------------------
389   read the line state of the serial port
390  *---------------------------------------------------------------------------*/
391 int ser_LineState (int serDevNo, unsigned short *lineState) {
392   SER_INFO *pSerDev;
393
394   if ( (serDevNo < (SER_MINPORT+1)) ||                   // check the serial device number
395        (serDevNo > (SER_MAXPORT+1))   ) {
396     return (SER_DEVNOTKNOWN_ERR);
397   }
398   pSerDev = &ser_Dev[(serDevNo-1)];
399
400   *lineState = pSerDev->ser_lineState;
401   pSerDev->ser_lineState = 0;
402
403   return (SER_OK);
404 }
405
406 /*----------------------------------------------------------------------------
407   serial port 0 interrupt
408  *---------------------------------------------------------------------------*/
409 static __irq void ser_irq_0 (void) {
410   SER_INFO *pSerDev = &ser_Dev[0];
411   volatile unsigned long iir;
412
413   iir = *(pSerDev->iir);
414    
415   switch (iir & 0x000F) {
416     case 0x4:                                            // RDA pending
417     case 0xC:                                            // CTI pending
418       while (*(pSerDev->lsr) & 0x01) {                   // Rx FIFO is not empty
419         IN_BUF_WR(pSerDev, *(pSerDev->rbr));             // Read Rx FIFO to buffer 
420       }
421       break;
422    
423     case 0x2:                                            // THRE pending
424         pSerDev->txFifoEmpty = 1;
425       break;
426    
427     default:
428       ; // Ignore interrupt
429   }
430
431   pSerDev->ser_lineState = (*(pSerDev->lsr)) & 0xE01E;  // UART 0 has no MSR register
432  
433   VICVectAddr = 0;
434 }
435
436 /*----------------------------------------------------------------------------
437   serial port 2 interrupt
438  *---------------------------------------------------------------------------*/
439 static __irq void ser_irq_2 (void) {
440   SER_INFO *pSerDev = &ser_Dev[1];
441   volatile unsigned long iir;
442  
443   iir = *(pSerDev->iir);
444    
445   switch (iir & 0x000F) {
446     case 0x4:                                            // RDA pending
447     case 0xC:                                            // CTI pending
448       while (*(pSerDev->lsr) & 0x01) {                   // Rx FIFO is not empty
449         IN_BUF_WR(pSerDev, *(pSerDev->rbr));             // Read Rx FIFO to buffer 
450       }
451       break;
452    
453     case 0x2:                                            // THRE pending
454         pSerDev->txFifoEmpty = 1;
455       break;
456    
457     default:
458       ; // Ignore interrupt
459   }
460   pSerDev->ser_lineState = (*(pSerDev->lsr)) & 0xE01E;  // UART 2 has no MSR register
461  
462   VICVectAddr = 0;
463 }
464
465
466
467 /*----------------------------------------------------------------------------
468   The following functions are used by the printf / scanf if stdout is
469   redirected to the serial port.
470  *---------------------------------------------------------------------------*/
471
472 #ifndef UART_PRINTF_BAUDRATE
473 #define UART_PRINTF_BAUDRATE 115200
474 #endif
475
476
477 #ifndef UART_PRINTF_PORT
478 #define UART_PRINTF_PORT 1
479 #endif
480
481 static int printfDevNo;
482
483 void init_serial (void)  {                               // Initialize Serial Interface
484
485   ser_OpenPort (UART_PRINTF_PORT, &printfDevNo);
486   ser_InitPort(printfDevNo,
487                UART_PRINTF_BAUDRATE,
488                8,   /* 8 data bits */
489                0,   /* No partity */
490                0);  /* 1 stop bit */
491 }
492
493 /* implementation of putchar (also used by printf function to output data)    */
494 #define CR     0x0D
495 int sendchar (int ch)  {                                 // Write character to Serial Port
496   int length = 1;
497   int cr = CR;
498
499   if (ch == '\n')  {
500     ser_Write (printfDevNo, (const char *)&cr, &length);
501   }
502   ser_Write (printfDevNo, (const char *)&ch, &length);
503
504   return (ch);
505 }
506
507
508 int getkey (void)  {                                     // Read character from Serial Port
509   int availChar;
510   int length = 1;
511   char data;
512
513   do {
514     ser_AvailChar(printfDevNo, &availChar);
515   } while (!availChar);
516
517   ser_Read (printfDevNo, &data, &length);
518
519   return (data);
520 }
521
522
523
Note: See TracBrowser for help on using the browser.