2 * FreeRTOS Kernel V10.0.0
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software. If you wish to use our Amazon
\r
14 * FreeRTOS name, please do so in a fair use way that does not cause confusion.
\r
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
18 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
19 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
23 * http://www.FreeRTOS.org
\r
24 * http://aws.amazon.com/freertos
\r
26 * 1 tab == 4 spaces!
\r
31 #include <embedded.h>
\r
32 #include "FreeRTOS.h"
\r
33 #include "portasm.h"
\r
38 #define serMAX_PORTS ( ( unsigned short ) 2 )
\r
40 #define serPORT_0_INT_REG ( 0xff44 )
\r
41 #define serPORT_0_BAUD_REG ( 0xff88 )
\r
42 #define serPORT_0_RX_REG ( 0xff86 )
\r
43 #define serPORT_0_TX_REG ( 0xff84 )
\r
44 #define serPORT_0_STATUS_REG ( 0xff82 )
\r
45 #define serPORT_0_CTRL_REG ( 0xff80 )
\r
46 #define serPORT_0_IRQ ( 0x14 )
\r
48 #define serPORT_1_INT_REG ( 0xff42 )
\r
49 #define serPORT_1_BAUD_REG ( 0xff18 )
\r
50 #define serPORT_1_RX_REG ( 0xff16 )
\r
51 #define serPORT_1_TX_REG ( 0xff14 )
\r
52 #define serPORT_1_STATUS_REG ( 0xff12 )
\r
53 #define serPORT_1_CTRL_REG ( 0xff10 )
\r
54 #define serPORT_1_IRQ ( 0x11 )
\r
56 #define serTX_EMPTY ( ( unsigned short ) 0x40 )
\r
57 #define serRX_READY ( ( unsigned short ) 0x80 )
\r
59 #define serRESET_PIC( usEOI_TYPE ) portOUTPUT_WORD( ( unsigned short ) 0xff22, usEOI_TYPE )
\r
60 #define serTX_HOLD_EMPTY_INT ( ( unsigned short ) 0x100 )
\r
62 #define serENABLE_INTERRUPTS ( ( unsigned short ) 0x80 )
\r
63 #define serMODE ( ( unsigned short ) 0x01 )
\r
64 #define serENABLE_TX_MACHINES ( ( unsigned short ) 0x40 )
\r
65 #define serENABLE_RX_MACHINES ( ( unsigned short ) 0x20 )
\r
66 #define serINTERRUPT_MASK ( ( unsigned short ) 0x08 )
\r
67 #define serCLEAR_ALL_STATUS_BITS ( ( unsigned short ) 0x00 )
\r
68 #define serINTERRUPT_PRIORITY ( ( unsigned short ) 0x01 ) /*< Just below the scheduler priority. */
\r
70 #define serDONT_BLOCK ( ( TickType_t ) 0 )
\r
128 typedef struct xCOM_PORT
\r
130 /* Hardware parameters for this port. */
\r
131 short sTxInterruptOn;
\r
132 unsigned short usIntReg;
\r
133 unsigned short usBaudReg;
\r
134 unsigned short usRxReg;
\r
135 unsigned short usTxReg;
\r
136 unsigned short usStatusReg;
\r
137 unsigned short usCtrlReg;
\r
139 unsigned short usIRQVector;
\r
141 /* Queues used for communications with com test task. */
\r
142 QueueHandle_t xRxedChars;
\r
143 QueueHandle_t xCharsForTx;
\r
145 /* This semaphore does nothing useful except test a feature of the
\r
147 SemaphoreHandle_t xTestSem;
\r
151 static xComPort xPorts[ serMAX_PORTS ] =
\r
153 { 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
154 { 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
157 typedef xComPort * xComPortHandle;
\r
160 * Lookup the baud rate from the enum.
\r
162 static unsigned long prvBaud( eBaud eWantedBaud );
\r
164 /* These prototypes are repeated here so we don't have to include the serial header. This allows
\r
165 the xComPortHandle structure details to be private to this file. */
\r
166 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength );
\r
167 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, TickType_t xBlockTime );
\r
168 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, TickType_t xBlockTime );
\r
169 void vSerialClose( xComPortHandle xPort );
\r
170 short sSerialWaitForSemaphore( xComPortHandle xPort );
\r
171 /*-----------------------------------------------------------*/
\r
173 static short xComPortISR( xComPort * const pxPort );
\r
175 #define vInterruptOn( pxPort, usInterrupt ) \
\r
177 unsigned short usIn; \
\r
179 portENTER_CRITICAL(); \
\r
181 if( pxPort->sTxInterruptOn == pdFALSE ) \
\r
183 usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
184 portOUTPUT_WORD( pxPort->usCtrlReg, usIn | usInterrupt ); \
\r
186 pxPort->sTxInterruptOn = pdTRUE; \
\r
189 portEXIT_CRITICAL(); \
\r
191 /*-----------------------------------------------------------*/
\r
193 #define vInterruptOff( pxPort, usInterrupt ) \
\r
195 unsigned short usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
196 if( usIn & usInterrupt ) \
\r
198 portOUTPUT_WORD( pxPort->usCtrlReg, usIn & ~usInterrupt); \
\r
199 pxPort->sTxInterruptOn = pdFALSE; \
\r
202 /*-----------------------------------------------------------*/
\r
205 /* Define an interrupt handler for each port */
\r
206 #define COM_IRQ_WRAPPER(N) \
\r
207 static void __interrupt COM_IRQ##N##_WRAPPER( void ) \
\r
209 if( xComPortISR( &( xPorts[##N##] ) ) ) \
\r
211 portEND_SWITCHING_ISR(); \
\r
217 COM_IRQ_WRAPPER( 0 )
\r
218 COM_IRQ_WRAPPER( 1 )
\r
220 static pxISR xISRs[ serMAX_PORTS ] =
\r
226 /*-----------------------------------------------------------*/
\r
228 static unsigned long prvBaud( eBaud eWantedBaud )
\r
230 switch( eWantedBaud )
\r
232 case ser50 : return 50UL;
\r
233 case ser75 : return 75UL;
\r
234 case ser110 : return 110UL;
\r
235 case ser134 : return 134UL;
\r
236 case ser150 : return 150UL;
\r
237 case ser200 : return 200UL;
\r
238 case ser300 : return 300UL;
\r
239 case ser600 : return 600UL;
\r
240 case ser1200 : return 1200UL;
\r
241 case ser1800 : return 1800UL;
\r
242 case ser2400 : return 2400UL;
\r
243 case ser4800 : return 4800UL;
\r
244 case ser19200 : return 19200UL;
\r
245 case ser38400 : return 38400UL;
\r
246 case ser57600 : return 57600UL;
\r
247 case ser115200 : return 115200UL;
\r
248 default : return 9600UL;
\r
252 /*-----------------------------------------------------------*/
\r
254 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )
\r
256 unsigned short usPort;
\r
257 xComPortHandle pxPort = NULL;
\r
258 unsigned long ulBaudDiv;
\r
260 /* BAUDDIV = ( Microprocessor Clock / Baud Rate ) / 16 */
\r
261 ulBaudDiv = ( configCPU_CLOCK_HZ / prvBaud( eWantedBaud ) ) / 16UL;
\r
263 /* Only n, 8, 1 is supported so these parameters are not required for this
\r
265 ( void ) eWantedParity;
\r
266 ( void ) eWantedDataBits;
\r
267 ( void ) eWantedStopBits;
\r
269 /* Currently only n,8,1 is supported. */
\r
271 usPort = ( unsigned short ) ePort;
\r
273 if( usPort < serMAX_PORTS )
\r
275 pxPort = &( xPorts[ usPort ] );
\r
277 portENTER_CRITICAL();
\r
279 unsigned short usInWord;
\r
281 /* Create the queues used by the com test task. */
\r
282 pxPort->xRxedChars = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
283 pxPort->xCharsForTx = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
285 /* Create the test semaphore. This does nothing useful except test a feature of the scheduler. */
\r
286 vSemaphoreCreateBinary( pxPort->xTestSem );
\r
288 /* There is no ISR here already to restore later. */
\r
289 setvect( ( short ) pxPort->usIRQVector, xISRs[ usPort ] );
\r
291 usInWord = portINPUT_WORD( pxPort->usIntReg );
\r
292 usInWord &= ~serINTERRUPT_MASK;
\r
293 usInWord |= serINTERRUPT_PRIORITY;
\r
294 portOUTPUT_WORD( pxPort->usIntReg, usInWord );
\r
296 portOUTPUT_WORD( pxPort->usBaudReg, ( unsigned short ) ulBaudDiv );
\r
297 portOUTPUT_WORD( pxPort->usCtrlReg, serENABLE_INTERRUPTS | serMODE | serENABLE_TX_MACHINES | serENABLE_RX_MACHINES );
\r
299 portOUTPUT_WORD( pxPort->usStatusReg, serCLEAR_ALL_STATUS_BITS );
\r
301 portEXIT_CRITICAL();
\r
305 } /*lint !e715 Some parameters are not used as only a subset of the serial port functionality is currently implemented. */
\r
306 /*-----------------------------------------------------------*/
\r
308 void vSerialPutString( xComPortHandle pxPort, const char * const pcString, unsigned short usStringLength )
\r
310 unsigned short usByte;
\r
313 pcNextChar = ( char * ) pcString;
\r
315 for( usByte = 0; usByte < usStringLength; usByte++ )
\r
317 xQueueSend( pxPort->xCharsForTx, pcNextChar, serDONT_BLOCK );
\r
321 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
323 /*-----------------------------------------------------------*/
\r
325 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, TickType_t xBlockTime )
\r
327 /* Get the next character from the buffer, note that this routine is only
\r
328 called having checked that the is (at least) one to get */
\r
329 if( xQueueReceive( pxPort->xRxedChars, pcRxedChar, xBlockTime ) )
\r
338 /*-----------------------------------------------------------*/
\r
340 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, TickType_t xBlockTime )
\r
342 if( xQueueSend( pxPort->xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )
\r
347 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
351 /*-----------------------------------------------------------*/
\r
353 portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort )
\r
355 const TickType_t xBlockTime = ( TickType_t ) 0xffff;
\r
357 /* This function does nothing interesting, but test the
\r
358 semaphore from ISR mechanism. */
\r
359 return xSemaphoreTake( xPort->xTestSem, xBlockTime );
\r
361 /*-----------------------------------------------------------*/
\r
363 void vSerialClose( xComPortHandle xPort )
\r
365 unsigned short usOutput;
\r
367 /* Turn off the interrupts. We may also want to delete the queues and/or
\r
368 re-install the original ISR. */
\r
370 portENTER_CRITICAL();
\r
372 usOutput = portINPUT_WORD( xPort->usCtrlReg );
\r
374 usOutput &= ~serENABLE_INTERRUPTS;
\r
375 usOutput &= ~serENABLE_TX_MACHINES;
\r
376 usOutput &= ~serENABLE_RX_MACHINES;
\r
377 portOUTPUT_WORD( xPort->usCtrlReg, usOutput );
\r
379 usOutput = portINPUT_WORD( xPort->usIntReg );
\r
380 usOutput |= serINTERRUPT_MASK;
\r
381 portOUTPUT_WORD( xPort->usIntReg, usOutput );
\r
383 portEXIT_CRITICAL();
\r
385 /*-----------------------------------------------------------*/
\r
386 unsigned short usStatus;
\r
387 static portBASE_TYPE xComPortISR( xComPort * const pxPort )
\r
389 unsigned short usStatusRegister;
\r
391 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
393 /* NOTE: THIS IS NOT AN EFFICIENT ISR AS IT IS DESIGNED SOLELY TO TEST
\r
394 THE SCHEDULER FUNCTIONALITY. REAL APPLICATIONS SHOULD NOT USE THIS
\r
397 usStatusRegister = portINPUT_WORD( pxPort->usStatusReg );
\r
399 if( usStatusRegister & serRX_READY )
\r
401 cChar = ( char ) portINPUT_WORD( pxPort->usRxReg );
\r
402 xQueueSendFromISR( pxPort->xRxedChars, &cChar, &xHigherPriorityTaskWoken );
\r
404 /* Also release the semaphore - this does nothing interesting and is just a test. */
\r
405 xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
\r
407 else if( pxPort->sTxInterruptOn && ( usStatusRegister & serTX_EMPTY ) )
\r
409 if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
\r
411 portOUTPUT_WORD( pxPort->usTxReg, ( unsigned short ) cChar );
\r
415 /* Queue empty, nothing to send */
\r
416 vInterruptOff( pxPort, serTX_HOLD_EMPTY_INT );
\r
420 serRESET_PIC( pxPort->usIRQVector );
\r
422 /* If posting to the queue woke a task that was blocked on the queue we may
\r
423 want to switch to the woken task - depending on its priority relative to
\r
424 the task interrupted by this ISR. */
\r
425 return xHigherPriorityTaskWoken;
\r