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