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