2 FreeRTOS.org V5.3.1 - Copyright (C) 2003-2009 Richard Barry.
\r
4 This file is part of the FreeRTOS.org distribution.
\r
6 FreeRTOS.org is free software; you can redistribute it and/or modify it
\r
7 under the terms of the GNU General Public License (version 2) as published
\r
8 by the 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.org without being obliged to provide
\r
11 the source code for any proprietary components. Alternative commercial
\r
12 license and support terms are also available upon request. See the
\r
13 licensing section of http://www.FreeRTOS.org for full details.
\r
15 FreeRTOS.org is distributed in the hope that it will be useful, but WITHOUT
\r
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
\r
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
20 You should have received a copy of the GNU General Public License along
\r
21 with FreeRTOS.org; if not, write to the Free Software Foundation, Inc., 59
\r
22 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
\r
25 ***************************************************************************
\r
27 * Get the FreeRTOS eBook! See http://www.FreeRTOS.org/Documentation *
\r
29 * This is a concise, step by step, 'hands on' guide that describes both *
\r
30 * general multitasking concepts and FreeRTOS specifics. It presents and *
\r
31 * explains numerous examples that are written using the FreeRTOS API. *
\r
32 * Full source code for all the examples is provided in an accompanying *
\r
35 ***************************************************************************
\r
39 Please ensure to read the configuration and relevant port sections of the
\r
40 online documentation.
\r
42 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
45 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
48 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
49 licensing and training services.
\r
55 + Call to the more efficient portSWITCH_CONTEXT() replaces the call to
\r
56 taskYIELD() in the ISR.
\r
60 + The semaphore task is not operational. This does nothing but check
\r
61 the semaphore from ISR functionality.
\r
62 + ISR modified slightly so only Rx or Tx is serviced per ISR - not both.
\r
64 Changes from V1.2.0:
\r
66 + Change so Tx uses a DMA channel, and Rx uses an interrupt.
\r
70 + The function xPortInitMinimal() has been renamed to
\r
71 xSerialPortInitMinimal() and the function xPortInit() has been renamed
\r
72 to xSerialPortInit().
\r
76 + Reverted back to the non-DMA serial port driver, with a slightly modified
\r
77 ISR. This is a better test of the scheduler mechanisms.
\r
78 + A critical section is now used in vInterruptOn().
\r
79 + Flag sTxInterruptOn has been added to the port structure. This allows
\r
80 checking of the interrupt enable status without performing any IO.
\r
84 + Use portTickType in place of unsigned pdLONG for delay periods.
\r
85 + Slightly more efficient vSerialSendString() implementation.
\r
86 + cQueueReieveFromISR() used in place of xQueueReceive() in ISR.
\r
91 #include "FreeRTOS.h"
\r
94 #include "portasm.h"
\r
97 #define serMAX_PORTS ( ( unsigned portSHORT ) 2 )
\r
99 #define serPORT_0_INT_REG ( 0xff44 )
\r
100 #define serPORT_0_BAUD_REG ( 0xff88 )
\r
101 #define serPORT_0_RX_REG ( 0xff86 )
\r
102 #define serPORT_0_TX_REG ( 0xff84 )
\r
103 #define serPORT_0_STATUS_REG ( 0xff82 )
\r
104 #define serPORT_0_CTRL_REG ( 0xff80 )
\r
105 #define serPORT_0_IRQ ( 0x14 )
\r
107 #define serPORT_1_INT_REG ( 0xff42 )
\r
108 #define serPORT_1_BAUD_REG ( 0xff18 )
\r
109 #define serPORT_1_RX_REG ( 0xff16 )
\r
110 #define serPORT_1_TX_REG ( 0xff14 )
\r
111 #define serPORT_1_STATUS_REG ( 0xff12 )
\r
112 #define serPORT_1_CTRL_REG ( 0xff10 )
\r
113 #define serPORT_1_IRQ ( 0x11 )
\r
115 #define serTX_EMPTY ( ( unsigned portSHORT ) 0x40 )
\r
116 #define serRX_READY ( ( unsigned portSHORT ) 0x80 )
\r
118 #define serRESET_PIC( usEOI_TYPE ) portOUTPUT_WORD( ( unsigned portSHORT ) 0xff22, usEOI_TYPE )
\r
119 #define serTX_HOLD_EMPTY_INT ( ( unsigned portSHORT ) 0x100 )
\r
121 #define serENABLE_INTERRUPTS ( ( unsigned portSHORT ) 0x80 )
\r
122 #define serMODE ( ( unsigned portSHORT ) 0x01 )
\r
123 #define serENABLE_TX_MACHINES ( ( unsigned portSHORT ) 0x40 )
\r
124 #define serENABLE_RX_MACHINES ( ( unsigned portSHORT ) 0x20 )
\r
125 #define serINTERRUPT_MASK ( ( unsigned portSHORT ) 0x08 )
\r
126 #define serCLEAR_ALL_STATUS_BITS ( ( unsigned portSHORT ) 0x00 )
\r
127 #define serINTERRUPT_PRIORITY ( ( unsigned portSHORT ) 0x01 ) /*< Just below the scheduler priority. */
\r
129 #define serDONT_BLOCK ( ( portTickType ) 0 )
\r
187 /* Must be same order as eBaud definitions. */
\r
188 static const unsigned portSHORT usBaudRateDivisor[] =
\r
190 0, /* Not sure if the first 6 are correct. First cannot be used. */
\r
210 typedef struct xCOM_PORT
\r
212 /* Hardware parameters for this port. */
\r
213 portSHORT sTxInterruptOn;
\r
214 unsigned portSHORT usIntReg;
\r
215 unsigned portSHORT usBaudReg;
\r
216 unsigned portSHORT usRxReg;
\r
217 unsigned portSHORT usTxReg;
\r
218 unsigned portSHORT usStatusReg;
\r
219 unsigned portSHORT usCtrlReg;
\r
221 unsigned portSHORT usIRQVector;
\r
223 /* Queues used for communications with com test task. */
\r
224 xQueueHandle xRxedChars;
\r
225 xQueueHandle xCharsForTx;
\r
227 /* This semaphore does nothing useful except test a feature of the
\r
229 xSemaphoreHandle xTestSem;
\r
233 static xComPort xPorts[ serMAX_PORTS ] =
\r
235 { 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
236 { 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
239 typedef xComPort * xComPortHandle;
\r
241 /* These prototypes are repeated here so we don't have to include the serial header. This allows
\r
242 the xComPortHandle structure details to be private to this file. */
\r
243 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength );
\r
244 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, portCHAR *pcRxedChar, portTickType xBlockTime );
\r
245 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, portCHAR cOutChar, portTickType xBlockTime );
\r
246 void vSerialClose( xComPortHandle xPort );
\r
247 portSHORT sSerialWaitForSemaphore( xComPortHandle xPort );
\r
248 /*-----------------------------------------------------------*/
\r
250 static portSHORT xComPortISR( xComPort * const pxPort );
\r
252 #define vInterruptOn( pxPort, usInterrupt ) \
\r
254 unsigned portSHORT usIn; \
\r
256 portENTER_CRITICAL(); \
\r
258 if( pxPort->sTxInterruptOn == pdFALSE ) \
\r
260 usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
261 portOUTPUT_WORD( pxPort->usCtrlReg, usIn | usInterrupt ); \
\r
263 pxPort->sTxInterruptOn = pdTRUE; \
\r
266 portEXIT_CRITICAL(); \
\r
268 /*-----------------------------------------------------------*/
\r
270 #define vInterruptOff( pxPort, usInterrupt ) \
\r
272 unsigned portSHORT usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
273 if( usIn & usInterrupt ) \
\r
275 portOUTPUT_WORD( pxPort->usCtrlReg, usIn & ~usInterrupt); \
\r
276 pxPort->sTxInterruptOn = pdFALSE; \
\r
279 /*-----------------------------------------------------------*/
\r
282 /* Define an interrupt handler for each port */
\r
283 #define COM_IRQ_WRAPPER(N) \
\r
284 static void __interrupt COM_IRQ##N##_WRAPPER( void ) \
\r
286 if( xComPortISR( &( xPorts[##N##] ) ) ) \
\r
288 portSWITCH_CONTEXT(); \
\r
294 COM_IRQ_WRAPPER( 0 )
\r
295 COM_IRQ_WRAPPER( 1 )
\r
297 static pxISR xISRs[ serMAX_PORTS ] =
\r
303 /*-----------------------------------------------------------*/
\r
305 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )
\r
307 unsigned portSHORT usPort;
\r
308 xComPortHandle pxPort = NULL;
\r
310 /* BAUDDIV = ( Microprocessor Clock / Baud Rate ) / 16 */
\r
312 /* Only n, 8, 1 is supported so these parameters are not required for this
\r
314 ( void ) eWantedParity;
\r
315 ( void ) eWantedDataBits;
\r
316 ( void ) eWantedStopBits;
\r
318 /* Currently only n,8,1 is supported. */
\r
320 usPort = ( unsigned portSHORT ) ePort;
\r
322 if( usPort < serMAX_PORTS )
\r
324 pxPort = &( xPorts[ usPort ] );
\r
326 portENTER_CRITICAL();
\r
328 unsigned portSHORT usInWord;
\r
330 /* Create the queues used by the com test task. */
\r
331 pxPort->xRxedChars = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( portCHAR ) );
\r
332 pxPort->xCharsForTx = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( portCHAR ) );
\r
334 /* Create the test semaphore. This does nothing useful except test a feature of the scheduler. */
\r
335 vSemaphoreCreateBinary( pxPort->xTestSem );
\r
337 /* There is no ISR here already to restore later. */
\r
338 _dos_setvect( ( portSHORT ) pxPort->usIRQVector, xISRs[ usPort ] );
\r
340 usInWord = portINPUT_WORD( pxPort->usIntReg );
\r
341 usInWord &= ~serINTERRUPT_MASK;
\r
342 usInWord |= serINTERRUPT_PRIORITY;
\r
343 portOUTPUT_WORD( pxPort->usIntReg, usInWord );
\r
345 portOUTPUT_WORD( pxPort->usBaudReg, usBaudRateDivisor[ eWantedBaud ] );
\r
346 portOUTPUT_WORD( pxPort->usCtrlReg, serENABLE_INTERRUPTS | serMODE | serENABLE_TX_MACHINES | serENABLE_RX_MACHINES );
\r
348 portOUTPUT_WORD( pxPort->usStatusReg, serCLEAR_ALL_STATUS_BITS );
\r
350 portEXIT_CRITICAL();
\r
354 } /*lint !e715 Some parameters are not used as only a subset of the serial port functionality is currently implemented. */
\r
355 /*-----------------------------------------------------------*/
\r
357 void vSerialPutString( xComPortHandle pxPort, const portCHAR * const pcString, unsigned portSHORT usStringLength )
\r
359 unsigned portSHORT usByte;
\r
360 portCHAR *pcNextChar;
\r
362 pcNextChar = ( portCHAR * ) pcString;
\r
364 for( usByte = 0; usByte < usStringLength; usByte++ )
\r
366 xQueueSend( pxPort->xCharsForTx, pcNextChar, serDONT_BLOCK );
\r
370 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
372 /*-----------------------------------------------------------*/
\r
374 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, portCHAR *pcRxedChar, portTickType xBlockTime )
\r
376 /* Get the next character from the buffer, note that this routine is only
\r
377 called having checked that the is (at least) one to get */
\r
378 if( xQueueReceive( pxPort->xRxedChars, pcRxedChar, xBlockTime ) )
\r
387 /*-----------------------------------------------------------*/
\r
389 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, portCHAR cOutChar, portTickType xBlockTime )
\r
391 if( xQueueSend( pxPort->xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )
\r
396 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
400 /*-----------------------------------------------------------*/
\r
402 portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort )
\r
404 const portTickType xBlockTime = ( portTickType ) 0xffff;
\r
406 /* This function does nothing interesting, but test the
\r
407 semaphore from ISR mechanism. */
\r
408 return xSemaphoreTake( xPort->xTestSem, xBlockTime );
\r
410 /*-----------------------------------------------------------*/
\r
412 void vSerialClose( xComPortHandle xPort )
\r
414 unsigned portSHORT usOutput;
\r
416 /* Turn off the interrupts. We may also want to delete the queues and/or
\r
417 re-install the original ISR. */
\r
419 portENTER_CRITICAL();
\r
421 usOutput = portINPUT_WORD( xPort->usCtrlReg );
\r
423 usOutput &= ~serENABLE_INTERRUPTS;
\r
424 usOutput &= ~serENABLE_TX_MACHINES;
\r
425 usOutput &= ~serENABLE_RX_MACHINES;
\r
426 portOUTPUT_WORD( xPort->usCtrlReg, usOutput );
\r
428 usOutput = portINPUT_WORD( xPort->usIntReg );
\r
429 usOutput |= serINTERRUPT_MASK;
\r
430 portOUTPUT_WORD( xPort->usIntReg, usOutput );
\r
432 portEXIT_CRITICAL();
\r
434 /*-----------------------------------------------------------*/
\r
436 static portBASE_TYPE xComPortISR( xComPort * const pxPort )
\r
438 unsigned portSHORT usStatusRegister;
\r
440 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE, xContinue = pdTRUE;
\r
442 /* NOTE: THIS IS NOT AN EFFICIENT ISR AS IT IS DESIGNED SOLELY TO TEST
\r
443 THE SCHEDULER FUNCTIONALITY. REAL APPLICATIONS SHOULD NOT USE THIS
\r
447 while( xContinue == pdTRUE )
\r
449 xContinue = pdFALSE;
\r
450 usStatusRegister = portINPUT_WORD( pxPort->usStatusReg );
\r
452 if( usStatusRegister & serRX_READY )
\r
454 cChar = ( portCHAR ) portINPUT_WORD( pxPort->usRxReg );
\r
455 xQueueSendFromISR( pxPort->xRxedChars, &cChar, &xHigherPriorityTaskWoken );
\r
457 /* Also release the semaphore - this does nothing interesting and is just a test. */
\r
458 xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
\r
460 /* We have performed an action this cycle - there may be other to perform. */
\r
461 xContinue = pdTRUE;
\r
464 if( pxPort->sTxInterruptOn && ( usStatusRegister & serTX_EMPTY ) )
\r
466 if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
\r
468 portOUTPUT_WORD( pxPort->usTxReg, ( unsigned portSHORT ) cChar );
\r
470 /* We have performed an action this cycle - there may be others to perform. */
\r
471 xContinue = pdTRUE;
\r
475 /* Queue empty, nothing to send */
\r
476 vInterruptOff( pxPort, serTX_HOLD_EMPTY_INT );
\r
481 serRESET_PIC( pxPort->usIRQVector );
\r
483 /* If posting to the queue woke a task that was blocked on the queue we may
\r
484 want to switch to the woken task - depending on its priority relative to
\r
485 the task interrupted by this ISR. */
\r
486 return xHigherPriorityTaskWoken;
\r