2 FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 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
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation; either version 2 of the License, or
\r
9 (at your option) any later version.
\r
11 FreeRTOS.org is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with FreeRTOS.org; if not, write to the Free Software
\r
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
20 A special exception to the GPL can be applied should you wish to distribute
\r
21 a combined work that includes FreeRTOS.org, without being obliged to provide
\r
22 the source code for any proprietary components. See the licensing section
\r
23 of http://www.FreeRTOS.org for full details of how and when the exception
\r
26 ***************************************************************************
\r
27 See http://www.FreeRTOS.org for documentation, latest information, license
\r
28 and contact details. Please ensure to read the configuration and relevant
\r
29 port sections of the online documentation.
\r
31 Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
\r
32 with commercial development and support options.
\r
33 ***************************************************************************
\r
38 #include <embedded.h>
\r
39 #include "FreeRTOS.h"
\r
40 #include "portasm.h"
\r
45 #define serMAX_PORTS ( ( unsigned portSHORT ) 2 )
\r
47 #define serPORT_0_INT_REG ( 0xff44 )
\r
48 #define serPORT_0_BAUD_REG ( 0xff88 )
\r
49 #define serPORT_0_RX_REG ( 0xff86 )
\r
50 #define serPORT_0_TX_REG ( 0xff84 )
\r
51 #define serPORT_0_STATUS_REG ( 0xff82 )
\r
52 #define serPORT_0_CTRL_REG ( 0xff80 )
\r
53 #define serPORT_0_IRQ ( 0x14 )
\r
55 #define serPORT_1_INT_REG ( 0xff42 )
\r
56 #define serPORT_1_BAUD_REG ( 0xff18 )
\r
57 #define serPORT_1_RX_REG ( 0xff16 )
\r
58 #define serPORT_1_TX_REG ( 0xff14 )
\r
59 #define serPORT_1_STATUS_REG ( 0xff12 )
\r
60 #define serPORT_1_CTRL_REG ( 0xff10 )
\r
61 #define serPORT_1_IRQ ( 0x11 )
\r
63 #define serTX_EMPTY ( ( unsigned portSHORT ) 0x40 )
\r
64 #define serRX_READY ( ( unsigned portSHORT ) 0x80 )
\r
66 #define serRESET_PIC( usEOI_TYPE ) portOUTPUT_WORD( ( unsigned portSHORT ) 0xff22, usEOI_TYPE )
\r
67 #define serTX_HOLD_EMPTY_INT ( ( unsigned portSHORT ) 0x100 )
\r
69 #define serENABLE_INTERRUPTS ( ( unsigned portSHORT ) 0x80 )
\r
70 #define serMODE ( ( unsigned portSHORT ) 0x01 )
\r
71 #define serENABLE_TX_MACHINES ( ( unsigned portSHORT ) 0x40 )
\r
72 #define serENABLE_RX_MACHINES ( ( unsigned portSHORT ) 0x20 )
\r
73 #define serINTERRUPT_MASK ( ( unsigned portSHORT ) 0x08 )
\r
74 #define serCLEAR_ALL_STATUS_BITS ( ( unsigned portSHORT ) 0x00 )
\r
75 #define serINTERRUPT_PRIORITY ( ( unsigned portSHORT ) 0x01 ) /*< Just below the scheduler priority. */
\r
77 #define serDONT_BLOCK ( ( portTickType ) 0 )
\r
135 typedef struct xCOM_PORT
\r
137 /* Hardware parameters for this port. */
\r
138 portSHORT sTxInterruptOn;
\r
139 unsigned portSHORT usIntReg;
\r
140 unsigned portSHORT usBaudReg;
\r
141 unsigned portSHORT usRxReg;
\r
142 unsigned portSHORT usTxReg;
\r
143 unsigned portSHORT usStatusReg;
\r
144 unsigned portSHORT usCtrlReg;
\r
146 unsigned portSHORT usIRQVector;
\r
148 /* Queues used for communications with com test task. */
\r
149 xQueueHandle xRxedChars;
\r
150 xQueueHandle xCharsForTx;
\r
152 /* This semaphore does nothing useful except test a feature of the
\r
154 xSemaphoreHandle xTestSem;
\r
158 static xComPort xPorts[ serMAX_PORTS ] =
\r
160 { 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
161 { 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
164 typedef xComPort * xComPortHandle;
\r
167 * Lookup the baud rate from the enum.
\r
169 static unsigned portLONG prvBaud( eBaud eWantedBaud );
\r
171 /* These prototypes are repeated here so we don't have to include the serial header. This allows
\r
172 the xComPortHandle structure details to be private to this file. */
\r
173 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength );
\r
174 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, portCHAR *pcRxedChar, portTickType xBlockTime );
\r
175 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, portCHAR cOutChar, portTickType xBlockTime );
\r
176 void vSerialClose( xComPortHandle xPort );
\r
177 portSHORT sSerialWaitForSemaphore( xComPortHandle xPort );
\r
178 /*-----------------------------------------------------------*/
\r
180 static portSHORT xComPortISR( xComPort * const pxPort );
\r
182 #define vInterruptOn( pxPort, usInterrupt ) \
\r
184 unsigned portSHORT usIn; \
\r
186 portENTER_CRITICAL(); \
\r
188 if( pxPort->sTxInterruptOn == pdFALSE ) \
\r
190 usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
191 portOUTPUT_WORD( pxPort->usCtrlReg, usIn | usInterrupt ); \
\r
193 pxPort->sTxInterruptOn = pdTRUE; \
\r
196 portEXIT_CRITICAL(); \
\r
198 /*-----------------------------------------------------------*/
\r
200 #define vInterruptOff( pxPort, usInterrupt ) \
\r
202 unsigned portSHORT usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
203 if( usIn & usInterrupt ) \
\r
205 portOUTPUT_WORD( pxPort->usCtrlReg, usIn & ~usInterrupt); \
\r
206 pxPort->sTxInterruptOn = pdFALSE; \
\r
209 /*-----------------------------------------------------------*/
\r
212 /* Define an interrupt handler for each port */
\r
213 #define COM_IRQ_WRAPPER(N) \
\r
214 static void __interrupt COM_IRQ##N##_WRAPPER( void ) \
\r
216 if( xComPortISR( &( xPorts[##N##] ) ) ) \
\r
218 portEND_SWITCHING_ISR(); \
\r
224 COM_IRQ_WRAPPER( 0 )
\r
225 COM_IRQ_WRAPPER( 1 )
\r
227 static pxISR xISRs[ serMAX_PORTS ] =
\r
233 /*-----------------------------------------------------------*/
\r
235 static unsigned portLONG prvBaud( eBaud eWantedBaud )
\r
237 switch( eWantedBaud )
\r
239 case ser50 : return 50UL;
\r
240 case ser75 : return 75UL;
\r
241 case ser110 : return 110UL;
\r
242 case ser134 : return 134UL;
\r
243 case ser150 : return 150UL;
\r
244 case ser200 : return 200UL;
\r
245 case ser300 : return 300UL;
\r
246 case ser600 : return 600UL;
\r
247 case ser1200 : return 1200UL;
\r
248 case ser1800 : return 1800UL;
\r
249 case ser2400 : return 2400UL;
\r
250 case ser4800 : return 4800UL;
\r
251 case ser19200 : return 19200UL;
\r
252 case ser38400 : return 38400UL;
\r
253 case ser57600 : return 57600UL;
\r
254 case ser115200 : return 115200UL;
\r
255 default : return 9600UL;
\r
259 /*-----------------------------------------------------------*/
\r
261 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )
\r
263 unsigned portSHORT usPort;
\r
264 xComPortHandle pxPort = NULL;
\r
265 unsigned portLONG ulBaudDiv;
\r
267 /* BAUDDIV = ( Microprocessor Clock / Baud Rate ) / 16 */
\r
268 ulBaudDiv = ( configCPU_CLOCK_HZ / prvBaud( eWantedBaud ) ) / 16UL;
\r
270 /* Only n, 8, 1 is supported so these parameters are not required for this
\r
272 ( void ) eWantedParity;
\r
273 ( void ) eWantedDataBits;
\r
274 ( void ) eWantedStopBits;
\r
276 /* Currently only n,8,1 is supported. */
\r
278 usPort = ( unsigned portSHORT ) ePort;
\r
280 if( usPort < serMAX_PORTS )
\r
282 pxPort = &( xPorts[ usPort ] );
\r
284 portENTER_CRITICAL();
\r
286 unsigned portSHORT usInWord;
\r
288 /* Create the queues used by the com test task. */
\r
289 pxPort->xRxedChars = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( portCHAR ) );
\r
290 pxPort->xCharsForTx = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( portCHAR ) );
\r
292 /* Create the test semaphore. This does nothing useful except test a feature of the scheduler. */
\r
293 vSemaphoreCreateBinary( pxPort->xTestSem );
\r
295 /* There is no ISR here already to restore later. */
\r
296 setvect( ( portSHORT ) pxPort->usIRQVector, xISRs[ usPort ] );
\r
298 usInWord = portINPUT_WORD( pxPort->usIntReg );
\r
299 usInWord &= ~serINTERRUPT_MASK;
\r
300 usInWord |= serINTERRUPT_PRIORITY;
\r
301 portOUTPUT_WORD( pxPort->usIntReg, usInWord );
\r
303 portOUTPUT_WORD( pxPort->usBaudReg, ( unsigned portSHORT ) ulBaudDiv );
\r
304 portOUTPUT_WORD( pxPort->usCtrlReg, serENABLE_INTERRUPTS | serMODE | serENABLE_TX_MACHINES | serENABLE_RX_MACHINES );
\r
306 portOUTPUT_WORD( pxPort->usStatusReg, serCLEAR_ALL_STATUS_BITS );
\r
308 portEXIT_CRITICAL();
\r
312 } /*lint !e715 Some parameters are not used as only a subset of the serial port functionality is currently implemented. */
\r
313 /*-----------------------------------------------------------*/
\r
315 void vSerialPutString( xComPortHandle pxPort, const portCHAR * const pcString, unsigned portSHORT usStringLength )
\r
317 unsigned portSHORT usByte;
\r
318 portCHAR *pcNextChar;
\r
320 pcNextChar = ( portCHAR * ) pcString;
\r
322 for( usByte = 0; usByte < usStringLength; usByte++ )
\r
324 xQueueSend( pxPort->xCharsForTx, pcNextChar, serDONT_BLOCK );
\r
328 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
330 /*-----------------------------------------------------------*/
\r
332 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, portCHAR *pcRxedChar, portTickType xBlockTime )
\r
334 /* Get the next character from the buffer, note that this routine is only
\r
335 called having checked that the is (at least) one to get */
\r
336 if( xQueueReceive( pxPort->xRxedChars, pcRxedChar, xBlockTime ) )
\r
345 /*-----------------------------------------------------------*/
\r
347 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, portCHAR cOutChar, portTickType xBlockTime )
\r
349 if( xQueueSend( pxPort->xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )
\r
354 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
358 /*-----------------------------------------------------------*/
\r
360 portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort )
\r
362 const portTickType xBlockTime = ( portTickType ) 0xffff;
\r
364 /* This function does nothing interesting, but test the
\r
365 semaphore from ISR mechanism. */
\r
366 return xSemaphoreTake( xPort->xTestSem, xBlockTime );
\r
368 /*-----------------------------------------------------------*/
\r
370 void vSerialClose( xComPortHandle xPort )
\r
372 unsigned portSHORT usOutput;
\r
374 /* Turn off the interrupts. We may also want to delete the queues and/or
\r
375 re-install the original ISR. */
\r
377 portENTER_CRITICAL();
\r
379 usOutput = portINPUT_WORD( xPort->usCtrlReg );
\r
381 usOutput &= ~serENABLE_INTERRUPTS;
\r
382 usOutput &= ~serENABLE_TX_MACHINES;
\r
383 usOutput &= ~serENABLE_RX_MACHINES;
\r
384 portOUTPUT_WORD( xPort->usCtrlReg, usOutput );
\r
386 usOutput = portINPUT_WORD( xPort->usIntReg );
\r
387 usOutput |= serINTERRUPT_MASK;
\r
388 portOUTPUT_WORD( xPort->usIntReg, usOutput );
\r
390 portEXIT_CRITICAL();
\r
392 /*-----------------------------------------------------------*/
\r
393 unsigned short usStatus;
\r
394 static portBASE_TYPE xComPortISR( xComPort * const pxPort )
\r
396 unsigned portSHORT usStatusRegister;
\r
398 portBASE_TYPE xTaskWokenByPost = pdFALSE, xAnotherTaskWokenByPost = pdFALSE, xTaskWokenByTx = pdFALSE;
\r
400 /* NOTE: THIS IS NOT AN EFFICIENT ISR AS IT IS DESIGNED SOLELY TO TEST
\r
401 THE SCHEDULER FUNCTIONALITY. REAL APPLICATIONS SHOULD NOT USE THIS
\r
404 usStatusRegister = portINPUT_WORD( pxPort->usStatusReg );
\r
406 if( usStatusRegister & serRX_READY )
\r
408 cChar = ( portCHAR ) portINPUT_WORD( pxPort->usRxReg );
\r
409 xTaskWokenByPost = xQueueSendFromISR( pxPort->xRxedChars, &cChar, xTaskWokenByPost );
\r
411 /* Also release the semaphore - this does nothing interesting and is just a test. */
\r
412 xAnotherTaskWokenByPost = xSemaphoreGiveFromISR( pxPort->xTestSem, xAnotherTaskWokenByPost );
\r
414 else if( pxPort->sTxInterruptOn && ( usStatusRegister & serTX_EMPTY ) )
\r
416 if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cChar, &xTaskWokenByTx ) == pdTRUE )
\r
418 portOUTPUT_WORD( pxPort->usTxReg, ( unsigned portSHORT ) cChar );
\r
422 /* Queue empty, nothing to send */
\r
423 vInterruptOff( pxPort, serTX_HOLD_EMPTY_INT );
\r
427 serRESET_PIC( pxPort->usIRQVector );
\r
429 /* If posting to the queue woke a task that was blocked on the queue we may
\r
430 want to switch to the woken task - depending on its priority relative to
\r
431 the task interrupted by this ISR. */
\r
432 if( xTaskWokenByPost || xAnotherTaskWokenByPost || xTaskWokenByTx)
\r