經過兩個星期的學習,終于成功寫出了第一個驅動程式->點亮LED小燈;感覺聽上去很簡單似的,哈哈,樓主我可是經過了無數次實驗才成功移植U-boot、Linux核心、最小根檔案系統,并完成了LED控制的驅動,過程經曆了多次百度CSDN論壇,還有請教韋老師,最後能夠在開發闆上完全運作,并對Linux驅動開發有了初步的了解 ;這裡補點雞湯:發這篇文章的初心出于讓更多人了解下相關領域,讓相關專業、領域的人士知道嵌入式Linux驅動的開發流程;空間就應該多一點這種正能量的文章,學到是自己的,大學的教學很少有這種嵌入式Linux驅動的開發,不喜勿噴!
該文屬自身感受和開發過程中遇到的問題在此和大家分享一下 :
U-boot基礎:很多人可能會說,現在直接用基于windows的MDK就可以完成開發(例如:keil),那為什麼還要用基于Linux的環境開發嵌入式呢?Keil這種內建的MDK适合中小型公司開發,不适合大公司協作,它隐藏了太多的技術細節,比如:單闆上電後是如何執行程式的?是不是必須要有main函數?在C調用函數之前需要對硬體進行什麼操作?中斷服務子程式是如何執行的?等等這寫問題,我想對技術有濃厚興趣的人一定很想了解。我來依照上述問題給出自己的一些想法 ;單闆上電後從程式連結位址(依賴.lds、Makefile檔案)處執行程式,涉及到位址就要用彙編,闆子上電的啟動需要依靠start.S這個啟動檔案 ,這個檔案裡包含各硬體的初始化,如:系統時鐘初始化(如果沒設定時鐘闆子以外部晶振12M速度運作,S3C2440),關看門狗,初始化SDRAM、初始化NAND FLASH(如果為NAND啟動)、代碼重定位(從FLASH将代碼全拷貝到SDRAM,為什麼要進行代碼重定位呢?如果程式從NOR FLASH啟動,那可以直接讀取代碼到處理器,但沒進行一些操作不能寫資料到NOR FLASH,并且NOR FLASH上運作程式效率會大打折扣;如果是NAND FLASH啟動,系統上電會把NAND FLASH前4K内容拷貝到片内SRAM(stepping-stone)運作,程式小于4K還可以,那大于4K呢?豈不是要丢失程式代碼,不能實作功能,是以需要進行代碼重定位)、初始化棧指針 ldr sp, =0x34000000(棧向下增長,将棧設定到記憶體頂邊境處 C函數的調用需要進棧出棧);那上面這些有關硬體啟動的就是bootloader的第一階段,第二階段是将核心從NAND FLASH讀出到SDRAM,并設定啟動參數(向核心傳遞記憶體、指令行參數、核心入口等),最後跳轉到核心處執行。U-boot在核心啟動後便不會起作用了。U-boot是一種很強大的bootloader,它可以支援多種單闆,可以去伺服器ftp://ftp.denx.de/pub/u-boot/下載下傳壓縮包進行解壓縮、修改、裁剪配置自己的bootloader。
這裡總結一下,U-boot的最終目的為啟動核心。
核心的啟動:核心可以到官網https://www.kernel.org/下載下傳;為什麼需要啟動核心呢?Linux核心的最終目的是挂接根檔案系統,讓上層軟體開發人調用核心标準接口。首先,解壓核心
解壓後的源碼如下:
想知道核心的組成結構可以參考它的頂層Makefile、.config檔案。
将核心打更新檔:
直接使用廠家的配置檔案
在Linxu終端執行make menuconfig
配置完成後執行make指令
這裡可能會遇到上面的問題,更改配置如下
不要選這項
3.4.2版本以上的核心不必更改此項。
再執行
等待核心編譯完成
核心映像檔案在這個檔案夾内
核心映像檔案uImage包括64位元組頭部(包含核心版本、加載位置、大小等資訊)和zImage(真正的核心 壓縮過的核心)。這裡的vmLinux是未壓縮的核心映像,為elf格式,用于kernel-debug,不能直接加載,不可以作為啟動核心。
編譯出uImage後用u-boot燒寫Kernel
注:如果沒有燒寫根檔案系統,啟動時會卡死在核心。
制作根檔案系統:
根檔案系統的任務是運作應用程式。使用busybox制作根檔案系統,busybox是一個開源的工具,下載下傳busybox源碼并解壓
安裝方法:用Vi編輯器打開INSTALL文檔
根據文檔提示,我們知道這個安裝步驟為紅圈圈中的三步。
執行指令配置busybox
選中Tab代碼補全功能。
在make之前修改Makefile
加上交叉編譯腳本,不然會出錯。
編譯完成後千萬别直接make install
這樣會破壞掉主機系統。
應該這樣
加上紅圈裡的東西再安裝。安裝完成後我們去到安裝目錄
下面我們需要導入glib庫,庫中包含一些動态庫和靜态庫,我們隻需要動态庫,可以從制作交叉編譯工具檔案夾下複制過來到lib目錄
上電自動挂接檔案系統,無需手動挂載。
燒寫根檔案系統到單闆,開始編寫驅動程式:
驅動的核心為該結構體,驅動的架構如下:
實作這兩個接口,open函數為初始化LED硬體接口用,write函數為LED具體操作
我們寫的内容需要告訴核心,那核心怎樣才知道有這個驅動呢?這就需要寫一個驅動注冊函數和解除安裝函數
僅僅這樣核心也不知道該驅動是否被加載,是以還需要一個宏來實作入口和出口:
最後再寫出測試函數就可以運作該驅動了
還要編寫Makefile(Linux編譯工具)
這裡注意選擇linux核心版本,由于用的是2.6.22.6核心的接口,是以換成其他版本的核心可能編譯不通過,會有錯誤。
再編譯測試程式,編譯測試程式時要用和根檔案系統下lib庫所用的版本一樣的交叉編譯器編譯,最後才會順利實作。
我這用的是3.4.5的,由于上次用了4.3.2的交叉編譯器,導緻最後運作失敗,搞了很久才弄出來,編譯後會産生這兩個檔案 把它們拷貝到根檔案目錄下
最後在單闆上裝載驅動!
這樣就可以測試了。
注:如何修改arm-linux-gcc 交叉編譯器版本
紅圈部分為交叉編譯器PATH,再執行