嵌入式 Linux 初学者指南 – 第 2 部分

大家好!我是大聪明-PLUS

在第一篇文章中,我们介绍了基础知识:嵌入式 Linux 是什么、它与常规发行版有何不同、它由什么组成、如何启动以及可以使用哪些工具来构建它。

我希望对这个主题感兴趣的人已经拥有一块带有 SoC 的电路板------没有它,一些步骤将会被遗漏,并且结果的享受将是不完整的。

现在是时候从理论转向实践了!

目录

3.了解Buildroot

3.1 准备

Buildroot 是一个多组件系统,需要工作环境才能运行。此外,最终的构建也需要在某个地方运行。所以,我们首先准备好所需的一切。

3.1.1. 必要设备

设备清单相当简单:

  • 带有 SoC 的单板计算机

  • MicroSD 卡

  • USB-MicroSD 适配器

  • USB-UART适配器

  • 用于连接适配器和单板计算机的电线

由于我们才刚刚开始使用这项技术,最好准备一块支持 Buildroot 的开发板。我使用的是 Sunxi 的 OrangePi PC,它基于 ARM 架构的 Allwinner H3 SoC。

3.1.2. 工作环境

您几乎可以在任何地方构建 EL,但我建议使用在 ext4 文件系统上部署了 Buildroot 环境的 Linux PC。就我而言,是 Ubuntu 22.04 LTS。

为了避免使主系统混乱,我们将在 Docker 容器中构建嵌入式 Linux。

在工作过程中,我们将通过 UART 与单板计算机通信,因此我们需要在操作系统上安装一个合适的实用程序。我的程序是minicom

复制代码
sudo` apt install `-y` minicom;    \
`sudo` usermod `-aG` dialout `$USER`; \
newgrp dialout`

还建议立即将所有内容安排为存储库,因此您需要安装git

复制代码
sudo` apt install `-y` `git

现在让我们创建一个工作目录、必要的子目录,将其全部包装在git一个存储库中并下载Buildroot:

复制代码
mkdir` `-p` `"$HOME"`/buildroot-builder/{docker,output};                               \
`cd` `"$HOME"`/buildroot-builder;                                                     \
`git` init `-b` master;                                                               \
`git` submodule add `--depth=1` https://github.com/buildroot/buildroot.git buildroot; \
`git` `-C` buildroot fetch `--depth=1` origin tag `2025`.05;                              \
`git` `-C` buildroot checkout `2025`.05;                                                \
`cat` > .gitignore `<< 'EOF'`
`/output`
`/buildroot/*`
`*.old`
`EOF`
`git` add buildroot docker .gitignore .gitmodules`

Buildroot 的最新版本将于 2025 年 7 月发布。

为了进一步熟悉组件的结构及其配置,我们还将从Linux下载U-Boot:

复制代码
git` clone `--depth=1` `-b` v2025.07 https://github.com/u-boot/u-boot.git  u-boot; \
`git` clone `--depth=1` `-b` v6.15    https://github.com/torvalds/linux.git linux`

所使用的版本是截至 2025 年 7 月的 Linux 和 U-Boot 的最新稳定版本。

让我们创建一个 Docker 镜像。在我的例子中,它基于Debian 11镜像:

复制代码
cat` > docker/Dockerfile `<< 'EOF'`
`FROM debian:11`

`ARG UID=1000`
`ARG GID=1000`
`ARG USERNAME=builder`

`RUN apt update &&                                              \`
`    apt install -y sudo git &&                                 \`
`    groupadd -g ${GID} ${USERNAME} &&                          \`
`    useradd -m -u ${UID} -g ${GID} -s /bin/bash ${USERNAME} && \`
`    echo "${USERNAME} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers`

`USER ${USERNAME}`

`WORKDIR /host`
`EOF`
docker build `--build-arg` `UID=$(id -u)` `--build-arg` `GID=$(id -g)` `--tag` buildroot-builder-image `-f` docker/Dockerfile docker`

让我们启动容器:

复制代码
`docker run `--name` buildroot-builder `-v` /home/`$USER`/buildroot-builder:/host `-it` buildroot-builder-image /bin/bash`

对于图形爱好者

让我们在容器中安装几个基本实用程序:

复制代码
sudo` apt update && `sudo` apt install `-y` mc nano`
  • mc--- 方便浏览目录

  • nano--- 用于编辑文本文件(Vim 爱好者请原谅我)

由于我们将首先练习独立于 Buildroot 设置 U-Boot 和 Linux,因此需要手动安装它们的一些依赖项:

复制代码
sudo` apt install `-y` flex bison`

安装最少的软件包集:

复制代码
sudo` apt install `-y` build-essential libncurses-dev debianutils pkg-config \
diffutils findutils binutils patch bzip2 unzip rsync `make` `bash`            \
gzip perl cpio file `gawk` `wget` `sed` `gcc` g`++` tar bc`

安装可选包:

复制代码
sudo` apt install `-y` openssh-client default-jdk python3-pip subversion \
mercurial graphviz python3 dblatex `curl` cvs `git` w3m;                  \
pip install matplotlib asciidoc argparse aiohttp bazaar`

对于那些已将图形放入容器并计划使用make gconfig或的用户make xconfig,需要交付以下包:

复制代码
sudo` apt install `-y` qtbase5-dev-tools libqt5widgets5 libglib2.0-dev \
libgtk2.0-dev libglade2-dev qtbase5-dev libqt5gui5 qt5-qmake`

我们还将设置BR2_EXTERNAL 环境变量,让 Buildroot 了解外部层。稍后我们将讨论修改 Buildroot 的机制,但现在,让我们简单地在external目录中创建一个最小的外部层结构:

复制代码
echo` `"export BR2_EXTERNAL=/host/external"` >> ~/.bashrc;  \
`source` ~/.bashrc;                                        \
`mkdir` `-p` `"$BR2_EXTERNAL"`/{board/test,configs};           \
`cd` `"$BR2_EXTERNAL"`;                                      \
`touch` external.mk;                                       \
`cat` > external.desc `<< 'EOF'` 
`name: TEST_EXTERNAL_LAYER`
`desc: Test external layer for Buildroot practice`
`EOF`
`cat` > Config.in `<< 'EOF'` 
`menu "Test external layer options"`
`endmenu`
`EOF

至此,工作环境的搭建就完成了。在开始构建之前,我们先来看看下载的项目内容。

3.2. 组件结构

如果您已经查看过u-bootlinuxbuildroot的内容,您可能会对其中丰富的目录和文件感到惊讶。别担心,没有必要彻底分析组件结构(至少目前不需要),但了解关键的目录和文件非常重要。

3.2.1. U-Boot

  • arch --- 位于相应子目录(armx86等)中的"与架构相关的"代码。其内容如下:

    • dts --- 设备树硬件描述文件(*.dts*.dtsi
  • board --- 特定于主板的代码。目录由供应商命名(例如sunxinvidia等)。其中包含用于初始化、电源设置和其他操作的主板特定代码。

  • configs --- 典型的 U-Boot 配置(*_defconfig

  • doc --- 官方文档。

  • 驱动程序------各种外围设备(UART、SPI 等)的驱动程序

3.2.2. Linux

  • 文档--- 官方文档。

  • arch --- 位于相应子目录(armx86等)中的"与架构相关的"代码。其内容如下:

    • boot/dts --- 设备树硬件描述文件(*.dts*.dtsi

    • configs --- 典型的 Linux 配置(*_defconfig

  • 驱动程序--- 各种设备(网络、总线、图形、声音等)的驱动程序

3.2.3. 构建根目录

  • board --- 特定主板的脚本、补丁和设置

  • configs --- 典型的 Buildroot 配置(*_defconfig

  • docs --- 官方文档。

  • --- 可通过 Buildroot 构建的包

3.2.4. 外层

可以想象,任何直接对u-bootlinuxbuildroot进行的更改都会淹没在浩瀚的文件和目录中。将整个源代码拖入代码库并非最佳选择。

为了解决这个问题,Buildroot 有一个解决方案------外部树 ,或外部层

实际上,外层只是一个目录,其中包含其配置、附加包、补丁、驱动程序、设备树文件等。对外层的结构没有特定要求,但官方文档建议遵循这种方法。

在准备工作环境时,我们创建了它的最小结构。目前缺少 U-Boot、Linux 和 Buildroot 的配置文件。让我们看看这些文件是什么以及如何创建它们。

3.3. 配置组件

每个组件,无论是 Buildroot、Linux 还是 U-Boot,都可以使用变量进行配置make。这些变量存储在文件中,文件可以分为几种类型:

  • 默认设置分布在各个组件文件中。

  • 当前设置 存储在**.config文件中。**

  • *_defconfig 文件- 非默认设置

创建最后两个有一组规则make

  • make board_defconfig---从指定的***_defconfig** 创建**.config文件**

  • make savedefconfig---从**.config** 创建***_defconfig文件**

如果您不熟悉make,请不要担心。我们稍后会详细介绍它的结构。现在,只需记住:make您需要从相应组件的根目录调用它。

有各种用于更改组件的**.config**文件的交互式菜单:

  • make menuconfig--- 基于curses的文本界面。

  • make nconfig--- 基于ncurses的文本界面。

  • make gconfig--- 基于GTK+ 的图形界面。

  • make xconfig--- 基于Qt的图形界面。

我将使用menuconfig作为最通用且易于使用的选项。

让我们尝试为组件创建一个**.config文件并使用** menuconfig更改其配置。

3.3.1 了解 MenuConfig

我建议从u-boot开始。正如我之前提到的,我的主板是 Sunxi 的 OrangePi PC,板载一个 ARM SoC。

进入u-boot 并创建一个**.config**文件:

复制代码
cd` /host/u-boot; \
`make` orangepi_pc_defconfig`

现在您可以调出配置菜单:

复制代码
make` menuconfig`

一个包含各种设置组的界面出现在我们面前。操作非常简单:

  • 向上和向下箭头 - 在项目之间移动。

  • 左右箭头或Tab - 在菜单和下面的按钮之间切换(选择退出帮助等)。

  • 输入--- 选择一项或确认一项操作。

  • 双击Esc返回上一级或退出菜单。

  • 此菜单对于所有组件都是相同的,因此您可以进行实验:浏览菜单,更改一些设置,查看主菜单和子菜单之一中的帮助,尝试使用搜索功能,将结果保存在 /host/u-boot/.config中,再次打开菜单并确保设置确实已更改。

完成了吗?这里有一个快速挑战来巩固一下:在 Linux 中启用对Realtek RTL8152/RTL8153 USB 网络驱动程序 内置支持。Linux 有一个特殊功能:make调用它时需要指定体系结构:

复制代码
cd` /host/linux; \
`make` `ARCH=`arm sunxi_defconfig; \
`make` `ARCH=`arm menuconfig`

任务完成了吗?如果完成了,你可以放心地删除u-bootlinux目录------它们已经不再需要了:

复制代码
cd` /host; \
`rm` `-rf` linux u-boot`

接下来,我们删除它们的依赖关系:

复制代码
sudo` apt remove `-y` flex bison && `sudo` apt autoremove `-y

稍后如何配置 Linux 和 U-Boot?当然是使用 Buildroot。

3.3.2. 通过 Buildroot 配置

我们进入buildroot ,在外层创建我们需要的***_defconfig文件的副本,之后我们创建一个** .config文件:

复制代码
cd` /host/buildroot;                                                  \
`cp` configs/orangepi_pc_defconfig ../external/configs/test_defconfig; \
`make` `O=`../output test_defconfig`

此参数O=指定 Buildroot 构建的输出目录。

现在我们可以访问make配置组件的规则:

  • make linux-menuconfig--- 调用 Linux 配置菜单

  • make uboot-menuconfig--- 调用 U-Boot 配置菜单

确保 Buildroot 配置中包含相应的组件。否则,命令将失败。
第一次调用这些规则时,您必须等待组件加载并配置其工作环境。

在组装之前,我建议更改每个组件中的一个参数:

  • u-boot

    复制代码
    make O=../output uboot-menuconfig
    • 启动选项

      • 自动启动选项

        • (5)自动启动前的延迟秒数

        • \* 通过特定的输入键/字符串停止自动启动

        • (%d 后再见 U-Boot...\n)自动启动停止提示

        • \* 启用 Ctrl-C 自动启动中断

    将配置保存到文件/host/external/board/test/u-boot.config

  • Linux

    复制代码
    make O=../output linux-menuconfig
    • 常规设置

      • (HelloLinux)本地版本 - 附加到内核版本

    将配置保存到文件/host/external/board/test/linux.config

  • 构建根

    复制代码
    make O=../output menuconfig
    • 系统配置

      • (你好 Buildroot!)系统横幅
    • 核心

      • 内核配置(使用自定义(def)配置文件)

      • ($(BR2_EXTERNAL)/board/test/linux.config) 配置文件路径

    • 引导加载程序

      • U-Boot

        • U-Boot 配置(使用自定义 (def)config 文件)

        • ($(BR2_EXTERNAL)/board/test/u-boot.config) 配置文件路径

    将配置保存到文件/host/output/.config

组件已配置完毕------现在您可以更新外层的 Buildroot 的***_defconfig文件:**

复制代码
make` `O=`../output savedefconfig`

设置已完成。让我们进入下一步:组装。

4. 第一步

4.1. 从 make 到 image

我想您make uboot-menuconfig已经make linux-menuconfig欣赏 Buildroot 的方法:您所需的一切都会自动下载、配置、编译和安装。

要组装所有组件,你只需要一个命令,以及一点耐心。这个命令已经很熟悉了make

4.1.1. 系统组装

那么,让我们开始构建系统:

复制代码
cd` /host/buildroot; \
`make` `O=`../output`

如果您遵循了选择电路板和配置组件的建议,则无需担心:一切都应该顺利组装。

当然,事情并不总是一帆风顺。有时,由于软件包版本不稳定、配置问题或第三方工具的意外行为,可能会出现构建错误。Buildroot 提供了一些用于解决此类问题的工具------我们稍后会介绍。

至于构建时间,它取决于许多因素:网络连接速度、RAM、处理器频率、磁盘速度以及核心数量。首次构建尤其耗时,因为 Buildroot 需要从头开始下载并编译所有软件包。

构建成功了吗?如果是这样,我建议对我们的代码库进行第一次提交:

复制代码
cd` `"$HOME"`/buildroot-builder; \
`git` add external;             \
`git` commit `-m` `"First step"`;   \
`git` tag FirstStep`

现在让我们看一下输出目录的内容。

4.1.2. 输出目录结构

其中可以找到几个关键目录:

  • build --- 下载所有软件包的源代码和中间构建文件

  • 主机是主机系统在构建过程中所需程序的隔离环境。它包含工具链、实用程序、库和头文件。

  • target --- 目标系统的根文件系统。此目录中的所有内容都可以在目标设备上访问。

  • 图像--- 包含构建工件的目录

最令我们感兴趣的是图像

4.1.3. 组装工件

工件列表取决于组件配置,但对于具有基本设置的 OrangePi PC 来说,它看起来像这样:

  • genimage.cfg --- 用于构建sdcard.img的配置文件

  • rootfs.* --- 根文件系统

  • sdcard.img - 用于在 SD 卡上录制的图像

  • sun8i-h3-orangepi-pc.dtb --- 编译的设备树

  • u-boot-sunxi-with-spl.bin --- 带有 SPL 的 U-Boot 可执行文件

  • u-boot.bin --- U-Boot 可执行文件

  • zImage是一个压缩的 Linux 内核。

我们稍后会详细讨论每个文件的功能。目前,我们只关注sdcard.img 文件

4.2. 准备发布

启动前只剩下两个步骤:将图像写入 SD 卡并将开发板连接到 PC。

4.2.1. 录制到 SD 卡

通常,将图像写入 SD 卡的命令位于buildroot/board/<board>readme.txt文件中。

对于 OrangePi PC,这是文件buildroot/board/orangepi/orangepi-pc/readme.txt。其中的命令如下:

复制代码
sudo` dd `if=`output/images/sdcard.img `of=`/dev/sdX`

让我们使用 MicroSD 转 USB 适配器将 SD 卡连接到电脑,然后在主操作系统中打开另一个终端。打开它lsblk并在列表中找到您的 SD 卡。在我的例子中,它是**/dev/sdb**。

确保你找到的驱动器是SD卡!否则,你可能会损坏另一个驱动器上的数据!

生成的命令是:

复制代码
sudo` umount /dev/sdb*;                                                                            \
`sudo` dd  `of=`/dev/sdb `if="$HOME"`/buildroot-builder/output/images/sdcard.img `bs=`1M `status=`progress; \
`sudo` sync`

bs --- 一次写入的数据量。

status=progess --- 录制过程的输出

您可以将 SD 卡与 PC 断开并将其连接到开发板。

4.2.2. 将开发板连接到 PC

您不能直接连接到开发板上的任意 UART,您需要找到正确的 UART。通常,它会通过开发板上的一组单独引脚进行路由:RX、TX 和 GND。在 OrangePi PC 上,它们位于 HDMI 和电源连接器之间。

通常,UART 以 115200 波特、8 个数据位、1 个停止位、无奇偶校验协议和无流量控制运行。

所有这些 UART 参数和引脚都可以在*.dts 和***.dtsi**文件中找到。设备树是一个复杂的主题,因此我们稍后会更详细地介绍它。

将开发板连接到 UART-USB 适配器:开发板的 RX 连接到适配器的 TX,反之亦然。将 GND 1 连接到 1。

在您的电脑上运行以下命令:

复制代码
`watch `-n` `1` `-t` `ls` /dev/ttyUSB* /dev/ttyACM*`

将适配器连接到电脑。运行的命令将显示适配器的路径。在我的例子中,它是**/dev/ttyUSB0**。

要终止命令,watch请按Ctrl+C

我们之前已经安装好了它minicom。我们通过传递找到的设备的路径和 UART 速度来调用它:

复制代码
`minicom `-D` /dev/ttyUSB0 `-b` `115200

现在我们需要配置我们的端口:

  • Ctrl+A、O

  • 转到串行端口设置选项卡

  • 通过按下键盘上相应的字母来配置端口。设置如下:

    • E - Bps/Par/Bits:115200 8N1

    • F - 硬件流控制:否

    • G - 软件流控制:否

  • **选择将设置保存为 dlf,**将设置保存为默认配置

  • **选择"退出"**关闭配置菜单

一切准备就绪,可以启动主板了。

4.3. 首次启动

启动开发板。如果所有配置和连接正确,您将在终端中看到以下内容:

  1. U-Boot启动流程

  2. 5 年后再见U -Boot...

  3. 内核启动过程

  4. 我们的Hello Buildroot 系统欢迎横幅在这里!

我建议您登录。用户名:root,无需密码。

最后要检查的是内核版本:

复制代码
`uname `-r

在内核版本旁边,您会看到**HelloLinux------**这意味着我们所有的设置都已正确应用。

要退出,minicom请按Ctrl+A、X

恭喜:您已经配置、构建并启动了自己的嵌入式 Linux 系统!

这条艰难的道路上,我们已经迈出了第一步。接下来还有更多。

结果

因此,我们使用 Docker 准备了一个工作环境,分析了 U-Boot、Linux、Buildroot 及其外层的结构,在我们的板上配置、构建和启动了嵌入式 Linux。

在你开始玩你的新"玩具"之前,请允许我先说几句关于下一章的内容。

简而言之,我们将深入探讨。我们将详细介绍 Buildroot和bashKConfig 基础知识。它是什么,它如何工作,为什么需要它,以及它带来了哪些机会。make

会有很多理论,但是没有它,嵌入式就不可能实现。

现在,我先不打扰你了。你可以自己动手试试:探索一下文件系统结构,尝试不同的命令,以及探索一下系统目录------例如**/proc**。

感谢您抽出时间。再见!

相关推荐
FoldWinCard7 小时前
D5 Linux 网络及端口命令
linux·运维·服务器
零涂毕业设计8 小时前
毕业设计模块开发-OLED显示屏(IIC协议0.96寸)STM32 ESP32 FPGA Linux驱动免费分享
linux·stm32·单片机·嵌入式·esp32·fpga·oled
tedcloud1238 小时前
OmniRoute怎么部署?开源AI模型路由平台Linux部署教程
linux·服务器·人工智能·开源·音视频
霸道流氓气质8 小时前
KMS 密钥管理服务(Key Management Service)原理与实践
linux·服务器·数据库
SakitamaX8 小时前
LVS(Linux Virtual Server)概念详解
linux·运维·lvs
小张同学a.9 小时前
Linux系统管理
linux·运维
阿龙的工作记录9 小时前
深入理解Linux设备驱动模型
linux·嵌入式硬件·工作记录
代码村新手9 小时前
Linux的基本指令
linux·运维·服务器
hkj880810 小时前
Ubuntu 切换java版本
java·linux·ubuntu
撩得Android一次心动11 小时前
Linux编程笔记3【个人用】
linux·笔记