2 * FreeRTOS Kernel V10.1.1
\r
3 * Copyright (C) 2018 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.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
30 #include <embedded.h>
\r
31 #include "FreeRTOS.h"
\r
32 #include "portasm.h"
\r
37 #define serMAX_PORTS ( ( unsigned short ) 2 )
\r
39 #define serPORT_0_INT_REG ( 0xff44 )
\r
40 #define serPORT_0_BAUD_REG ( 0xff88 )
\r
41 #define serPORT_0_RX_REG ( 0xff86 )
\r
42 #define serPORT_0_TX_REG ( 0xff84 )
\r
43 #define serPORT_0_STATUS_REG ( 0xff82 )
\r
44 #define serPORT_0_CTRL_REG ( 0xff80 )
\r
45 #define serPORT_0_IRQ ( 0x14 )
\r
47 #define serPORT_1_INT_REG ( 0xff42 )
\r
48 #define serPORT_1_BAUD_REG ( 0xff18 )
\r
49 #define serPORT_1_RX_REG ( 0xff16 )
\r
50 #define serPORT_1_TX_REG ( 0xff14 )
\r
51 #define serPORT_1_STATUS_REG ( 0xff12 )
\r
52 #define serPORT_1_CTRL_REG ( 0xff10 )
\r
53 #define serPORT_1_IRQ ( 0x11 )
\r
55 #define serTX_EMPTY ( ( unsigned short ) 0x40 )
\r
56 #define serRX_READY ( ( unsigned short ) 0x80 )
\r
58 #define serRESET_PIC( usEOI_TYPE ) portOUTPUT_WORD( ( unsigned short ) 0xff22, usEOI_TYPE )
\r
59 #define serTX_HOLD_EMPTY_INT ( ( unsigned short ) 0x100 )
\r
61 #define serENABLE_INTERRUPTS ( ( unsigned short ) 0x80 )
\r
62 #define serMODE ( ( unsigned short ) 0x01 )
\r
63 #define serENABLE_TX_MACHINES ( ( unsigned short ) 0x40 )
\r
64 #define serENABLE_RX_MACHINES ( ( unsigned short ) 0x20 )
\r
65 #define serINTERRUPT_MASK ( ( unsigned short ) 0x08 )
\r
66 #define serCLEAR_ALL_STATUS_BITS ( ( unsigned short ) 0x00 )
\r
67 #define serINTERRUPT_PRIORITY ( ( unsigned short ) 0x01 ) /*< Just below the scheduler priority. */
\r
69 #define serDONT_BLOCK ( ( TickType_t ) 0 )
\r
127 typedef struct xCOM_PORT
\r
129 /* Hardware parameters for this port. */
\r
130 short sTxInterruptOn;
\r
131 unsigned short usIntReg;
\r
132 unsigned short usBaudReg;
\r
133 unsigned short usRxReg;
\r
134 unsigned short usTxReg;
\r
135 unsigned short usStatusReg;
\r
136 unsigned short usCtrlReg;
\r
138 unsigned short usIRQVector;
\r
140 /* Queues used for communications with com test task. */
\r
141 QueueHandle_t xRxedChars;
\r
142 QueueHandle_t xCharsForTx;
\r
144 /* This semaphore does nothing useful except test a feature of the
\r
146 SemaphoreHandle_t xTestSem;
\r
150 static xComPort xPorts[ serMAX_PORTS ] =
\r
152 { 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
153 { 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
156 typedef xComPort * xComPortHandle;
\r
159 * Lookup the baud rate from the enum.
\r
161 static unsigned long prvBaud( eBaud eWantedBaud );
\r
163 /* These prototypes are repeated here so we don't have to include the serial header. This allows
\r
164 the xComPortHandle structure details to be private to this file. */
\r
165 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength );
\r
166 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, TickType_t xBlockTime );
\r
167 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, TickType_t xBlockTime );
\r
168 void vSerialClose( xComPortHandle xPort );
\r
169 short sSerialWaitForSemaphore( xComPortHandle xPort );
\r
170 /*-----------------------------------------------------------*/
\r
172 static short xComPortISR( xComPort * const pxPort );
\r
174 #define vInterruptOn( pxPort, usInterrupt ) \
\r
176 unsigned short usIn; \
\r
178 portENTER_CRITICAL(); \
\r
180 if( pxPort->sTxInterruptOn == pdFALSE ) \
\r
182 usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
183 portOUTPUT_WORD( pxPort->usCtrlReg, usIn | usInterrupt ); \
\r
185 pxPort->sTxInterruptOn = pdTRUE; \
\r
188 portEXIT_CRITICAL(); \
\r
190 /*-----------------------------------------------------------*/
\r
192 #define vInterruptOff( pxPort, usInterrupt ) \
\r
194 unsigned short usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
\r
195 if( usIn & usInterrupt ) \
\r
197 portOUTPUT_WORD( pxPort->usCtrlReg, usIn & ~usInterrupt); \
\r
198 pxPort->sTxInterruptOn = pdFALSE; \
\r
201 /*-----------------------------------------------------------*/
\r
204 /* Define an interrupt handler for each port */
\r
205 #define COM_IRQ_WRAPPER(N) \
\r
206 static void __interrupt COM_IRQ##N##_WRAPPER( void ) \
\r
208 if( xComPortISR( &( xPorts[##N##] ) ) ) \
\r
210 portEND_SWITCHING_ISR(); \
\r
216 COM_IRQ_WRAPPER( 0 )
\r
217 COM_IRQ_WRAPPER( 1 )
\r
219 static pxISR xISRs[ serMAX_PORTS ] =
\r
225 /*-----------------------------------------------------------*/
\r
227 static unsigned long prvBaud( eBaud eWantedBaud )
\r
229 switch( eWantedBaud )
\r
231 case ser50 : return 50UL;
\r
232 case ser75 : return 75UL;
\r
233 case ser110 : return 110UL;
\r
234 case ser134 : return 134UL;
\r
235 case ser150 : return 150UL;
\r
236 case ser200 : return 200UL;
\r
237 case ser300 : return 300UL;
\r
238 case ser600 : return 600UL;
\r
239 case ser1200 : return 1200UL;
\r
240 case ser1800 : return 1800UL;
\r
241 case ser2400 : return 2400UL;
\r
242 case ser4800 : return 4800UL;
\r
243 case ser19200 : return 19200UL;
\r
244 case ser38400 : return 38400UL;
\r
245 case ser57600 : return 57600UL;
\r
246 case ser115200 : return 115200UL;
\r
247 default : return 9600UL;
\r
251 /*-----------------------------------------------------------*/
\r
253 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )
\r
255 unsigned short usPort;
\r
256 xComPortHandle pxPort = NULL;
\r
257 unsigned long ulBaudDiv;
\r
259 /* BAUDDIV = ( Microprocessor Clock / Baud Rate ) / 16 */
\r
260 ulBaudDiv = ( configCPU_CLOCK_HZ / prvBaud( eWantedBaud ) ) / 16UL;
\r
262 /* Only n, 8, 1 is supported so these parameters are not required for this
\r
264 ( void ) eWantedParity;
\r
265 ( void ) eWantedDataBits;
\r
266 ( void ) eWantedStopBits;
\r
268 /* Currently only n,8,1 is supported. */
\r
270 usPort = ( unsigned short ) ePort;
\r
272 if( usPort < serMAX_PORTS )
\r
274 pxPort = &( xPorts[ usPort ] );
\r
276 portENTER_CRITICAL();
\r
278 unsigned short usInWord;
\r
280 /* Create the queues used by the com test task. */
\r
281 pxPort->xRxedChars = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
282 pxPort->xCharsForTx = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
284 /* Create the test semaphore. This does nothing useful except test a feature of the scheduler. */
\r
285 vSemaphoreCreateBinary( pxPort->xTestSem );
\r
287 /* There is no ISR here already to restore later. */
\r
288 setvect( ( short ) pxPort->usIRQVector, xISRs[ usPort ] );
\r
290 usInWord = portINPUT_WORD( pxPort->usIntReg );
\r
291 usInWord &= ~serINTERRUPT_MASK;
\r
292 usInWord |= serINTERRUPT_PRIORITY;
\r
293 portOUTPUT_WORD( pxPort->usIntReg, usInWord );
\r
295 portOUTPUT_WORD( pxPort->usBaudReg, ( unsigned short ) ulBaudDiv );
\r
296 portOUTPUT_WORD( pxPort->usCtrlReg, serENABLE_INTERRUPTS | serMODE | serENABLE_TX_MACHINES | serENABLE_RX_MACHINES );
\r
298 portOUTPUT_WORD( pxPort->usStatusReg, serCLEAR_ALL_STATUS_BITS );
\r
300 portEXIT_CRITICAL();
\r
304 } /*lint !e715 Some parameters are not used as only a subset of the serial port functionality is currently implemented. */
\r
305 /*-----------------------------------------------------------*/
\r
307 void vSerialPutString( xComPortHandle pxPort, const char * const pcString, unsigned short usStringLength )
\r
309 unsigned short usByte;
\r
312 pcNextChar = ( char * ) pcString;
\r
314 for( usByte = 0; usByte < usStringLength; usByte++ )
\r
316 xQueueSend( pxPort->xCharsForTx, pcNextChar, serDONT_BLOCK );
\r
320 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
322 /*-----------------------------------------------------------*/
\r
324 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, TickType_t xBlockTime )
\r
326 /* Get the next character from the buffer, note that this routine is only
\r
327 called having checked that the is (at least) one to get */
\r
328 if( xQueueReceive( pxPort->xRxedChars, pcRxedChar, xBlockTime ) )
\r
337 /*-----------------------------------------------------------*/
\r
339 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, TickType_t xBlockTime )
\r
341 if( xQueueSend( pxPort->xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )
\r
346 vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
\r
350 /*-----------------------------------------------------------*/
\r
352 portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort )
\r
354 const TickType_t xBlockTime = ( TickType_t ) 0xffff;
\r
356 /* This function does nothing interesting, but test the
\r
357 semaphore from ISR mechanism. */
\r
358 return xSemaphoreTake( xPort->xTestSem, xBlockTime );
\r
360 /*-----------------------------------------------------------*/
\r
362 void vSerialClose( xComPortHandle xPort )
\r
364 unsigned short usOutput;
\r
366 /* Turn off the interrupts. We may also want to delete the queues and/or
\r
367 re-install the original ISR. */
\r
369 portENTER_CRITICAL();
\r
371 usOutput = portINPUT_WORD( xPort->usCtrlReg );
\r
373 usOutput &= ~serENABLE_INTERRUPTS;
\r
374 usOutput &= ~serENABLE_TX_MACHINES;
\r
375 usOutput &= ~serENABLE_RX_MACHINES;
\r
376 portOUTPUT_WORD( xPort->usCtrlReg, usOutput );
\r
378 usOutput = portINPUT_WORD( xPort->usIntReg );
\r
379 usOutput |= serINTERRUPT_MASK;
\r
380 portOUTPUT_WORD( xPort->usIntReg, usOutput );
\r
382 portEXIT_CRITICAL();
\r
384 /*-----------------------------------------------------------*/
\r
385 unsigned short usStatus;
\r
386 static portBASE_TYPE xComPortISR( xComPort * const pxPort )
\r
388 unsigned short usStatusRegister;
\r
390 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
392 /* NOTE: THIS IS NOT AN EFFICIENT ISR AS IT IS DESIGNED SOLELY TO TEST
\r
393 THE SCHEDULER FUNCTIONALITY. REAL APPLICATIONS SHOULD NOT USE THIS
\r
396 usStatusRegister = portINPUT_WORD( pxPort->usStatusReg );
\r
398 if( usStatusRegister & serRX_READY )
\r
400 cChar = ( char ) portINPUT_WORD( pxPort->usRxReg );
\r
401 xQueueSendFromISR( pxPort->xRxedChars, &cChar, &xHigherPriorityTaskWoken );
\r
403 /* Also release the semaphore - this does nothing interesting and is just a test. */
\r
404 xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
\r
406 else if( pxPort->sTxInterruptOn && ( usStatusRegister & serTX_EMPTY ) )
\r
408 if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
\r
410 portOUTPUT_WORD( pxPort->usTxReg, ( unsigned short ) cChar );
\r
414 /* Queue empty, nothing to send */
\r
415 vInterruptOff( pxPort, serTX_HOLD_EMPTY_INT );
\r
419 serRESET_PIC( pxPort->usIRQVector );
\r
421 /* If posting to the queue woke a task that was blocked on the queue we may
\r
422 want to switch to the woken task - depending on its priority relative to
\r
423 the task interrupted by this ISR. */
\r
424 return xHigherPriorityTaskWoken;
\r