initial usb
[rapper.git] / new_cmsis / usb / serial.c
1 /*----------------------------------------------------------------------------\r
2  *      Name:    serial.c\r
3  *      Purpose: serial port handling for LPC17xx\r
4  *      Version: V1.20\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
13  *\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
18 #include "serial.h"\r
19 \r
20 \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
26 \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
34 \r
35 // buffer type\r
36 typedef struct __SER_BUF_T {\r
37   unsigned char data[SER_BUF_SIZE];\r
38   unsigned int wrIdx;\r
39   unsigned int rdIdx;\r
40 } SER_BUF_T;\r
41 \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
45 SER_BUF_T              ser_in;\r
46 \r
47 /*----------------------------------------------------------------------------\r
48   open the serial port\r
49  *---------------------------------------------------------------------------*/\r
50 void ser_OpenPort (char portNum) {\r
51 \r
52   if ( portNum == 0 )\r
53   {\r
54         /* Port 0 */\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
58   }\r
59   else\r
60   {\r
61         /* Port 1 */\r
62         NVIC_DisableIRQ(UART1_IRQn);\r
63         PINCON->PINSEL4 &= ~0x0000000F;\r
64         PINCON->PINSEL4 |= 0x0000000A;    /* Enable RxD1 P2.1, TxD1 P2.0 */\r
65   }\r
66   return;\r
67 }\r
68 \r
69 /*----------------------------------------------------------------------------\r
70   close the serial port\r
71  *---------------------------------------------------------------------------*/\r
72 void ser_ClosePort (char portNum ) {\r
73   if ( portNum == 0 )\r
74   {\r
75         /* POrt 0 */\r
76         PINCON->PINSEL0 &= ~0x000000F0;\r
77         /* Disable the interrupt in the VIC and UART controllers */\r
78         UART0->IER = 0;\r
79         NVIC_DisableIRQ(UART0_IRQn);\r
80   }\r
81   else\r
82   {\r
83         /* Port 1 */\r
84         PINCON->PINSEL4 &= ~0x0000000F;\r
85         /* Disable the interrupt in the VIC and UART controllers */\r
86         UART1->IER = 0;\r
87         NVIC_DisableIRQ(UART1_IRQn);\r
88   }\r
89   return;\r
90 }\r
91 \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
97 \r
98   unsigned char lcr_p, lcr_s, lcr_d;\r
99   unsigned int dll;\r
100   unsigned int pclkdiv, pclk;\r
101 \r
102   switch (databits) {\r
103     case 5:                                            // 5 Data bits\r
104       lcr_d = 0x00;\r
105     break;\r
106     case 6:                                            // 6 Data bits\r
107       lcr_d = 0x01;\r
108     break;\r
109     case 7:                                            // 7 Data bits\r
110       lcr_d = 0x02;\r
111     break;\r
112     case 8:                                            // 8 Data bits\r
113     default:\r
114       lcr_d = 0x03;\r
115     break;\r
116   }\r
117 \r
118   switch (stopbits) {\r
119     case 1:                                            // 1,5 Stop bits\r
120     case 2:                                            // 2   Stop bits\r
121       lcr_s = 0x04;\r
122     break;\r
123     case 0:                                            // 1   Stop bit\r
124     default:\r
125       lcr_s = 0x00;\r
126     break;\r
127   }\r
128 \r
129   switch (parity) {\r
130     case 1:                                            // Parity Odd\r
131       lcr_p = 0x08;\r
132     break;\r
133     case 2:                                            // Parity Even\r
134       lcr_p = 0x18;\r
135     break;\r
136     case 3:                                            // Parity Mark\r
137       lcr_p = 0x28;\r
138     break;\r
139     case 4:                                            // Parity Space\r
140       lcr_p = 0x38;\r
141     break;\r
142     case 0:                                            // Parity None\r
143     default:\r
144       lcr_p = 0x00;\r
145     break;\r
146   }\r
147 \r
148   SER_BUF_RESET(ser_out);                              // reset out buffer\r
149   SER_BUF_RESET(ser_in);                               // reset in buffer\r
150 \r
151   /* Bit 6~7 is for UART0 */\r
152   pclkdiv = (SC->PCLKSEL0 >> 6) & 0x03;\r
153 \r
154   switch ( pclkdiv )\r
155   {\r
156         case 0x00:\r
157         default:\r
158           pclk = SystemFrequency/4;\r
159           break;\r
160         case 0x01:\r
161           pclk = SystemFrequency;\r
162           break;\r
163         case 0x02:\r
164           pclk = SystemFrequency/2;\r
165           break;\r
166         case 0x03:\r
167           pclk = SystemFrequency/8;\r
168           break;\r
169   }\r
170 \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
178 \r
179   UART0->FCR = 0x07;                            /* Enable and reset TX and RX FIFO. */\r
180   ser_txRestart = 1;                                   // TX fifo is empty\r
181 \r
182   /* Enable the UART Interrupt */\r
183   NVIC_EnableIRQ(UART0_IRQn);\r
184   return;\r
185 }\r
186 \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
192 \r
193   unsigned char lcr_p, lcr_s, lcr_d;\r
194   unsigned int dll;\r
195   unsigned int pclkdiv, pclk;\r
196 \r
197   switch (databits) {\r
198     case 5:                                            // 5 Data bits\r
199       lcr_d = 0x00;\r
200     break;\r
201     case 6:                                            // 6 Data bits\r
202       lcr_d = 0x01;\r
203     break;\r
204     case 7:                                            // 7 Data bits\r
205       lcr_d = 0x02;\r
206     break;\r
207     case 8:                                            // 8 Data bits\r
208     default:\r
209       lcr_d = 0x03;\r
210     break;\r
211   }\r
212 \r
213   switch (stopbits) {\r
214     case 1:                                            // 1,5 Stop bits\r
215     case 2:                                            // 2   Stop bits\r
216       lcr_s = 0x04;\r
217     break;\r
218     case 0:                                            // 1   Stop bit\r
219     default:\r
220       lcr_s = 0x00;\r
221     break;\r
222   }\r
223 \r
224   switch (parity) {\r
225     case 1:                                            // Parity Odd\r
226       lcr_p = 0x08;\r
227     break;\r
228     case 2:                                            // Parity Even\r
229       lcr_p = 0x18;\r
230     break;\r
231     case 3:                                            // Parity Mark\r
232       lcr_p = 0x28;\r
233     break;\r
234     case 4:                                            // Parity Space\r
235       lcr_p = 0x38;\r
236     break;\r
237     case 0:                                            // Parity None\r
238     default:\r
239       lcr_p = 0x00;\r
240     break;\r
241   }\r
242 \r
243   SER_BUF_RESET(ser_out);                              // reset out buffer\r
244   SER_BUF_RESET(ser_in);                               // reset in buffer\r
245 \r
246   /* Bit 8,9 are for UART1 */\r
247   pclkdiv = (SC->PCLKSEL0 >> 8) & 0x03;\r
248 \r
249   switch ( pclkdiv )\r
250   {\r
251         case 0x00:\r
252         default:\r
253           pclk = SystemFrequency/4;\r
254           break;\r
255         case 0x01:\r
256           pclk = SystemFrequency;\r
257           break;\r
258         case 0x02:\r
259           pclk = SystemFrequency/2;\r
260           break;\r
261         case 0x03:\r
262           pclk = SystemFrequency/8;\r
263           break;\r
264   }\r
265 \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
273 \r
274   UART1->FCR = 0x07;                            /* Enable and reset TX and RX FIFO. */\r
275   ser_txRestart = 1;                                   // TX fifo is empty\r
276 \r
277   /* Enable the UART Interrupt */\r
278   NVIC_EnableIRQ(UART1_IRQn);\r
279   return;\r
280 }\r
281 \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
287 \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
292 \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
296   }\r
297   return (bytesRead);\r
298 }\r
299 \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
305 \r
306   // Write *length bytes\r
307   bytesToWrite = *length;\r
308   bytesWritten = bytesToWrite;\r
309 \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
313       bytesToWrite--;\r
314   }\r
315 \r
316   if (ser_txRestart) {\r
317     ser_txRestart = 0;\r
318         if ( portNum == 0 )\r
319         {\r
320           UART0->THR = SER_BUF_RD(ser_out);             // Write to the Tx Register\r
321     }\r
322         else\r
323         {\r
324       UART1->THR = SER_BUF_RD(ser_out);             // Write to the Tx Register\r
325         }\r
326   }\r
327 \r
328   return (bytesWritten);\r
329 }\r
330 \r
331 /*----------------------------------------------------------------------------\r
332   check if character(s) are available at the serial interface\r
333  *---------------------------------------------------------------------------*/\r
334 void ser_AvailChar (int *availChar) {\r
335 \r
336   *availChar = SER_BUF_COUNT(ser_in);\r
337 \r
338 }\r
339 \r
340 /*----------------------------------------------------------------------------\r
341   read the line state of the serial port\r
342  *---------------------------------------------------------------------------*/\r
343 void ser_LineState (unsigned short *lineState) {\r
344 \r
345   *lineState = ser_lineState;\r
346   ser_lineState = 0;\r
347 \r
348 }\r
349 \r
350 /*----------------------------------------------------------------------------\r
351   serial port 0 interrupt\r
352  *---------------------------------------------------------------------------*/\r
353 void UART0_IRQHandler(void)\r
354 {\r
355   volatile unsigned long iir;\r
356 \r
357   iir = UART0->IIR;\r
358 \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
362     }\r
363   }\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
367       ser_txRestart = 0;\r
368     }\r
369         else {\r
370       ser_txRestart = 1;\r
371         }\r
372   }\r
373   ser_lineState = UART0->LSR & 0x1E;            // update linestate\r
374   return;\r
375 }\r
376 \r
377 /*----------------------------------------------------------------------------\r
378   serial port 1 interrupt\r
379  *---------------------------------------------------------------------------*/\r
380 void UART1_IRQHandler(void)\r
381 {\r
382   volatile unsigned long iir;\r
383 \r
384   iir = UART1->IIR;\r
385 \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
389     }\r
390   }\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
394       ser_txRestart = 0;\r
395     }\r
396         else {\r
397       ser_txRestart = 1;\r
398         }\r
399   }\r
400   ser_lineState = ((UART1->MSR<<8)|UART1->LSR) & 0xE01E;    // update linestate\r
401   return;\r
402 }\r
403 \r
404 \r