2 FreeRTOS V7.4.1 - Copyright (C) 2013 Real Time Engineers Ltd.
\r
4 FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT
\r
5 http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
10 * Complete, revised, and edited pdf reference manuals are also *
\r
13 * Purchasing FreeRTOS documentation will not only help you, by *
\r
14 * ensuring you get running as quickly as possible and with an *
\r
15 * in-depth knowledge of how to use FreeRTOS, it will also help *
\r
16 * the FreeRTOS project to continue with its mission of providing *
\r
17 * professional grade, cross platform, de facto standard solutions *
\r
18 * for microcontrollers - completely free of charge! *
\r
20 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
22 * Thank you for using FreeRTOS, and thank you for your support! *
\r
24 ***************************************************************************
\r
27 This file is part of the FreeRTOS distribution.
\r
29 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
30 the terms of the GNU General Public License (version 2) as published by the
\r
31 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
33 >>>>>>NOTE<<<<<< The modification to the GPL is included to allow you to
\r
34 distribute a combined work that includes FreeRTOS without being obliged to
\r
35 provide the source code for proprietary components outside of the FreeRTOS
\r
38 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
39 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
40 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
\r
41 details. You should have received a copy of the GNU General Public License
\r
42 and the FreeRTOS license exception along with FreeRTOS; if not it can be
\r
43 viewed here: http://www.freertos.org/a00114.html and also obtained by
\r
44 writing to Real Time Engineers Ltd., contact details for whom are available
\r
45 on the FreeRTOS WEB site.
\r
49 ***************************************************************************
\r
51 * Having a problem? Start by reading the FAQ "My application does *
\r
52 * not run, what could be wrong?" *
\r
54 * http://www.FreeRTOS.org/FAQHelp.html *
\r
56 ***************************************************************************
\r
59 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
60 license and Real Time Engineers Ltd. contact details.
\r
62 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
63 including FreeRTOS+Trace - an indispensable productivity tool, and our new
\r
64 fully thread aware and reentrant UDP/IP stack.
\r
66 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
67 Integrity Systems, who sell the code with commercial support,
\r
68 indemnification and middleware, under the OpenRTOS brand.
\r
70 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
71 engineered and independently SIL3 certified version for use in safety and
\r
72 mission critical applications that require provable dependability.
\r
78 + Call to the more efficient portSWITCH_CONTEXT() replaces the call to
\r
79 taskYIELD() in the ISR.
\r
83 + The semaphore task is not operational. This does nothing but check
\r
84 the semaphore from ISR functionality.
\r
85 + ISR modified slightly so only Rx or Tx is serviced per ISR - not both.
\r
87 Changes from V1.2.0:
\r
89 + Change so Tx uses a DMA channel, and Rx uses an interrupt.
\r
93 + The function xPortInitMinimal() has been renamed to
\r
94 xSerialPortInitMinimal() and the function xPortInit() has been renamed
\r
95 to xSerialPortInit().
\r
99 + Reverted back to the non-DMA serial port driver, with a slightly modified
\r
100 ISR. This is a better test of the scheduler mechanisms.
\r
101 + A critical section is now used in vInterruptOn().
\r
102 + Flag sTxInterruptOn has been added to the port structure. This allows
\r
103 checking of the interrupt enable status without performing any IO.
\r
105 Changes from V2.0.0
\r
107 + Use portTickType in place of unsigned pdLONG for delay periods.
\r
108 + Slightly more efficient vSerialSendString() implementation.
\r
109 + cQueueReieveFromISR() used in place of xQueueReceive() in ISR.
\r
112 #include <stdlib.h>
\r
114 #include "FreeRTOS.h"
\r
117 #include "portasm.h"
\r
118 #include "semphr.h"
\r
120 #define serMAX_PORTS ( ( unsigned short ) 2 )
\r
122 #define serPORT_0_INT_REG ( 0xff44 )
\r
123 #define serPORT_0_BAUD_REG ( 0xff88 )
\r
124 #define serPORT_0_RX_REG ( 0xff86 )
\r
125 #define serPORT_0_TX_REG ( 0xff84 )
\r
126 #define serPORT_0_STATUS_REG ( 0xff82 )
\r
127 #define serPORT_0_CTRL_REG ( 0xff80 )
\r
128 #define serPORT_0_IRQ ( 0x14 )
\r
130 #define serPORT_1_INT_REG ( 0xff42 )
\r
131 #define serPORT_1_BAUD_REG ( 0xff18 )
\r
132 #define serPORT_1_RX_REG ( 0xff16 )
\r
133 #define serPORT_1_TX_REG ( 0xff14 )
\r
134 #define serPORT_1_STATUS_REG ( 0xff12 )
\r
135 #define serPORT_1_CTRL_REG ( 0xff10 )
\r
136 #define serPORT_1_IRQ ( 0x11 )
\r
138 #define serTX_EMPTY ( ( unsigned short ) 0x40 )
\r
139 #define serRX_READY ( ( unsigned short ) 0x80 )
\r
141 #define serRESET_PIC( usEOI_TYPE ) portOUTPUT_WORD( ( unsigned short ) 0xff22, usEOI_TYPE )
\r
142 #define serTX_HOLD_EMPTY_INT ( ( unsigned short ) 0x100 )
\r
144 #define serENABLE_INTERRUPTS ( ( unsigned short ) 0x80 )
\r
145 #define serMODE ( ( unsigned short ) 0x01 )
\r
146 #define serENABLE_TX_MACHINES ( ( unsigned short ) 0x40 )
\r
147 #define serENABLE_RX_MACHINES ( ( unsigned short ) 0x20 )
\r
148 #define serINTERRUPT_MASK ( ( unsigned short ) 0x08 )
\r
149 #define serCLEAR_ALL_STATUS_BITS ( ( unsigned short ) 0x00 )
\r
150 #define serINTERRUPT_PRIORITY ( ( unsigned short ) 0x01 ) /*< Just below the scheduler priority. */
\r
152 #define serDONT_BLOCK ( ( portTickType ) 0 )
\r
210 /* Must be same order as eBaud definitions. */
\r
211 static const unsigned short usBaudRateDivisor[] =
\r
213 0, /* Not sure if the first 6 are correct. First cannot be used. */
\r
233 typedef struct xCOM_PORT
\r
235 /* Hardware parameters for this port. */
\r
236 short sTxInterruptOn;
\r
237 unsigned short usIntReg;
\r
238 unsigned short usBaudReg;
\r
239 unsigned short usRxReg;
\r
240 unsigned short usTxReg;
\r
241 unsigned short usStatusReg;
\r
242 unsigned short usCtrlReg;
\r
244 unsigned short usIRQVector;
\r
246 /* Queues used for communications with com test task. */
\r
247 xQueueHandle xRxedChars;
\r
248 xQueueHandle xCharsForTx;
\r
250 /* This semaphore does nothing useful except test a feature of the
\r
252 xSemaphoreHandle xTestSem;
\r
256 static xComPort xPorts[ serMAX_PORTS ] =
\r
258 { 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
259 { 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
262 typedef xComPort * xComPortHandle;
\r
264 /* These prototypes are repeated here so we don't have to include the serial header. This allows
\r
265 the xComPortHandle structure details to be private to this file. */
\r
266 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength );
\r
267 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, portTickType xBlockTime );
\r
268 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, portTickType xBlockTime );
\r
269 void vSerialClose( xComPortHandle xPort );
\r
270 short sSerialWaitForSemaphore( xComPortHandle xPort );
\r
271 /*-----------------------------------------------------------*/
\r
273 static short xComPortISR( xComPort * const pxPort );
\r
275 #define vInterruptOn( pxPort, usInterrupt ) \
\r
277 unsigned short usIn; \
\r
279 portENTER_CRITICAL(); \
\r
281 if( pxPort->sTxInterruptOn == pdFALSE ) \
\r
283 usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
284 portOUTPUT_WORD( pxPort->usCtrlReg, usIn | usInterrupt ); \
\r
286 pxPort->sTxInterruptOn = pdTRUE; \
\r
289 portEXIT_CRITICAL(); \
\r
291 /*-----------------------------------------------------------*/
\r
293 #define vInterruptOff( pxPort, usInterrupt ) \
\r
295 unsigned short usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
296 if( usIn & usInterrupt ) \
\r
298 portOUTPUT_WORD( pxPort->usCtrlReg, usIn & ~usInterrupt); \
\r
299 pxPort->sTxInterruptOn = pdFALSE; \
\r
302 /*-----------------------------------------------------------*/
\r
305 /* Define an interrupt handler for each port */
\r
306 #define COM_IRQ_WRAPPER(N) \
\r
307 static void __interrupt COM_IRQ##N##_WRAPPER( void ) \
\r
309 if( xComPortISR( &( xPorts[##N##] ) ) ) \
\r
311 portSWITCH_CONTEXT(); \
\r
317 COM_IRQ_WRAPPER( 0 )
\r
318 COM_IRQ_WRAPPER( 1 )
\r
320 static pxISR xISRs[ serMAX_PORTS ] =
\r
326 /*-----------------------------------------------------------*/
\r
328 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )
\r
330 unsigned short usPort;
\r
331 xComPortHandle pxPort = NULL;
\r
333 /* BAUDDIV = ( Microprocessor Clock / Baud Rate ) / 16 */
\r
335 /* Only n, 8, 1 is supported so these parameters are not required for this
\r
337 ( void ) eWantedParity;
\r
338 ( void ) eWantedDataBits;
\r
339 ( void ) eWantedStopBits;
\r
341 /* Currently only n,8,1 is supported. */
\r
343 usPort = ( unsigned short ) ePort;
\r
345 if( usPort < serMAX_PORTS )
\r
347 pxPort = &( xPorts[ usPort ] );
\r
349 portENTER_CRITICAL();
\r
351 unsigned short usInWord;
\r
353 /* Create the queues used by the com test task. */
\r
354 pxPort->xRxedChars = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
355 pxPort->xCharsForTx = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
357 /* Create the test semaphore. This does nothing useful except test a feature of the scheduler. */
\r
358 vSemaphoreCreateBinary( pxPort->xTestSem );
\r
360 /* There is no ISR here already to restore later. */
\r
361 _dos_setvect( ( short ) pxPort->usIRQVector, xISRs[ usPort ] );
\r
363 usInWord = portINPUT_WORD( pxPort->usIntReg );
\r
364 usInWord &= ~serINTERRUPT_MASK;
\r
365 usInWord |= serINTERRUPT_PRIORITY;
\r
366 portOUTPUT_WORD( pxPort->usIntReg, usInWord );
\r
368 portOUTPUT_WORD( pxPort->usBaudReg, usBaudRateDivisor[ eWantedBaud ] );
\r
369 portOUTPUT_WORD( pxPort->usCtrlReg, serENABLE_INTERRUPTS | serMODE | serENABLE_TX_MACHINES | serENABLE_RX_MACHINES );
\r
371 portOUTPUT_WORD( pxPort->usStatusReg, serCLEAR_ALL_STATUS_BITS );
\r
373 portEXIT_CRITICAL();
\r
377 } /*lint !e715 Some parameters are not used as only a subset of the serial port functionality is currently implemented. */
\r
378 /*-----------------------------------------------------------*/
\r
380 void vSerialPutString( xComPortHandle pxPort, const char * const pcString, unsigned short usStringLength )
\r
382 unsigned short usByte;
\r
385 pcNextChar = ( char * ) pcString;
\r
387 for( usByte = 0; usByte < usStringLength; usByte++ )
\r
389 xQueueSend( pxPort->xCharsForTx, pcNextChar, serDONT_BLOCK );
\r
393 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
395 /*-----------------------------------------------------------*/
\r
397 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, portTickType xBlockTime )
\r
399 /* Get the next character from the buffer, note that this routine is only
\r
400 called having checked that the is (at least) one to get */
\r
401 if( xQueueReceive( pxPort->xRxedChars, pcRxedChar, xBlockTime ) )
\r
410 /*-----------------------------------------------------------*/
\r
412 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, portTickType xBlockTime )
\r
414 if( xQueueSend( pxPort->xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )
\r
419 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
423 /*-----------------------------------------------------------*/
\r
425 portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort )
\r
427 const portTickType xBlockTime = ( portTickType ) 0xffff;
\r
429 /* This function does nothing interesting, but test the
\r
430 semaphore from ISR mechanism. */
\r
431 return xSemaphoreTake( xPort->xTestSem, xBlockTime );
\r
433 /*-----------------------------------------------------------*/
\r
435 void vSerialClose( xComPortHandle xPort )
\r
437 unsigned short usOutput;
\r
439 /* Turn off the interrupts. We may also want to delete the queues and/or
\r
440 re-install the original ISR. */
\r
442 portENTER_CRITICAL();
\r
444 usOutput = portINPUT_WORD( xPort->usCtrlReg );
\r
446 usOutput &= ~serENABLE_INTERRUPTS;
\r
447 usOutput &= ~serENABLE_TX_MACHINES;
\r
448 usOutput &= ~serENABLE_RX_MACHINES;
\r
449 portOUTPUT_WORD( xPort->usCtrlReg, usOutput );
\r
451 usOutput = portINPUT_WORD( xPort->usIntReg );
\r
452 usOutput |= serINTERRUPT_MASK;
\r
453 portOUTPUT_WORD( xPort->usIntReg, usOutput );
\r
455 portEXIT_CRITICAL();
\r
457 /*-----------------------------------------------------------*/
\r
459 static portBASE_TYPE xComPortISR( xComPort * const pxPort )
\r
461 unsigned short usStatusRegister;
\r
463 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE, xContinue = pdTRUE;
\r
465 /* NOTE: THIS IS NOT AN EFFICIENT ISR AS IT IS DESIGNED SOLELY TO TEST
\r
466 THE SCHEDULER FUNCTIONALITY. REAL APPLICATIONS SHOULD NOT USE THIS
\r
470 while( xContinue == pdTRUE )
\r
472 xContinue = pdFALSE;
\r
473 usStatusRegister = portINPUT_WORD( pxPort->usStatusReg );
\r
475 if( usStatusRegister & serRX_READY )
\r
477 cChar = ( char ) portINPUT_WORD( pxPort->usRxReg );
\r
478 xQueueSendFromISR( pxPort->xRxedChars, &cChar, &xHigherPriorityTaskWoken );
\r
480 /* Also release the semaphore - this does nothing interesting and is just a test. */
\r
481 xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
\r
483 /* We have performed an action this cycle - there may be other to perform. */
\r
484 xContinue = pdTRUE;
\r
487 if( pxPort->sTxInterruptOn && ( usStatusRegister & serTX_EMPTY ) )
\r
489 if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
\r
491 portOUTPUT_WORD( pxPort->usTxReg, ( unsigned short ) cChar );
\r
493 /* We have performed an action this cycle - there may be others to perform. */
\r
494 xContinue = pdTRUE;
\r
498 /* Queue empty, nothing to send */
\r
499 vInterruptOff( pxPort, serTX_HOLD_EMPTY_INT );
\r
504 serRESET_PIC( pxPort->usIRQVector );
\r
506 /* If posting to the queue woke a task that was blocked on the queue we may
\r
507 want to switch to the woken task - depending on its priority relative to
\r
508 the task interrupted by this ISR. */
\r
509 return xHigherPriorityTaskWoken;
\r