]> git.sur5r.net Git - freertos/blob - Demo/WizNET_DEMO_TERN_186/serial/serial.c
Update in preparation for the V4.3.1 release.
[freertos] / Demo / WizNET_DEMO_TERN_186 / serial / serial.c
1 /*\r
2         FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.\r
3 \r
4         This file is part of the FreeRTOS.org distribution.\r
5 \r
6         FreeRTOS.org is free software; you can redistribute it and/or modify\r
7         it under the terms of the GNU General Public License as published by\r
8         the Free Software Foundation; either version 2 of the License, or\r
9         (at your option) any later version.\r
10 \r
11         FreeRTOS.org is distributed in the hope that it will be useful,\r
12         but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14         GNU General Public License for more details.\r
15 \r
16         You should have received a copy of the GNU General Public License\r
17         along with FreeRTOS.org; if not, write to the Free Software\r
18         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19 \r
20         A special exception to the GPL can be applied should you wish to distribute\r
21         a combined work that includes FreeRTOS.org, without being obliged to provide\r
22         the source code for any proprietary components.  See the licensing section \r
23         of http://www.FreeRTOS.org for full details of how and when the exception\r
24         can be applied.\r
25 \r
26         ***************************************************************************\r
27         See http://www.FreeRTOS.org for documentation, latest information, license \r
28         and contact details.  Please ensure to read the configuration and relevant \r
29         port sections of the online documentation.\r
30 \r
31         Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along\r
32         with commercial development and support options.\r
33         ***************************************************************************\r
34 */\r
35 \r
36 \r
37 #include <stdlib.h>\r
38 #include <embedded.h>\r
39 #include "FreeRTOS.h"\r
40 #include "portasm.h"\r
41 #include "queue.h"\r
42 #include "task.h"\r
43 #include "semphr.h"\r
44 \r
45 #define serMAX_PORTS                    ( ( unsigned portSHORT ) 2 )\r
46 \r
47 #define serPORT_0_INT_REG               ( 0xff44 )\r
48 #define serPORT_0_BAUD_REG              ( 0xff88 )\r
49 #define serPORT_0_RX_REG                ( 0xff86 )\r
50 #define serPORT_0_TX_REG                ( 0xff84 )\r
51 #define serPORT_0_STATUS_REG    ( 0xff82 )\r
52 #define serPORT_0_CTRL_REG              ( 0xff80 )\r
53 #define serPORT_0_IRQ                   ( 0x14 )\r
54 \r
55 #define serPORT_1_INT_REG               ( 0xff42 )\r
56 #define serPORT_1_BAUD_REG              ( 0xff18 )\r
57 #define serPORT_1_RX_REG                ( 0xff16 )\r
58 #define serPORT_1_TX_REG                ( 0xff14 )\r
59 #define serPORT_1_STATUS_REG    ( 0xff12 )\r
60 #define serPORT_1_CTRL_REG              ( 0xff10 )\r
61 #define serPORT_1_IRQ                   ( 0x11 )\r
62 \r
63 #define serTX_EMPTY                             ( ( unsigned portSHORT ) 0x40 )\r
64 #define serRX_READY                             ( ( unsigned portSHORT ) 0x80 )\r
65 \r
66 #define serRESET_PIC( usEOI_TYPE )      portOUTPUT_WORD( ( unsigned portSHORT ) 0xff22, usEOI_TYPE )\r
67 #define serTX_HOLD_EMPTY_INT            ( ( unsigned portSHORT ) 0x100 )\r
68 \r
69 #define serENABLE_INTERRUPTS            ( ( unsigned portSHORT ) 0x80 )\r
70 #define serMODE                                         ( ( unsigned portSHORT ) 0x01 )\r
71 #define serENABLE_TX_MACHINES           ( ( unsigned portSHORT ) 0x40 )\r
72 #define serENABLE_RX_MACHINES           ( ( unsigned portSHORT ) 0x20 )\r
73 #define serINTERRUPT_MASK                       ( ( unsigned portSHORT ) 0x08 )\r
74 #define serCLEAR_ALL_STATUS_BITS        ( ( unsigned portSHORT ) 0x00 )\r
75 #define serINTERRUPT_PRIORITY           ( ( unsigned portSHORT ) 0x01 ) /*< Just below the scheduler priority. */\r
76 \r
77 #define serDONT_BLOCK                           ( ( portTickType ) 0 )\r
78 \r
79 typedef enum\r
80\r
81         serCOM1 = 0, \r
82         serCOM2, \r
83         serCOM3, \r
84         serCOM4, \r
85         serCOM5, \r
86         serCOM6, \r
87         serCOM7, \r
88         serCOM8 \r
89 } eCOMPort;\r
90 \r
91 typedef enum \r
92\r
93         serNO_PARITY, \r
94         serODD_PARITY, \r
95         serEVEN_PARITY, \r
96         serMARK_PARITY, \r
97         serSPACE_PARITY \r
98 } eParity;\r
99 \r
100 typedef enum \r
101\r
102         serSTOP_1, \r
103         serSTOP_2 \r
104 } eStopBits;\r
105 \r
106 typedef enum \r
107 {\r
108         serBITS_5,\r
109         serBITS_6,\r
110         serBITS_7,\r
111         serBITS_8\r
112 } eDataBits;\r
113 \r
114 typedef enum\r
115 {\r
116         ser50 = 0,\r
117         ser75,\r
118         ser110,\r
119         ser134,\r
120         ser150,\r
121         ser200,\r
122         ser300,\r
123         ser600,\r
124         ser1200,\r
125         ser1800,\r
126         ser2400,\r
127         ser4800,\r
128         ser9600,\r
129         ser19200,\r
130         ser38400,\r
131         ser57600,\r
132         ser115200\r
133 } eBaud;\r
134 \r
135 typedef struct xCOM_PORT\r
136 {\r
137         /* Hardware parameters for this port. */\r
138         portSHORT sTxInterruptOn;\r
139         unsigned portSHORT usIntReg;\r
140         unsigned portSHORT usBaudReg;\r
141         unsigned portSHORT usRxReg;\r
142         unsigned portSHORT usTxReg;\r
143         unsigned portSHORT usStatusReg;\r
144         unsigned portSHORT usCtrlReg;\r
145 \r
146         unsigned portSHORT usIRQVector;\r
147 \r
148         /* Queues used for communications with com test task. */\r
149         xQueueHandle xRxedChars; \r
150         xQueueHandle xCharsForTx;\r
151 \r
152         /* This semaphore does nothing useful except test a feature of the\r
153         scheduler. */\r
154         xSemaphoreHandle xTestSem;\r
155 \r
156 } xComPort;\r
157 \r
158 static xComPort xPorts[ serMAX_PORTS ] = \r
159 {\r
160         { pdFALSE, serPORT_0_INT_REG, serPORT_0_BAUD_REG, serPORT_0_RX_REG, serPORT_0_TX_REG, serPORT_0_STATUS_REG, serPORT_0_CTRL_REG, serPORT_0_IRQ, NULL, NULL, NULL },\r
161         { pdFALSE, serPORT_1_INT_REG, serPORT_1_BAUD_REG, serPORT_1_RX_REG, serPORT_1_TX_REG, serPORT_1_STATUS_REG, serPORT_1_CTRL_REG, serPORT_1_IRQ, NULL, NULL, NULL }\r
162 };\r
163 \r
164 typedef xComPort * xComPortHandle;\r
165 \r
166 /**\r
167  * Lookup the baud rate from the enum.\r
168  */\r
169 static unsigned portLONG prvBaud( eBaud eWantedBaud ); \r
170 \r
171 /* These prototypes are repeated here so we don't have to include the serial header.  This allows\r
172 the xComPortHandle structure details to be private to this file. */\r
173 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength );\r
174 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, portCHAR *pcRxedChar, portTickType xBlockTime );\r
175 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, portCHAR cOutChar, portTickType xBlockTime );\r
176 void vSerialClose( xComPortHandle xPort );\r
177 portSHORT sSerialWaitForSemaphore( xComPortHandle xPort );\r
178 /*-----------------------------------------------------------*/\r
179 \r
180 static portSHORT xComPortISR( xComPort * const pxPort );\r
181 \r
182 #define vInterruptOn( pxPort, usInterrupt )                                                                             \\r
183 {                                                                                                                                                               \\r
184 unsigned portSHORT usIn;                                                                                                                \\r
185                                                                                                                                                                 \\r
186         portENTER_CRITICAL();                                                                                                           \\r
187         {                                                                                                                                                       \\r
188                 if( pxPort->sTxInterruptOn == pdFALSE )                                                                 \\r
189                 {                                                                                                                                               \\r
190                         usIn = portINPUT_WORD( pxPort->usCtrlReg );                                                     \\r
191                         portOUTPUT_WORD( pxPort->usCtrlReg, usIn | usInterrupt );                       \\r
192                                                                                                                                                                 \\r
193                         pxPort->sTxInterruptOn = pdTRUE;                                                                        \\r
194                 }                                                                                                                                               \\r
195         }                                                                                                                                                       \\r
196         portEXIT_CRITICAL();                                                                                                            \\r
197 }                                                                                                                                                               \r
198 /*-----------------------------------------------------------*/\r
199 \r
200 #define vInterruptOff( pxPort, usInterrupt )                                                                    \\r
201 {                                                                                                                                                               \\r
202         unsigned portSHORT usIn = portINPUT_WORD( pxPort->usCtrlReg );                          \\r
203         if( usIn & usInterrupt )                                                                                                        \\r
204         {                                                                                                                                                       \\r
205                 portOUTPUT_WORD( pxPort->usCtrlReg, usIn & ~usInterrupt);                               \\r
206                 pxPort->sTxInterruptOn = pdFALSE;                                                                               \\r
207         }                                                                                                                                                       \\r
208 }\r
209 /*-----------------------------------------------------------*/\r
210 \r
211 \r
212 /* Define an interrupt handler for each port */\r
213 #define COM_IRQ_WRAPPER(N)                                                                              \\r
214         static void __interrupt COM_IRQ##N##_WRAPPER( void )            \\r
215         {                                                                                                                       \\r
216         if( xComPortISR( &( xPorts[##N##] ) ) )                 \\r
217         {                                                       \\r
218                         portEND_SWITCHING_ISR();                            \\r
219                 }                                                       \\r
220         }\r
221 \r
222   \r
223 \r
224 COM_IRQ_WRAPPER( 0 )\r
225 COM_IRQ_WRAPPER( 1 )\r
226 \r
227 static pxISR xISRs[ serMAX_PORTS ] = \r
228 {\r
229         COM_IRQ0_WRAPPER, \r
230         COM_IRQ1_WRAPPER\r
231 };\r
232 \r
233 /*-----------------------------------------------------------*/\r
234 \r
235 static unsigned portLONG prvBaud( eBaud eWantedBaud )\r
236 {\r
237         switch( eWantedBaud )\r
238     {\r
239                 case ser50                      :       return 50UL;\r
240                 case ser75                      :       return 75UL;\r
241                 case ser110                     :       return 110UL;\r
242                 case ser134                     :       return 134UL;\r
243                 case ser150                     :       return 150UL;\r
244                 case ser200                     :       return 200UL;\r
245                 case ser300                     :       return 300UL;\r
246                 case ser600                     :       return 600UL;\r
247                 case ser1200            :       return 1200UL;\r
248                 case ser1800            :       return 1800UL;\r
249                 case ser2400            :       return 2400UL;\r
250                 case ser4800            :       return 4800UL;\r
251                 case ser19200           :       return 19200UL;\r
252                 case ser38400           :       return 38400UL;\r
253                 case ser57600           :       return 57600UL;\r
254                 case ser115200          :       return 115200UL;\r
255                 default                         :       return 9600UL;\r
256     }\r
257 }\r
258 \r
259 /*-----------------------------------------------------------*/\r
260 \r
261 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )\r
262 {\r
263 unsigned portSHORT usPort;\r
264 xComPortHandle pxPort = NULL;\r
265 unsigned portLONG ulBaudDiv;\r
266 \r
267         /* BAUDDIV = ( Microprocessor Clock / Baud Rate ) / 16 */\r
268     ulBaudDiv = ( configCPU_CLOCK_HZ / prvBaud( eWantedBaud ) ) / 16UL;\r
269 \r
270         /* Only n, 8, 1 is supported so these parameters are not required for this\r
271         port. */\r
272         ( void ) eWantedParity;\r
273         ( void ) eWantedDataBits;\r
274     ( void ) eWantedStopBits;\r
275 \r
276         /* Currently only n,8,1 is supported. */\r
277 \r
278         usPort = ( unsigned portSHORT ) ePort;\r
279         \r
280         if( usPort < serMAX_PORTS )\r
281         {\r
282                 pxPort = &( xPorts[ usPort ] );\r
283 \r
284                 portENTER_CRITICAL();\r
285                 {\r
286                         unsigned portSHORT usInWord;\r
287 \r
288                         /* Create the queues used by the com test task. */\r
289                         pxPort->xRxedChars = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( portCHAR ) );\r
290                         pxPort->xCharsForTx = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( portCHAR ) );\r
291 \r
292                         /* Create the test semaphore.  This does nothing useful except test a feature of the scheduler. */\r
293                         vSemaphoreCreateBinary( pxPort->xTestSem );\r
294 \r
295                         /* There is no ISR here already to restore later. */\r
296                         setvect( ( portSHORT ) pxPort->usIRQVector, xISRs[ usPort ] );\r
297 \r
298                         usInWord = portINPUT_WORD( pxPort->usIntReg );\r
299                         usInWord &= ~serINTERRUPT_MASK;\r
300                         usInWord |= serINTERRUPT_PRIORITY;\r
301                         portOUTPUT_WORD( pxPort->usIntReg, usInWord );\r
302 \r
303                         portOUTPUT_WORD( pxPort->usBaudReg, ( unsigned portSHORT ) ulBaudDiv );\r
304                         portOUTPUT_WORD( pxPort->usCtrlReg, serENABLE_INTERRUPTS | serMODE | serENABLE_TX_MACHINES | serENABLE_RX_MACHINES );\r
305 \r
306                         portOUTPUT_WORD( pxPort->usStatusReg, serCLEAR_ALL_STATUS_BITS );\r
307                 }\r
308                 portEXIT_CRITICAL();\r
309         }\r
310 \r
311         return pxPort;\r
312 } /*lint !e715 Some parameters are not used as only a subset of the serial port functionality is currently implemented. */\r
313 /*-----------------------------------------------------------*/\r
314 \r
315 void vSerialPutString( xComPortHandle pxPort, const portCHAR * const pcString, unsigned portSHORT usStringLength )\r
316 {\r
317 unsigned portSHORT usByte;\r
318 portCHAR *pcNextChar;\r
319 \r
320         pcNextChar = ( portCHAR * ) pcString;\r
321 \r
322         for( usByte = 0; usByte < usStringLength; usByte++ )\r
323         {\r
324                 xQueueSend( pxPort->xCharsForTx, pcNextChar, serDONT_BLOCK );\r
325                 pcNextChar++;\r
326         }\r
327 \r
328         vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );\r
329 }\r
330 /*-----------------------------------------------------------*/\r
331 \r
332 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, portCHAR *pcRxedChar, portTickType xBlockTime )\r
333 {\r
334         /* Get the next character from the buffer, note that this routine is only \r
335         called having checked that the is (at least) one to get */\r
336         if( xQueueReceive( pxPort->xRxedChars, pcRxedChar, xBlockTime ) )\r
337         {\r
338                 return pdTRUE;\r
339         }\r
340         else\r
341         {\r
342                 return pdFALSE;\r
343         }\r
344 }\r
345 /*-----------------------------------------------------------*/\r
346 \r
347 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, portCHAR cOutChar, portTickType xBlockTime )\r
348 {\r
349         if( xQueueSend( pxPort->xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )\r
350         {\r
351                 return pdFAIL;\r
352         }\r
353 \r
354         vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );\r
355 \r
356         return pdPASS;\r
357 }\r
358 /*-----------------------------------------------------------*/\r
359 \r
360 portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort )\r
361 {\r
362 const portTickType xBlockTime = ( portTickType ) 0xffff;\r
363 \r
364         /* This function does nothing interesting, but test the \r
365         semaphore from ISR mechanism. */\r
366         return xSemaphoreTake( xPort->xTestSem, xBlockTime );\r
367 }\r
368 /*-----------------------------------------------------------*/\r
369 \r
370 void vSerialClose( xComPortHandle xPort )\r
371 {\r
372 unsigned portSHORT usOutput;\r
373 \r
374         /* Turn off the interrupts.  We may also want to delete the queues and/or\r
375         re-install the original ISR. */\r
376 \r
377         portENTER_CRITICAL();\r
378         {\r
379                 usOutput = portINPUT_WORD( xPort->usCtrlReg );\r
380 \r
381                 usOutput &= ~serENABLE_INTERRUPTS;\r
382                 usOutput &= ~serENABLE_TX_MACHINES;\r
383                 usOutput &= ~serENABLE_RX_MACHINES;\r
384                 portOUTPUT_WORD( xPort->usCtrlReg, usOutput );\r
385 \r
386                 usOutput = portINPUT_WORD( xPort->usIntReg );\r
387                 usOutput |= serINTERRUPT_MASK;\r
388                 portOUTPUT_WORD( xPort->usIntReg, usOutput );\r
389         }\r
390         portEXIT_CRITICAL();\r
391 }\r
392 /*-----------------------------------------------------------*/\r
393 unsigned short usStatus;\r
394 static portBASE_TYPE xComPortISR( xComPort * const pxPort )\r
395 {\r
396 unsigned portSHORT usStatusRegister;\r
397 portCHAR cChar;\r
398 portBASE_TYPE xTaskWokenByPost = pdFALSE, xAnotherTaskWokenByPost = pdFALSE, xTaskWokenByTx = pdFALSE;\r
399 \r
400         /* NOTE:  THIS IS NOT AN EFFICIENT ISR AS IT IS DESIGNED SOLELY TO TEST\r
401         THE SCHEDULER FUNCTIONALITY.  REAL APPLICATIONS SHOULD NOT USE THIS\r
402         FUNCTION. */\r
403 \r
404         usStatusRegister = portINPUT_WORD( pxPort->usStatusReg );\r
405 \r
406         if( usStatusRegister & serRX_READY )\r
407         {\r
408                 cChar = ( portCHAR ) portINPUT_WORD( pxPort->usRxReg );\r
409                 xTaskWokenByPost = xQueueSendFromISR( pxPort->xRxedChars, &cChar, xTaskWokenByPost );\r
410 \r
411                 /* Also release the semaphore - this does nothing interesting and is just a test. */\r
412                 xAnotherTaskWokenByPost = xSemaphoreGiveFromISR( pxPort->xTestSem, xAnotherTaskWokenByPost );\r
413         }\r
414         else if( pxPort->sTxInterruptOn && ( usStatusRegister & serTX_EMPTY ) )\r
415         {\r
416                 if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cChar, &xTaskWokenByTx ) == pdTRUE )\r
417                 {\r
418                         portOUTPUT_WORD( pxPort->usTxReg, ( unsigned portSHORT ) cChar );\r
419                 }\r
420                 else\r
421                 {\r
422                         /* Queue empty, nothing to send */\r
423                         vInterruptOff( pxPort, serTX_HOLD_EMPTY_INT );\r
424                 }\r
425         }\r
426 \r
427     serRESET_PIC( pxPort->usIRQVector );\r
428 \r
429         /* If posting to the queue woke a task that was blocked on the queue we may\r
430         want to switch to the woken task - depending on its priority relative to\r
431         the task interrupted by this ISR. */\r
432         if( xTaskWokenByPost || xAnotherTaskWokenByPost || xTaskWokenByTx)\r
433         {\r
434                 return pdTRUE;\r
435         }\r
436         else\r
437         {\r
438                 return pdFALSE;\r
439         }\r
440 }\r
441 \r
442 \r
443 \r
444 \r
445 \r