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