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