總結:軟件開發的3個方向 與 嵌入式Linux學習路線(驅動方向)


--- title: 嵌入式Linux學習路線圖(驅動方向) date: 2020-05-09 07:17:58 categories: tags: - embeded - summary - arm - Linux ---

曾經和同事一起吃飯,聽他們吐槽程序員壓力太大,我開玩笑說去送外賣會不會更好;但細數了一下,還是程序員香。

我想,能夠選擇程序員作為職業生涯的開始應該算是一種幸運:收入還行,雖然會頂着項目進度的壓力,但只需要吃學習的苦。

現在軟件開發非常熱門,下至各種操作系統、上至五花八門的框架;讓初學者眼花繚亂,很多人很迷茫,擔心學習的某樣東西以后很快被新興事物代替。

我曾聽過亞馬遜創始人Jeff Bezos說過的一句話:

人們經常問,在接下來的10年里,會有什么樣的變化。但是我只問,未來的10年,什么是不變的?——Jeff Bezos

我認為,行業和方向都不是最重要的,按我對《軟技能:代碼之外的生存指南》其中提到的“沖量”的理解,競爭力=選擇+積累。

程序員的三大方向

韋東山將程序員的方向分為3類:專業領域業務領域操作系統領域。而按我的理解是:專業領域業務領域底層領域

負責底層領域的人,主要的工作是向其他開發人員提供操作底層硬件的接口,有時候甚至需要搭建業務開發人員程序運行的系統環境,計算軟件運行時所需要的最小資源;配合硬件工程師進行聯調,從軟、硬件2個角度排除解決PCBA上存在的問題;有時候還需要參與硬件設計(主要是CPU外圍),設計行業應用的數據鏈路架構。

從事業務開發的人,需要了解一些操作系統知識,善用各種庫進行,常常使用操作系統的接口(系統調用)進行應用層開發。一般都需要從行業出發、對產品有一定的認識,了解一些業務需求,搞清楚業務的關系。

所以,當領導的人,多是做應用的。一旦鑽入了某個行業,很難換行業。因此,選擇一個好的行業非常重要。——韋東山

專業開發的人來說,他們常常面對的是業務中某一個核心需求的實現,像科研人員一樣,更多地需要對理論知識有足夠的積累;高數中的很多東西是他們的老朋友;編程語言只是他們實現目標的工具。

這3類工種直接可以沒有明確的界定,只要學習能力足夠強,甚至可以相互轉換,而且這種轉換后的變化可能是更加得心應手的工作。

我們來講講底層領域吧。

底層領域

底層開發需要在於芯片廠商或者板級開發商的BSP,包括3種:

0、BSP開發

1、裸機開發

2、基於操作系統的驅動開發

BSP開發:我曾經以為底層移植需要從通用的BootLoader或者kernel做移植,沒成想實際上這一塊屬於板級供應商的工作。除非是進入到這些供應商從事工作或者進行產品底層的深度定制,否則沒啥機會用到芯片上的編程經驗。

實際上,大部分的移植工作都只是簡單的適配。

裸機開發往往是面對一些對資源要求比較苛刻,無法運行操作系統的場景。例如物聯網領域,尤其是通過電池供電產品;也有一些不需要上系統的原因在於調度和通訊的方式比較簡單,用前后台(輪詢+中斷)系統足以解決這些問題。

操作系統開發的開發根據系統的不同而不同;嵌入式常見的操作系統很多(過時的WinCE就不說了),由簡到難的有:uCos、FreeRTOS;VxWorks,RT-Thread,Linux...

其中,比較成熟而被人廣泛認識的有:Linux、FreeRTOS、RT-Thead。

我建議學習的路線,“從裸機到系統”:

0、學習一款MCU,例如STM32

1、了解操作系統原理

2、買個資料豐富、有條理而且社區友好的開發板,移植並開發有關的系統

3、在2的基礎上,研究Linux

2010和2011年RTOS使用榜

當然,不僅如此,經常和硬件工程師打交道也是一項工作內容。

操作系統領域所包含的內容,簡單地說,就是制作出一台裝好系統的專用“電腦”,可以分為:

  • 為產品規划硬件:按需求、性能、成本和資源選擇主芯片,搭配周邊外設,交由硬件開發人員設計。
  • 給單板適配操作系統、編寫驅動以控制外部設備
  • 定制維護、升級等整體量產方案
  • 為應用開發人員搭建開發環境
  • 從系統角度解決疑難雜症

韋東山:我在中興公司上班時,寫驅動的時間其實是很少的,大部分時間是調試:系統調優,上幫APP工程師、下幫硬件工程師查找問題。我們從廠家、網上得到的源碼,很多都是標准的,當然可以直接用。但是在你的產品上也許優化一下更好。比如我們可以把攝像頭驅動和DMA驅動揉合起來,讓攝像頭的數據直接通過DMA發到DSP去。

我們可以在軟件和硬件之間起橋梁作用,對於實體產品,有可能是軟件出問題也可能是硬件出問題,一般是底層系統工程師比較容易找出問題。當硬件、軟件應用出現問題,他們解決不了時,從底層軟件角度給他們出主意,給他們提供工具。再比如方案選擇:芯片性能能否達標、可用的BSP是否完善等等,這只能由負責整個方案的人來考慮,他必須懂底層。

在操作系統領域,對知識的要求很多:

  • 外語能力:熟讀各種芯片手冊(我曾見過一種很少見的配置說明,要需要有一定的理解能力)
  • 硬件能力:懂硬件知識才能看懂電路圖
  • 系統框架:有編寫、移植驅動程序的能力,匯編
  • 系統理論:對操作系統本身有一定的理解,才能解決各類疑難問題
  • 通信協議:從最簡單的串口到SPI、IIC、CAN上至TCP/IP
  • 驅動開發:外設的配置
  • 應用開發:C/C++

缺點: 它絕對是一個大坑,沒有興趣、沒有毅力的人慎選:

  • 發育緩慢:廣而雜的知識,要學很久;沒有經驗的時候,需要從軟件開發開始學習
  • 崗位機會少:絕對比APP的職位少(數量減少、薪資提高)
  • 門檻高(當然薪水相對就高)

優點

  • 不擔心行業限制:學好后,行業通殺,想換行就換行;想自己做產品就自己做產品。
  • 工作量穩定:不會被經常變動的需求搞得天天加班。(所以說文檔先行,先規划再開發)

驅動開發,我認為適合於這些人:

1、硬件工程師:想轉軟件開發,從底層軟件入門會比較好,硬件經驗能夠用得上;

2、應用開發人員:想深入了解底層的人,不會整天被底層卡脖子;

3、裸機開發人員:面對日益復雜的資源調度處理開始力不從心;有資源能夠上系統的硬件平台可以搞搞。

4、想擁有整體調試能力的人:擁有底層能力對調試來講是一把利刃;

嵌入式軟件中一定有的部分:

  • 簡單的OS:內核、驅動、任務。

  • 比較龐大的OS:bootloader、內核、驅動、文件系統、應用程序(任務)。

零基礎快速入門

假設您是零基礎,我們規划了如下入門路線圖:

前面的知識,是后面知識的基礎,建議按順序學習。每一部分,不一定需要學得很深入透徹

軟件

C語言:

  • 基本語法
  • 結構體、指針
  • 復雜宏定義

通用:

  • 數據結構+算法

應用

PC-Linux(例如Centos、Ubuntu)

  • Linux常見命令
  • 開發環境配置、搭建
  • Linux常見編輯器的使用(vim,emacs)

硬件

  • 原理圖、芯片手冊
  • 各類通訊協議

我們學習硬件知識的目的在於能看懂原理圖,看懂通信協議,看懂芯片手冊;不求能設計原理圖,更不求能設計電路板。對於正統的方法,你應該這樣學習:

①學習《微機原理》,理解一個計算機的組成及各個部件的交互原理。

②學習《數字電路》,理解各種門電路的原理及使用,還可以掌握一些邏輯運算(與、或等)。

嵌入式學習路線

裸機程序

概述:從簡單的裸機開發入手,先掌握硬件操作。對於基於ARM+Linux的裸機學習,這么做可以學得更深,並且更貼合后續的Linux學習。

Linux驅動開發 = Linux驅動程序軟件框架 + 通過軟件操作硬件

實際上這個部分就是通過軟件操作硬件:不需要依賴其他框架,你可以按你自己的意願來組織編寫代碼;你只需要知道如何讀寫物理地址即可。(必要時,使用芯片提供的資源對硬件進行控制)

一切從零編寫代碼、管理代碼,可以讓我們學習到更多知識:

實際上這些知識在BootLoader中學習會更有體會

  • 需要了解芯片的上電啟動過程,知道第1條代碼如何運行
  • 需要掌握怎么把程序讀入內存
  • 需要理解內存怎么規划使用,比如棧在哪,堆在哪
  • 需要理解代碼重定位
  • 需要知道中斷發生后,軟硬件怎么保護現場、跳到中斷入口、調用中斷程序、恢復現場

你會知道:

  • main函數不是我們編寫的第1個函數(鏈接地址,加載地址的概念等內容)
  • 芯片從上電開始,程序是怎么被搬運執行的(不同芯片加載代碼的差異)
  • 函數調用過程中,參數是如何傳遞的(C函數形參列表與匯編寄存器的對應關系)
  • 中斷發生時,每一個寄存器的值都要小心對待(異常模式)
  • 代碼段、數據段、BSS段(程序在內存中的分布情況)
  • 程序的運行:上電復位、代碼重定位、位置無關碼、CPU異常/中斷
  • 驅動硬件:時鍾,內存,中斷,GPIO,IIC,SPI,Flash,LCD等(片內資源如何使用)

學習裸機開發的目的有兩個:

1、掌握裸機程序的結構,為后續的u-boot作准備

2、練習硬件知識,即:怎么看原理圖、芯片手冊,怎么寫代碼來操作硬件

后面的u-boot可以認為是裸機程序的集合,我們在裸機開發中逐個掌握各個部件,再集合起來就可以得到一個u-boot了。后續的驅動開發,也涉及硬件操作,你可以在裸機開發中學習硬件知識。

注意:如果你並不關心裸機的程序結構,不關心bootloader的實現,這部分是可以先略過的。

推薦兩本書:杜春蕾的《ARM體系結構與編程》,韋東山的《嵌入式Linux應用開發完全手冊》。

BootLoader

概述:

如果你是軟件工程師,無論是ARM9、ARM11、A8還是A9,對我們來說是沒有差別的。一款芯片,上面有CPU,還有眾多的片上設備(比如UART、USB、LCD控制器)。我們寫程序時,並不涉及CPU,只是去操作那些片上設備。

所以:差別在於片上設備,不在於CPU核;差別在於寄存器操作不一樣。

因為我們寫驅動並不涉及CPU的核心,只是操作CPU之外的設備,只是讀寫這些設備的寄存器。

學習目標:

  • uboot框架、修改uboot命令、uboot啟動內核的細節
  • 適配uboot的方法(適配相近的硬件板子到實際的板子上,並做修改)
  • 讀寫不同的介質下的程序
  • 調通網絡,能夠啟動內核

學習方法:

①先學習《從零編寫bootloader》,這可以從最少的代碼理解bootloader的主要功能

②再看書上對u-boot的講解,並結合《分析u-boot 1.1.6的視頻》來理解

③最后,有時間有興趣的話,看《移植一個全新u-boot的視頻》,這不是必須的。

學習程度:

  • 理解u-boot的啟動過程,特別是u-boot代碼重定位:怎么從Flash上把自己讀入內存
  • 知道bootloader如何給內核傳遞參數
  • 知道bootloader是根據“bootcmd”指定的命令啟動內核
  • 掌握BootLoader一些調試技巧

內核

描述:內核本身不是我們學習的重點,但是了解一下內核的啟動過程,還是很有必要的:工作中有可能要修改內核以適配硬件,掌握了啟動過程才知道去修改哪些文件。

  • 結合代碼分析內核啟動流程
  • 配置、適配內核

學習程度:

①知道機器ID的作用,根據機器ID找到單板對應的文件

②知道Makefile、Kconfig的作用,知道怎么簡單地配置內核

③知道怎么修改分區

④作為入門:只求理解,不要求能移植

文件系統

文件系統的學習其實指的是:構建一個根目錄文件系統,此后將其制作為鏡像;這個鏡像的類型是我們平時所說的

概述:

在驅動程序開發階段,我們喜歡搭建一個最小根文件系統來調試驅動;

在開發應用程序時,也需要搭建文件系統,把各種庫、配置文件放進去;

在發布產品時,你還需要修改配置文件,使得產品可以自動運行程序;

甚至你想實現插上U盤后自動啟動某個程序,這也要要修改配置文件;

這一切,都需要你理解根文件系統的構成,理解內核啟動后是根據什么配置文件來啟動哪些應用程序。

學習內容:

  • init進程
  • 構建最小根文件系統,燒寫到單板上

學習程度:

①理解配置文件的作用

②知道根文件系統中lib里的文件來自哪里

③可以制作、燒寫文件系統映象文件

驅動

字符驅動設備

描述:

對每一個驅動,先了解硬件原理,然后從零寫代碼,從簡單到復雜,逐漸完善它的功能。

以LED、按鍵驅動為例,練習開發過程中碰到的機制:查詢、休眠-喚醒、中斷、異步通知、poll、同步、互斥等等。后續更復雜的驅動程序,就是在這些機制的基礎上,根據硬件特性設計出精巧的軟件框架。

學習內容:

  • 設備框架
  • 應用與驅動的關系
  • 查詢、中斷、休眠喚醒、poll、異步、同步、互斥、阻塞

學習路線:

  • 字符設備驅動程序之概念介紹、編寫編譯、測試改進、操作LED
  • 字符設備驅動程序之查詢方式的按鍵驅動程序
  • 字符設備驅動程序之中斷方式的按鍵驅動:Linux異常處理結構、Linux中斷處理結構、編寫代碼、poll機制、異步通知、同步互斥阻塞、定時器防抖動
  • 輸入子系統概念介紹、編寫驅動程序
    • 應用程序、庫、內核、驅動程序的關系
    • Linux驅動程序的分類和開發步驟
    • 驅動程序的加載和卸載
  • 字符設備驅動程序開發
    • 字符設備驅動程序中重要的數據結構和函數
    • LED驅動程序源碼分析
  • Linux異常處理體系結構
    • Linux異常處理體系結構概述
    • Linux異常處理的層次結構
    • 常見的異常
  • Linux中斷處理體系結構
    • 中斷處理體系結構的初始化
    • 用戶注冊中斷處理函數的過程
    • 中斷的處理過程
    • 卸載中斷處理函數
    • 使用中斷的驅動程序示例
    • 按鍵驅動程序源碼分析、測試程序情景分析

學習方法:

1、沿着數據流向,從應用程序出發,對驅動程序的使用進行情景分析。

所謂情景分析,就是假設應用程序發起某個操作,你去分析其中的運作過程。比如應用程序調用open、read、ioctl等操作時涉及驅動的哪些函數調用。你要思考一個問題:一個應用程序,怎么獲得按鍵信息,怎么去控制LED。把其中數據的流向弄清楚了,對字符驅動程序也就基本理解了。

2、學習異常和中斷時,可以結合書和視頻;對於驅動程序中其他內容的學習,可以不看書。

其他常見驅動

概述:

學習不同的驅動有2個好處:

1、在你工作中遇到同類驅動時提供借鑒

2、供你學習、練習,煅煉閱讀驅動程序的“語感”,提升編寫程序的能力,增加調試經驗

也許有人說:在工作中我們基本上只是移植、修改驅動而已,很少從頭編寫。這話沒錯,但是能修改的前提是理解;想更好地理解,最好的方法是從零寫一個出來。在學習階段,不要怕耗費太多時間,從零開始編寫,慢慢完善它,在這過程中你既理解了這個驅動,也煅煉了能力,做到觸類旁通。

學習內容:

  • 輸入子系統、輸出系統(LCD)、USB設備驅動,塊設備(FLASH)驅動、網卡驅動,IIC,SPI,聲卡,攝像頭,熱插拔。

學習方法:

1、再次強調,不能光看不練:一定要寫程序,即使照抄也得寫

2、必學:NAND Flash、Nor Flash、hotplug_uevent機制、IIC、SPI

3、學完之后,強烈建議換一個不同的開發板,嘗試在新板上寫驅動程序。

直到你自認為:

1、給你一個新板,你可以很快實現相關驅動

2、給你一個新硬件,你可以很快給它編寫/移植驅動。

按視頻學習會一切順利,很多問題你可能沒想到、沒想通,換一個新板會讓你真正掌握。

學習路線:

  • 驅動程序分層分離概念、總線驅動設備模型
  • USB驅動程序
  • 塊設備驅動程序
  • NAND FLASH驅動程序
  • NOR FLASH驅動程序
  • 網卡驅動程序
  • 移植DM9000C驅動程序
  • 內核下的I2C驅動程序
  • DMA驅動程序
  • hotplug_uevent機制

驅動調試

有一種說法,程序是三分寫七分調。大部分人很快可以寫完程序,但是會把大部分的時間花在調試上面。

驅動調試:

  • JTAG原理與調試
  • printk的使用
  • 打印到proc虛擬文件
  • 根據pc值確定出錯的代碼位置、根據棧信息確定函數調用過程
  • 自制工具:寄存器編輯器(devmem)
  • 修改系統時鍾中斷定位系統僵死問題

應用調試:

  • 使用strace命令跟蹤系統調用
  • 使用gdb和gdbserver
  • 配置修改內核打印用戶態段錯誤信息
  • 應用調試之自制系統調用

怎么學習嵌入式Linux操作系統?

學習操作系統理論知識

可以從中了解到一些基礎概念:

1、操作系統常見名詞

2、系統各部分的層次結構

3、任務的調度原理

4、常見的操作系統

...

簡單的操作系統

很多操作系統都不要求芯片有mmu,像FreeRTOS、uCos都是很適合學習的。很容易從中理解到一些操作系統的核心。

學習Linux操作系統

Linux系統本身的知識:

1、操作系統具有進程管理、存儲管理、文件管理和設備管理等功能,這些核心功能非常穩定可靠,基本上不需要我們修改代碼。我們只需要針對自己的硬件完善驅動程序

2、學習驅動時必定會涉及其他知識,比如存儲管理、進程調度。當你深入理解了驅動程序后,也會加深對操作系統其他部分的理解

3、Linux內核中大部分代碼都是設備驅動程序,可以認為Linux內核由各類驅動構成。但是,要成為該領域的高手,一定要深入理解Linux操作系統本身,要去研讀它的源代碼

在忙完工作,閑暇之余,可以看看這些書:

  • 趙炯的《Linux內核完全注釋》,這本比較薄,推薦這本。他后來又出了《Linux內核完全剖析》,太厚了,搞不好看了后面就忘記前面了。
  • 毛德操、胡希明的《LINUX核心源代碼情景分析》,此書分上下冊,巨厚無比。當作字典看即可:想深入理解某方面的知識,就去看某章節。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM