天天看點

VXWORKS——驅動開發

簡介:在VxWorks嵌入式開發中,BootRom是VxWorks作業系統內建的啟動代碼,在Tomado內建開發環境的Build菜單中可以直接編譯BootRom,它的功能和U-boot類似,都是Bootloader程式。隻是BootRom是由VxWorks提供的一個bootloader程式,通過它可以和Tornado內建的一些工具進行VxWorks核心的下載下傳和調試工作。

  通常,BootRom軟體有以下功能:

  (1)通過序列槽下載下傳作業系統映像;

  (2)通過序列槽更新自身映像;

  (3)通過序列槽下載下傳系統配置檔案、系統資訊檔案;

  (4)加載作業系統映像,使其正常啟動;

  (5)其他的輔助功能,如位址内容檢視功能、位址内容修改功能和bootrom菜單顯示資訊控制功能

1、usrTffsConfig (0, 0, "/kernel" );

vxworks的tffs位于dosfs檔案系統和底層硬體中,目的是dosfs檔案系統是針對磁盤的FAT檔案系統,而大部分嵌入式儲存設備是flash,flash和磁盤在實體特性上差别很大,讀寫方式不同:磁盤是一個一個位元組修改,而flash在寫之前必須擦除,其擦除和寫有次數限制(大部分是10W次);tffs屏蔽了底層裝置差異。

dosfs位于tffs上層,包含翻譯層、MTD層和socket層。翻譯層由vxworks提供,不需要修改,我們隻需要修改MTD層和socket層。

翻譯層主要實作TrueFFS和dosFs之間的進階互動功能,也包含了控制flash映射到塊、wear-leveling、碎片回收和資料完整性所需的智能化處理功能。

MTD層:即裝置驅動層,包含flash讀、寫、擦除、ID識别等驅動。

socket層:用來提供tffs和闆卡硬體(如flash卡)的接口服務。

2、VXWORKS的BSP開發方法

一般分為公共特性的BSP開發和特有特性的BSP開發。

公共特性的開發對平台來說是各個産品需要做适配的工作,并且不需要修改或者修改很少的vxworks核心代碼,在核心配置中增加需要相應的特性即可。但增加特性後,會在BSP目錄下的config.h檔案增加INCLUDE宏;并且在usrboot()即核心啟動程式中添加相應的初始化函數。例如增加tffs特性:在核心配置tffs後,config.h會增加INCLUDE_TFFS宏,并自動在prjconfig.C檔案(此檔案也是根據配置生成的)的usrIosExtraInit()函數增加tffsDrv()和usrTffsConfig()函數。

特有特性的BSP開發是各個産品負責的,每個産品由于硬體配置不一樣,是以BSP特性也需要做相應的改變。這種特有特性的開發則需要将和BSP相關的.c和.h檔案放在自己的BSP目錄下,修改産品的初始化代碼,添加相關的BSP初始化(取代公共特性開發中vxworks自動添加的步驟)。例如增加tffs特性:不需要配置核心支援tffs特性,取代的是将systffs.c、systffs.h放在BSP目錄下,在初始化中添加tffsDrv()和usrTffsConfig()函數。

3、TFFS中兩大資料結構:FLSOCKET和FLFLASH

FLFLASH是MTD層維護資料的結構:結構中包含了MTD維護的資料和flash的操作方法,包括重映射、讀、寫、擦除等函數指針。這個資料結構包含socket指針,指向flash對應的socket資料結構。

FLSOCKET是socket層維護的資料結構:為TFFS提供了指向處理flash硬體接口的函數指針。

4.用usrTffsConfig()給flash挂接dos裝置

用usrTffsConfig(drive,removable,fileName)在tffs flash驅動裝置上挂在檔案系統。它的參數如下:

drive:制定tffs flash驅動裝置的驅動号,有效值是從0到BSP中套接字接口數量。

Removable:指定是否為可移動裝置。固定的為0,可移動的為1.

fileName:指定挂載點,例如,”/tffs0/”.

在shell中輸入tffsDevFormat(0,0) 成功後,繼續輸入usrTffsconfig(0,0,”/tffs0/”),傳回value=0=0x0,成功。

此時用 devs 指令檢視挂接的裝置名,發現 /tffs0/ ,說明裝置挂接成功。接下來就可以使用 dosfs 檔案系統相關指令操作 flash 裝置了,如 ls,copy 等。

VxWorks的裝置驅動程式有三張表來維護: Fd Table、Dev Table、Drv Table,分别表示檔案描述符表、裝置清單、驅動程式表。

調用open、read、write、ioctl這些函數時都要使用一個句柄即檔案描述符,即fd Table(檔案描述符表)。在終端模式下用指令iosFdShow函數檢視已使用的檔案描述符内容:

->iosFdShow

   fd         name                        drv

  3           /pcConsole/0           2

  4           /vio/1                          7

Fd Table中包含有句柄号(fd),對應的裝置名稱(name),驅動号(drv),這一個表聯系着另外兩個重要的表:Dev Table和Drv table。

dev tabel中維護系統中所有的裝置,在指令行中敲入devs便可以檢視dev Table的内容,就是裝置清單:

->devs

drv name

  0 /null

  1 /tyCo/0

  1 /tyCo/1

  2 /pcConsole/0

  2 /pcConsole/1

  4 /ata0a

  6 host:

  7 /vio

  8 /ghDev

  9 xxdev

dev table中包含兩個内容:一個是驅動号(drv),一個是裝置名稱(name),仔細對比上面的dev tabel和fd table就可以發現,這兩個表中裝置名稱和驅動号是對應着的。

Drv table ,驅動程式表,維護者所有的驅動程式,在指令行裡:

-> iosDrvShow

drv    create          delete             open           close             read            write            ioctl

  1    388660          0                   388660      3886a0     388eb0     388da0     3886e0

  2    30bae0          0                  30bae0            0           388eb0     388da0     30baf0

  3         0                 0                 384040       3840a0     3840d0     384120     384240

  4    36d3f0       36d7f0           36d030       36d490     36e180      36e1f0     36eb60

  5         0                 0                     0            33e970        33f8b0       33f2d0     356ec0

  6    348e80     349380         3499e0      349ec0       34c2f0       34c640     34c870

  7    3918c0          0              3918c0        3919a0       388eb0     388da0     391a40

  8    318620          0               318620       3186e0       318650     318680     3186b0

  9    318840     318850        318870      3188a0       318900     318930     3188d0

從上面的表中可以看到驅動号(drv)和七個函數。驅動号是驅動程式的一個索引号,這個索引将三張表聯系起來,任何一張表都能夠通過這個索引找到彼此;Drv table後面有七個驅動函數,下面所列的數字是這些函數的位址。

例如:

open的第一個參數是一個裝置名,系統就會首先在dev Table裝置清單中尋找該裝置名"/ghDev",找到之後就知道了這個裝置的驅動号8,8号裝置找到了怎麼執行相應的open函數呢,這時候系統找到Drv table中與8号對應的驅動程式們的位址,找到與open對應的函數的入口位址318620,便将程式跳轉至318620處執行。執行完後為這個已經open成功的8号裝置"/ghDev"配置設定一個fd,并添加到fd table中去,便于應用程式繼續使用該裝置。在執行完open之後,接着就要對裝置進行各種read\write操作,同樣在drv tabel中找到相應的入口函數執行。

兩個疑問:

1、怎樣把我的open函數、wrie函數等加到Drv Table中去呢?

2、怎麼讓系統把我自己的裝置也列入到dev table裝置清單中呢?

答案就是兩個函數:iosDrvInstall()、iosDevAdd()。

/dev/null是個黑洞裝置 ,它丢棄一切寫入其中的資料,空裝置通常被用于丢棄不需要的輸出流。任何寫入該裝置資料都會被丢棄掉。從這個裡面讀取資料傳回空(也有人認為是讀該空裝置,直接讀到檔案尾,那就是傳回-1)。将一些不用内容經常發送給這個裝置,丢棄不需要的資料。

5、taskSpawn 建立并激活一個新的任務

int taskSpawn

    (

    char          *name,        

    int           priority,     

    int           options,      

    int           stackSize,    

    FUNCPTR       entryPt,      

    int           arg1,         

    int           arg2,

    int           arg3,

    int           arg4,

    int           arg5,

    int           arg6,

    int           arg7,

    int           arg8,

    int           arg9,

    int           arg10 

    )

使用i檢視系統中的任務。

一般來說,應用程式的優先級不應當比系統任務高。系統預設任務優先級是100   最好把使用者任務優先級設定成100開外。

堆棧大小一般是根據你程式的記憶體使用情況而定的,如果拿不準,可以預設大一些,然後根據運作情況(Tornado裡有插件可以時時查詢)再降低。一般要有50%的餘量。

你可以先設定一個比較大的數,然後根據運作後的情況再減小棧,shell裡可以檢視到棧使用的峰值,你可以在這個基礎上考慮20%的備援。

如果棧溢出,那麼和記憶體越界操作是等同效果的。

6、任務的狀态

就緒(READY):任務隻需要等待CPU資源;

阻塞(PEND):由于CPU以外的資源不可用而阻塞;

睡眠(DELAY):任務處于睡眠狀态;

挂起(SUSPEND):這種任務狀态不能執行

DELAY+S既處于睡眠狀态又處于挂起狀态:挂起異常的任務(預設的異常處理)

PEND+S既處于阻塞狀态又處于挂起狀态

PEND+T逾時阻塞

PEND+S+T逾時阻塞并挂起

State+T處于state帶有一個繼承優先級的任務狀态。

7、控制任務排程的函數調用

kernelTimeSlice()控制輪轉排程:參數為時間片的長度,即每個任務放棄CPU給另一個同優先級的任務前,系統允許它運作的最大長度。

taskPrioritySet()改變任務的優先級

taskLock()禁止任務排程

taskUnlock()允許任務排程

wind核心的優先級 256個,編号0~255,優先級0最高,255最低。

任務的優先級在建立時指定,任務可以調用taskPrioritySet改變自己的優先級。

8、輪轉排程:讓優先級相同的、處于就緒态的任務公平的共享CPU。輪轉排程使用時間片來配置設定CPU,每個任務執行一個預先确定的時間段(即時間片)。

使用輪轉排程算法時,每個任務都有一個運作時間計數器

随着系統時鐘增加而增加,達到規定的值(時間片的值)時,清0,此時,任務放到所在優先級隊列的尾部。

一個新加入的任務放在所屬優先級隊列的尾部,計數器初始為0.當被高優先級任務搶占時,儲存它的目前運作時間計數器,下次被排程時,恢複這個值。

9、搶占上鎖

在實際應用中,有時候需要避免搶占,以免發生不合理的搶占或者發生一些意想不到的情況。wind的排程器提供:

taskLock()和taskUnlock()來禁止/允許搶占。

禁止:當該任務執行時,将不會發生基于優先級的搶占;

隻能防止任務的上下文切換,不能禁止中斷;

禁止搶占可以用來實作互斥;但應當盡量使禁止搶占時間最小。

vxworks動态連結功能很容易實作代碼共享,一個被多任務調用的單個備份稱為共享代碼。

共享代碼必須是可重入的:被多個任務同時調用而不會發生沖突。

慣例:

所有name_r()命名的子程式被認為是不可重入的;

vxworks的I/O驅動程式是可重入的。

編寫可重入代碼的技術:

使用動态堆棧變量;

使用信号量保護全局或靜态變量;

任務變量。

10、vxworks系統根任務:

usrRoot是核心執行的第一個任務。prjConfig.c檔案中有usrRoot()函數。

vxwork提供豐富的任務控制功能,包含在taskLib庫中。包括任務的建立、控制和擷取任務資訊。

11、taskSpawn

堆棧是系統資源,位于記憶體中,其底端是TCB(任務控制塊)和任務名,堆棧使用0xEE填充。

成功傳回任務ID号:四位元組

失敗傳回ERROR:

s_intlib_not_isr_callable程式不能從一個ISR中調用;

s_objlib_obj_id_error不正确的任務ID

s_memobjlib_not_initialized在指定的分區中,沒有足夠的記憶體用于發起任務

s_memlib_block_error不能對記憶體分區互斥通路

s_tasklib_illegal_priority非法的優先級

任務名約定:所有從目标機啟動的任務以字母t開頭命名,從主機啟動的任務以字母u開頭命名。

若沒有任務名,則vxworks為其配置設定一個獨一無二的名字tN,N是随未命名任務數遞增的一個十進制整數。

12、任務運作的控制

taskSuspend()挂起任務

taskResume()恢複任務

taskRestart()重新開機任務

taskDelay()任務延時,機關為tick,将會導緻任務呗移到相同優先級就緒隊列的尾部。例如taskDelay(0)可以将CPU交給同優先級的另一個任務。

nanosleep()任務延時,機關為納秒,參數不能是0.

13、POSIX和wind排程方法的差異:

不同:

POSIX排程基于程序,而WIND排程基于任務。

程序與任務的不同:

任務可以直接通路記憶體,而程序不可以;

程序僅僅繼承了父程序的特定特征,而任務則操作在與父任務完全一樣的環境中。

程序與任務的相似之處:

任務和程序都可以被單獨排程。

POSIX與wind的優先級編号方案不同:

POSIX的優先級數大,優先級高;

wind的優先級數大,優先級低。