Chinaunix首页 | 论坛 | 博客
  • 博客访问: 225303
  • 博文数量: 49
  • 博客积分: 2101
  • 博客等级: 大尉
  • 技术积分: 525
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-07 10:38
文章分类

全部博文(49)

文章存档

2010年(49)

我的朋友

分类: 嵌入式

2010-09-07 13:50:16

1启动顺序

usrConfig.c ,usrInit()调用sysHwInit(), 对系统硬件进行基本的初始化,使其处于安静状态。sysHwInit()(在sysLib.c 中)调用sysSerial.c 中的sysSerialHwInit()BSP 串行器件进行初始化,使其处于静态;sysSerialHwInit()再通过xxDevInit()复位串行通道。

usrInit()函数的最后,产生根任务usrRoot()usrRoot()调用sysClkConnect()sysHwInit2()主要安装系统中断, 它调用sysSerialHwInit2() 连接串行中断。如果定义了INCLUDE_TTY_DEV,而没有定义INCLUDE_TYCODRV_5_2,usrRoot()任务中调用ttyDrv()来初始化串行设备驱动,并通过ttyDevCreate()函数创建串行设备。串行驱动是在VxWorks系统开始过程中被初始化的。

 

2. 编码步骤

1)初始化

①定义系统可支持的串行通道数。

②初始化驱动的设备描述

③写设备初始化代码

2)写入口程序

3)写中断服务程序管理中断

4)使用模板wind/target/src/drv/ssio/templateSio.c

 

3.详细步骤介绍

1)定义系统可支持的串行通道数。

config.h 中定义串口通道数NUM_TTY

2)初始化驱动的设备描述

TEMPLATE_CHAN 例子如下所示:

typedef struct

{

/* SIO_CHAN *MUST* be first */

SIO_CHAN sio; /* standard SIO_CHAN element */

UINT32 ioBase;

UINT32 vecBase;

UINT32 intLevel;

/* callbacks */

STATUS (*getTxChar) (void *, char *);

void (*putRcvChar) (void *, char);

void (*errorRtn) (void *, int, void *, int);

void * getTxArg;

void * putRcvArg;

void * errorArg;

/* misc */

int intConnect; /* intConnect done flag */

int baudFreq; /* current baud rate */

int mode; /* current mode (interrupt or poll) */

int clkFreq; /* input clock frequency */

uint_t options; /* Hardware options */

int scanMode; /* keyboard mapping mode */

} TEMPLATE_CHAN;

XX_DRV 结构中每一个通道有一个XX_CHAN 结构。

在上面的例子中,TEMPLATE_CHAN 中的SIO_CHAN 必须被第一个定义!

SIO_CHAN 指向SIO_DRV_FUNCS, SIO_DRV_FUNCS 结构提供驱动的入口函数。

SIO_DRV_FUNCS 定义在wind/target/h/sioLib.h 中。如下:

struct sio_drv_funcs /* driver functions */

{

int (*ioctl)

(

SIO_CHAN * pSioChan,

int cmd,

void * arg

);

int (*txStartup)

(

SIO_CHAN * pSioChan

);

int (*callbackInstall)

(

SIO_CHAN * pSioChan,

int callbackType,

STATUS (*callback)(void *, ...),

void * callbackArg

);

int (*pollInput)

(

SIO_CHAN * pSioChan,

char * inChar

);

int (*pollOutput)

3

(

SIO_CHAN * pSioChan,

char outChar

);

};

xxIoctl() 支持设备特定的ioctl 命令

xxTxStartup() 初始化一个传输循环(transmit cycle)

xxCallBackInstall() 安装到高层协议的入口(I/O system,target agent(目标代理),等等)

xxPollInput() 轮巡模式输入

xxPollOutPut() 轮巡模式输出

a.启动发送循环

因为串口发送数据时需要启动,xxTxStartup()就是用来启动串口数据发送,当发送成功后会触发串口中断,中断根据缓存中是否还有数据来决定是否继续发送,当缓存清空后串口将恢复初始状态,并等待下一次传送的启动。

b.驱动回调安装程序

回调用于层间协作,上层将本层函数安装在下层,这个函数就是回调,而下层在一定条件下触发回调,例如作为一个驱动,是一个底层,他在收到一个数据时,除了完成本层的处理工作外,还将进行回调,将这个数据交给上层应用层来做进一步处理,这在分层的数据通信中很普遍。

int xxCallbackInstall (pSioChan,callbackType, callback, callbackArg)

pSioChan 指向SIO_CHAN结构的指针

callbackTypSIO_CALLBACK_GET_TX_CHAR or SIO_CALLBACK_PUT_RCV_CHAR

callback 指向回调函数的指针

callbackArg:传给回调函数的参数

/******************************************************************************

*

* templateCallbackInstall - install ISR callbacks to get/put chars

*

* This driver allows interrupt callbacks for transmitting characters

* and receiving characters. In general, drivers may support other

* types of callbacks too.

*

* RETURNS: OK on success, or ENOSYS for an unsupported callback type.

*/

LOCAL int templateCallbackInstall

(

SIO_CHAN * pSioChan, /* channel */

int callbackType, /* type of callback */

STATUS (*callback)(void *,...), /* callback */

4

void * callbackArg /* parameter to callback */

) {

TEMPLATE_CHAN * pChan = (TEMPLATE_CHAN *)pSioChan;

switch (callbackType)

{

case SIO_CALLBACK_GET_TX_CHAR:

pChan->getTxChar = (STATUS (*)(void *, char *))callback;

pChan->getTxArg = callbackArg;

return (OK);

case SIO_CALLBACK_PUT_RCV_CHAR:

pChan->putRcvChar = (void (*)(void *, char))callback;

pChan->putRcvArg = callbackArg;

return (OK);

case SIO_CALLBACK_ERROR:

pChan->errorRtn = (void (*)(void *, int, void *, int))callback;

pChan->errorArg = callbackArg;

return (OK);

default:

return (ENOSYS);

} }

3)驱动初始化:void xxDevInit (pxxDrv)

这个函数是用来复位芯片,使芯片处于安静的状态。

4)写函数

用户通过I/O系统的write()操作是调用tyWrite()——在驱动列表中的ttyDrv的写入口函数。tyWrite()把数据拷贝到环形缓冲中,并且调用xxTxStartup( )来初始化一个发送周期。

当设备输出完毕后,设备就给CPU一个中断表示可以接受下一个字符,然后进入中断xxInTxt( )。函数xxIntTx ( )通过调用回调函数getTxChar从高层协议去字节,把字节写入到设备。如果需要的话清除中断。如果需要的话在没有数据等待发送的时候,复位发送中断。

5)读函数

串口的读操作相对于写操作来说复杂一些。数据的读写有两种方式:查询式和中断式。

查询方式根据事先设定的时间间隔定时读端口,不论端口是否有数据,操作都要进行。所以查询方式并不能完全适应实时操作系统的及时相应要求,因此在嵌入式实时操作系统中应用的比较少。而中断方式(或者类似中断的机制)则使用比较多。VxWorks提供的Select函数,可以使任务阻塞在一个或者多个I/O设备上,并能制定最多所等待的时间。利用Select函数可以将读串口设备的操作阻塞在设备的读操作上,当有数据可读时,被阻塞的任务就继续向下执行,这是就可以对串口继续读操作,将数据从端口读入。因此可以将读端口的操作单独放在一个任务中,利用Select将任务阻塞在端口读操作,而当端口有数据时继续该任务。Select函数是一种类似于事件触发的机制,利用Select函数可以实现类似于中断的方式的数据读操作。

下面简单说明一下利用Select实现串口的读操作。

FOREVER

{

/*清除等待设备集合中的读屏蔽位*/

FD_ZERO(&readFds);

/*初始化屏蔽位为等待串口状态*/

SerialDevFd,& readFds;

Width = SerialDevFd + 1;

/*阻塞,等待串口设备变为就绪状态*/

if(select(width,& readFds,NULL,NULL,NULL) == ERROR)

return (ERROR);

if(FD_ISSET(SerialDevFd,&readFds))

{

FOREVER

{

/*当端口仍有未读数据*/

If((DataLen = read(SerialDevFd,ComReadBuffer,MAX_IN_DATA)) == ERROR)

{

printf(“\nError in read comport”);

return(ERROR);

}

if(DataLen == 0)

breake;

/*处理所读出的数据,如将其写到缓存或直接处理*/

}

}

}

当采用中断方式读数据时,接收中断服务程序void xxIntRcvpSioChan)实现从设备中读字节,并通过调用回调函数putRcvChar来将字节传给高层协议。

/******************************************************************************

*

* templateSioIntRcv - handle a channel's receive-character interrupt

*

* RETURNS: N/A

*/

LOCAL void templateSioIntRcv

(

6

TEMPLATE_CHAN * pChan /* channel generating the interrupt */

)

{

char inChar; /* rcvr data */

char crData = 0; /* rcvr status */

STATUS status = OK;

/*

* TODO -

*

* Get status and data from the device. Determine if valid data is ready

* or not.

*

* For PCI devices, do an immediate return if device is not asserting

* an interrupt.

*/

TEMPLATE_SIO_READ8(pChan, TEMPLATE_CSR_ID, &crData);

/* Check for error conditions */

if (crData & TEMPLATE_CR_OKAY)

{

TEMPLATE_SIO_READ8(pChan, TEMPLATE_DATA_ID, &inChar);

#if 0 /* Keyboard emulation code */

/*

* TODO - For a keyboard type device we would map the raw scan code

* to ASCII, or other mapping. Do that here.

*/

if (pChan->scanMode == SIO_KYBD_MODE_ASCII)

inChar = templateAsciiTbl[(UINT8)inChar];

#endif

}

else

{

/*

* TODO - Determine precise error condition and perform

* recovery actions.

*/

status = ERROR;

7

}

/*

* TODO - Typically, acknowledge the interrupt as soon as possible.

* Usually before passing data or error conditions upstream.

*/

TEMPLATE_SIO_WRITE8(pChan,

TEMPLATE_CSR_ID, TEMPLATE_RESET_INT); /* ack interrupt*/

if (status == ERROR)

{

/* send error notification upstream */

(*pChan->errorRtn) (pChan->errorArg, SIO_ERROR_UNKNWN, NULL, 0);

}

else

{

/* send data character upstream */

(*pChan->putRcvChar) (pChan->putRcvArg, inChar);

} }

6 I/O控制函数ioctl()

指向驱动的标准I/O控制接口函数。此函数为任何驱动提供主要的控制接口。为了

实现标准的SIO设备的I/O控制,用以下的定义:

SIO_BAUD_SET 设定一个新的波特率

SIO_BAUD_GET 得到当前的波特率

SIO_HW_OPTS_SET 设定一个新的硬件属性

SIO_HW_OPTS_GET 得到当前的硬件属性

SIO_MODE_SET 设定一个新的操作模式

SIO_MODE_GET 得到当前的操作模式

SIO_AVAIL_MODES_GET 得到可能的模式

SIO_OPEN 打开一个通道

SIO_HUP 关闭一个通道

7)修改sysSerial.c

sysSerial.c,主要需要修改三个函数,sysSerialHwInit( ),sysSerialHwInit2( ),

sysSerialChanGet( )

sysSerialHwInit( )主要完成以下功能:初始化和硬件相关的的驱动的XX_CHAN结构(例如寄存器地址);调用xxDevInit()来执行实际的设备初始化;设定标志位来标志ISR仍然没有被安装。此函数是被sysHwInit( )调用的。

sysSerialHwInit2( )主要是连接中断服务程序。在intConnect()中的第三个参数应该是指向xx_CHAN结构的一个指针。此函数是由usrRoot任务在系统启动过程中由sysClkConnect()调用的。它设定标志位标志ISR已经被安装。sysSerialChanGet( )主要是把通道号转换成一个SIO_CHAN结构的指针。
阅读(1479) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~