簡介:在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的優先級數大,優先級低。