?? serial.c
字號(hào):
/*
This serial port driver is borrowed heavily from DZComm. I have
simplified it by removing a lot of the functionality (hardware
flow control, etc.). For more details and the full version see
http://dzcomm.sourceforge.net
FreeRTOS.org V4.1.1 - Copyright (C) 2003-2006 Richard Barry.
This file is part of the FreeRTOS.org distribution.
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
/*
Changes from V1.00:
+ Call to the more efficient portSWITCH_CONTEXT() replaces the call to
taskYIELD() in the ISR.
Changes from V1.2.0:
+ Added vSerialPutString().
Changes from V1.2.3
+ The function xPortInitMinimal() has been renamed to
xSerialPortInitMinimal() and the function xPortInit() has been renamed
to xSerialPortInit().
Changes From V2.0.0
+ Use portTickType in place of unsigned pdLONG for delay periods.
+ cQueueReieveFromISR() used in place of xQueueReceive() in ISR.
*/
#include <stdlib.h>
#include <dos.h>
#include "FreeRTOS.h"
#include "queue.h"
#include "task.h"
#include "semphr.h"
#include "portasm.h"
#define serMAX_IRQs ( 16 )
#define serTRANSMIT_HOLD_EMPTY_INT ( 0x02 )
#define serCOM1_STANDARD_IRQ ( ( unsigned portCHAR ) 4 )
#define serCOM2_STANDARD_IRQ ( ( unsigned portCHAR ) 3 )
#define serIMR_8259_0 ( ( unsigned portCHAR ) 0x21 )
#define serIMR_8259_1 ( ( unsigned portCHAR ) 0xa1 )
#define serISR_8259_0 ( ( unsigned portCHAR ) 0x20 )
#define serISR_8259_1 ( ( unsigned portCHAR ) 0xa0 )
#define serALL_COMS_INTERRUPTS ( ( unsigned portCHAR ) 0x0f )
#define serALL_MODEM_CTRL_INTERRUPTS ( ( unsigned portCHAR ) 0x0f )
#define serTRANSMIT_HOLD_OFFSET ( 0 )
#define serRECEIVE_DATA_OFFSET ( 0 )
#define serBAUD_RATE_DIVISOR_LOW_OFFSET ( 0 )
#define serBAUD_RATE_DIVISOR_HIGH_OFFSET ( 1 )
#define serINTERRUPT_ENABLE_OFFSET ( 1 )
#define serINTERRUPT_ID_OFFSET ( 2 )
#define serFIFO_CTRL_OFFSET ( 2 )
#define serLINE_CTRL_OFFSET ( 3 )
#define serMODEM_CTRL_OFFSET ( 4 )
#define serLINE_STATUS_OFFSET ( 5 )
#define serMODEM_STATUS_OFFSET ( 6 )
#define serSCR_OFFSET ( 7 )
#define serMAX_BAUD ( ( unsigned portLONG ) 115200UL )
#define serNO_INTERRUPTS ( 0x00 )
#define vInterruptOn( pxPort, ucInterrupt ) \
{ \
unsigned portCHAR ucIn = portINPUT_BYTE( pxPort->usInterruptEnableReg ); \
if( !( ucIn & ucInterrupt ) ) \
{ \
portOUTPUT_BYTE( pxPort->usInterruptEnableReg, ucIn | ucInterrupt ); \
} \
}
/*-----------------------------------------------------------*/
#define vInterruptOff( pxPort, ucInterrupt ) \
{ \
unsigned portCHAR ucIn = portINPUT_BYTE( pxPort->usInterruptEnableReg ); \
if( ucIn & ucInterrupt ) \
{ \
portOUTPUT_BYTE( pxPort->usInterruptEnableReg, ucIn & ~ucInterrupt); \
} \
}
/*-----------------------------------------------------------*/
typedef enum
{
serCOM1,
serCOM2,
serCOM3,
serCOM4,
serCOM5,
serCOM6,
serCOM7,
serCOM8
} eCOMPort;
typedef enum
{
serNO_PARITY,
serODD_PARITY,
serEVEN_PARITY,
serMARK_PARITY,
serSPACE_PARITY
} eParity;
typedef enum
{
serSTOP_1,
serSTOP_2
} eStopBits;
typedef enum
{
serBITS_5,
serBITS_6,
serBITS_7,
serBITS_8
} eDataBits;
typedef enum
{
ser50,
ser75,
ser110,
ser134,
ser150,
ser200,
ser300,
ser600,
ser1200,
ser1800,
ser2400,
ser4800,
ser9600,
ser19200,
ser38400,
ser57600,
ser115200
} eBaud;
/* This *MUST* match the order in the eBaud definition. */
unsigned portLONG ulBaudFromEnum[] =
{
( unsigned portLONG ) 50,
( unsigned portLONG ) 75,
( unsigned portLONG ) 110,
( unsigned portLONG ) 134,
( unsigned portLONG ) 150,
( unsigned portLONG ) 200,
( unsigned portLONG ) 300,
( unsigned portLONG ) 600,
( unsigned portLONG ) 1200,
( unsigned portLONG ) 1800,
( unsigned portLONG ) 2400,
( unsigned portLONG ) 4800,
( unsigned portLONG ) 9600,
( unsigned portLONG ) 19200,
( unsigned portLONG ) 38400UL,
( unsigned portLONG ) 57600UL,
( unsigned portLONG ) 115200UL
};
typedef struct xCOM_PORT
{
unsigned portSHORT sPort; /* comm port address eg. 0x3f8 */
unsigned portCHAR ucIRQ; /* comm IRQ eg. 3 */
/* Next two fields used for setting up the IRQ routine and
* (un)masking the interrupt in certain circumstances.
*/
unsigned portSHORT usIRQVector;
unsigned portCHAR ucInterruptEnableMast;
/* Read/Write buffers. */
xQueueHandle xRxedChars;
xQueueHandle xCharsForTx;
/* This lot are set up to minimise CPU time where accessing the comm
* port's registers.
*/
unsigned portSHORT usTransmitHoldReg;
unsigned portSHORT usReceiveDataRegister;
unsigned portSHORT usBaudRateDivisorLow;
unsigned portSHORT usBaudRateDivisorHigh;
unsigned portSHORT usInterruptEnableReg;
unsigned portSHORT usInterruptIDReg;
unsigned portSHORT usFIFOCtrlReg;
unsigned portSHORT usLineCtrlReg;
unsigned portSHORT usModemCtrlReg;
unsigned portSHORT usLineStatusReg;
unsigned portSHORT usModemStatusReg;
unsigned portSHORT usSCRReg;
unsigned portSHORT us8259InterruptServiceReg;
unsigned portSHORT us8259InterruptMaskReg;
/* This semaphore does nothing useful except test a feature of the
scheduler. */
xSemaphoreHandle xTestSem;
} xComPort;
typedef xComPort *xComPortHandle;
/* A xComPort structure can be associated with each IRQ. Initially none
are create/installed. */
xComPort *xPortStatus[ serMAX_IRQs ] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
/*-----------------------------------------------------------*/
/* These prototypes are repeated here so we don't have to include the serial header. This allows
the xComPortHandle structure details to be private to this file. */
xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength );
portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, portCHAR *pcRxedChar, portTickType xBlockTime );
portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, portCHAR cOutChar, portTickType xBlockTime );
portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort );
static void prvSetupPortHardware( xComPort *pxPort, eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits );
static portSHORT sComPortISR( const xComPort * const pxPort );
/*-----------------------------------------------------------*/
/* Define an interrupt handler for each slot in the xPortStatus array. */
#define COM_IRQ_WRAPPER(N) \
static void __interrupt COM_IRQ##N##_WRAPPER( void ) \
{ \
portDISABLE_INTERRUPTS(); \
if( sComPortISR( xPortStatus[##N##] ) ) \
{ \
portSWITCH_CONTEXT(); \
} \
}
COM_IRQ_WRAPPER( 0 )
COM_IRQ_WRAPPER( 1 )
COM_IRQ_WRAPPER( 2 )
COM_IRQ_WRAPPER( 3 )
COM_IRQ_WRAPPER( 4 )
COM_IRQ_WRAPPER( 5 )
COM_IRQ_WRAPPER( 6 )
COM_IRQ_WRAPPER( 7 )
COM_IRQ_WRAPPER( 8 )
COM_IRQ_WRAPPER( 9 )
COM_IRQ_WRAPPER( 10 )
COM_IRQ_WRAPPER( 11 )
COM_IRQ_WRAPPER( 12 )
COM_IRQ_WRAPPER( 13 )
COM_IRQ_WRAPPER( 14 )
COM_IRQ_WRAPPER( 15 )
static pxISR xISRs[ serMAX_IRQs ] =
{
COM_IRQ0_WRAPPER,
COM_IRQ1_WRAPPER,
COM_IRQ2_WRAPPER,
COM_IRQ3_WRAPPER,
COM_IRQ4_WRAPPER,
COM_IRQ5_WRAPPER,
COM_IRQ6_WRAPPER,
COM_IRQ7_WRAPPER,
COM_IRQ8_WRAPPER,
COM_IRQ9_WRAPPER,
COM_IRQ10_WRAPPER,
COM_IRQ11_WRAPPER,
COM_IRQ12_WRAPPER,
COM_IRQ13_WRAPPER,
COM_IRQ14_WRAPPER,
COM_IRQ15_WRAPPER
};
static pxISR xOldISRs[ serMAX_IRQs ] = { NULL };
/*-----------------------------------------------------------*/
xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )
{
xComPort *pxPort;
/* Create a structure to handle this port. */
pxPort = ( xComPort * ) pvPortMalloc( sizeof( xComPort ) );
if( pxPort != NULL )
{
/* Create the queues used by the comtest 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 );
prvSetupPortHardware( pxPort, ePort, eWantedBaud, eWantedParity, eWantedDataBits, eWantedStopBits );
return pxPort;
}
return NULL;
}
/*-----------------------------------------------------------*/
static void prvSetupPortHardware( xComPort *pxPort, eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits )
{
portSHORT sIn;
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -