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