2 FreeRTOS V8.0.1 - Copyright (C) 2014 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS provides completely free yet professionally developed, *
\r
10 * robust, strictly quality controlled, supported, and cross *
\r
11 * platform software that has become a de facto standard. *
\r
13 * Help yourself get started quickly and support the FreeRTOS *
\r
14 * project by purchasing a FreeRTOS tutorial book, reference *
\r
15 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
19 ***************************************************************************
\r
21 This file is part of the FreeRTOS distribution.
\r
23 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
24 the terms of the GNU General Public License (version 2) as published by the
\r
25 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
27 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
28 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
29 >>! obliged to provide the source code for proprietary components !<<
\r
30 >>! outside of the FreeRTOS kernel. !<<
\r
32 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
33 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
34 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
35 link: http://www.freertos.org/a00114.html
\r
39 ***************************************************************************
\r
41 * Having a problem? Start by reading the FAQ "My application does *
\r
42 * not run, what could be wrong?" *
\r
44 * http://www.FreeRTOS.org/FAQHelp.html *
\r
46 ***************************************************************************
\r
48 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
49 license and Real Time Engineers Ltd. contact details.
\r
51 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
52 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
53 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
55 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
56 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
57 licenses offer ticketed support, indemnification and middleware.
\r
59 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
60 engineered and independently SIL3 certified version for use in safety and
\r
61 mission critical applications that require provable dependability.
\r
69 + Call to the more efficient portSWITCH_CONTEXT() replaces the call to
\r
70 taskYIELD() in the ISR.
\r
74 + The semaphore task is not operational. This does nothing but check
\r
75 the semaphore from ISR functionality.
\r
76 + ISR modified slightly so only Rx or Tx is serviced per ISR - not both.
\r
78 Changes from V1.2.0:
\r
80 + Change so Tx uses a DMA channel, and Rx uses an interrupt.
\r
84 + The function xPortInitMinimal() has been renamed to
\r
85 xSerialPortInitMinimal() and the function xPortInit() has been renamed
\r
86 to xSerialPortInit().
\r
90 + Reverted back to the non-DMA serial port driver, with a slightly modified
\r
91 ISR. This is a better test of the scheduler mechanisms.
\r
92 + A critical section is now used in vInterruptOn().
\r
93 + Flag sTxInterruptOn has been added to the port structure. This allows
\r
94 checking of the interrupt enable status without performing any IO.
\r
98 + Use TickType_t in place of unsigned pdLONG for delay periods.
\r
99 + Slightly more efficient vSerialSendString() implementation.
\r
100 + cQueueReieveFromISR() used in place of xQueueReceive() in ISR.
\r
103 #include <stdlib.h>
\r
105 #include "FreeRTOS.h"
\r
108 #include "portasm.h"
\r
109 #include "semphr.h"
\r
111 #define serMAX_PORTS ( ( unsigned short ) 2 )
\r
113 #define serPORT_0_INT_REG ( 0xff44 )
\r
114 #define serPORT_0_BAUD_REG ( 0xff88 )
\r
115 #define serPORT_0_RX_REG ( 0xff86 )
\r
116 #define serPORT_0_TX_REG ( 0xff84 )
\r
117 #define serPORT_0_STATUS_REG ( 0xff82 )
\r
118 #define serPORT_0_CTRL_REG ( 0xff80 )
\r
119 #define serPORT_0_IRQ ( 0x14 )
\r
121 #define serPORT_1_INT_REG ( 0xff42 )
\r
122 #define serPORT_1_BAUD_REG ( 0xff18 )
\r
123 #define serPORT_1_RX_REG ( 0xff16 )
\r
124 #define serPORT_1_TX_REG ( 0xff14 )
\r
125 #define serPORT_1_STATUS_REG ( 0xff12 )
\r
126 #define serPORT_1_CTRL_REG ( 0xff10 )
\r
127 #define serPORT_1_IRQ ( 0x11 )
\r
129 #define serTX_EMPTY ( ( unsigned short ) 0x40 )
\r
130 #define serRX_READY ( ( unsigned short ) 0x80 )
\r
132 #define serRESET_PIC( usEOI_TYPE ) portOUTPUT_WORD( ( unsigned short ) 0xff22, usEOI_TYPE )
\r
133 #define serTX_HOLD_EMPTY_INT ( ( unsigned short ) 0x100 )
\r
135 #define serENABLE_INTERRUPTS ( ( unsigned short ) 0x80 )
\r
136 #define serMODE ( ( unsigned short ) 0x01 )
\r
137 #define serENABLE_TX_MACHINES ( ( unsigned short ) 0x40 )
\r
138 #define serENABLE_RX_MACHINES ( ( unsigned short ) 0x20 )
\r
139 #define serINTERRUPT_MASK ( ( unsigned short ) 0x08 )
\r
140 #define serCLEAR_ALL_STATUS_BITS ( ( unsigned short ) 0x00 )
\r
141 #define serINTERRUPT_PRIORITY ( ( unsigned short ) 0x01 ) /*< Just below the scheduler priority. */
\r
143 #define serDONT_BLOCK ( ( TickType_t ) 0 )
\r
201 /* Must be same order as eBaud definitions. */
\r
202 static const unsigned short usBaudRateDivisor[] =
\r
204 0, /* Not sure if the first 6 are correct. First cannot be used. */
\r
224 typedef struct xCOM_PORT
\r
226 /* Hardware parameters for this port. */
\r
227 short sTxInterruptOn;
\r
228 unsigned short usIntReg;
\r
229 unsigned short usBaudReg;
\r
230 unsigned short usRxReg;
\r
231 unsigned short usTxReg;
\r
232 unsigned short usStatusReg;
\r
233 unsigned short usCtrlReg;
\r
235 unsigned short usIRQVector;
\r
237 /* Queues used for communications with com test task. */
\r
238 QueueHandle_t xRxedChars;
\r
239 QueueHandle_t xCharsForTx;
\r
241 /* This semaphore does nothing useful except test a feature of the
\r
243 SemaphoreHandle_t xTestSem;
\r
247 static xComPort xPorts[ serMAX_PORTS ] =
\r
249 { 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
250 { 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
253 typedef xComPort * xComPortHandle;
\r
255 /* These prototypes are repeated here so we don't have to include the serial header. This allows
\r
256 the xComPortHandle structure details to be private to this file. */
\r
257 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength );
\r
258 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, TickType_t xBlockTime );
\r
259 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, TickType_t xBlockTime );
\r
260 void vSerialClose( xComPortHandle xPort );
\r
261 short sSerialWaitForSemaphore( xComPortHandle xPort );
\r
262 /*-----------------------------------------------------------*/
\r
264 static short xComPortISR( xComPort * const pxPort );
\r
266 #define vInterruptOn( pxPort, usInterrupt ) \
\r
268 unsigned short usIn; \
\r
270 portENTER_CRITICAL(); \
\r
272 if( pxPort->sTxInterruptOn == pdFALSE ) \
\r
274 usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
275 portOUTPUT_WORD( pxPort->usCtrlReg, usIn | usInterrupt ); \
\r
277 pxPort->sTxInterruptOn = pdTRUE; \
\r
280 portEXIT_CRITICAL(); \
\r
282 /*-----------------------------------------------------------*/
\r
284 #define vInterruptOff( pxPort, usInterrupt ) \
\r
286 unsigned short usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
287 if( usIn & usInterrupt ) \
\r
289 portOUTPUT_WORD( pxPort->usCtrlReg, usIn & ~usInterrupt); \
\r
290 pxPort->sTxInterruptOn = pdFALSE; \
\r
293 /*-----------------------------------------------------------*/
\r
296 /* Define an interrupt handler for each port */
\r
297 #define COM_IRQ_WRAPPER(N) \
\r
298 static void __interrupt COM_IRQ##N##_WRAPPER( void ) \
\r
300 if( xComPortISR( &( xPorts[##N##] ) ) ) \
\r
302 portSWITCH_CONTEXT(); \
\r
308 COM_IRQ_WRAPPER( 0 )
\r
309 COM_IRQ_WRAPPER( 1 )
\r
311 static pxISR xISRs[ serMAX_PORTS ] =
\r
317 /*-----------------------------------------------------------*/
\r
319 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )
\r
321 unsigned short usPort;
\r
322 xComPortHandle pxPort = NULL;
\r
324 /* BAUDDIV = ( Microprocessor Clock / Baud Rate ) / 16 */
\r
326 /* Only n, 8, 1 is supported so these parameters are not required for this
\r
328 ( void ) eWantedParity;
\r
329 ( void ) eWantedDataBits;
\r
330 ( void ) eWantedStopBits;
\r
332 /* Currently only n,8,1 is supported. */
\r
334 usPort = ( unsigned short ) ePort;
\r
336 if( usPort < serMAX_PORTS )
\r
338 pxPort = &( xPorts[ usPort ] );
\r
340 portENTER_CRITICAL();
\r
342 unsigned short usInWord;
\r
344 /* Create the queues used by the com test task. */
\r
345 pxPort->xRxedChars = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
346 pxPort->xCharsForTx = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
348 /* Create the test semaphore. This does nothing useful except test a feature of the scheduler. */
\r
349 vSemaphoreCreateBinary( pxPort->xTestSem );
\r
351 /* There is no ISR here already to restore later. */
\r
352 _dos_setvect( ( short ) pxPort->usIRQVector, xISRs[ usPort ] );
\r
354 usInWord = portINPUT_WORD( pxPort->usIntReg );
\r
355 usInWord &= ~serINTERRUPT_MASK;
\r
356 usInWord |= serINTERRUPT_PRIORITY;
\r
357 portOUTPUT_WORD( pxPort->usIntReg, usInWord );
\r
359 portOUTPUT_WORD( pxPort->usBaudReg, usBaudRateDivisor[ eWantedBaud ] );
\r
360 portOUTPUT_WORD( pxPort->usCtrlReg, serENABLE_INTERRUPTS | serMODE | serENABLE_TX_MACHINES | serENABLE_RX_MACHINES );
\r
362 portOUTPUT_WORD( pxPort->usStatusReg, serCLEAR_ALL_STATUS_BITS );
\r
364 portEXIT_CRITICAL();
\r
368 } /*lint !e715 Some parameters are not used as only a subset of the serial port functionality is currently implemented. */
\r
369 /*-----------------------------------------------------------*/
\r
371 void vSerialPutString( xComPortHandle pxPort, const char * const pcString, unsigned short usStringLength )
\r
373 unsigned short usByte;
\r
376 pcNextChar = ( char * ) pcString;
\r
378 for( usByte = 0; usByte < usStringLength; usByte++ )
\r
380 xQueueSend( pxPort->xCharsForTx, pcNextChar, serDONT_BLOCK );
\r
384 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
386 /*-----------------------------------------------------------*/
\r
388 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, TickType_t xBlockTime )
\r
390 /* Get the next character from the buffer, note that this routine is only
\r
391 called having checked that the is (at least) one to get */
\r
392 if( xQueueReceive( pxPort->xRxedChars, pcRxedChar, xBlockTime ) )
\r
401 /*-----------------------------------------------------------*/
\r
403 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, TickType_t xBlockTime )
\r
405 if( xQueueSend( pxPort->xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )
\r
410 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
414 /*-----------------------------------------------------------*/
\r
416 portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort )
\r
418 const TickType_t xBlockTime = ( TickType_t ) 0xffff;
\r
420 /* This function does nothing interesting, but test the
\r
421 semaphore from ISR mechanism. */
\r
422 return xSemaphoreTake( xPort->xTestSem, xBlockTime );
\r
424 /*-----------------------------------------------------------*/
\r
426 void vSerialClose( xComPortHandle xPort )
\r
428 unsigned short usOutput;
\r
430 /* Turn off the interrupts. We may also want to delete the queues and/or
\r
431 re-install the original ISR. */
\r
433 portENTER_CRITICAL();
\r
435 usOutput = portINPUT_WORD( xPort->usCtrlReg );
\r
437 usOutput &= ~serENABLE_INTERRUPTS;
\r
438 usOutput &= ~serENABLE_TX_MACHINES;
\r
439 usOutput &= ~serENABLE_RX_MACHINES;
\r
440 portOUTPUT_WORD( xPort->usCtrlReg, usOutput );
\r
442 usOutput = portINPUT_WORD( xPort->usIntReg );
\r
443 usOutput |= serINTERRUPT_MASK;
\r
444 portOUTPUT_WORD( xPort->usIntReg, usOutput );
\r
446 portEXIT_CRITICAL();
\r
448 /*-----------------------------------------------------------*/
\r
450 static portBASE_TYPE xComPortISR( xComPort * const pxPort )
\r
452 unsigned short usStatusRegister;
\r
454 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE, xContinue = pdTRUE;
\r
456 /* NOTE: THIS IS NOT AN EFFICIENT ISR AS IT IS DESIGNED SOLELY TO TEST
\r
457 THE SCHEDULER FUNCTIONALITY. REAL APPLICATIONS SHOULD NOT USE THIS
\r
461 while( xContinue == pdTRUE )
\r
463 xContinue = pdFALSE;
\r
464 usStatusRegister = portINPUT_WORD( pxPort->usStatusReg );
\r
466 if( usStatusRegister & serRX_READY )
\r
468 cChar = ( char ) portINPUT_WORD( pxPort->usRxReg );
\r
469 xQueueSendFromISR( pxPort->xRxedChars, &cChar, &xHigherPriorityTaskWoken );
\r
471 /* Also release the semaphore - this does nothing interesting and is just a test. */
\r
472 xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
\r
474 /* We have performed an action this cycle - there may be other to perform. */
\r
475 xContinue = pdTRUE;
\r
478 if( pxPort->sTxInterruptOn && ( usStatusRegister & serTX_EMPTY ) )
\r
480 if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
\r
482 portOUTPUT_WORD( pxPort->usTxReg, ( unsigned short ) cChar );
\r
484 /* We have performed an action this cycle - there may be others to perform. */
\r
485 xContinue = pdTRUE;
\r
489 /* Queue empty, nothing to send */
\r
490 vInterruptOff( pxPort, serTX_HOLD_EMPTY_INT );
\r
495 serRESET_PIC( pxPort->usIRQVector );
\r
497 /* If posting to the queue woke a task that was blocked on the queue we may
\r
498 want to switch to the woken task - depending on its priority relative to
\r
499 the task interrupted by this ISR. */
\r
500 return xHigherPriorityTaskWoken;
\r