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