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