⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 st16954sio.c

📁 vxworks下串口驱动如何开发 主要针对16c954的非智能串口的初始化和 收发数据
💻 C
📖 第 1 页 / 共 2 页
字号:
/* st16954Sio.c - ST 16C552 DUART tty driver */

#include "copyright_wrs.h"

/*
DESCRIPTION
This is the device driver for the Startech ST16C552 DUART, similar, but
not quite identical to the National Semiconductor 16550 UART.

The chip is a dual universal asynchronous receiver/transmitter with 16
byte transmit and receive FIFOs and a programmable baud-rate
generator. Full modem control capability is included and control over
the four interrupts that can be generated: Tx, Rx, Line status, and
modem status.  Only the Rx and Tx interrupts are used by this driver.
The FIFOs are enabled for both Tx and Rx by this driver.

Only asynchronous serial operation is supported by the UART which
supports 5 to 8 bit bit word lengths with or without parity and with
one or two stop bits. The only serial word format supported by the
driver is 8 data bits, 1 stop bit, no parity,  The default baud rate is
determined by the BSP by filling in the ST16954_CHAN structure before
calling ambaDevInit().

The exact baud rates supported by this driver will depend on the
crystal fitted (and consequently the input clock to the baud-rate
generator), but in general, baud rates from about 50 to about 115200
are possible.

.SH DATA STRUCTURES
An ST16954_CHAN data structure is used to describe the two channels of
the chip and, if necessary, an ST16954_MUX structure is used to
describe the multiplexing of the interrupts for the two channels of the
DUART.  These structures are described in h/drv/sio/ambaSio.h.

.SH CALLBACKS
Servicing a "transmitter ready" interrupt involves making a callback to
a higher level library in order to get a character to transmit.  By
default, this driver installs dummy callback routines which do nothing.
A higher layer library that wants to use this driver (e.g. ttyDrv)
will install its own callback routine using the SIO_INSTALL_CALLBACK
ioctl command.  Likewise, a receiver interrupt handler makes a callback
to pass the character to the higher layer library.

.SH MODES
This driver supports both polled and interrupt modes.

.SH USAGE
The driver is typically only called by the BSP. The directly callable
routines in this module are st16954DevInit(), st16954Int(),
st16954IntRd(), st16954IntWr(), and st16954MuxInt.

The BSP's sysHwInit() routine typically calls sysSerialHwInit(), which
initialises all the hardware-specific values in the ST16954_CHAN
structure before calling st16954DevInit() which resets the device and
installs the driver function pointers. After this the UART will be
enabled and ready to generate interrupts, but those interrupts will be
disabled in the interrupt controller.

The following example shows the first parts of the initialisation:

.CS
#include "st16954Sio.h"

LOCAL ST16954_CHAN st16954Chan[N_16954_CHANNELS];

void sysSerialHwInit (void)
    {
    int i;

    for (i = 0; i < N_16954_CHANNELS; i++)
	{
	st16954Chan[i].regDelta = devParas[i].regSpace;
	st16954Chan[i].regs = devParas[i].baseAdrs;
	st16954Chan[i].baudRate = CONSOLE_BAUD_RATE;
	st16954Chan[i].xtal = UART_XTAL_FREQ;
	st16954Chan[i].level = devParas[i].intLevel;

	/@
	 * Initialise driver functions, getTxChar, putRcvChar and
	 * channelMode and init UART.
	 @/

	st16954DevInit(&st16954Chan[i]);
	}
    }
.CE

The BSP's sysHwInit2() routine typically calls sysSerialHwInit2(),
which connects the chips interrupts via intConnect() (either the single
interrupt `st16954Int', the three interrupts `st16954IntWr',
`st16954IntRd', and `st16954IntEx', or the multiplexed interrupt
handler `st16954MuxInt' which will cope with both channels of a DUART
producing the same interrupt). It then enables those interrupts in the
interrupt controller as shown in the following example:

.CS
void sysSerialHwInit2 (void)
    {
    /@ Connect the multiplexed interrupt handler @/

    (void) intConnect (INUM_TO_IVEC(devParas[0].vector),
			st16954MuxInt, (int) &st16954Mux);
    intEnable (devParas[0].intLevel);
    }
.CE

.SH BSP
By convention all the BSP-specific serial initialisation is performed
in a file called sysSerial.c, which is #include'ed by sysLib.c.
sysSerial.c implements at least four functions, sysSerialHwInit()
sysSerialHwInit2(), sysSerialChanGet(), and sysSerialReset(). The first
two have been described above, the others work as follows:

sysSerialChanGet is called by usrRoot to get the serial channel
descriptor associated with a serial channel number. The routine takes a
single parameter which is a channel number ranging between zero and
NUM_TTY. It returns a pointer to the corresponding channel descriptor,
SIO_CHAN *, which is just the address of the ST16954_CHAN strucure.

sysSerialReset is called from sysToMonitor() and should reset the
serial devices to an inactive state (prevent them from generating any
interrupts).

.SH INCLUDE FILES:
st16954Sio.h sioLib.h

SEE ALSO:
.I "Startech ST16C552 Data Sheet"
*/

#include "vxWorks.h"
#include "intLib.h"
#include "errnoLib.h"
#include "errno.h"
#include "sioLib.h"
#include "st16954Sio.h"


/* locals */

LOCAL BOOL multiplexed = FALSE;	/* whether int from mux-ed handler */

/* function prototypes */
STATUS st16954Ioctl (ST16954_CHAN * pSioChan, int request, int arg);
int st16954PollInput (ST16954_CHAN * pSioChan, char *);
int st16954PollOutput (ST16954_CHAN * pSioChan, char *, int);
LOCAL STATUS st16954DummyCallback ();
LOCAL void st16954InitChannel (ST16954_CHAN *);
LOCAL int st16954TxStartup (ST16954_CHAN * pSioChan);
int st16954CallbackInstall (ST16954_CHAN * pSioChan, int callbackType,
			       STATUS (*callback)(), void * callbackArg);


/* driver functions */

LOCAL SIO_DRV_FUNCS st16954SioDrvFuncs =
    {
    (int (*)())st16954Ioctl,
    (int (*)())st16954TxStartup,
    (int (*)())st16954CallbackInstall,
    (int (*)())st16954PollInput,
    (int (*)(SIO_CHAN *,char))st16954PollOutput
    };

/*******************************************************************************
*
* st16954DummyCallback - dummy callback routine.
*
* RETURNS: ERROR, always.
*/

LOCAL STATUS st16954DummyCallback (void)
    {
    return ERROR;
    }

/*******************************************************************************
*
* st16954DevInit - initialise an ST16954 channel
*
* This routine initialises some SIO_CHAN function pointers and then resets
* the chip in a quiescent state.  Before this routine is called, the BSP
* must already have initialised all the device addresses, etc. in the
* ST16954_CHAN structure.
*
* RETURNS: N/A
*/

void st16954DevInit
    (
    ST16954_CHAN *	pChan
    )
    {
    int oldlevel = intLock();


    /* initialise the driver function pointers in the SIO_CHAN */

    pChan->sio.pDrvFuncs = &st16954SioDrvFuncs;


    /* set the non BSP-specific constants */

    pChan->getTxChar = st16954DummyCallback;
    pChan->putRcvChar = st16954DummyCallback;

    pChan->channelMode = 0;    /* undefined */


    /* reset the chip */

    st16954InitChannel(pChan);

    intUnlock(oldlevel);

    }

/*******************************************************************************
*
* st16954InitChannel - initialise UART
*
* This routine performs hardware initialisation of the UART channel.
*
* RETURNS: N/A
*/
/* nBaudrate---2400,3200,4800,6525,7680,9309,9600,10593,11520,13050,14400,
        15360,19200,23040,26100,27927,28800,30720,31779,38400,51200,57600,
        76800,102400,115200,122880,153600,204800,307200,614400*/
/* nDataBits---8,7,6,5bits, nStopBits---1=1 stop bit, 2= 1.5 or 2 stop bits */
/* nParityBits---001B:even parity; 011B:odd parity; x0B: No parity; 101B,Parity 
   bit forced to 1; 111B, Parity bit forced to 0 */
/* mode---1: internal loop mode enabled; 0:Normal mode */

LOCAL void st16954InitChannel
    (
    ST16954_CHAN *	pChan	/* ptr to ST16954 struct describing channel */
    )
    {

    char inchar;
    unsigned int nLen;

    /* Reset Port */

    ST16954_REG_WRITE(pChan, SPR, SPR_CSR);
    ST16954_REG_WRITE(pChan, CSR, 0x00);
	
    /* Configure Port -  Set 8 bits, 1 stop bit, no parity. */

    /* Set Line Control Register */

    ST16954_REG_WRITE(pChan, LCR, LCR_EFREN);

    /* Set divisor latches to set baud rate */

    ST16954_REG_WRITE(pChan, DLL,  pChan->xtal/(16*pChan->baudRate));
    ST16954_REG_WRITE(pChan, DLM, (pChan->xtal/(16*pChan->baudRate)) >> 8);

     /* EFR, enhance mode select and CTS and RTS control disabled*/

    ST16954_REG_WRITE(pChan, EFR, EFR_ENM); 

    /* Enable access to the divisor latches by setting DLAB in LCR. */

    ST16954_REG_WRITE(pChan, LCR,  pChan->lcr);
	
    /* MCR, MCR4 = 1, Enable loop mode, MCR1 = 1, RTS active, enable external interrupt */

    if((pChan->mode) == 0)  /* normal mode */
    {
        ST16954_REG_WRITE(pChan, MCR,  MCR_DTR | MCR_RTS | MCR_INT);	  
    }
    else
    {
	ST16954_REG_WRITE(pChan, MCR,  MCR_LOOP | MCR_DTR | MCR_RTS | MCR_INT);	
    }

    if((pChan->fifosize) == 0)
    {
        ST16954_REG_WRITE(pChan, FCR,  FCR_RXCLR | FCR_TXCLR);
   }
    else
    {
        ST16954_REG_WRITE(pChan, FCR,  FCR_EN |FCR_RXCLR | FCR_TXCLR);
    }
	
    ST16954_REG_WRITE(pChan, SPR,  SPR_ACR);       
    ST16954_REG_WRITE(pChan, ACR,  ACR_950 | ACR_ICREN);	  
    ST16954_REG_WRITE(pChan, SPR,  SPR_TTL);      
    ST16954_REG_WRITE(pChan, TTL,  0x00);        
    ST16954_REG_WRITE(pChan, SPR,  SPR_RTL);        
    ST16954_REG_WRITE(pChan, RTL,  0x7F);        
    ST16954_REG_WRITE(pChan, SPR,  SPR_FCL);        
    ST16954_REG_WRITE(pChan, FCL,  0x01);        
    ST16954_REG_WRITE(pChan, SPR,  SPR_FCH);        
    ST16954_REG_WRITE(pChan, FCH,  0x7F);      
	
    ST16954_REG_WRITE(pChan, SPR, SPR_ACR); /* SPR = 0, PT ACR */

    ST16954_REG_READ(pChan, ACR, inchar);/* Get ACR to char inchar */

    ST16954_REG_WRITE(pChan, ACR, inchar | ACR_ADDEN | ACR_ICREN);/* Set ACR[7], to enable access to RFL, ect */

    ST16954_REG_READ(pChan, RFL, nLen);   /* Read RFL to get the number of characters in the receiver FIFO */
    nLen=nLen & 0xFF;
	
    ST16954_REG_WRITE(pChan, SPR, SPR_ACR);			            /* SPR = 0, PT ACR */

    /*ST16954_REG_WRITE(pChan, ACR, inchar & (~ACR_ADDEN) & (~ACR_ICREN)); */   /* Restore ACR, LSR enabled */
    ST16954_REG_WRITE(pChan, ACR, inchar & (~ACR_ADDEN));
	
    while (nLen > 0)
    {
        ST16954_REG_READ(pChan, RHR, inchar);				            /* Clear the reciever FIFO */
        nLen --;
    }
    /* Disable interrupts */

    ST16954_REG_WRITE(pChan, IER, pChan->ier);
    ST16954_REG_READ(pChan, RHR, inchar);

    }

/*******************************************************************************
*
* st16954Ioctl - special device control
*
* This routine handles the IOCTL messages from the user.
*
* RETURNS: OK on success, EIO on device error, ENOSYS on unsupported
* request.
*/

STATUS st16954Ioctl
    (
    ST16954_CHAN *		pChan, /* ptr to SIO_CHAN describing this channel */
    int			request,  /* request code */
    int			arg	  /* some argument */
    )
    {
    int 		oldlevel; /* current interrupt level mask */
    STATUS		status;	  /* status to return */
/*    ST16954_CHAN *	pChan = (ST16954_CHAN *)pSioChan;*/
    UINT32		brd;	  /* baud rate divisor */


    status = OK;	/* preset to return OK */
    switch (request)
	{
	case SIO_BAUD_SET:
	    /*
	     * Set the baud rate. Return EIO for an invalid baud rate, or
	     * OK on success.
	     *
	     * baudrate divisor must be non-zero and must fit in a 16-bit
	     * register.
	     */
	    brd = pChan->xtal/(16*arg);	/* calculate baudrate divisor */

	    if ((brd < 1) || (brd > 0xFFFF))
	    	{
	    	status = EIO;		/* baud rate out of range */
	    	break;
	    	}

	    /* disable interrupts during chip access */

	    oldlevel = intLock ();


	    /* Enable access to the divisor latches by setting DLAB in LCR. */

	    ST16954_REG_WRITE(pChan, LCR, LCR_EFREN);


	    /* Set divisor latches. */

	    ST16954_REG_WRITE(pChan, DLL, brd);
	    ST16954_REG_WRITE(pChan, DLM, brd >> 8);

            ST16954_REG_WRITE(pChan, EFR, EFR_ENM); 

	    /* Restore Line Control Register */

	    ST16954_REG_WRITE(pChan, LCR, pChan->lcr);

	    pChan->baudRate = arg;

	    intUnlock (oldlevel);

	    break;


	case SIO_BAUD_GET:
	    *(int *)arg = pChan->baudRate;
	    break;


	case SIO_MODE_SET:
	    if ((arg != SIO_MODE_POLL) && (arg != SIO_MODE_INT))
		{
		status = EIO;
		break;
		}

	    oldlevel = intLock ();

	    if (arg == SIO_MODE_INT)
		{
		/* Enable appropriate interrupts */
		ST16954_REG_WRITE(pChan,
				IER, pChan->ier | RxFIFO_BIT | TxFIFO_BIT);
		}
	    else
		{
		/* Disable the interrupts */
		ST16954_REG_WRITE(pChan, IER, 0);
		}

	    pChan->channelMode = arg;
	    intUnlock(oldlevel);

	    break;


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -