2 FreeRTOS V8.2.1 - Copyright (C) 2015 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 This file is part of the FreeRTOS distribution.
\r
9 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
10 the terms of the GNU General Public License (version 2) as published by the
\r
11 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
13 ***************************************************************************
\r
14 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
15 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
16 >>! obliged to provide the source code for proprietary components !<<
\r
17 >>! outside of the FreeRTOS kernel. !<<
\r
18 ***************************************************************************
\r
20 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
21 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
22 FOR A PARTICULAR PURPOSE. Full license text is available on the following
\r
23 link: http://www.freertos.org/a00114.html
\r
25 ***************************************************************************
\r
27 * FreeRTOS provides completely free yet professionally developed, *
\r
28 * robust, strictly quality controlled, supported, and cross *
\r
29 * platform software that is more than just the market leader, it *
\r
30 * is the industry's de facto standard. *
\r
32 * Help yourself get started quickly while simultaneously helping *
\r
33 * to support the FreeRTOS project by purchasing a FreeRTOS *
\r
34 * tutorial book, reference manual, or both: *
\r
35 * http://www.FreeRTOS.org/Documentation *
\r
37 ***************************************************************************
\r
39 http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
\r
40 the FAQ page "My application does not run, what could be wrong?". Have you
\r
41 defined configASSERT()?
\r
43 http://www.FreeRTOS.org/support - In return for receiving this top quality
\r
44 embedded software for free we request you assist our global community by
\r
45 participating in the support forum.
\r
47 http://www.FreeRTOS.org/training - Investing in training allows your team to
\r
48 be as productive as possible as early as possible. Now you can receive
\r
49 FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
\r
50 Ltd, and the world's leading authority on the world's leading RTOS.
\r
52 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
53 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
54 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
56 http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
\r
57 Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
\r
59 http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
\r
60 Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
61 licenses offer ticketed support, indemnification and commercial middleware.
\r
63 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
64 engineered and independently SIL3 certified version for use in safety and
\r
65 mission critical applications that require provable dependability.
\r
72 #include <embedded.h>
\r
73 #include "FreeRTOS.h"
\r
74 #include "portasm.h"
\r
79 #define serMAX_PORTS ( ( unsigned short ) 2 )
\r
81 #define serPORT_0_INT_REG ( 0xff44 )
\r
82 #define serPORT_0_BAUD_REG ( 0xff88 )
\r
83 #define serPORT_0_RX_REG ( 0xff86 )
\r
84 #define serPORT_0_TX_REG ( 0xff84 )
\r
85 #define serPORT_0_STATUS_REG ( 0xff82 )
\r
86 #define serPORT_0_CTRL_REG ( 0xff80 )
\r
87 #define serPORT_0_IRQ ( 0x14 )
\r
89 #define serPORT_1_INT_REG ( 0xff42 )
\r
90 #define serPORT_1_BAUD_REG ( 0xff18 )
\r
91 #define serPORT_1_RX_REG ( 0xff16 )
\r
92 #define serPORT_1_TX_REG ( 0xff14 )
\r
93 #define serPORT_1_STATUS_REG ( 0xff12 )
\r
94 #define serPORT_1_CTRL_REG ( 0xff10 )
\r
95 #define serPORT_1_IRQ ( 0x11 )
\r
97 #define serTX_EMPTY ( ( unsigned short ) 0x40 )
\r
98 #define serRX_READY ( ( unsigned short ) 0x80 )
\r
100 #define serRESET_PIC( usEOI_TYPE ) portOUTPUT_WORD( ( unsigned short ) 0xff22, usEOI_TYPE )
\r
101 #define serTX_HOLD_EMPTY_INT ( ( unsigned short ) 0x100 )
\r
103 #define serENABLE_INTERRUPTS ( ( unsigned short ) 0x80 )
\r
104 #define serMODE ( ( unsigned short ) 0x01 )
\r
105 #define serENABLE_TX_MACHINES ( ( unsigned short ) 0x40 )
\r
106 #define serENABLE_RX_MACHINES ( ( unsigned short ) 0x20 )
\r
107 #define serINTERRUPT_MASK ( ( unsigned short ) 0x08 )
\r
108 #define serCLEAR_ALL_STATUS_BITS ( ( unsigned short ) 0x00 )
\r
109 #define serINTERRUPT_PRIORITY ( ( unsigned short ) 0x01 ) /*< Just below the scheduler priority. */
\r
111 #define serDONT_BLOCK ( ( TickType_t ) 0 )
\r
169 typedef struct xCOM_PORT
\r
171 /* Hardware parameters for this port. */
\r
172 short sTxInterruptOn;
\r
173 unsigned short usIntReg;
\r
174 unsigned short usBaudReg;
\r
175 unsigned short usRxReg;
\r
176 unsigned short usTxReg;
\r
177 unsigned short usStatusReg;
\r
178 unsigned short usCtrlReg;
\r
180 unsigned short usIRQVector;
\r
182 /* Queues used for communications with com test task. */
\r
183 QueueHandle_t xRxedChars;
\r
184 QueueHandle_t xCharsForTx;
\r
186 /* This semaphore does nothing useful except test a feature of the
\r
188 SemaphoreHandle_t xTestSem;
\r
192 static xComPort xPorts[ serMAX_PORTS ] =
\r
194 { 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
195 { 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
198 typedef xComPort * xComPortHandle;
\r
201 * Lookup the baud rate from the enum.
\r
203 static unsigned long prvBaud( eBaud eWantedBaud );
\r
205 /* These prototypes are repeated here so we don't have to include the serial header. This allows
\r
206 the xComPortHandle structure details to be private to this file. */
\r
207 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength );
\r
208 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, TickType_t xBlockTime );
\r
209 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, TickType_t xBlockTime );
\r
210 void vSerialClose( xComPortHandle xPort );
\r
211 short sSerialWaitForSemaphore( xComPortHandle xPort );
\r
212 /*-----------------------------------------------------------*/
\r
214 static short xComPortISR( xComPort * const pxPort );
\r
216 #define vInterruptOn( pxPort, usInterrupt ) \
\r
218 unsigned short usIn; \
\r
220 portENTER_CRITICAL(); \
\r
222 if( pxPort->sTxInterruptOn == pdFALSE ) \
\r
224 usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
225 portOUTPUT_WORD( pxPort->usCtrlReg, usIn | usInterrupt ); \
\r
227 pxPort->sTxInterruptOn = pdTRUE; \
\r
230 portEXIT_CRITICAL(); \
\r
232 /*-----------------------------------------------------------*/
\r
234 #define vInterruptOff( pxPort, usInterrupt ) \
\r
236 unsigned short usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
237 if( usIn & usInterrupt ) \
\r
239 portOUTPUT_WORD( pxPort->usCtrlReg, usIn & ~usInterrupt); \
\r
240 pxPort->sTxInterruptOn = pdFALSE; \
\r
243 /*-----------------------------------------------------------*/
\r
246 /* Define an interrupt handler for each port */
\r
247 #define COM_IRQ_WRAPPER(N) \
\r
248 static void __interrupt COM_IRQ##N##_WRAPPER( void ) \
\r
250 if( xComPortISR( &( xPorts[##N##] ) ) ) \
\r
252 portEND_SWITCHING_ISR(); \
\r
258 COM_IRQ_WRAPPER( 0 )
\r
259 COM_IRQ_WRAPPER( 1 )
\r
261 static pxISR xISRs[ serMAX_PORTS ] =
\r
267 /*-----------------------------------------------------------*/
\r
269 static unsigned long prvBaud( eBaud eWantedBaud )
\r
271 switch( eWantedBaud )
\r
273 case ser50 : return 50UL;
\r
274 case ser75 : return 75UL;
\r
275 case ser110 : return 110UL;
\r
276 case ser134 : return 134UL;
\r
277 case ser150 : return 150UL;
\r
278 case ser200 : return 200UL;
\r
279 case ser300 : return 300UL;
\r
280 case ser600 : return 600UL;
\r
281 case ser1200 : return 1200UL;
\r
282 case ser1800 : return 1800UL;
\r
283 case ser2400 : return 2400UL;
\r
284 case ser4800 : return 4800UL;
\r
285 case ser19200 : return 19200UL;
\r
286 case ser38400 : return 38400UL;
\r
287 case ser57600 : return 57600UL;
\r
288 case ser115200 : return 115200UL;
\r
289 default : return 9600UL;
\r
293 /*-----------------------------------------------------------*/
\r
295 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )
\r
297 unsigned short usPort;
\r
298 xComPortHandle pxPort = NULL;
\r
299 unsigned long ulBaudDiv;
\r
301 /* BAUDDIV = ( Microprocessor Clock / Baud Rate ) / 16 */
\r
302 ulBaudDiv = ( configCPU_CLOCK_HZ / prvBaud( eWantedBaud ) ) / 16UL;
\r
304 /* Only n, 8, 1 is supported so these parameters are not required for this
\r
306 ( void ) eWantedParity;
\r
307 ( void ) eWantedDataBits;
\r
308 ( void ) eWantedStopBits;
\r
310 /* Currently only n,8,1 is supported. */
\r
312 usPort = ( unsigned short ) ePort;
\r
314 if( usPort < serMAX_PORTS )
\r
316 pxPort = &( xPorts[ usPort ] );
\r
318 portENTER_CRITICAL();
\r
320 unsigned short usInWord;
\r
322 /* Create the queues used by the com test task. */
\r
323 pxPort->xRxedChars = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
324 pxPort->xCharsForTx = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
326 /* Create the test semaphore. This does nothing useful except test a feature of the scheduler. */
\r
327 vSemaphoreCreateBinary( pxPort->xTestSem );
\r
329 /* There is no ISR here already to restore later. */
\r
330 setvect( ( short ) pxPort->usIRQVector, xISRs[ usPort ] );
\r
332 usInWord = portINPUT_WORD( pxPort->usIntReg );
\r
333 usInWord &= ~serINTERRUPT_MASK;
\r
334 usInWord |= serINTERRUPT_PRIORITY;
\r
335 portOUTPUT_WORD( pxPort->usIntReg, usInWord );
\r
337 portOUTPUT_WORD( pxPort->usBaudReg, ( unsigned short ) ulBaudDiv );
\r
338 portOUTPUT_WORD( pxPort->usCtrlReg, serENABLE_INTERRUPTS | serMODE | serENABLE_TX_MACHINES | serENABLE_RX_MACHINES );
\r
340 portOUTPUT_WORD( pxPort->usStatusReg, serCLEAR_ALL_STATUS_BITS );
\r
342 portEXIT_CRITICAL();
\r
346 } /*lint !e715 Some parameters are not used as only a subset of the serial port functionality is currently implemented. */
\r
347 /*-----------------------------------------------------------*/
\r
349 void vSerialPutString( xComPortHandle pxPort, const char * const pcString, unsigned short usStringLength )
\r
351 unsigned short usByte;
\r
354 pcNextChar = ( char * ) pcString;
\r
356 for( usByte = 0; usByte < usStringLength; usByte++ )
\r
358 xQueueSend( pxPort->xCharsForTx, pcNextChar, serDONT_BLOCK );
\r
362 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
364 /*-----------------------------------------------------------*/
\r
366 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, TickType_t xBlockTime )
\r
368 /* Get the next character from the buffer, note that this routine is only
\r
369 called having checked that the is (at least) one to get */
\r
370 if( xQueueReceive( pxPort->xRxedChars, pcRxedChar, xBlockTime ) )
\r
379 /*-----------------------------------------------------------*/
\r
381 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, TickType_t xBlockTime )
\r
383 if( xQueueSend( pxPort->xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )
\r
388 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
392 /*-----------------------------------------------------------*/
\r
394 portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort )
\r
396 const TickType_t xBlockTime = ( TickType_t ) 0xffff;
\r
398 /* This function does nothing interesting, but test the
\r
399 semaphore from ISR mechanism. */
\r
400 return xSemaphoreTake( xPort->xTestSem, xBlockTime );
\r
402 /*-----------------------------------------------------------*/
\r
404 void vSerialClose( xComPortHandle xPort )
\r
406 unsigned short usOutput;
\r
408 /* Turn off the interrupts. We may also want to delete the queues and/or
\r
409 re-install the original ISR. */
\r
411 portENTER_CRITICAL();
\r
413 usOutput = portINPUT_WORD( xPort->usCtrlReg );
\r
415 usOutput &= ~serENABLE_INTERRUPTS;
\r
416 usOutput &= ~serENABLE_TX_MACHINES;
\r
417 usOutput &= ~serENABLE_RX_MACHINES;
\r
418 portOUTPUT_WORD( xPort->usCtrlReg, usOutput );
\r
420 usOutput = portINPUT_WORD( xPort->usIntReg );
\r
421 usOutput |= serINTERRUPT_MASK;
\r
422 portOUTPUT_WORD( xPort->usIntReg, usOutput );
\r
424 portEXIT_CRITICAL();
\r
426 /*-----------------------------------------------------------*/
\r
427 unsigned short usStatus;
\r
428 static portBASE_TYPE xComPortISR( xComPort * const pxPort )
\r
430 unsigned short usStatusRegister;
\r
432 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
434 /* NOTE: THIS IS NOT AN EFFICIENT ISR AS IT IS DESIGNED SOLELY TO TEST
\r
435 THE SCHEDULER FUNCTIONALITY. REAL APPLICATIONS SHOULD NOT USE THIS
\r
438 usStatusRegister = portINPUT_WORD( pxPort->usStatusReg );
\r
440 if( usStatusRegister & serRX_READY )
\r
442 cChar = ( char ) portINPUT_WORD( pxPort->usRxReg );
\r
443 xQueueSendFromISR( pxPort->xRxedChars, &cChar, &xHigherPriorityTaskWoken );
\r
445 /* Also release the semaphore - this does nothing interesting and is just a test. */
\r
446 xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
\r
448 else if( pxPort->sTxInterruptOn && ( usStatusRegister & serTX_EMPTY ) )
\r
450 if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
\r
452 portOUTPUT_WORD( pxPort->usTxReg, ( unsigned short ) cChar );
\r
456 /* Queue empty, nothing to send */
\r
457 vInterruptOff( pxPort, serTX_HOLD_EMPTY_INT );
\r
461 serRESET_PIC( pxPort->usIRQVector );
\r
463 /* If posting to the queue woke a task that was blocked on the queue we may
\r
464 want to switch to the woken task - depending on its priority relative to
\r
465 the task interrupted by this ISR. */
\r
466 return xHigherPriorityTaskWoken;
\r