2 FreeRTOS V6.0.4 - Copyright (C) 2010 Real Time Engineers Ltd.
\r
4 ***************************************************************************
\r
8 * + New to FreeRTOS, *
\r
9 * + Wanting to learn FreeRTOS or multitasking in general quickly *
\r
10 * + Looking for basic training, *
\r
11 * + Wanting to improve your FreeRTOS skills and productivity *
\r
13 * then take a look at the FreeRTOS eBook *
\r
15 * "Using the FreeRTOS Real Time Kernel - a Practical Guide" *
\r
16 * http://www.FreeRTOS.org/Documentation *
\r
18 * A pdf reference manual is also available. Both are usually delivered *
\r
19 * to your inbox within 20 minutes to two hours when purchased between 8am *
\r
20 * and 8pm GMT (although please allow up to 24 hours in case of *
\r
21 * exceptional circumstances). Thank you for your support! *
\r
23 ***************************************************************************
\r
25 This file is part of the FreeRTOS distribution.
\r
27 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
28 the terms of the GNU General Public License (version 2) as published by the
\r
29 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
30 ***NOTE*** The exception to the GPL is included to allow you to distribute
\r
31 a combined work that includes FreeRTOS without being obliged to provide the
\r
32 source code for proprietary components outside of the FreeRTOS kernel.
\r
33 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
\r
34 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
\r
35 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
36 more details. You should have received a copy of the GNU General Public
\r
37 License and the FreeRTOS license exception along with FreeRTOS; if not it
\r
38 can be viewed here: http://www.freertos.org/a00114.html and also obtained
\r
39 by writing to Richard Barry, contact details for whom are available on the
\r
44 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
47 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
50 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
51 licensing and training services.
\r
56 #include <embedded.h>
\r
57 #include "FreeRTOS.h"
\r
58 #include "portasm.h"
\r
63 #define serMAX_PORTS ( ( unsigned short ) 2 )
\r
65 #define serPORT_0_INT_REG ( 0xff44 )
\r
66 #define serPORT_0_BAUD_REG ( 0xff88 )
\r
67 #define serPORT_0_RX_REG ( 0xff86 )
\r
68 #define serPORT_0_TX_REG ( 0xff84 )
\r
69 #define serPORT_0_STATUS_REG ( 0xff82 )
\r
70 #define serPORT_0_CTRL_REG ( 0xff80 )
\r
71 #define serPORT_0_IRQ ( 0x14 )
\r
73 #define serPORT_1_INT_REG ( 0xff42 )
\r
74 #define serPORT_1_BAUD_REG ( 0xff18 )
\r
75 #define serPORT_1_RX_REG ( 0xff16 )
\r
76 #define serPORT_1_TX_REG ( 0xff14 )
\r
77 #define serPORT_1_STATUS_REG ( 0xff12 )
\r
78 #define serPORT_1_CTRL_REG ( 0xff10 )
\r
79 #define serPORT_1_IRQ ( 0x11 )
\r
81 #define serTX_EMPTY ( ( unsigned short ) 0x40 )
\r
82 #define serRX_READY ( ( unsigned short ) 0x80 )
\r
84 #define serRESET_PIC( usEOI_TYPE ) portOUTPUT_WORD( ( unsigned short ) 0xff22, usEOI_TYPE )
\r
85 #define serTX_HOLD_EMPTY_INT ( ( unsigned short ) 0x100 )
\r
87 #define serENABLE_INTERRUPTS ( ( unsigned short ) 0x80 )
\r
88 #define serMODE ( ( unsigned short ) 0x01 )
\r
89 #define serENABLE_TX_MACHINES ( ( unsigned short ) 0x40 )
\r
90 #define serENABLE_RX_MACHINES ( ( unsigned short ) 0x20 )
\r
91 #define serINTERRUPT_MASK ( ( unsigned short ) 0x08 )
\r
92 #define serCLEAR_ALL_STATUS_BITS ( ( unsigned short ) 0x00 )
\r
93 #define serINTERRUPT_PRIORITY ( ( unsigned short ) 0x01 ) /*< Just below the scheduler priority. */
\r
95 #define serDONT_BLOCK ( ( portTickType ) 0 )
\r
153 typedef struct xCOM_PORT
\r
155 /* Hardware parameters for this port. */
\r
156 short sTxInterruptOn;
\r
157 unsigned short usIntReg;
\r
158 unsigned short usBaudReg;
\r
159 unsigned short usRxReg;
\r
160 unsigned short usTxReg;
\r
161 unsigned short usStatusReg;
\r
162 unsigned short usCtrlReg;
\r
164 unsigned short usIRQVector;
\r
166 /* Queues used for communications with com test task. */
\r
167 xQueueHandle xRxedChars;
\r
168 xQueueHandle xCharsForTx;
\r
170 /* This semaphore does nothing useful except test a feature of the
\r
172 xSemaphoreHandle xTestSem;
\r
176 static xComPort xPorts[ serMAX_PORTS ] =
\r
178 { 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
179 { 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
182 typedef xComPort * xComPortHandle;
\r
185 * Lookup the baud rate from the enum.
\r
187 static unsigned long prvBaud( eBaud eWantedBaud );
\r
189 /* These prototypes are repeated here so we don't have to include the serial header. This allows
\r
190 the xComPortHandle structure details to be private to this file. */
\r
191 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength );
\r
192 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, portTickType xBlockTime );
\r
193 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, portTickType xBlockTime );
\r
194 void vSerialClose( xComPortHandle xPort );
\r
195 short sSerialWaitForSemaphore( xComPortHandle xPort );
\r
196 /*-----------------------------------------------------------*/
\r
198 static short xComPortISR( xComPort * const pxPort );
\r
200 #define vInterruptOn( pxPort, usInterrupt ) \
\r
202 unsigned short usIn; \
\r
204 portENTER_CRITICAL(); \
\r
206 if( pxPort->sTxInterruptOn == pdFALSE ) \
\r
208 usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
209 portOUTPUT_WORD( pxPort->usCtrlReg, usIn | usInterrupt ); \
\r
211 pxPort->sTxInterruptOn = pdTRUE; \
\r
214 portEXIT_CRITICAL(); \
\r
216 /*-----------------------------------------------------------*/
\r
218 #define vInterruptOff( pxPort, usInterrupt ) \
\r
220 unsigned short usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
221 if( usIn & usInterrupt ) \
\r
223 portOUTPUT_WORD( pxPort->usCtrlReg, usIn & ~usInterrupt); \
\r
224 pxPort->sTxInterruptOn = pdFALSE; \
\r
227 /*-----------------------------------------------------------*/
\r
230 /* Define an interrupt handler for each port */
\r
231 #define COM_IRQ_WRAPPER(N) \
\r
232 static void __interrupt COM_IRQ##N##_WRAPPER( void ) \
\r
234 if( xComPortISR( &( xPorts[##N##] ) ) ) \
\r
236 portEND_SWITCHING_ISR(); \
\r
242 COM_IRQ_WRAPPER( 0 )
\r
243 COM_IRQ_WRAPPER( 1 )
\r
245 static pxISR xISRs[ serMAX_PORTS ] =
\r
251 /*-----------------------------------------------------------*/
\r
253 static unsigned long prvBaud( eBaud eWantedBaud )
\r
255 switch( eWantedBaud )
\r
257 case ser50 : return 50UL;
\r
258 case ser75 : return 75UL;
\r
259 case ser110 : return 110UL;
\r
260 case ser134 : return 134UL;
\r
261 case ser150 : return 150UL;
\r
262 case ser200 : return 200UL;
\r
263 case ser300 : return 300UL;
\r
264 case ser600 : return 600UL;
\r
265 case ser1200 : return 1200UL;
\r
266 case ser1800 : return 1800UL;
\r
267 case ser2400 : return 2400UL;
\r
268 case ser4800 : return 4800UL;
\r
269 case ser19200 : return 19200UL;
\r
270 case ser38400 : return 38400UL;
\r
271 case ser57600 : return 57600UL;
\r
272 case ser115200 : return 115200UL;
\r
273 default : return 9600UL;
\r
277 /*-----------------------------------------------------------*/
\r
279 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )
\r
281 unsigned short usPort;
\r
282 xComPortHandle pxPort = NULL;
\r
283 unsigned long ulBaudDiv;
\r
285 /* BAUDDIV = ( Microprocessor Clock / Baud Rate ) / 16 */
\r
286 ulBaudDiv = ( configCPU_CLOCK_HZ / prvBaud( eWantedBaud ) ) / 16UL;
\r
288 /* Only n, 8, 1 is supported so these parameters are not required for this
\r
290 ( void ) eWantedParity;
\r
291 ( void ) eWantedDataBits;
\r
292 ( void ) eWantedStopBits;
\r
294 /* Currently only n,8,1 is supported. */
\r
296 usPort = ( unsigned short ) ePort;
\r
298 if( usPort < serMAX_PORTS )
\r
300 pxPort = &( xPorts[ usPort ] );
\r
302 portENTER_CRITICAL();
\r
304 unsigned short usInWord;
\r
306 /* Create the queues used by the com test task. */
\r
307 pxPort->xRxedChars = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
308 pxPort->xCharsForTx = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
310 /* Create the test semaphore. This does nothing useful except test a feature of the scheduler. */
\r
311 vSemaphoreCreateBinary( pxPort->xTestSem );
\r
313 /* There is no ISR here already to restore later. */
\r
314 setvect( ( short ) pxPort->usIRQVector, xISRs[ usPort ] );
\r
316 usInWord = portINPUT_WORD( pxPort->usIntReg );
\r
317 usInWord &= ~serINTERRUPT_MASK;
\r
318 usInWord |= serINTERRUPT_PRIORITY;
\r
319 portOUTPUT_WORD( pxPort->usIntReg, usInWord );
\r
321 portOUTPUT_WORD( pxPort->usBaudReg, ( unsigned short ) ulBaudDiv );
\r
322 portOUTPUT_WORD( pxPort->usCtrlReg, serENABLE_INTERRUPTS | serMODE | serENABLE_TX_MACHINES | serENABLE_RX_MACHINES );
\r
324 portOUTPUT_WORD( pxPort->usStatusReg, serCLEAR_ALL_STATUS_BITS );
\r
326 portEXIT_CRITICAL();
\r
330 } /*lint !e715 Some parameters are not used as only a subset of the serial port functionality is currently implemented. */
\r
331 /*-----------------------------------------------------------*/
\r
333 void vSerialPutString( xComPortHandle pxPort, const char * const pcString, unsigned short usStringLength )
\r
335 unsigned short usByte;
\r
338 pcNextChar = ( char * ) pcString;
\r
340 for( usByte = 0; usByte < usStringLength; usByte++ )
\r
342 xQueueSend( pxPort->xCharsForTx, pcNextChar, serDONT_BLOCK );
\r
346 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
348 /*-----------------------------------------------------------*/
\r
350 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, portTickType xBlockTime )
\r
352 /* Get the next character from the buffer, note that this routine is only
\r
353 called having checked that the is (at least) one to get */
\r
354 if( xQueueReceive( pxPort->xRxedChars, pcRxedChar, xBlockTime ) )
\r
363 /*-----------------------------------------------------------*/
\r
365 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, portTickType xBlockTime )
\r
367 if( xQueueSend( pxPort->xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )
\r
372 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
376 /*-----------------------------------------------------------*/
\r
378 portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort )
\r
380 const portTickType xBlockTime = ( portTickType ) 0xffff;
\r
382 /* This function does nothing interesting, but test the
\r
383 semaphore from ISR mechanism. */
\r
384 return xSemaphoreTake( xPort->xTestSem, xBlockTime );
\r
386 /*-----------------------------------------------------------*/
\r
388 void vSerialClose( xComPortHandle xPort )
\r
390 unsigned short usOutput;
\r
392 /* Turn off the interrupts. We may also want to delete the queues and/or
\r
393 re-install the original ISR. */
\r
395 portENTER_CRITICAL();
\r
397 usOutput = portINPUT_WORD( xPort->usCtrlReg );
\r
399 usOutput &= ~serENABLE_INTERRUPTS;
\r
400 usOutput &= ~serENABLE_TX_MACHINES;
\r
401 usOutput &= ~serENABLE_RX_MACHINES;
\r
402 portOUTPUT_WORD( xPort->usCtrlReg, usOutput );
\r
404 usOutput = portINPUT_WORD( xPort->usIntReg );
\r
405 usOutput |= serINTERRUPT_MASK;
\r
406 portOUTPUT_WORD( xPort->usIntReg, usOutput );
\r
408 portEXIT_CRITICAL();
\r
410 /*-----------------------------------------------------------*/
\r
411 unsigned short usStatus;
\r
412 static portBASE_TYPE xComPortISR( xComPort * const pxPort )
\r
414 unsigned short usStatusRegister;
\r
416 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
418 /* NOTE: THIS IS NOT AN EFFICIENT ISR AS IT IS DESIGNED SOLELY TO TEST
\r
419 THE SCHEDULER FUNCTIONALITY. REAL APPLICATIONS SHOULD NOT USE THIS
\r
422 usStatusRegister = portINPUT_WORD( pxPort->usStatusReg );
\r
424 if( usStatusRegister & serRX_READY )
\r
426 cChar = ( char ) portINPUT_WORD( pxPort->usRxReg );
\r
427 xQueueSendFromISR( pxPort->xRxedChars, &cChar, &xHigherPriorityTaskWoken );
\r
429 /* Also release the semaphore - this does nothing interesting and is just a test. */
\r
430 xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
\r
432 else if( pxPort->sTxInterruptOn && ( usStatusRegister & serTX_EMPTY ) )
\r
434 if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
\r
436 portOUTPUT_WORD( pxPort->usTxReg, ( unsigned short ) cChar );
\r
440 /* Queue empty, nothing to send */
\r
441 vInterruptOff( pxPort, serTX_HOLD_EMPTY_INT );
\r
445 serRESET_PIC( pxPort->usIRQVector );
\r
447 /* If posting to the queue woke a task that was blocked on the queue we may
\r
448 want to switch to the woken task - depending on its priority relative to
\r
449 the task interrupted by this ISR. */
\r
450 return xHigherPriorityTaskWoken;
\r