1. 程式人生 > >實時系統的裝置驅動實現

實時系統的裝置驅動實現

        第一是筆者看到了關於RTOS驅動開發介紹的文章,作者的特點是從系統的層次上分析問題(為大家鋪路),好東西大家一起用(博大的胸襟);第二是筆者能夠看懂一些,分享一下,爭取做到準確...         筆者一位低一年級的同學參加過嵌入式軟體的培訓,告訴我他學過ARM板上寫Linux驅動,我很羨慕,因為寫驅動是比較難的事情,這裡思考的是UCOS的驅動設計 ,至今沒做過Linux驅動。
        裝置驅動一般包含2個方面:一個是任務級的處理,另一個是中斷處理。對資料的處理以及上述2個方面的協調,是非常重要的,而且需要解決很多細節問題。
裝置驅動的兩個方面
許多裝置驅動都支援中斷。事實上,如果裝置驅動編寫時不考慮中斷,就容易很多。這是因為編寫無中斷支援的裝置驅動更為簡單,如果學會了怎樣編寫支援中斷的驅動,那麼其他的實現也就輕而易舉了。先簡單回顧一下裝置驅動的基礎:初始化,傳送,接收,控制,關閉。這根本沒什麼難的!大多數情況下,裝置驅動就這麼些內容,當然也可以新增一些額外的錯誤處理,或者提供一個ioctl()函式,但最主要的就是能夠收發資料。沒什麼太複雜的!那為什麼我們在編寫裝置驅動時,總覺得被束縛而難以開始呢?這一般是因為,在正常工作之前,除非有一些適合的工具,否則不能看到裝置在做什麼。但是,如果有正確的框架,讓裝置工作起來還是很容易的。
        在RTOS下,我們所說的裝置驅動的兩個方面是指什麼呢?一方面是任務環境的介面(API),另一方面是中斷服務及相關處理。協調這兩方面的潛在問題是什麼呢?一個是資料破壞;另一個是任務排程。資料破壞如沒有二次訪問的保護;任務排程,不合理的任務排程,可能導致系統崩潰。 使用UCOS的互斥訊號量機制實現串列埠驅動的設計
void OutputByte(char c)
{
 OSMutexPend(&Recmutex,0,&err);
 USARTSendChar(c);
 while(status);                //等待發送完畢
 OSMutexPost(&Recmutex);
}
這裡串列埠資源只有一個,互斥訊號也是一個,以下串列埠資源等同於一個互斥訊號。
1.互斥訊號量申請到資源時會鎖定該訊號(flag = 0),使用完成後用OSMutexPost來釋放訊號(flag = 1)。
2.如果當前任務申請該訊號時,該資源未被釋放(flag = 0),就將當前任務放到訊息等待佇列中並掛起當前任務。
3.OSMutexPost函式首先檢查有無任務等待該訊號,有則喚醒等待佇列中優先順序最高的任務,沒有就釋放訊號(flag = 1)。 這裡面為什麼看不到中斷服務呢? Colin Walls給的中斷例子
void OutputCharacter(char c)
{
 if(PortReadyFlag != TRUE)
 {
  AddToPortWait(ThisTaskID);  //
  SuspendTask();
 }
 PORTOUTPUT = c;
}
這段程式碼檢查現在是否可以輸出字元。如果不能,他將建立一個機制,使得當該埠就緒時,中斷服務(ISR)例程能通知該任務,然後當前任務被掛起,直到知道埠有效,輸出字元。這裡所謂的機制(埠就緒時,觸發中斷服務,ISR例程能通知該任務)可以通過配置相應的串列埠中斷實現。
針對這個埠的ISR
interrupt void WriterPort(void)
{
 TASKID tid;
 PortReadyFlag = TRUE;
 tid = GetFromPortWaitList();
 if(tid!=NULL)
 {
  PortReadyFlag = FALSE;
  ResumeTask(tid);  //使該任務就緒
  RunScheduler(); //任務排程
 }
}
這是另一種裝置驅動的實現方式,由於使用了中斷,實時性很高。這裡也回答了上面的例子看不到中斷,原因是UCOS是搶佔式任務排程,只需將對應任務設為就緒狀態,就能執行到該任務(當無更高優先順序的就緒任務時),無需自行切換到該任務。 總結:這裡介紹的是實時系統的裝置驅動實現,當用到多工排程時,應該對相應的外設包裝,確保不會發生衝突和系統崩潰。對於Windows和Linux裝置驅動的實現原理,筆者沒見過。不論哪種系統,如果所以裝置驅動都按統一的模板來編寫,可以減少很多麻煩。
所涉及內容參考書籍
Colin Walls的《嵌入式軟體概論》(我見過最好的“概論”了) 邵貝貝譯的uc/os II (第二版)