<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > vxworks嵌入式操作系統串行設備驅動(dòng)程序的編寫(xiě)

vxworks嵌入式操作系統串行設備驅動(dòng)程序的編寫(xiě)

作者: 時(shí)間:2012-08-21 來(lái)源:網(wǎng)絡(luò ) 收藏

摘要:目前,基于的軟件開(kāi)發(fā)是國內外研究的熱點(diǎn),又是目前最流行的之一。本文的目的在于通過(guò)分析操作系統下通信的運行機制,提出在此操作系統下開(kāi)發(fā)開(kāi)發(fā)的基本思路。

本文引用地址:http://dyxdggzs.com/article/148563.htm

1. 概 述

我們在基于嵌入式操作系統開(kāi)發(fā)產(chǎn)品時(shí),經(jīng)常會(huì )根據自行設計的硬件電路開(kāi)發(fā)專(zhuān)用的。Vxworks下的驅動(dòng)程序根據的不同特性,,大體可分為:char driver、serial driver、block driver、end driver、scsi driver等類(lèi)型,其中以char driver最簡(jiǎn)單,最基礎,以serial driver最常用。掌握驅動(dòng)程序的基本工作流程,無(wú)論對我們開(kāi)發(fā)上層的應用還是自己相應的驅動(dòng)程序,都很有幫助。本文主要以i8250串口驅動(dòng)程序為例,介紹一下驅動(dòng)程序的基本思路。

驅動(dòng)程序,簡(jiǎn)而言之就是對具體的硬件設備進(jìn)行管理和服務(wù)的程序。為了提高代碼的可移植性,vxworks將所有的輸入/輸出設備都看成是一個(gè)文件,我們對設備的輸入/輸出操作,都可以看作是對指定文件的讀寫(xiě)操作。例如,我們用c 標準庫函數open()打開(kāi)一個(gè)文件,可以是打開(kāi)一個(gè)傳統意義上的文本文件,也可以是指定一個(gè)輸入/輸出設備,如指定對某一個(gè)串口的輸入/輸出操作。在vxworks操作系統中,驅動(dòng)程序的主要作用是完成對相關(guān)設備的讀、寫(xiě)、打開(kāi)、建立、關(guān)閉及控制等功能中的一項或幾項,具體情況視具體的設備及設計要求而定。

概括的說(shuō),驅動(dòng)程序主要完成以下幾項工作:

(1)相關(guān)設備的初始化。

(2)底層輸入/輸出函數與上層標準輸入/輸出函數的掛接。

(3)相關(guān)設備與對應驅動(dòng)程序的掛接。

我們就按照這個(gè)思路,以I8250串口為例,分析一下串行設備驅動(dòng)程序的及加載流程。首先,給出串行設備驅動(dòng)的結構框圖:

需要說(shuō)明的是,ttyDrv是一個(gè)虛擬的設備驅動(dòng),與tylib一起,用于處理I/O系統與底層實(shí)際設備之間的通信。主要完成以下工作:

(1)處理I/O系統的各種需求,如在driver talbe 中添加相應的驅動(dòng)條目、創(chuàng )建設備標識符(devise descriptor)。

(2)實(shí)現與上層標準I/O函數及實(shí)際驅動(dòng)程序的無(wú)縫連接。其中,ttyDrv完成open和ioctl兩項功能(ttyopen()和ttyioctl())。Tylib完成read和write兩項功能(tyRead()和tyWrite())。

(3)管理輸入/輸出數據緩沖區。

下面,我們結合圖(一)給出的框圖,以i8250為例,開(kāi)始分析串行設備驅動(dòng)的設計流程。用戶(hù)在編寫(xiě)自己的驅動(dòng)程序時(shí),可以不按照系統函數命名的方法命名,也可以不按照系統給定的方法進(jìn)行函數功能的劃分,但其初始化及實(shí)現流程卻不能改變。

2. 驅動(dòng)程序設計流程分析

⑴ i8250相關(guān)硬件設備的初始化。

編寫(xiě)驅動(dòng)程序的第一步是完成相關(guān)硬件的初始化。與I8250相關(guān)的硬件初始化函數主要有以下三個(gè):sysSerialHwInit()、i8250HrdInit()、i8250InitChannel(),其調用順序是:sysSerialHwInit()ài8250HrdInit()ài8250InitChannel(),這條工作鏈的主要作用是,完成對I8250_CHAN數據結構的初始化。

下面對分別這幾個(gè)函數的功能介紹一下:

l

sysSerialHwInit()

本函數完成的主要任務(wù)是初始化設備的中斷向量、串口的通信模式及相關(guān)存貯器,在函數的最后調用i8250HrdInit()對I8250_CHAN結構進(jìn)一步初始化。

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地址寫(xiě)入1bye*/

i8250Chan[i].inByte = sysInByte; /*掛接輸出函數,此函數從指定的I/O地址讀出1byte*/

i8250HrdInit(i8250Chan[i]);/*調用i8250HrdInit()進(jìn)一步完成初始化*/

}

}

l i8250HrdInit()

本函數完成的主要工作是掛接相應的入口函數,具體說(shuō)明如下:

void i8250HrdInit

(

I8250_CHAN * pChan /* 指向相應設備的指針*/

)

{

if (i8250SioDrvFuncs.ioctl == NULL)

{

i8250SioDrvFuncs.ioctl = (int (*)())i8250Ioctl;/*掛接用于處理控制I8250相關(guān)輸入

輸出命令的函數*/

i8250SioDrvFuncs.txStartup = (int (*)())i8250Startup;/*如果設備工作于中斷模式下,

啟用此函數用于打開(kāi)中斷,使設備開(kāi)始工作*/

i8250SioDrvFuncs.callbackInstall = i8250CallbackInstall;/*安裝上層提供的回調函數,

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

i8250SioDrvFuncs.pollInput = (int (*)())i8250PRxChar;/*掛接輸入輪詢(xún)函數*/

i8250SioDrvFuncs.pollOutput = (int (*)(SIO_CHAN *,char))i8250PTxChar;/*掛接輸出輪詢(xún)函數*/

}

pChan->pDrvFuncs = i8250SioDrvFuncs;/*初始化CHAN結構,掛接接口函數列表*/

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

}

由上面掛接的函數可以看出,i8250驅動(dòng)主要實(shí)現了三個(gè)功能:read、write、ioctl,而并沒(méi)有實(shí)現所有和七項功能。同時(shí),值的注意的是,對同一種設備的驅動(dòng)只需掛接一次。

同時(shí)ttyDrv通過(guò)SIO_DRV_FUNCS使用xxDrv(i8250Drv)提供的服務(wù),而xxDrv通過(guò)回調函數(本例中是由i8250CallbackInstall()安裝的tyIRd()、tyITx())完成ttyDrv提出的請求。原理如下圖示:

i8250InitChannel()

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

static void i8250InitChannel

(

I8250_CHAN * pChan /* pointer to device */

)

{

int oldLevel;

ldLevel = intLock (); /*關(guān)中斷進(jìn)入臨界區*

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

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

intUnlock (oldLevel); /*開(kāi)中斷響應,出臨界區*/

}

⑵ 掛接中斷服務(wù)程序

對i8250的硬件初始化完成后,接著(zhù)掛接相關(guān)的中斷服務(wù)程序。主要有sysSerialHwinit2()函數完成。需要注意的是,掛接中斷應放在系統初始化的最后,主要是因為中斷掛接函數intCONnect()需要調用malloc()函數,如果在系統的內存分配還未初始化前調用,則會(huì )出錯。下面請看源代碼:

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()的入口參數。

至此,設備硬件的初始化、相關(guān)的低層函數的掛接、中斷初始化基本完成。開(kāi)始進(jìn)行下一步,將設備的驅動(dòng)函數安裝在Driver Table 中。

⑶ 與上層標準輸入/輸出函數的掛接

在此處I/O系統通過(guò)調用ttyDrv()(在沒(méi)有定義INCLUDE_TYCODRV_5_2的情況下)將相應驅動(dòng)函數添加到Driver Table中,從而完成與上層標準輸入/輸出函數的掛接。

由上圖知,iosDrvInstall()函數在Driver Table中掛接的函數是tyWrite()和tyRead(),而不是我們實(shí)際編寫(xiě)的輸入/輸出函數。其具體的調用過(guò)程是:

① 當用戶(hù)調用write函數進(jìn)行寫(xiě)操作時(shí),根據相應的fd調用在Driver Table中注冊的函數tyWrite(),此函數的作用是將用戶(hù)緩沖區的內容寫(xiě)入相應的輸出ring buffer,當發(fā)現緩沖區內有內容時(shí),開(kāi)始調用回調函數tyITX(),從ring buffer讀取字符,由I8250Startup()啟動(dòng)中斷輸出,最后由設備的輸出中斷服務(wù)程序(在本例中調用的是sysOutbyte())將字符發(fā)往指定的串口。

② 當串口接收到數據時(shí)會(huì )調用輸入中斷服務(wù)程序(在本例中是sysInbyte()),將輸入的字符寫(xiě)入指定的緩沖區。然后由回調函數tyIRd()將緩沖區的內容讀入ring buffer,當用戶(hù)調用read函數進(jìn)行寫(xiě)操作時(shí),會(huì )根據相應的fd調用在Driver Table中注冊的函數tyRead(),此函數會(huì )將ring buffer中的內容讀入用戶(hù)緩沖區。

關(guān)于具體的中斷輸入/輸出函數如何調用,本文不做詳細分析,請參閱i8250int()及i8250Startup()。

對于輸入/輸出控制函數ioctl()的掛接,則是直接將命令傳到由用戶(hù)編寫(xiě)的i8250ioctl()函數,其具體的實(shí)現代碼與驅動(dòng)的設計思路無(wú)緊密的聯(lián)系,本文也不做具體分析。

⑷ 具體設備與相關(guān)驅動(dòng)的掛接

當Driver Table中相應的驅動(dòng)函數掛接完成,開(kāi)始編寫(xiě)驅動(dòng)程序的最后一步:在Device Table中加入設備,完成具體設備與相關(guān)驅動(dòng)的掛接。此項工作是由ttyDevCreat()函數完成的。本函數主要實(shí)現以下功能:

① 分配并初始化一個(gè)device descriptor。

② 通過(guò)調用tyDevInit()初始化tyLib。此處主要完成輸入/輸出ring buffer的創(chuàng )建、建立用與相關(guān)函數的信號量、初始化selectLib。

③ 調用iosDevAdd()將串口設備加入Device Table。對于設備特性的描述信息是由sysSerialChanGet()函數得到,并以參數形式傳入的。

④ 為底層設備安裝回調函數,在本例中是為i8250CHAN 安裝tyIRd()、tyITx()兩處回調函數。

⑤ 開(kāi)中斷,設備開(kāi)始以中斷方式工作。

至此,驅動(dòng)程序的分析全部完成。與掛接驅動(dòng)函數不同,在安裝設備的過(guò)程中,無(wú)論設備相同與否,有幾個(gè)設備則上述過(guò)程需調用幾次。以上各函數的加載主要在usrinit()函數中完成。

3. 結束語(yǔ)

需要說(shuō)明的是,在VxWorks下,設備驅動(dòng)程序既可以嵌入內核隨系統一起啟動(dòng),也可以作為可加載模塊在系統啟動(dòng)之后運行。相比之下,后一種方式比較簡(jiǎn)單,不用修改系統內核,引入錯誤的可能性小。但是無(wú)論采取哪種方式,其基本思路及需要完成的工作是相同的。本文沒(méi)有按照系統的調用過(guò)程進(jìn)行一步步分析,主要基于上述考慮。用戶(hù)在編寫(xiě)相關(guān)驅動(dòng)程序時(shí),中心任務(wù)是按步驟完成上述功能,而沒(méi)有必要去死搬系統的加載步驟。

linux操作系統文章專(zhuān)題:linux操作系統詳解(linux不再難懂)


評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>