您当前的位置:五五电子网电子知识单片机-工控设备嵌入式系统-技术vxworks嵌入式操作系统下串行设备驱动程序开发思路 正文
vxworks嵌入式操作系统下串行设备驱动程序开发思路

vxworks嵌入式操作系统下串行设备驱动程序开发思路

点击数:7995 次   录入时间:03-04 11:37:01   整理:http://www.55dianzi.com   嵌入式系统-技术

    基于嵌入式操作系统的软件开发是国内外研究的热点,vxworks嵌入式操作系统又是目前最流行的嵌入式操作系统之一。本文的目的在于通过分析vxworks操作系统下串行通信设备驱动程序的运行机制,提出在此操作系统下开发串行设备驱动程序开发的基本思路。

    1. 概 述

    我们在基于vxworks嵌入式操作系统开发产品时,经常会根据自行设计的硬件电路开发专用的驱动程序。Vxworks下的驱动程序根据设备的不同特性,,大体可分为:char driver、serial driver、bLOCk driver、end driver、scsi driver等类型,其中以char driver最简单,最基础,以serial driver最常用。掌握驱动程序的基本工作流程,无论对我们开发上层的应用还是自己编写相应的驱动程序,都很有帮助。本文主要以i8250串口驱动程序为例,介绍一下串行驱动程序编写的基本思路。

    驱动程序,简而言之就是对具体的硬件设备进行管理和服务的程序。为了提高代码的可移植性,vxworks将所有的输入/输出设备都看成是一个文件,我们对设备的输入/输出操作,都可以看作是对指定文件的读写操作。例如,我们用c 标准库函数open()打开一个文件,可以是打开一个传统意义上的文本文件,也可以是指定一个输入/输出设备,如指定对某一个串口的输入/输出操作。在vxworks操作系统中,驱动程序的主要作用是完成对相关设备的读、写、打开、建立、关闭及控制等功能中的一项或几项,具体情况视具体的设备及设计要求而定。

    概括的说,驱动程序主要完成以下几项工作:

    (1)相关设备的初始化。

    (2)底层输入/输出函数与上层标准输入/输出函数的挂接。

    (3)相关设备与对应驱动程序的挂接。

    我们就按照这个思路,以I8250串口为例,分析一下串行设备驱动程序的编写及加载流程。首先,给出串行设备驱动的结构框图:

     

     

    需要说明的是,ttyDrv是一个虚拟的设备驱动,与tylib一起,用于处理I/O系统与底层实际设备之间的通信。主要完成以下工作:

    (1)处理I/O系统的各种需求,如在driver talbe 中添加相应的驱动条目、创建设备标识符(devise descriptor)。

    (2)实现与上层标准I/O函数及实际驱动程序的无缝连接。其中,ttyDrv完成open和ioctl两项功能(ttyopen()和ttyioctl())。Tylib完成read和write两项功能(tyRead()和tyWrite())。

    (3)管理输入/输出数据缓冲区。

    下面,我们结合图(一)给出的框图,以i8250为例,开始分析串行设备驱动的设计流程。用户在编写自己的驱动程序时,可以不按照系统函数命名的方法命名,也可以不按照系统给定的方法进行函数功能的划分,但其初始化及实现流程却不能改变。

    2. 驱动程序设计流程分析

    ⑴ i8250相关硬件设备的初始化。

    编写驱动程序的第一步是完成相关硬件的初始化。与I8250相关的硬件初始化函数主要有以下三个:sysSerialHwInit()、i8250HrdInit()、i8250InitChannel(),其调用顺序是:sysSerialHwInit()ài8250HrdInit()ài8250InitChannel(),这条工作链的主要作用是,完成对I8250_CHAN数据结构的初始化。

    下面对分别这几个函数的功能介绍一下:

    l

    sysSerialHwInit()

    本函数完成的主要任务是初始化设备的中断向量、串口的通信模式及相关存贮器,在函数的最后调用i8250HrdInit()对I8250_CHAN结构进一步初始化。

    void sysSerialHwInit (void)

    {

    int i;

    for (i=0;i

    {

    i8250Chan[i].int_vec = devParas[i].vector; /*初始化中断向量*/

    i8250Chan[i].channelMode = 0; /*初始化SIO_MODE 可以是INT或POLL*/

    i8250Chan[i].lcr = UART_REG(UART_LCR,i); /*初始化line control register*/

    ………………………

    i8250Chan[i].outByte = sysOutByte; /*挂接输出函数,此函数向指定的I/O地址写入1bye*/

    i8250Chan[i].inByte = sysInByte; /*挂接输出函数,此函数从指定的I/O地址读出1byte*/

    i8250HrdInit(&i8250Chan[i]);/*调用i8250HrdInit()进一步完成初始化*/

    }

    }

    l i8250HrdInit()

    本函数完成的主要工作是挂接相应的入口函数,具体说明如下:

    void i8250HrdInit

    (

    I8250_CHAN * pChan /* 指向相应设备的指针*/

    )

    {

    if (i8250SioDrvFuncs.ioctl == NULL)

    {

    i8250SioDrvFuncs.ioctl = (int (*)())i8250Ioctl;/*挂接用于处理控制I8250相关输入

    输出命令的函数*/

    i8250SioDrvFuncs.txStartup = (int (*)())i8250Startup;/*如果设备工作于中断模式下,

    启用此函数用于打开中断,使设备开始工作*/

    i8250SioDrvFuncs.callbackInstall = i8250CallbackInstall;/*安装上层提供的回调函数,

    本例中是安装的tyIRd()、tyITx()*/

    i8250SioDrvFuncs.pollInput = (int (*)())i8250PRxChar;/*挂接输入轮询函数*/

    i8250SioDrvFuncs.pollOutput = (int (*)(SIO_CHAN *,char))i8250PTxChar;/*挂接输出轮询函数*/

    }

    pChan->pDrvFuncs = &i8250SioDrvFuncs;/*初始化CHAN结构,挂接接口函数列表*/

    i8250InitChannel(pChan); /* reset the channel */

    }

    由上面挂接的函数可以看出,i8250驱动主要实现了三个功能:read、write、ioctl,而并没有实现所有和七项功能。同时,值的注意的是,对同一种设备的驱动只需挂接一次。

    同时ttyDrv通过SIO_DRV_FUNCS使用xxDrv(i8250Drv)提供的服务,而xxDrv通过回调函数(本例中是由i8250CallbackInstall()安装的tyIRd()、tyITx())完成ttyDrv提出的请求。原理如下图示:

     

7

    i8250InitChannel()

    本函数的主要作用是初始化特定的CHAN所描述的信道。具体分析如下。

    statIC void i8250InitChannel

    (

    I8250_CHAN * pChan /* pointer to device */

    )

    {

    int oldLevel;

    ldLevel = intLock (); /*关中断进入临界区*

    (void) i8250BaudSet(pChan, I8250_DEFAULT_BAUD);/*设置信道的波特率*/

    …………………………………

    intUnlock (oldLevel); /*开中断响应,出临界区*/

    }

    ⑵ 挂接中断服务程序

    对i8250的硬件初始化完成后,接着挂接相关的中断服务程序。主要有sysSerialHwinit2()函数完成。需要注意的是,挂接中断应放在系统初始化的最后,主要是因为中断挂接函数iNTCONnect()需要调用malloc()函数,如果在系统的内存分配还未初始化前调用,则会出错。下面请看源代码:

    void sysSerialHwInit2 (void)

    {

    int i;

    for (i=0;i

    if (i8250Chan[i].int_vec)

    {

    (void) intConnect (INUM_TO_IVEC (i8250Chan[i].int_vec), i8250Int, (int)&i8250Chan[i] );

    sysIntEnablePIC (devParas[i].intLevel);

    }

    }

    其中,宏INUM_TO_IVEC的作用是把中断号转为中断向量。i8250Int是指向输入/输出中断处理函数的指针。描述相应硬件的结构i8250Chan为函数i8250int()的入口参数。

    至此,设备硬件的初始化、相关的低层函数的挂接、中断初始化基本完成。开始进行下一步,将设备的驱动函数安装在Driver Table 中。

    ⑶ 与上层标准输入/输出函数的挂接

    在此处I/O系统通过调用ttyDrv()(在没有定义INCLUDE_TYCODRV_5_2的情况下)将相应驱动函数添加到Driver Table中,从而完成与上层标准输入/输出函数的挂接。

     

[1] [2]  下一页


本文关键字:嵌入式  操作系统  程序开发  嵌入式系统-技术单片机-工控设备 - 嵌入式系统-技术