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