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