📄 serial.c
字号:
/*-----------------------------------------------------------*/
static portSHORT xComPortISR( xComPort * const pxPort );
#define vInterruptOn( pxPort, usInterrupt ) \
{ \
unsigned portSHORT usIn; \
\
portENTER_CRITICAL(); \
{ \
if( pxPort->sTxInterruptOn == pdFALSE ) \
{ \
usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
portOUTPUT_WORD( pxPort->usCtrlReg, usIn | usInterrupt ); \
\
pxPort->sTxInterruptOn = pdTRUE; \
} \
} \
portEXIT_CRITICAL(); \
}
/*-----------------------------------------------------------*/
#define vInterruptOff( pxPort, usInterrupt ) \
{ \
unsigned portSHORT usIn = portINPUT_WORD( pxPort->usCtrlReg ); \
if( usIn & usInterrupt ) \
{ \
portOUTPUT_WORD( pxPort->usCtrlReg, usIn & ~usInterrupt); \
pxPort->sTxInterruptOn = pdFALSE; \
} \
}
/*-----------------------------------------------------------*/
/* Define an interrupt handler for each port */
#define COM_IRQ_WRAPPER(N) \
static void __interrupt COM_IRQ##N##_WRAPPER( void ) \
{ \
if( xComPortISR( &( xPorts[##N##] ) ) ) \
{ \
portSWITCH_CONTEXT(); \
} \
}
COM_IRQ_WRAPPER( 0 )
COM_IRQ_WRAPPER( 1 )
static pxISR xISRs[ serMAX_PORTS ] =
{
COM_IRQ0_WRAPPER,
COM_IRQ1_WRAPPER
};
/*-----------------------------------------------------------*/
xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )
{
unsigned portSHORT usPort;
xComPortHandle pxPort = NULL;
/* BAUDDIV = ( Microprocessor Clock / Baud Rate ) / 16 */
/* Only n, 8, 1 is supported so these parameters are not required for this
port. */
( void ) eWantedParity;
( void ) eWantedDataBits;
( void ) eWantedStopBits;
/* Currently only n,8,1 is supported. */
usPort = ( unsigned portSHORT ) ePort;
if( usPort < serMAX_PORTS )
{
pxPort = &( xPorts[ usPort ] );
portENTER_CRITICAL();
{
unsigned portSHORT usInWord;
/* Create the queues used by the com test task. */
pxPort->xRxedChars = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( portCHAR ) );
pxPort->xCharsForTx = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( portCHAR ) );
/* Create the test semaphore. This does nothing useful except test a feature of the scheduler. */
vSemaphoreCreateBinary( pxPort->xTestSem );
/* There is no ISR here already to restore later. */
_dos_setvect( ( portSHORT ) pxPort->usIRQVector, xISRs[ usPort ] );
usInWord = portINPUT_WORD( pxPort->usIntReg );
usInWord &= ~serINTERRUPT_MASK;
usInWord |= serINTERRUPT_PRIORITY;
portOUTPUT_WORD( pxPort->usIntReg, usInWord );
portOUTPUT_WORD( pxPort->usBaudReg, usBaudRateDivisor[ eWantedBaud ] );
portOUTPUT_WORD( pxPort->usCtrlReg, serENABLE_INTERRUPTS | serMODE | serENABLE_TX_MACHINES | serENABLE_RX_MACHINES );
portOUTPUT_WORD( pxPort->usStatusReg, serCLEAR_ALL_STATUS_BITS );
}
portEXIT_CRITICAL();
}
return pxPort;
} /*lint !e715 Some parameters are not used as only a subset of the serial port functionality is currently implemented. */
/*-----------------------------------------------------------*/
void vSerialPutString( xComPortHandle pxPort, const portCHAR * const pcString, unsigned portSHORT usStringLength )
{
unsigned portSHORT usByte;
portCHAR *pcNextChar;
pcNextChar = ( portCHAR * ) pcString;
for( usByte = 0; usByte < usStringLength; usByte++ )
{
xQueueSend( pxPort->xCharsForTx, pcNextChar, serDONT_BLOCK );
pcNextChar++;
}
vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
}
/*-----------------------------------------------------------*/
portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, portCHAR *pcRxedChar, portTickType xBlockTime )
{
/* Get the next character from the buffer, note that this routine is only
called having checked that the is (at least) one to get */
if( xQueueReceive( pxPort->xRxedChars, pcRxedChar, xBlockTime ) )
{
return pdTRUE;
}
else
{
return pdFALSE;
}
}
/*-----------------------------------------------------------*/
portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, portCHAR cOutChar, portTickType xBlockTime )
{
if( xQueueSend( pxPort->xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )
{
return pdFAIL;
}
vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
return pdPASS;
}
/*-----------------------------------------------------------*/
portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort )
{
const portTickType xBlockTime = ( portTickType ) 0xffff;
/* This function does nothing interesting, but test the
semaphore from ISR mechanism. */
return xSemaphoreTake( xPort->xTestSem, xBlockTime );
}
/*-----------------------------------------------------------*/
void vSerialClose( xComPortHandle xPort )
{
unsigned portSHORT usOutput;
/* Turn off the interrupts. We may also want to delete the queues and/or
re-install the original ISR. */
portENTER_CRITICAL();
{
usOutput = portINPUT_WORD( xPort->usCtrlReg );
usOutput &= ~serENABLE_INTERRUPTS;
usOutput &= ~serENABLE_TX_MACHINES;
usOutput &= ~serENABLE_RX_MACHINES;
portOUTPUT_WORD( xPort->usCtrlReg, usOutput );
usOutput = portINPUT_WORD( xPort->usIntReg );
usOutput |= serINTERRUPT_MASK;
portOUTPUT_WORD( xPort->usIntReg, usOutput );
}
portEXIT_CRITICAL();
}
/*-----------------------------------------------------------*/
static portBASE_TYPE xComPortISR( xComPort * const pxPort )
{
unsigned portSHORT usStatusRegister;
portCHAR cChar;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE, xContinue = pdTRUE;
/* NOTE: THIS IS NOT AN EFFICIENT ISR AS IT IS DESIGNED SOLELY TO TEST
THE SCHEDULER FUNCTIONALITY. REAL APPLICATIONS SHOULD NOT USE THIS
FUNCTION. */
while( xContinue == pdTRUE )
{
xContinue = pdFALSE;
usStatusRegister = portINPUT_WORD( pxPort->usStatusReg );
if( usStatusRegister & serRX_READY )
{
cChar = ( portCHAR ) portINPUT_WORD( pxPort->usRxReg );
xQueueSendFromISR( pxPort->xRxedChars, &cChar, &xHigherPriorityTaskWoken );
/* Also release the semaphore - this does nothing interesting and is just a test. */
xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
/* We have performed an action this cycle - there may be other to perform. */
xContinue = pdTRUE;
}
if( pxPort->sTxInterruptOn && ( usStatusRegister & serTX_EMPTY ) )
{
if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
{
portOUTPUT_WORD( pxPort->usTxReg, ( unsigned portSHORT ) cChar );
/* We have performed an action this cycle - there may be others to perform. */
xContinue = pdTRUE;
}
else
{
/* Queue empty, nothing to send */
vInterruptOff( pxPort, serTX_HOLD_EMPTY_INT );
}
}
}
serRESET_PIC( pxPort->usIRQVector );
/* If posting to the queue woke a task that was blocked on the queue we may
want to switch to the woken task - depending on its priority relative to
the task interrupted by this ISR. */
return xHigherPriorityTaskWoken;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -