RT-Thread设备框架学习感悟
前面幾周跟著野火的教程從0到1實現(xiàn)了RT-Thread的內(nèi)核,對RT-Thread的調(diào)度機制和線程、定時器的底層實現(xiàn)有了總體的了解。后面還需進一步對齊實現(xiàn)細節(jié)進行探索,但大致先了解其框架,后面再進行細致的了解。在學(xué)習(xí)新知識時,最重要的是思維模式的轉(zhuǎn)變。先了解其大致框架,再深入去了解細節(jié)。有些人(就是我,后來太痛苦終于悟了)學(xué)一個新知識,剛上來就從頭到尾一個字一個字仔細看,生怕錯過什么重要的內(nèi)容,搞不懂關(guān)鍵點就立馬停下來去查,一查發(fā)現(xiàn)哇!解釋內(nèi)容這么多,看解釋的時候又發(fā)現(xiàn)有不懂得地方,又停下來去查,如此一環(huán)套一環(huán),何時是個頭。而且這樣學(xué)習(xí)的結(jié)果就是學(xué)一個新知識很快就會筋疲力盡,覺得自己什么都不懂,自信心受到打擊,從而陷入對自己的深深懷疑之中,最后很可能放棄學(xué)習(xí)(這種學(xué)習(xí)方式就像C語言中函數(shù)的遞歸調(diào)用,一層套一層,層層套娃,很容易導(dǎo)致棧空間不夠用,最后造成程序崩潰。在陳正沖老師的《C語言深度剖析》中,就建議盡量不要使用遞歸,如果要使用一定要注意遞歸調(diào)用的深度和對應(yīng)使用的棧空間)!其實你想想看,這些知識是前人付出多少心血才總結(jié)出來的,哪可能會讓你一上來就搞得門兒清?除非你天賦異稟異于常人。因此在學(xué)習(xí)新知識的時候,先了解其大概,不求甚解,遇到了問題先保持疑問,帶著疑問繼續(xù)學(xué)下去。動手做起來再說,做的好不好,完不完美那是另一回事,先做,在做的過程中逐漸完善。有些人總是思前想后覺得要考慮的周到,完美再去做,這也沒錯,但是你考慮的就會和實際情況一模一樣嗎?在做中學(xué)習(xí),諸葛亮舌戰(zhàn)群儒說筆下雖有千言,而心中實無一策。我們也要做到不能心中雖有千言,而手上絲毫不動。很多問題其實在你學(xué)習(xí)后面的知識的過程中就自然而然的解決了。還記得去年學(xué)習(xí)Linux,對Linux的驅(qū)動開發(fā)、應(yīng)用開發(fā)學(xué)的是一知半解,云里霧里。那時還在學(xué)習(xí)RT-Thread,學(xué)了一段時間Linux之后回過頭再看RT-Thread發(fā)現(xiàn)好多在學(xué)習(xí)RT-Thread的疑問自然懂了。這就是當(dāng)你接觸了一個高等級的知識后,再回過頭去看低等級的知識時發(fā)現(xiàn)就豁然開朗了。
比如在深入學(xué)習(xí)STM32時,你就會發(fā)現(xiàn)main函數(shù)并不是上電就開始運行的第一個函數(shù),在main函數(shù)之前,在startup_xxx.S文件中(基于執(zhí)行效率的考慮,使用匯編語言編寫),系統(tǒng)做了好多事情,如完成堆和棧的內(nèi)存分配等,最后在跳轉(zhuǎn)到用戶main函數(shù)運行。假使這個時候你發(fā)現(xiàn)匯編語言好像你什么都不會,對ARM的架構(gòu)也不是很了解,然后買了本匯編語言和ARM-Cortex內(nèi)核權(quán)威指南吭哧吭哧的開始讀,希望能先解決掉這兩個不懂得內(nèi)容,你就會發(fā)現(xiàn)你看的時候?qū)嶋H上會碰到更多不懂得知識。假使你真的堅持住了,學(xué)完了這兩本書,肯定你的知識層次會提高很多,但同時和你一塊的人早都跑遠了。因此,在實際學(xué)習(xí)新知識時,先了解個大概,后面再去進行細節(jié)的完善,當(dāng)你有一個整個框架的時候再將細節(jié)逐漸補齊就會發(fā)現(xiàn)是水到渠成。
學(xué)習(xí)嵌入式的知識更要學(xué)會嵌入式的知識過于龐雜,硬件、協(xié)議、軟件,這每一個都是大部頭,如果心里沒有規(guī)劃,遇到什么都想去搞明白、研究透徹,那學(xué)來學(xué)去就忘記自己究竟想學(xué)什么了。確定自己學(xué)習(xí)的主線,先將該主線補齊,再去深入研究該主線上的分支。
當(dāng)設(shè)計一個產(chǎn)品時,需要使用單片機還是Linux取決于硬件成本和軟件成本,而不是一味的根據(jù)個人喜好去選擇高性能的或套件更完善的,嵌入式中沒有最好的,只有最合適的(此處可以參照清華大學(xué)曾鳴老師的《嵌入式ARM微控制器》,該課程邏輯清晰,值得反復(fù)刷)。因此,既要學(xué)會使用MCU跑裸機或RTOS用于一些低端的設(shè)備,也要學(xué)會Linux用于要求較高的場合。
在上層軟件對底層硬件的操作上,單片機和Linux的實現(xiàn)沒有太大的區(qū)別:
在單片機程序中沒有程序分層的概念,應(yīng)用程序和驅(qū)動程序混著寫,至少沒有明確的界限,很可能一個人就包攬了從硬件設(shè)計、模塊調(diào)試(針對各模塊進行驅(qū)動程序開發(fā),如開發(fā)SPI、I2C器件的通訊程序,對外留出調(diào)用接口)、功能實現(xiàn)(應(yīng)用程序開發(fā),即使用接口對外圍器件進行操作,程序?qū)崿F(xiàn)各個功能模塊的相互配合,從而實現(xiàn)既定功能)的全部內(nèi)容,一般小公司都這么干,講究全能型,什么活都能干,不需要有規(guī)范的標準,反正能搞出來,能以最短的時間實現(xiàn)既定的功能需求就是最好的。
Linux程序中驅(qū)動程序和應(yīng)用程序進行了分層,驅(qū)動程序訪問寄存器,應(yīng)用程序只能通過驅(qū)動程序?qū)崿F(xiàn)對寄存器的訪問,而不能直接去操作寄存器。為什么要設(shè)計成應(yīng)用分層有以下原因?
- 保證程序運行的安全性
Linux系統(tǒng)比較復(fù)雜,龐大,因此其中應(yīng)用程序很多。如果在軟件程序中開發(fā)對底層寄存器的訪問,那軟件的設(shè)計不良可能會導(dǎo)致程序運行崩潰。因此在Linux系統(tǒng)中,將對底層寄存器訪問的重要工作交給驅(qū)動程序去完成(系統(tǒng)認為驅(qū)動程序比較靠譜,只相信驅(qū)動程序的話,一般驅(qū)動程序開發(fā)需要即懂硬件又懂軟件,從而才能設(shè)計出可靠的驅(qū)動程序,一般該工作由驅(qū)動工程師完成)
- 保證應(yīng)用程序的可移植性
驅(qū)動程序是和底層硬件直接打交道的,因此驅(qū)動程序和硬件之間是強相關(guān)的。在A款芯片上開發(fā)的驅(qū)動程序想在B款芯片上面使用就要修改,因此只要硬件有改動,就需要檢查驅(qū)動程序是否也需要針對硬件的改動作出修改。而軟件程序是和驅(qū)動程序打交道的,具體點來說是和驅(qū)動程序的調(diào)用接口打交道的。只要驅(qū)動程序提供的調(diào)用接口不變,底層硬件如何改變,應(yīng)用程序是不會care的,也是不需要作任何修改的。這樣做的好處就是,在需要將A款芯片上的程序移植到B款芯片上的時候,只需要根據(jù)硬件的變化修改驅(qū)動程序,應(yīng)用程序不需要修改。
- 程序分層易于團隊協(xié)作
不像單片機程序,Linux項目一般規(guī)模比較大,一個人很難全套都搞定,因此就需要分工協(xié)作。將程序分為驅(qū)動程序和應(yīng)用程序有利于團隊協(xié)作,具體點就是做應(yīng)用程序的只需關(guān)心如何實現(xiàn)業(yè)務(wù)邏輯,做驅(qū)動程序的只需要關(guān)心如何能提供對硬件操作的接口。舉例假如要做一個人臉識別項目,有擅長做圖像處理的,只要能給到他圖像,他就能進行圖像分析,具體你這個圖像是用什么拍的,他是不關(guān)心的。而不同攝像頭的硬件操作可能是存在差異的,因此使用哪款硬件,驅(qū)動工程師就需要針對硬件進行驅(qū)動程序的更改。
?
前面對RT-Thread的內(nèi)核通過從0到1的實現(xiàn)已經(jīng)有了大概的認識,接下來學(xué)習(xí)RT-Thread的設(shè)備驅(qū)動框架,和Linux的驅(qū)動樹進行類比,其實RT-Thread的很多設(shè)計思想和具體實現(xiàn)都有借鑒Linux的設(shè)計,好的東西當(dāng)然大家都要借鑒!因此,學(xué)習(xí)RT-Thread設(shè)備驅(qū)動框架又會促進對Linux的設(shè)備樹的理解。白巖松說過,學(xué)習(xí)就是這樣一個相互作用的過程,當(dāng)你還不知道你學(xué)的知識有什么用的時候,堅持學(xué)就完事了。你不知道有什么用是因為你讀的書還太少,當(dāng)你讀的書多了,學(xué)的知識多了,這些點才會被連起來,到時候就不是零零散散,而會成勢。
RT-Thread的設(shè)備管理框架如上圖所示,可以將以上分為應(yīng)用層、驅(qū)動層、硬件層。RT-Thread的設(shè)計思想借鑒了Linux的應(yīng)用層和驅(qū)動層設(shè)計理念,因此其設(shè)備框架和Linux非常相似,也許以后RT-Thread會引入設(shè)備樹?
【應(yīng)用層】應(yīng)用層只需關(guān)心業(yè)務(wù)邏輯,而不需要關(guān)心底層硬件
【驅(qū)動層】對應(yīng)用層提供接口使其可以間接的使用硬件,從而搭建起了應(yīng)用層和硬件層之間的橋梁,驅(qū)動層未實現(xiàn)的硬件驅(qū)動應(yīng)用層無法調(diào)用。
【硬件層】具體的硬件,可配置其內(nèi)部的寄存器實現(xiàn)硬件功能的定制
可以這樣去理解,【硬件層】是一堆原材料,【驅(qū)動層】是一個工匠,他可以將這些原材料打造成各種各樣的工具,【應(yīng)用層】是人,他只能使用工匠打造好的工具而不能直接去使用原材料。
應(yīng)用層通過驅(qū)動層實現(xiàn)對硬件層設(shè)備的訪問,驅(qū)動層程序的升級更改并不會影響應(yīng)用層大程序。以此可以實現(xiàn)驅(qū)動層程序和應(yīng)用層程序的低耦合,可獨立進行開發(fā)。
要使用一個設(shè)備,要首先將其注冊到I/O設(shè)備管理器中,讓系統(tǒng)知道其的存在。設(shè)備被創(chuàng)建之后需要實現(xiàn)其對硬件的操作方法。根據(jù)設(shè)備功能的不同,可以選擇實現(xiàn)部分操作方法或全部操作方法。
當(dāng)設(shè)備被注冊到I/O設(shè)備管理器之后,用戶應(yīng)用程序通過I/O設(shè)備管理器的接口來訪問硬件設(shè)備。具體映射關(guān)系如下:
應(yīng)用程序需要對硬件進行操作時可以按照如下步驟:
或?qū)懺O(shè)備rt_size_t?rt_device_write(rt_device_t?dev, rt_off_t?pos,const?void* buffer, rt_size_t?size);或控制設(shè)備rt_err_t?rt_device_control(rt_device_t?dev, rt_uint8_t?cmd, void* arg);。
5、關(guān)閉設(shè)備rt_err_t?rt_device_open(rt_device_t?dev, rt_uint16_t?oflags);。打開設(shè)備和關(guān)閉設(shè)備一般需成對使用,因為打開設(shè)備會對打開設(shè)備次數(shù)加1,關(guān)閉設(shè)備會對打開的設(shè)備次數(shù)減1。如果不成對使用,則很可能設(shè)備并不會被完全關(guān)閉。例如調(diào)用了2次打開設(shè)備后調(diào)用1次關(guān)閉設(shè)備,實際上此時設(shè)備并未被關(guān)閉,仍是處于打開狀態(tài),只有當(dāng)設(shè)備打開次數(shù)減為0時才會真正關(guān)閉設(shè)備。
?
需要注意的是,只有官方提供的BSP包才可以使用ENV工具進行配置。RT-Thread官方已經(jīng)對主流芯片和開發(fā)板進行BSP包支持,因此在實際的項目使用中,我們可以先找自己項目使用的芯片對應(yīng)的BSP包,再使用ENV工具對內(nèi)核和功能組件進行配置,使用ENV下載軟件包,生成MDK項目工程,在此基礎(chǔ)之上進行項目開發(fā)。
ENV工具是針對全功能版本的RT-Thread源碼進行配置的工具,因此不適用于使用RT-Thread Nano的版本。ENV工具常用的命令也沒有幾條,用幾遍就記住了,記不住搜一下就出來了。
當(dāng)使用ENV工具在配置工程后重新創(chuàng)建工程時,會發(fā)現(xiàn)調(diào)試選項會恢復(fù)成默認的。針對此問題,在《嵌入式實時操作系統(tǒng) RT-Thread設(shè)計與實現(xiàn)》P193有說明,可以雙擊打開BSP中的template.uvprojx工程,直接修改其中的調(diào)試選項,如此使用Scons命令生成的新工程也會包含對模板文件中的修改。
?
RTT學(xué)習(xí)--制作BSP2https://blog.csdn.net/weixin_42381351/article/details/91127709
參考如上這篇文章將RT-Thread完整版移植到STM32F105芯片上。
?
總結(jié)
以上是生活随笔為你收集整理的RT-Thread设备框架学习感悟的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: koa --- 自制简易的koa-ro
- 下一篇: koa --- nunjucks