??最近,有個(gè)需求需要驗(yàn)證一下嵌入式 LINUX 系統(tǒng)在 STM32上使用效果,正好手里有一塊前幾年的 STM32F769I-EVAL 的評(píng)估板,如下圖所示的這個(gè):
這塊評(píng)估板的功能應(yīng)該是非常全了,價(jià)格也是不便宜(應(yīng)該算是挺貴)。ST 官網(wǎng)對(duì)于這塊評(píng)估板的介紹參見(jiàn)
Evaluation board with STM32F769NI MCU。
??熟悉 ST 的
開(kāi)發(fā)板的都知道,ST 的開(kāi)發(fā)板主要有 ST 官方的 Nucleo 系列、Discovery Kits 系列、Evaluation 系列以及第三方開(kāi)發(fā)板這些組成。其中,ST 自家開(kāi)發(fā)板中 Evaluation 系列是功能最全的,也是價(jià)格最高的。第三方開(kāi)發(fā)板差異就比加大了。
嵌入式 Linux 環(huán)境
??在開(kāi)始實(shí)際的移植編譯工作之前,有必要先來(lái)說(shuō)一下我們要搭建的完整的 Linux 運(yùn)行環(huán)境是啥樣的,以及包含那些部分。廢話不多說(shuō),直接上圖:

- U-Boot 本質(zhì)就是就是一個(gè)復(fù)雜點(diǎn)的裸機(jī)程序(鏡像是 u-boot.bin),與我們通常編寫(xiě)的 ARM 裸機(jī)程序沒(méi)有本質(zhì)區(qū)別。U-Boot 是無(wú)條件啟動(dòng)的,從零開(kāi)始啟動(dòng)的。
- Linux Kernel 本身也是一個(gè)裸機(jī)程序(鏡像是 zImage),和 U-Boot、裸機(jī)程序無(wú)本質(zhì)區(qū)別。要說(shuō)不同的地方,那就是內(nèi)核運(yùn)行起來(lái)后,在軟件上分為內(nèi)核層和應(yīng)用層,分層后兩層的權(quán)限不同,內(nèi)存訪問(wèn)和設(shè)備操作的管理上更加精細(xì)(內(nèi)核可以隨便訪問(wèn)各種硬件,而應(yīng)用程序只能被限制地訪問(wèn)硬件和內(nèi)存地址)。
??內(nèi)核是不能開(kāi)機(jī)自動(dòng)完全從零開(kāi)始啟動(dòng)的,內(nèi)核啟動(dòng)需要?jiǎng)e人幫忙。U-Boot 需幫助內(nèi)核實(shí)現(xiàn)重定位,U-Boot 還要給內(nèi)核提供啟動(dòng)參數(shù)。 - 我們的嵌入式 Linux 中的應(yīng)用程序所需的編譯工具鏈也需要我們自己編譯,現(xiàn)有的就只有 ARM 提供的 Cortex-A 系列的(有些開(kāi)發(fā)板廠商也提供自己編譯好的 Linux 編譯套件)。這里需要注意,嵌入式 linux 編譯套件往往不是通用的!
- 根文件系統(tǒng)包括 Linux 啟動(dòng)時(shí)所必須的目錄和關(guān)鍵性的文件,例如 Linux 啟動(dòng)時(shí)都需要有 init 目錄下的相關(guān)文件。Linux 啟動(dòng)時(shí),第一個(gè)必須掛載的是根文件系統(tǒng);若系統(tǒng)不能從指定設(shè)備上掛載根文件系統(tǒng),則系統(tǒng)會(huì)出錯(cuò)而退出啟動(dòng)。成功之后可以自動(dòng)或手動(dòng)掛載其他的文件系統(tǒng)。
- 這里的應(yīng)用程序必須使用我們自己編譯出的配套的編譯套件來(lái)編譯。根文件系統(tǒng)就是第一個(gè)需要使用我們自己的編譯套件來(lái)編譯的程序。
??嵌入式環(huán)境與我們熟悉的 PC 環(huán)境還是有很大區(qū)別的。尤其是對(duì)于部分芯片,它沒(méi)有 MMU,也就不能使用虛擬內(nèi)存相關(guān)的所有技術(shù)。也就意味著,嵌入式中的地址都是實(shí)際的物理地址。
??其次,嵌入式環(huán)境的另一個(gè)大特點(diǎn)就是資源非常緊張,這就導(dǎo)致了我們可能需要將最終的多部分的可執(zhí)行程序放到不同的地方。舉個(gè)例子,STM32 的 MCU 中,往往不能存放 Linux Kernel,我們需要將 Linux Kernel 放到一些外部存儲(chǔ)器中。
??對(duì)于 ARM 平臺(tái),ARM 給出了兩個(gè)概念:加載域 和 執(zhí)行域,加載域?qū)?yīng)加載地址,執(zhí)行域?qū)?yīng)了一個(gè)執(zhí)行地址。關(guān)于 ARM 的分散加載機(jī)制,可以參見(jiàn)博文 ARM 之十三 armlink(Keil) 分散加載機(jī)制詳解 及 分散加載文件的編寫(xiě) 即可。
??進(jìn)一步具體到 STM32 芯片,我們的程序是放到內(nèi)部的 FLASH 上的,F(xiàn)LASH 就是加載域,F(xiàn)LASH 上的具體地址就是加載域地址。同時(shí),ST 芯片的設(shè)計(jì)可以從 FLASH 上執(zhí)行代碼(速度相對(duì)較慢),此時(shí)的加載域與執(zhí)行域是同一個(gè);還有一種更高效的方式是將代碼放到 RAM 中執(zhí)行(存放還是在 FLASH),此時(shí) RAM 就是執(zhí)行域,程序在 RAM 中的地址就是執(zhí)行域地址。
嵌入式系統(tǒng)啟動(dòng)
??前面介紹了嵌入式系統(tǒng)的組成部分,接下來(lái)看看整個(gè)系統(tǒng)如何工作起來(lái)。一般 SoC 內(nèi)部會(huì)有個(gè)固化的引導(dǎo)程序,這個(gè)固化的 BootLoader 我在博文 STM32 之十四 System Memory、Bootloader 中有過(guò)詳細(xì)的介紹。這段程序的會(huì)初始化部分外設(shè)以與外部通信,具體可以參考官方手冊(cè)。
嵌入式系統(tǒng)構(gòu)建工具
??構(gòu)建一整套嵌入式 Linux 系統(tǒng)是一件很龐大的事情,需要做很多工作。因此,誕生了一些嵌入式系統(tǒng)構(gòu)建工具,以幫助開(kāi)發(fā)者簡(jiǎn)化嵌入式系統(tǒng)的構(gòu)建過(guò)程,減少工作量。常用的嵌入式系統(tǒng)構(gòu)建工具有如下幾個(gè):
- Buildroot: Linux 平臺(tái)上的一個(gè)用于構(gòu)建嵌入式 Linux 系統(tǒng)的框架。整個(gè) Buildroot 是由 Makefile 腳本和 Kconfig 配置文件構(gòu)成的。使用它可以和編譯 Linux 內(nèi)核一樣,通過(guò)使用 Kbuild/Kconfig 系統(tǒng)編譯出一個(gè)完整的可以直接燒寫(xiě)到機(jī)器上運(yùn)行的 Linux 系統(tǒng)軟件(包含boot、kernel、rootfs 以及 rootfs 中的各種庫(kù)和應(yīng)用程序、交叉編譯工具鏈)。
??官方網(wǎng)站:https://buildroot.org/,提供了非常詳細(xì)的文檔。 - Yocto: Yocto Project 推出的一個(gè)開(kāi)源的協(xié)作軟件,提供模板、工具和方法幫你創(chuàng)建定制的 Linux 系統(tǒng)和嵌入式產(chǎn)品,而無(wú)需關(guān)心硬件體系。適合嵌入式Linux開(kāi)發(fā)人員使用,極大地簡(jiǎn)化你的開(kāi)發(fā)過(guò)程。Yocto 推薦使用 OpenEmbedded 構(gòu)建系統(tǒng)。
??Yocto Project 是 Linux 基金會(huì)的一個(gè)協(xié)作開(kāi)源項(xiàng)目,其目標(biāo)是生成工具和流程,以便為嵌入式和物聯(lián)網(wǎng)軟件創(chuàng)建獨(dú)立于嵌入式硬件底層架構(gòu)的 Linux 發(fā)行版。官方網(wǎng)站:https://www.yoctoproject.org/,提供了非常詳細(xì)的文檔。 - OpenEmbedded: 一個(gè)開(kāi)源的嵌入式 Linux 系統(tǒng)構(gòu)建環(huán)境,它允許開(kāi)發(fā)人員為嵌入式系統(tǒng)創(chuàng)建一個(gè)完整的 Linux 發(fā)行版。由OpenEmbedded 社區(qū)開(kāi)發(fā),該社區(qū)于 2003 年正式成立。OpenEmbedded 的構(gòu)建系統(tǒng)基于 BitBake 構(gòu)建工具,其操作行為與 Gentoo Linux ebuilds 相似。
??官方網(wǎng)站:http://www.openembedded.org/wiki/Main_Page,提供了非常詳細(xì)的文檔。 - PTXdist: Pengutronix 在 2001 年開(kāi)發(fā)的一個(gè)構(gòu)建系統(tǒng),用于生成固件鏡像。采用了 Linux 內(nèi)核中的配置系統(tǒng) Kconfig 來(lái)選擇和配置每個(gè)包。
??官方網(wǎng)站:https://www.ptxdist.org/,提供了非常詳細(xì)的文檔。
??當(dāng)然,我們也可以選擇自己動(dòng)手,根據(jù)上面嵌入式 Linux 環(huán)境,一點(diǎn)一點(diǎn)來(lái)構(gòu)建其中的各個(gè)部分。后續(xù),我就以手里的 STM32F769I-EVAL 的評(píng)估板為載體,盡量不使用已有的嵌入式構(gòu)建工具,來(lái)一步一步搭建這個(gè)嵌入式 Linux 環(huán)境。
搭建過(guò)程
??工欲善其事,必先利其器。第一步就是搭建 LINUX 系統(tǒng)開(kāi)發(fā)環(huán)境,為此特地在筆記本上安裝了 Ubuntu,具體使用的桌面開(kāi)發(fā)環(huán)境是 Ubuntu 20.04.3 LTS。至于為啥選擇 Linux 系統(tǒng),而不是直接使用 Windows 系統(tǒng)想必大家都清楚為啥。
??接下來(lái)準(zhǔn)備好一個(gè)目錄,后續(xù)所有的操作均在此目錄中進(jìn)行。我的操作是新建 /home/zcshou/STM32LINUX
這個(gè)目錄,用于存放整個(gè)要為 STM32 嵌入式 Linux 環(huán)境編譯的源代碼,后續(xù)都在這個(gè)目錄中進(jìn)行。如下圖所示:
??最開(kāi)始我想按照上面說(shuō)的嵌入式環(huán)境的各個(gè)部分來(lái)分別寫(xiě)幾篇博文來(lái)完整介紹整個(gè)搭建過(guò)程,然而寫(xiě)著寫(xiě)著內(nèi)容越來(lái)越多,最終超過(guò)了 CSDN 編輯器的限制!最終決定把內(nèi)容拆分成多篇文章。具體搭建過(guò)程就是如下幾步:
- 編譯 U-Boot。參見(jiàn)博文 U-Boot 之一 零基礎(chǔ)編譯 U-Boot 過(guò)程詳解 及 編譯后的使用說(shuō)明
- 編譯 Linux Kernel。參見(jiàn)博文 Linux 之九 零基礎(chǔ)編譯嵌入式 Linux Kernel 過(guò)程詳解 及 編譯后的使用說(shuō)明
- 編譯交叉編譯工具鏈。參見(jiàn)博文 Linux 之十 編譯自己的嵌入式 Linux 交叉編譯工具鏈
- 編譯 RootFS。參見(jiàn)博文 Linux 之十一 編譯嵌入式 Linux 下的 RootFS
參考
- https://codeantenna.com/a/wf8KVWOhym
- https://www.its404.com/article/qq_44034198/110872972