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