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