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