U-Boot 之一 零基础编译 U-Boot 过程详解 及 编译后的使用说明
??在之前的博文 Linux 之八 完整嵌入式 Linux 環(huán)境介紹及搭建過程詳解 中我們說了要一步步搭建整個嵌入式 Linux 運行環(huán)境,今天就開始編譯 U-Boot。我所使用的硬件平臺及整個要搭建的嵌入式 Linux 環(huán)境見博文 Linux 之八 完整嵌入式 Linux 環(huán)境介紹及搭建過程詳解,這里的編譯都是基于以上環(huán)境的,就不過多說明了。
??這篇博文我們僅僅關(guān)注編譯過程本身,想要吃透 U-Boot,有太多東西需要學(xué)習(xí)!最開始我想放到一篇文章中,寫著寫著內(nèi)容越來越多,最終超過了 CSDN 編輯器的限制。。。最終決定把內(nèi)容拆分成多篇文章。你可能需要:
編譯過程
??注意,這篇文章中使用的示例是 STM32f769-Disco 的配置,還沒有更換移植的 STM32f769-eval。STM32f769-eval 的 完整移植參考 U-Boot 之三 U-Boot 源碼文件解析及移植過程詳解 即可。
編譯環(huán)境
??Ubuntu 20.04.3 LTS 準(zhǔn)備就緒之后,還有一些工具需要安裝。第一個就是 GCC,GCC 就使用 Ubuntu 自帶的 9.3.0 版即可。在編譯 U-Boot 的過程中,我們還需要安裝其他一些依賴工具,這個在后面用到的時候缺啥裝啥就可以(出現(xiàn)各種錯誤的時候再安裝相應(yīng)工具即可)。
??U-Boot 本身沒有提供對于我使用的 STM32F769-EVAL 板子的支持,我這里就是用它支持的 STM32f769-Disco 板子來進(jìn)行編譯。如果不出意外,編譯之后運行肯定會有問題,到時候我們在一個一個解決問題即可。在博文 U-Boot 之三 U-Boot 源碼文件解析及移植過程詳解 中我詳細(xì)介紹了如何將 U-Boot 移植到新板子。
??這里介紹一下安裝依賴包的一些方法。正常我們應(yīng)該是先使用 find 命令查找依賴是否存在。因為存在一種情況是,依賴文件本身存在但是沒有在環(huán)境變量 LD_LIBRARY_PATH 里,如果不存在直接安裝即可。
這樣我們可以查看響應(yīng)的依賴包的具體說明,然后根據(jù)需要來安裝。
過程
??在開始編譯之前,我們先介紹兩個命令:make clean 用于清空編譯中間文件 和 make distclean 用于清除所有編譯產(chǎn)生的文件。如果我們想要重新編譯,可以使用以上兩個命令清理環(huán)境(這兩個命令在 U-Boot 根目錄的 Makefile 中有詳細(xì)的定義,在博文 U-Boot 之四 構(gòu)建過程(Kconfig 配置 + Kbuild 編譯)詳解 中會有說明)。
第一步肯定是獲取 U-Boot 的源代碼,我這里直接使用了當(dāng)前最新存檔版:u-boot-2021.10.tar.bz2。這里需要重點注意,我最開始直接使用 Git 獲取了最新的源代碼,結(jié)果編譯之后運行直接 HardFault,分析好久沒找到原因,最后決定使用一個穩(wěn)定發(fā)布版試試,結(jié)果沒有問題。。。
??成功下載并解壓源代碼之后(注意我這里將解壓后的文件名命名為了 u-boot),我們需要進(jìn)入 u-boot 目錄下,使用命令:cd u-boot。此后就在 u-boot 目錄下進(jìn)行各種操作。
第二步就是生成配置,直接使用命令:make stm32f769-disco_defconfig。不出意外的話會出現(xiàn)以下錯誤:
/bin/sh: 1: bison: not found
??這個錯誤是由于我們沒有安裝 bison 這個工具。Bison 是一個通用解析器生成器。GUN 軟件之一,官網(wǎng) https://www.gnu.org/software/bison/。Ubuntu 下直接使用命令:sudo apt install bison 即可(這個不是最新版,如果需要最新版需要自己從源碼安裝)。
/bin/sh: 1: flex: not found
??這個錯誤是由于我們沒有安裝 flex 這個工具。flex 是一個詞法分析器。用來將一個 .l 文件生成一個 .c 程序文件。源代碼托管于 Github:https://github.com/westes/flex。Ubuntu 下直接使用命令:sudo apt iinstall flex 即可。
正常完成如下所示:
第三步修改配置(裁剪)。直接使用命令:make menuconfig。不出意外的話會出現(xiàn)以下錯誤:
??這個錯誤是由于我們沒有安裝 ncurses 這個工具。ncurses(new curses)是一套編程庫,它提供了一系列的函數(shù)以便使用者調(diào)用它們?nèi)ド苫谖谋镜挠脩艚缑妗UN 軟件之一,官網(wǎng):https://invisible-island.net/ncurses/。Ubuntu 下直接使用命令:sudo apt iinstall libncurses-dev 即可。安裝成功之后,重新 make menuconfig,就會進(jìn)入下面的界面:
我們需要做的就是選擇其中的 SPL / TPL 菜單項,然后回車,在其中下翻頁找到 Activate Falcon Mode 項,將選擇去掉。
??其中還有很多項,這個就需要根據(jù)自己需要來具體進(jìn)行裁剪了。當(dāng)然有個前提是,修改了配置很大可能還需要配套修改對應(yīng)的源代碼,因為之所以修改肯定是為了適應(yīng)自己開發(fā)板。
這個錯誤提示很明顯,就是終端界面太小,把終端拖大一些就好了。
第四步就是真正的編譯了,直接使用命令:CROSS_COMPILE=arm-none-eabi- ARCH=arm make -j8 不出意外的話會出現(xiàn)以下錯誤:
/bin/sh: 1: arm-none-eabi-gcc: not found
這個錯誤是由于我們沒有安裝 GCC for ARM 導(dǎo)致的。也就是沒有編譯 U-Boot 使用的編譯器。解決方法也非常簡單,就是安裝 GCC for ARM 即可。
??這里有個需要注意的點,如果大家搜索 Ubuntu 下安裝 GCC for ARM,很多文章都過推薦使用 apt 命令來安裝,類似于:sudo apt-get install gcc-arm-none-eabi,這個版本并不是最新的(貌似使用這個舊版本也可以,我選擇了使用最新版)。更重要的是,ARM 之前已經(jīng)宣布不再更新 Launchpad 上的 GCC for ARM 了(具體見 Launchpad 上的說明)。 其只在 ARM 的官網(wǎng)提供編譯好的壓縮包及源代碼的壓縮包。
這里簡單來講解一下直接從 ARM 官網(wǎng)下載壓縮包的安裝方法:
??這里有一點需要注意,通過壓縮包安裝不能解決依賴關(guān)系,需要我們自己運行嘗試,看看少啥安啥。目前已知的依賴是 ncures5(會報錯:error while loading shared libraries: libncurses.so.5),其需要安裝 sudo apt install libncurses5(貌似應(yīng)該是需要 32 位的,我們上面安裝的 libncurses-dev 應(yīng)該是 64 位的)。
至于需不需要其他的依賴,大家自行嘗試,我這里是沒有提示需要其他任何組件。
這個錯誤主要是由于 U-Boot 代碼使用了 openssl 中的相代碼,而我們的環(huán)境中沒有安裝 openssl。Ubuntu 下直接使用命令:sudo apt install libssl-dev 即可。
正常編譯完成之后。我們需要的文件就有了。我們真正需要的是根目錄下的 u-boot.bin 和 spl 目錄下的 u-boot-spl.bin。
其他一些問題。我在試用 make CHANGELOG 命令時出現(xiàn)錯誤 unrecognized command line option ‘-mno-unaligned-access’,不知道為啥,也沒找到如何解決。
使用說明
??經(jīng)過上面的編譯之后,我們需要的 U-Boot 就編譯出來了。U-Boot 編譯完成后實際包含兩部分:spl/u-boot-spl.bin 和 u-boot.bin。下圖是針對 STM32F769 的一個布局映射圖:
- spl/u-boot-spl.bin 負(fù)責(zé)初始化 sdram,配置時鐘,引導(dǎo)加載 U-Boot。需要將 SPL 燒寫在 0x08000000 地址,即內(nèi)部 flash首地址
- u-boot.bin 是 uboot 主程序,負(fù)責(zé) relocate 向量表及自身。并完成開發(fā)板的基本初始化,然后引導(dǎo)內(nèi)核。需要將 SPL 燒寫在 0x08008000 地址。
燒寫完之后重啟,就會看到如下信息:
U-Boot SPL 2021.10 (Dec 24 2021 - 20:53:15 +0800) Trying to boot from XIPU-Boot 2021.10 (Dec 24 2021 - 20:53:15 +0800)Model: STMicroelectronics STM32F769-DISCO board DRAM: 16 MiB stm32fx_rcc_clock rcc@40023800: set_rate not implemented for clock index 4 stm32fx_rcc_clock rcc@40023800: set_rate not implemented for clock index 4 stm32fx_rcc_clock rcc@40023800: set_rate not implemented for clock index 4 Flash: 1 MiB MMC: sdio2@40011c00: 0 Loading Environment from nowhere... OK In: serial Out: serial Err: serial Net: Warning: ethernet@40028000 (eth0) using random MAC address - fa:d8:b5:97:81:15 eth0: ethernet@40028000 Hit SPACE in 3 seconds to stop autoboot. MMC: no card present U-Boot >Flash: 1 MiB
??通過 STM32F769 的手冊可以知道,它的 FLASH 大小是 2M,這里 U-Boot 顯示為 1M,明顯是不對的!關(guān)于 FLASH 的初始化可以在文件:drivers\mtd\stm32_flash.c 找到如下接口:
unsigned long flash_init(void) {unsigned long total_size = 0;u8 i, j;for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {flash_info[i].flash_id = FLASH_STM32;flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT;flash_info[i].start[0] = CONFIG_SYS_FLASH_BASE + (i << 20);flash_info[i].size = sect_sz_kb[0];for (j = 1; j < CONFIG_SYS_MAX_FLASH_SECT; j++) {flash_info[i].start[j] = flash_info[i].start[j - 1]+ (sect_sz_kb[j - 1]);flash_info[i].size += sect_sz_kb[j];}total_size += flash_info[i].size;}return total_size; }其中,宏 CONFIG_SYS_MAX_FLASH_BANKS 很重要。在前面的移植章節(jié)我們已經(jīng)說過,STM32F769 是復(fù)用了 STM32F746 的相關(guān)文件的。那么,最終我們會在在 include\configs\stm32f746-disco.h 中找到該宏的定義:
對比這個 STM32F769 和 STM32F746 這兩個 CPU,STM32F746 只有一個 BANK,但是 STM32F769 卻有兩個 BANK。那么是不是把他改成 2 就可以了呢?答案是不可以!我們繼續(xù)分析上面的代碼。
??我們再看第二個宏值 CONFIG_SYS_MAX_FLASH_SECT,它被定義為 8,接下來的 for 循環(huán)就是把這 8 個扇區(qū)的大小加起來,每個扇區(qū)的值放在了 arch\arm\include\asm\arch-stm32f7\stm32.h 文件中的 sect_sz_kb 變量中,如下所示:
static const u32 sect_sz_kb[CONFIG_SYS_MAX_FLASH_SECT] = {[0 ... 3] = 32 * 1024,[4] = 128 * 1024,[5 ... 7] = 256 * 1024 };這個就很清楚了,就是 SMT32 的 FLASH 的扇區(qū)大小分配。知道了代碼的實現(xiàn),我們再來看看 STM32 手冊手冊中對于 FLASH 的定義,如下圖所示:
通過上面的圖我們可以看到,STM32F769 的 FLASH 本身支持單 BANK 和 雙 BANK 模式,不過雙 BANK 模式,每個扇區(qū)的大小與 單 BANK 不一樣。默認(rèn)情況是 單 BANK 模式的。因此,我們最終的處理方案是 CONFIG_SYS_MAX_FLASH_BANKS 保持為 1,把宏 CONFIG_SYS_MAX_FLASH_SECT 改為 12 ,并且必須要修改 sect_sz_kb 。
Warning: ethernet@40028000 (eth0) using random MAC address
??每塊網(wǎng)卡都有一個MAC 地址,MAC 地址是一個 6 字節(jié)(48bit)的數(shù)據(jù)。前 3 字節(jié)稱為 OUI,是由 IEEE 組織注冊給網(wǎng)絡(luò)設(shè)備生產(chǎn)商的;每個廠商擁有一個或多個 OUI,彼此不同。后三字節(jié)則是由網(wǎng)絡(luò)設(shè)備生產(chǎn)商分配給自己生產(chǎn)的每一個擁有 MAC 地址的設(shè)備,互不重復(fù)。
??U-Boot 在啟動過程中提示使用了隨機(jī) MAC 地址,這是因為如果 MAC 地址相同的兩塊開發(fā)板在同一局域網(wǎng)中,會互相影響。那么,如果我們想要自己固定一個固定的 MAC 地址應(yīng)該如何操作呢?如下圖所示默認(rèn)開啟了不設(shè)置 MAC 地址時使用隨機(jī)地址:
知道了為何會有這個隨機(jī) MAC 地址后,我們就可以根據(jù)源代碼針對性進(jìn)行修改。這里我提供我所使用的的兩種方法:
??我們需要注意的是,如果選擇了手動修改 MAC 地址,必須自己保證 MAC 不能重復(fù)。一個比較常用的方法是:網(wǎng)卡生產(chǎn)商的 OUI + 芯片的唯一 ID 組成 MAC。注意,部分網(wǎng)卡中會有專門記錄 MAC 地址的地方,我們只需要讀取即可。
set_rate not implemented for clock index 4
??這個其實并不是個錯誤,應(yīng)該算是源代碼中的一個 BUG,通過搜索該提示文字關(guān)鍵字,我們最終可以找到函數(shù) static ulong stm32_set_rate(struct clk *ckl, ulong rate),如下圖所示:
由于 stm32_set_rate 被調(diào)用了多次,而每次調(diào)用第一個 if 條件存在不成立的情況,因此就會一直打印該提示信息。
MMC: no card present
??STM32F769-EVAL 開發(fā)板上是有 SD 卡的。但是這里顯示 沒有卡。不出意外的話,這里是由于 STM32F769-Disco 與 STM32F769-EVAL 在這方面配置不同導(dǎo)致。下圖是兩款開發(fā)板關(guān)于 SD 卡的說明:
從中我們可以看出,兩款開發(fā)板使用的 SDMMC 并不相同!EVAL 開發(fā)板有兩個 SD 卡插槽:SD1 -> SDMMC1,SD2 -> SDMMC2。而 Discovery 板子只有一個 SD卡插槽:SD -> SDMMC2。關(guān)鍵在于 SDMMC2 的管腳使用是不一樣的!這里我們需要更改對應(yīng)的引腳。
SD 目前還是有問題,后續(xù)再解決一下!
參考
總結(jié)
以上是生活随笔為你收集整理的U-Boot 之一 零基础编译 U-Boot 过程详解 及 编译后的使用说明的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux 之八 完整嵌入式 Linux
- 下一篇: U-Boot 之二 详解使用 eclip