Automatically calculate make dependencies
[rapper.git] / src / usb / serial.c
1 /*----------------------------------------------------------------------------
2  *      Name:    serial.c
3  *      Purpose: serial port handling for LPC17xx
4  *      Version: V1.20
5  *----------------------------------------------------------------------------
6  *      This software is supplied "AS IS" without any warranties, express,
7  *      implied or statutory, including but not limited to the implied
8  *      warranties of fitness for purpose, satisfactory quality and
9  *      noninfringement. Keil extends you a royalty-free right to reproduce
10  *      and distribute executable files created using this software for use
11  *      on NXP Semiconductors LPC microcontroller devices only. Nothing else
12  *      gives you the right to use this software.
13  *
14  * Copyright (c) 2009 Keil - An ARM Company. All rights reserved.
15  *---------------------------------------------------------------------------*/
16 #include <board.h>                                   // LPC17xx definitions
17 #include "lpc_types.h"
18 #include "serial.h"
19
20
21 /*----------------------------------------------------------------------------
22   Defines for ring buffers
23  *---------------------------------------------------------------------------*/
24 #define SER_BUF_SIZE               (128)               // serial buffer in bytes (power 2)
25 #define SER_BUF_MASK               (SER_BUF_SIZE-1ul)  // buffer size mask
26
27 /* Buffer read / write macros */
28 #define SER_BUF_RESET(serBuf)      (serBuf.rdIdx = serBuf.wrIdx = 0)
29 #define SER_BUF_WR(serBuf, dataIn) (serBuf.data[SER_BUF_MASK & serBuf.wrIdx++] = (dataIn))
30 #define SER_BUF_RD(serBuf)         (serBuf.data[SER_BUF_MASK & serBuf.rdIdx++])
31 #define SER_BUF_EMPTY(serBuf)      (serBuf.rdIdx == serBuf.wrIdx)
32 #define SER_BUF_FULL(serBuf)       (serBuf.rdIdx == serBuf.wrIdx+1)
33 #define SER_BUF_COUNT(serBuf)      (SER_BUF_MASK & (serBuf.wrIdx - serBuf.rdIdx))
34
35 // buffer type
36 typedef struct __SER_BUF_T {
37   unsigned char data[SER_BUF_SIZE];
38   unsigned int wrIdx;
39   unsigned int rdIdx;
40 } SER_BUF_T;
41
42 unsigned long          ser_txRestart;                  // NZ if TX restart is required
43 unsigned short         ser_lineState;                  // ((msr << 8) | (lsr))
44 SER_BUF_T              ser_out;                        // Serial data buffers
45 SER_BUF_T              ser_in;
46
47 /*----------------------------------------------------------------------------
48   open the serial port
49  *---------------------------------------------------------------------------*/
50 void ser_OpenPort (char portNum) {
51
52   if ( portNum == 0 )
53   {
54         /* Port 0 */
55         NVIC_DisableIRQ(UART0_IRQn);
56         PINCON->PINSEL0 &= ~0x000000F0;
57         PINCON->PINSEL0 |= 0x00000050;     /* RxD0 is P0.3 and TxD0 is P0.2 */
58   }
59   else
60   {
61         /* Port 1 */
62         NVIC_DisableIRQ(UART1_IRQn);
63         PINCON->PINSEL4 &= ~0x0000000F;
64         PINCON->PINSEL4 |= 0x0000000A;    /* Enable RxD1 P2.1, TxD1 P2.0 */
65   }
66   return;
67 }
68
69 /*----------------------------------------------------------------------------
70   close the serial port
71  *---------------------------------------------------------------------------*/
72 void ser_ClosePort (char portNum ) {
73   if ( portNum == 0 )
74   {
75         /* POrt 0 */
76         PINCON->PINSEL0 &= ~0x000000F0;
77         /* Disable the interrupt in the VIC and UART controllers */
78         UART0->IER = 0;
79         NVIC_DisableIRQ(UART0_IRQn);
80   }
81   else
82   {
83         /* Port 1 */
84         PINCON->PINSEL4 &= ~0x0000000F;
85         /* Disable the interrupt in the VIC and UART controllers */
86         UART1->IER = 0;
87         NVIC_DisableIRQ(UART1_IRQn);
88   }
89   return;
90 }
91
92 /*----------------------------------------------------------------------------
93   initialize the serial port
94  *---------------------------------------------------------------------------*/
95 void ser_InitPort0 (unsigned long baudrate, unsigned int  databits,
96                   unsigned int  parity,   unsigned int  stopbits) {
97
98   unsigned char lcr_p, lcr_s, lcr_d;
99   unsigned int dll;
100   unsigned int pclkdiv, pclk;
101
102   switch (databits) {
103     case 5:                                            // 5 Data bits
104       lcr_d = 0x00;
105     break;
106     case 6:                                            // 6 Data bits
107       lcr_d = 0x01;
108     break;
109     case 7:                                            // 7 Data bits
110       lcr_d = 0x02;
111     break;
112     case 8:                                            // 8 Data bits
113     default:
114       lcr_d = 0x03;
115     break;
116   }
117
118   switch (stopbits) {
119     case 1:                                            // 1,5 Stop bits
120     case 2:                                            // 2   Stop bits
121       lcr_s = 0x04;
122     break;
123     case 0:                                            // 1   Stop bit
124     default:
125       lcr_s = 0x00;
126     break;
127   }
128
129   switch (parity) {
130     case 1:                                            // Parity Odd
131       lcr_p = 0x08;
132     break;
133     case 2:                                            // Parity Even
134       lcr_p = 0x18;
135     break;
136     case 3:                                            // Parity Mark
137       lcr_p = 0x28;
138     break;
139     case 4:                                            // Parity Space
140       lcr_p = 0x38;
141     break;
142     case 0:                                            // Parity None
143     default:
144       lcr_p = 0x00;
145     break;
146   }
147
148   SER_BUF_RESET(ser_out);                              // reset out buffer
149   SER_BUF_RESET(ser_in);                               // reset in buffer
150
151   /* Bit 6~7 is for UART0 */
152   pclkdiv = (SC->PCLKSEL0 >> 6) & 0x03;
153
154   switch ( pclkdiv )
155   {
156         case 0x00:
157         default:
158           pclk = SystemFrequency/4;
159           break;
160         case 0x01:
161           pclk = SystemFrequency;
162           break;
163         case 0x02:
164           pclk = SystemFrequency/2;
165           break;
166         case 0x03:
167           pclk = SystemFrequency/8;
168           break;
169   }
170
171   dll = (pclk/16)/baudrate ;    /*baud rate */
172   UART0->FDR = 0;                             // Fractional divider not used
173   UART0->LCR = 0x80 | lcr_d | lcr_p | lcr_s;  // Data bits, Parity,   Stop bit
174   UART0->DLL = dll;                           // Baud Rate depending on PCLK
175   UART0->DLM = (dll >> 8);                    // High divisor latch
176   UART0->LCR = 0x00 | lcr_d | lcr_p | lcr_s;  // DLAB = 0
177   UART0->IER = 0x03;                          // Enable TX/RX interrupts
178
179   UART0->FCR = 0x07;                            /* Enable and reset TX and RX FIFO. */
180   ser_txRestart = 1;                                   // TX fifo is empty
181
182   /* Enable the UART Interrupt */
183   NVIC_EnableIRQ(UART0_IRQn);
184   return;
185 }
186
187 /*----------------------------------------------------------------------------
188   initialize the serial port
189  *---------------------------------------------------------------------------*/
190 void ser_InitPort1 (unsigned long baudrate, unsigned int  databits,
191                   unsigned int  parity,   unsigned int  stopbits) {
192
193   unsigned char lcr_p, lcr_s, lcr_d;
194   unsigned int dll;
195   unsigned int pclkdiv, pclk;
196
197   switch (databits) {
198     case 5:                                            // 5 Data bits
199       lcr_d = 0x00;
200     break;
201     case 6:                                            // 6 Data bits
202       lcr_d = 0x01;
203     break;
204     case 7:                                            // 7 Data bits
205       lcr_d = 0x02;
206     break;
207     case 8:                                            // 8 Data bits
208     default:
209       lcr_d = 0x03;
210     break;
211   }
212
213   switch (stopbits) {
214     case 1:                                            // 1,5 Stop bits
215     case 2:                                            // 2   Stop bits
216       lcr_s = 0x04;
217     break;
218     case 0:                                            // 1   Stop bit
219     default:
220       lcr_s = 0x00;
221     break;
222   }
223
224   switch (parity) {
225     case 1:                                            // Parity Odd
226       lcr_p = 0x08;
227     break;
228     case 2:                                            // Parity Even
229       lcr_p = 0x18;
230     break;
231     case 3:                                            // Parity Mark
232       lcr_p = 0x28;
233     break;
234     case 4:                                            // Parity Space
235       lcr_p = 0x38;
236     break;
237     case 0:                                            // Parity None
238     default:
239       lcr_p = 0x00;
240     break;
241   }
242
243   SER_BUF_RESET(ser_out);                              // reset out buffer
244   SER_BUF_RESET(ser_in);                               // reset in buffer
245
246   /* Bit 8,9 are for UART1 */
247   pclkdiv = (SC->PCLKSEL0 >> 8) & 0x03;
248
249   switch ( pclkdiv )
250   {
251         case 0x00:
252         default:
253           pclk = SystemFrequency/4;
254           break;
255         case 0x01:
256           pclk = SystemFrequency;
257           break;
258         case 0x02:
259           pclk = SystemFrequency/2;
260           break;
261         case 0x03:
262           pclk = SystemFrequency/8;
263           break;
264   }
265
266   dll = (pclk/16)/baudrate ;    /*baud rate */
267   UART1->FDR = 0;                             // Fractional divider not used
268   UART1->LCR = 0x80 | lcr_d | lcr_p | lcr_s;  // Data bits, Parity,   Stop bit
269   UART1->DLL = dll;                           // Baud Rate depending on PCLK
270   UART1->DLM = (dll >> 8);                    // High divisor latch
271   UART1->LCR = 0x00 | lcr_d | lcr_p | lcr_s;  // DLAB = 0
272   UART1->IER = 0x03;                          // Enable TX/RX interrupts
273
274   UART1->FCR = 0x07;                            /* Enable and reset TX and RX FIFO. */
275   ser_txRestart = 1;                                   // TX fifo is empty
276
277   /* Enable the UART Interrupt */
278   NVIC_EnableIRQ(UART1_IRQn);
279   return;
280 }
281
282 /*----------------------------------------------------------------------------
283   read data from serial port
284  *---------------------------------------------------------------------------*/
285 int ser_Read (char *buffer, const int *length) {
286   int bytesToRead, bytesRead;
287
288   /* Read *length bytes, block if *bytes are not avaialable     */
289   bytesToRead = *length;
290   bytesToRead = (bytesToRead < (*length)) ? bytesToRead : (*length);
291   bytesRead = bytesToRead;
292
293   while (bytesToRead--) {
294     while (SER_BUF_EMPTY(ser_in));                     // Block until data is available if none
295     *buffer++ = SER_BUF_RD(ser_in);
296   }
297   return (bytesRead);
298 }
299
300 /*----------------------------------------------------------------------------
301   write data to the serial port
302  *---------------------------------------------------------------------------*/
303 int ser_Write (char portNum, const char *buffer, int *length) {
304   int  bytesToWrite, bytesWritten;
305
306   // Write *length bytes
307   bytesToWrite = *length;
308   bytesWritten = bytesToWrite;
309
310   while (!SER_BUF_EMPTY(ser_out));               // Block until space is available if none
311   while (bytesToWrite) {
312       SER_BUF_WR(ser_out, *buffer++);            // Read Rx FIFO to buffer
313       bytesToWrite--;
314   }
315
316   if (ser_txRestart) {
317     ser_txRestart = 0;
318         if ( portNum == 0 )
319         {
320           UART0->THR = SER_BUF_RD(ser_out);             // Write to the Tx Register
321     }
322         else
323         {
324       UART1->THR = SER_BUF_RD(ser_out);             // Write to the Tx Register
325         }
326   }
327
328   return (bytesWritten);
329 }
330
331 /*----------------------------------------------------------------------------
332   check if character(s) are available at the serial interface
333  *---------------------------------------------------------------------------*/
334 void ser_AvailChar (int *availChar) {
335
336   *availChar = SER_BUF_COUNT(ser_in);
337
338 }
339
340 /*----------------------------------------------------------------------------
341   read the line state of the serial port
342  *---------------------------------------------------------------------------*/
343 void ser_LineState (unsigned short *lineState) {
344
345   *lineState = ser_lineState;
346   ser_lineState = 0;
347
348 }
349
350 /*----------------------------------------------------------------------------
351   serial port 0 interrupt
352  *---------------------------------------------------------------------------*/
353 void UART0_IRQHandler(void)
354 {
355   volatile unsigned long iir;
356
357   iir = UART0->IIR;
358
359   if ((iir & 0x4) || (iir & 0xC)) {            // RDA or CTI pending
360     while (UART0->LSR & 0x01) {                 // Rx FIFO is not empty
361       SER_BUF_WR(ser_in, UART0->RBR);           // Read Rx FIFO to buffer
362     }
363   }
364   if ((iir & 0x2)) {                           // TXMIS pending
365         if (SER_BUF_COUNT(ser_out) != 0) {
366       UART0->THR = SER_BUF_RD(ser_out);         // Write to the Tx FIFO
367       ser_txRestart = 0;
368     }
369         else {
370       ser_txRestart = 1;
371         }
372   }
373   ser_lineState = UART0->LSR & 0x1E;            // update linestate
374   return;
375 }
376
377 /*----------------------------------------------------------------------------
378   serial port 1 interrupt
379  *---------------------------------------------------------------------------*/
380 void UART1_IRQHandler(void)
381 {
382   volatile unsigned long iir;
383
384   iir = UART1->IIR;
385
386   if ((iir & 0x4) || (iir & 0xC)) {            // RDA or CTI pending
387     while (UART1->LSR & 0x01) {                 // Rx FIFO is not empty
388       SER_BUF_WR(ser_in, UART1->RBR);           // Read Rx FIFO to buffer
389     }
390   }
391   if ((iir & 0x2)) {                           // TXMIS pending
392         if (SER_BUF_COUNT(ser_out) != 0) {
393       UART1->THR = SER_BUF_RD(ser_out);         // Write to the Tx FIFO
394       ser_txRestart = 0;
395     }
396         else {
397       ser_txRestart = 1;
398         }
399   }
400   ser_lineState = ((UART1->MSR<<8)|UART1->LSR) & 0xE01E;    // update linestate
401   return;
402 }
403
404