嵌入式驅(qū)動(dòng)自學(xué)者的親身感受,有什么建議?
ID:技術(shù)讓夢(mèng)想更偉大
整理:李肖遙
嵌入式驅(qū)動(dòng)自學(xué)者的感受
學(xué)習(xí)嵌入式,或者說(shuō)學(xué)習(xí)現(xiàn)代的計(jì)算機(jī)編程,如果你想學(xué)好,有一個(gè)比較要求,那就是你能接受它的設(shè)定、它的模式。反過(guò)來(lái)說(shuō),當(dāng)你真正接受它的設(shè)定、它的模式,并記住它們時(shí),我認(rèn)為,你已經(jīng)學(xué)好了。 昨天,我又置之死地而后生了一次。 最近一直在搞驅(qū)動(dòng),一個(gè)LCD驅(qū)動(dòng)搞得我?guī)缀跻艞壚^續(xù)走嵌入式這條路。昨夜,睡不覺(jué),打開(kāi)嵌入學(xué)習(xí)視頻,躺在已關(guān)燈很久的房間的床上,大概凌晨3,4點(diǎn)吧。之前我一直都是學(xué)習(xí)著驅(qū)動(dòng)自編源碼的教學(xué),是那種幾乎和裸板程序沒(méi)多大區(qū)別的編程方式,只是多使用了一些向內(nèi)核注冊(cè)的接口函數(shù)。 而最近我想換一下,因?yàn)楹芏嘣O(shè)備驅(qū)動(dòng),內(nèi)核都是自帶的,而且是各種平臺(tái)的設(shè)備驅(qū)動(dòng)都有,我想如果能熟悉掌握內(nèi)核自帶驅(qū)動(dòng)的編程,那以后要做某個(gè)設(shè)備的驅(qū)動(dòng)時(shí),我只需要在自帶驅(qū)動(dòng)中修改一下便好了,通過(guò)學(xué)習(xí)LCD平臺(tái)設(shè)備的驅(qū)動(dòng),我了解了其編程想法,同時(shí)也認(rèn)同這種想法,甚至讓我疑惑,學(xué)習(xí)資料中教自編驅(qū)動(dòng)的意義,為何不直接教如果修改內(nèi)核源碼驅(qū)動(dòng)? 于是,繼續(xù)按著書(shū)去修改內(nèi)核驅(qū)動(dòng)源碼,但問(wèn)題是,書(shū)中說(shuō)他們這種修改,代碼成功運(yùn)行了,但我這,無(wú)論怎么調(diào)試都失敗,我反復(fù)檢測(cè),我的修改是否與書(shū)中一致,檢測(cè)了很多遍依然沒(méi)發(fā)現(xiàn)哪一步不同,不過(guò),有一點(diǎn)發(fā)現(xiàn)是,書(shū)中的內(nèi)核源碼和我內(nèi)核使用的源碼有一點(diǎn)點(diǎn)區(qū)別(當(dāng)然書(shū)里并沒(méi)有把所有的源碼都貼上,只是修改部分附近會(huì)聯(lián)帶著一些,這就是發(fā)現(xiàn),這些聯(lián)帶的沒(méi)需要修改的源碼和我的源碼有點(diǎn)區(qū)別,比如,我的源碼中多了一些設(shè)置(看似無(wú)關(guān)緊要的設(shè)置))。 與書(shū)核對(duì)無(wú)誤但失敗后,我又與成功運(yùn)行的自編驅(qū)動(dòng)核對(duì),我陸續(xù)發(fā)現(xiàn)我修改的內(nèi)涵源碼中,沒(méi)有去啟動(dòng)設(shè)備,也更沒(méi)有去點(diǎn)亮背光,而在顯存分配后的寄存器設(shè)置似乎也有問(wèn)題,因?yàn)檫@里的地址使用各種宏定義不同的累加或計(jì)算,最后算得地址和我的寄存器地址也不知是否吻合,因?yàn)轵?qū)動(dòng)源碼中最后計(jì)算得到的是虛擬地址。于是我對(duì)比自編驅(qū)動(dòng),一點(diǎn)點(diǎn)修改嘗試,到睡覺(jué)前都沒(méi)成功。 我是想學(xué)得理直氣壯一點(diǎn)的,最后是能一眼就能找到問(wèn)題,并迅速輕松解決問(wèn)題的,我也承認(rèn)自己確實(shí)是有些浮躁。但是經(jīng)過(guò)了昨晚床上的一點(diǎn)絕望的思考掙扎后,我好像想通了: 為什么嵌入式學(xué)習(xí)視頻老師要教自編驅(qū)動(dòng)。 下面我說(shuō)下自編驅(qū)動(dòng)與內(nèi)核驅(qū)動(dòng)源碼各自的問(wèn)題:
自便驅(qū)動(dòng):
程序簡(jiǎn)單簡(jiǎn)潔,它只能驅(qū)動(dòng)特定的某個(gè)設(shè)備。如果設(shè)備換了需要支持另一款設(shè)備,那么你需要重新修改該驅(qū)動(dòng);如果需要系統(tǒng)同時(shí)支持兩種LCD,那么它就會(huì)變成復(fù)雜并且對(duì)于內(nèi)核驅(qū)動(dòng)的簡(jiǎn)潔優(yōu)勢(shì)會(huì)削弱不少;如果你想驅(qū)動(dòng)支持多種設(shè)備,那自編驅(qū)動(dòng),相對(duì)了內(nèi)核驅(qū)動(dòng)源碼的簡(jiǎn)潔優(yōu)勢(shì)會(huì)變成了劣勢(shì),因?yàn)榫幊趟枷氲倪m用范圍不同而產(chǎn)生的結(jié)果。
內(nèi)核自帶驅(qū)動(dòng)源碼:
①?gòu)南到y(tǒng)層次去考量,變量、宏定義使用多, 甚至有些宏定義的值為了方便能讓各種在不同的階段需要不同的值調(diào)用,把簡(jiǎn)單的一個(gè)賦值調(diào)用變成了需要進(jìn)行多次運(yùn)算才能檢測(cè)到該值是否滿足使用要求,因?yàn)槲覀儾皇窃擈?qū)動(dòng)的編碼者,不清楚這樣做的好處,也或許是內(nèi)核驅(qū)動(dòng)源碼的開(kāi)發(fā)者從整個(gè)系統(tǒng)的編程簡(jiǎn)潔性去考量,這樣做或許也是為了讓整個(gè)系統(tǒng)代碼更少,簡(jiǎn)潔的一種做法,因?yàn)槊總€(gè)設(shè)備你都給它賦具體的值的話,整個(gè)系統(tǒng)中有幾百種驅(qū)動(dòng)設(shè)備源碼,給所有設(shè)備的這個(gè)位置參數(shù)都賦一個(gè)值的話,那各設(shè)備關(guān)于這個(gè)值的代碼就要多了幾百行了,所以還不如,讓各設(shè)備根據(jù)各種平臺(tái)去對(duì)某個(gè)宏進(jìn)行各自的計(jì)算來(lái)得到合適的值,但某些計(jì)算中相同的算法的也整合在一起,這樣就減少了系統(tǒng)不少行代碼。所以系統(tǒng)中驅(qū)動(dòng)源碼是系統(tǒng)開(kāi)發(fā)者對(duì)系統(tǒng)源碼的整合,是基于系統(tǒng)層的整合。所以,對(duì)于我這種對(duì)單個(gè)設(shè)備驅(qū)動(dòng)編碼的人,就會(huì)覺(jué)得系統(tǒng)源碼有好多不人性化的地方,會(huì)覺(jué)得簡(jiǎn)單的地方也被弄得很復(fù)雜。
②內(nèi)核自帶驅(qū)動(dòng)還有一些代碼是為了兼容以前的版本而添加了, 比如以前硬件內(nèi)存資源稀少,需要使用調(diào)色板的方法來(lái)減少程序運(yùn)行時(shí)的內(nèi)存使用量,這也會(huì)真假代碼的復(fù)雜性,這一步雖不是必要的,但如果沒(méi)弄好,那LCD驅(qū)動(dòng)也不能正常使用。
③程序復(fù)雜, 為了適用在多種設(shè)備型號(hào),更簡(jiǎn)單地添加不同型號(hào)的設(shè)備驅(qū)動(dòng),內(nèi)核對(duì)驅(qū)動(dòng)抽象分離,把驅(qū)動(dòng)分為平臺(tái)管理部分,驅(qū)動(dòng)代碼部分(與硬件無(wú)關(guān)碼),和設(shè)備代碼部分(硬件相關(guān)代碼)。用戶添加新型號(hào)設(shè)備驅(qū)動(dòng)時(shí),只需要在平臺(tái)管理部分檢查添加設(shè)備的匹配信息,和提供一個(gè)硬件設(shè)備相關(guān)的代碼(有格式)文件即可。 現(xiàn)在,站在驅(qū)動(dòng)開(kāi)發(fā)者而非系統(tǒng)開(kāi)發(fā)者的角度去衡量。
①自編的驅(qū)動(dòng),簡(jiǎn)潔,要點(diǎn)明確。 這個(gè)對(duì)于驅(qū)動(dòng)開(kāi)發(fā)者的用處就是:無(wú)論你使用的是哪個(gè)版本的內(nèi)核,哪個(gè)芯片平臺(tái),你可以通過(guò)自編碼比較簡(jiǎn)單方便地就可以確認(rèn)硬件設(shè)備的情況,是否正常。如果自編碼通過(guò),那可以試用自編碼上使用的參數(shù)去與內(nèi)核進(jìn)行核對(duì)、修改,然后再去測(cè)試。如果不成功,對(duì)于內(nèi)核中多余的設(shè)置(這些大多可能是提供內(nèi)核用做基本判斷的變量)可以先屏蔽,編譯出錯(cuò)了,根據(jù)提示,找到出錯(cuò)的位置修改添加。因?yàn)檫@些多余的設(shè)置,設(shè)置對(duì)了還行,設(shè)置錯(cuò)了,你又不好去定位錯(cuò)在哪。 自編的驅(qū)動(dòng)在此處的用處,調(diào)試時(shí),可以讓你排除多余的失敗可能性問(wèn)題,在較少的代碼去查出錯(cuò)誤位置,如果你確定你的設(shè)置滿足了該設(shè)備的必需設(shè)置,還是失敗,你可以比較放心地去懷疑是硬件問(wèn)題了。如果自編碼成功,那個(gè)又可以當(dāng)做你修改內(nèi)核驅(qū)動(dòng)的一個(gè)標(biāo)準(zhǔn)。
②內(nèi)核驅(qū)動(dòng)源碼支持管理多種型號(hào)的設(shè)備的優(yōu)勢(shì)是我用使用它的原因。 先了解本版本本平臺(tái)的設(shè)備驅(qū)動(dòng)結(jié)構(gòu),如果是添加型號(hào)支持,那就根據(jù)自編驅(qū)動(dòng)的參數(shù)與設(shè)置即可,如果是第一次啟動(dòng)這類設(shè)備,你就還需要檢測(cè)結(jié)構(gòu)是完整性,如果結(jié)構(gòu)完整,參數(shù)無(wú)誤依舊錯(cuò)誤,那就把內(nèi)核驅(qū)動(dòng)源碼精簡(jiǎn)到自編碼的簡(jiǎn)單粗暴設(shè)置吧。最終就變成了在基于內(nèi)核驅(qū)動(dòng)架構(gòu)下的自編驅(qū)動(dòng)。如果還不行,那無(wú)疑是結(jié)構(gòu)性問(wèn)題了。 所以自編驅(qū)動(dòng),還是有其存在價(jià)值的。內(nèi)核驅(qū)動(dòng)源碼內(nèi)容會(huì)變,平臺(tái)會(huì)變,但自編驅(qū)動(dòng)是變得最小的一個(gè),也是最容易實(shí)現(xiàn)驅(qū)動(dòng)目的的一個(gè)。是一碼打天下不可缺少的重要組成部分。
對(duì)于嵌入式驅(qū)動(dòng)開(kāi)發(fā)的建議
1) 為了今后的發(fā)展,你除了考慮廣度以外,更重要的是注意知識(shí)的深度。
譬如,做過(guò)網(wǎng)絡(luò)驅(qū)動(dòng),那么是不是只停留在會(huì)寫(xiě)驅(qū)動(dòng)的表層上,有沒(méi)有對(duì)Linux內(nèi)核的網(wǎng)絡(luò)結(jié)構(gòu),TCP/IP協(xié)議作過(guò)深入的了解。
2) 在Linux下開(kāi)發(fā)很多時(shí)候都要利用現(xiàn)成的東西,沒(méi)必要什么都自己搞。關(guān)鍵是變成自己的驅(qū)動(dòng)后是否了解原作者編寫(xiě)時(shí)背后的一些東西。你應(yīng)該不止是簡(jiǎn)單的讓它工作。寫(xiě)驅(qū)動(dòng)的時(shí)候就要考慮它的性能問(wèn)題,并給出測(cè)試的方法(當(dāng)然可以利用現(xiàn)成的許多工具,譬如測(cè)試網(wǎng)絡(luò)性能的netperf等)。
當(dāng)你寫(xiě)過(guò)Flash驅(qū)動(dòng),可能會(huì)知道Flash的性能有時(shí)候有多重要。
3) C程序的自我修煉,是否考慮到軟件工程方面的一些東西,程序的可維護(hù)性和擴(kuò)展性,譬如LCD驅(qū)動(dòng),是不是從Sharp到NEC的只需要集中修改很少的幾個(gè)地方?
對(duì)于不同品牌的Flash,如果使得Flash的驅(qū)動(dòng)做的更具有靈活性。
4) 如果有時(shí)間結(jié)余,可以關(guān)注Linux內(nèi)核的發(fā)展。譬如LCD的驅(qū)動(dòng)有沒(méi)有考慮到V4L2通用架構(gòu),譬如網(wǎng)絡(luò)驅(qū)動(dòng)用到了NAPI了嗎?當(dāng)然在此之前,假設(shè)已經(jīng)對(duì)LDD3, ULK2理解的比較熟了。
5) 現(xiàn)在所作的這些驅(qū)動(dòng)還算不得非常核心的東西。如果你想有更好的發(fā)展,可以考慮往audio,video,net方面發(fā)展,你應(yīng)該多注意真?zhèn)€行業(yè)需要什么樣的人才,上述每一項(xiàng)都需要很厚的底蘊(yùn),譬如video,需要了解MPEG4, H264等,怎么也要個(gè)1到2年才能算個(gè)入行阿,所以我建議不要只顧悶頭做東西,要適當(dāng)關(guān)注目前的一些應(yīng)用。
6) 對(duì)硬件知識(shí)的補(bǔ)給,做嵌入式Linux這一行不可能不讀硬件的Spec,如果你對(duì)硬件的工作機(jī)制理解的比較透,會(huì)有助你寫(xiě)出性能好的驅(qū)動(dòng)程序。
順便提一點(diǎn),適時(shí)的提高你的英語(yǔ)水平,對(duì)你的職業(yè)生涯絕對(duì)有幫助。(不要等需要的時(shí)候再補(bǔ),來(lái)不及)
7) 如果有時(shí)間,平時(shí)注意對(duì)Linux應(yīng)用程序編寫(xiě)的了解/積累,也將有助于你寫(xiě)出很好功能很好的驅(qū)動(dòng)程序。
8) 永遠(yuǎn)不能以為自己做了很多東西,就驅(qū)動(dòng)而言,像TVIN/TVOUT, USB, SDIO等等,好多未知領(lǐng)域呢。在問(wèn)題還沒(méi)有解決之前很難說(shuō)清是哪里不對(duì)了。
有時(shí)候是datasheet里面的一句話沒(méi)有注意,還有好幾次調(diào)不出來(lái)最后查到是PCB的問(wèn)題,所以有時(shí)候特別暈。
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!