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