尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

用Buildroot为RK3568构建定制Linux系统:从配置到部署

用Buildroot为RK3568构建定制Linux系统:从配置到部署 拿到一块 RK3568 的开发板很多人的第一反应是直接去瑞芯微官网拖 SDK几个 TB 的代码拉下来编译一天烧进去然后用着用着就开始头疼文件系统里塞满用不到的东西内核版本被厂商焊死想换掉 BusyBox 的 init 流程都像在拆炸弹。我最初也是这个路子直到把项目改成基于 Buildroot 构建才发现 RK3568 这种平台完全可以用更干净、更可控的方式定制出一套 Linux 系统。这篇文章就把我在 RK3568 上从配置 Buildroot 到完成部署的全过程拆开讲一遍包括选型思路、内核与 U-Boot 的对接、rootfs 裁剪、分区烧录和二次开发时踩到的一堆坑。不管是刚接触 Buildroot 的新手还是已经用厂商 SDK 做过几版固件、想摆脱“全家桶”的嵌入式工程师这篇文章都值得你花十分钟看完。我会尽量把所有操作背后的原因讲清楚而不只是丢一堆命令让你复制。1. 为什么围着 Buildroot 转RK3568 系统构建的选型思路1.1 三套方案的优劣势对比先说说我为什么没继续用厂商 SDK。瑞芯微官方 SDK 确实省事内核、U-Boot、ATF、rootfs 全部集成好甚至自带一套编译脚本对于快速出 demo 来说体验很好。但它的问题在于代码树极其庞大每次同步都是几个 GB而且大量补丁打到内核里导致内核版本停留在某个固定 release 上很难升级。对产品化项目来说这种“大而全”反而成了交付负担——你很难向团队解释清楚为什么 rootfs 里会有二十几个自己都叫不上名字的服务。Yocto 我也试过。它适合大团队、多产品线、需要长期维护复杂镜像的场景bitbake 的配方体系足够严谨但学习曲线也确实陡初期的构建时间更是劝退。对于 RK3568 这类单板产品往往只有一块板子、一套外设、一个明确的业务功能Yocto 的“重”和 Buildroot 的“轻”对比特别明显。Buildroot 的优势在于:配置模型简单基于 Kconfig 的 menuconfig 界面做过 Linux 内核配置的人几乎没有上手成本。编译速度快全量构建一次 RK3568 镜像在我 i5 的机器上大概 20 到 40 分钟改配置增量编译更快。产物清晰output/images 下放着的就是你最终需要烧录的镜像中间文件都在 output/build 里方便排查。源码级管理每个组件都有明确的版本号方便复现和审计这点对做产品的公司很重要。1.2 Buildroot 模式下内核、U-Boot、rootfs 怎么分工Buildroot 和“自己手动交叉编译内核 手工制作 rootfs”最大的不同是它把整条链路纳入了同一套构建体系。你在 menuconfig 里选了内核版本、选了 U-Boot 配置、选了要装哪些库它就会按依赖关系依次完成下载、解压、打补丁、编译、安装到 target 目录最后通过 genimage 工具把所有部分拼成一个完整的烧录镜像。这套模式下你的实际工作量变成了三块选好每一个组件的版本和配置项让它们能正确编译。写或者改 genimage 的镜像描述文件确定分区布局。准备自己的业务程序、配置文件、初始化脚本通过 rootfs overlay 的方式打进镜像。把这三块理清楚整个定制流程就通了。后面几个部分我都是按这个思路展开的。2. 开工前的平台梳理与工程初始化2.1 RK3568 的硬件特性对构建方案的影响RK3568 是瑞芯微推出的一颗四核 Cortex-A55 处理器主频最高 2.0GHz内置 Mali-G52 GPU、VPU 视频编解码单元、双千兆网口、多路显示接口定位是工业控制、边缘计算、智能网关这一类场景。它的启动流程和 RK3399、RK3588 类似都是“BootROM - U-Boot TPL/SPL - ATF - U-Boot proper - 内核”的多级引导所以在 Buildroot 里把arm-trusted-firmware、U-Boot、Linux kernel三项都勾上是必须的。硬件差异还会直接影响几个配置选项内存大小和类型会影响 U-Boot 里的 DDR 初始化参数但 Buildroot 里使用的 U-Boot defconfig 已经针对不同公板做了预设比如evb-rk3568默认支持 2GB/4GB LPDDR4如果你用的是自研板需要留意自己板子的 DDR 颗粒型号和 U-Boot 配置是否匹配。显示接口、触摸屏、PCIe、USB 3.0 这些外设主要影响设备树文件的选择而不影响 Buildroot 本身的编译选项。存储介质SD 卡、eMMC、NVMe影响的是分区表和烧录方式Buildroot 的 genimage 配置可以同时生成 SD 卡镜像和烧录到 eMMC 的镜像格式。我用的是一块 RK3568 核心板加自研底板底板上有两路千兆网口、三路串口、一个 M.2 接口所以后面的设备树和内核配置都会围绕这些外设展开。2.2 拉取 Buildroot 并启用 RK3568 defconfig开始之前先把 Buildroot 源码拉下来。我习惯用 git 管理这样后续升级版本、回溯问题都方便git clone https://gitlab.com/buildroot.org/buildroot.git cd buildroot git checkout 2024.02.xBuildroot 官方仓库里已经带了 RK3568 的默认配置这个配置是个很好的起点make rockchip_rk3568_defconfig执行完后output/.config就是当前的完整配置。你可以先跑一次make用默认配置生成一套可启动的镜像确认自己手上这块板能正常进入系统再开始定制化修改。这一步非常重要因为如果一开始就叠加自己的各种改动出了问题根本分不清是配置问题还是编译环境问题。首次编译前要装好依赖。Buildroot 官方文档列得很详细在 Debian/Ubuntu 上通常需要这些包sudo apt install -y build-essential flex bison bc libssl-dev \ libncurses-dev libfile-which-perl unzip rsync \ cpio python3 python3-pip device-tree-compiler \ swig libpython3-dev如果编译过程中报缺少某个工具按提示补装就行不要急着怪 Buildroot。2.3 用外部树管理自己的定制层官方 defconfig 能让你跑起来但真正的产品需求肯定要加自己的包、改内核设备树、塞自己的应用。我强烈建议使用BR2_EXTERNAL机制把定制内容放到 Buildroot 源码树之外而不是直接在output目录里改。先建一个外部树mkdir -p my-rk3568-board/board/overlay mkdir -p my-rk3568-board/package/myapp mkdir -p my-rk3568-board/configs然后在my-rk3568-board/external.mk、Config.in和external.desc里声明这个外部树。具体写法可以看 Buildroot 官方文档的“Using Buildroot external”章节。这样做的核心好处是Buildroot 升级时你的定制层不受影响团队协作时只需要把my-rk3568-board这个目录提交到 git别人拉下来就能构建同一套镜像。外部树配好后用这种方式加载它make BR2_EXTERNAL/path/to/my-rk3568-board rockchip_rk3568_defconfig之后在make menuconfig里就能看到外部树中的软件包和配置文件了。3. 菜单配置中的关键决策点rootfs 定制与内核集成3.1 工具链选择glibc、musl 还是 Buildroot 内部工具链进入make menuconfig后第一件要定的事是工具链。Target options 里选AArch64little endian没问题关键是 Toolchain 子菜单里的选择。Buildroot 默认会使用它自己编译的内部工具链版本通常比较新支持 glibc 和 musl 两种 C 库。我的项目实测下来情况如下C 库优势劣势适用场景glibc兼容性最好各大软件包的测试最充分体积偏大内存占用略高双目视觉、AI 推理、需要跑复杂中间件的场景musl静态链接方便镜像体积小个别二进制依赖 glibc 特有行为时会出问题网络设备、资源受限的边缘网关RK3568 本身性能不弱内存一般也有 1GB 以上所以只要没有体积上的强制要求我建议直接用 glibc。别为了省几十 MB 去选 musl等到后面要跑某个闭源库时发现它对 glibc 有依赖再回头换工具链代价是一整次全量重编。外部工具链比如 Linaro 的 aarch64 GCC我也试过好处是编译速度快一些坏处是版本和 Buildroot 内各软件包可能会有兼容性问题。非特殊需求不要自讨苦吃。3.2 软件包裁剪与运行环境搭建Buildroot 的一个核心理念是“按需选择”但这里有个容易误判的地方你选的包越多构建时间越长体积越膨胀但完全裸奔的 BusyBox 系统又满足不了日常调试需求。我的建议是先确定“运行一套业务系统至少需要什么”再往里加调试工具。以我的项目为例我在 System configuration 和 Target packages 里做了这些调整开启ssh我选的 dropbear轻量或openssh用于远程登录。开发阶段 openssh 更顺手产品阶段换成 dropbear 更省资源。开启network-manager或systemd-networkd。如果配置了 systemd直接交给 systemd 管理网络更简洁。文件系统工具按需选e2fsprogs、dosfstools、util-linux、parted方便在板子上查分区和格式化。调试工具至少保留tcpdump、strace、htop、i2c-tools排查外设问题时没有它们是寸步难行。应用运行环境按业务定比如要跑 Python 脚本就选python3要跑 C 服务就确认glibc和动态链接器正常。这里想强调一个容易被忽略的点BusyBox本身也可以裁剪。Buildroot 里busybox的配置是独立的它提供了ps、ls、sh等命令如果不需要某个 applet在busybox menuconfig里关掉可以省下不少空间。但别裁得太狠我见过有人把vi关掉结果现场调试时连配置文件都没法改只好重新烧固件。3.3 内核、U-Boot 和 ATF 的对接方式RK3568 的定制绕不开这三样arm-trusted-firmwareATF、U-Boot、Linux kernel。Buildroot 把这三者都纳入了配置体系你需要做的是让它们版本匹配。内核部分我选了自定义 Git 仓库的方式指向 Rockchip 官方 Linux 内核因为仓库里带了一批 Rockchip 平台的补丁和 defconfigBR2_LINUX_KERNELy BR2_LINUX_KERNEL_CUSTOM_GITy BR2_LINUX_KERNEL_CUSTOM_REPO_URLhttps://github.com/rockchip-linux/kernel.git BR2_LINUX_KERNEL_CUSTOM_REPO_VERSIONdevelop-5.10 BR2_LINUX_KERNEL_DEFCONFIGrockchip_linux BR2_LINUX_KERNEL_DTS_SUPPORTy BR2_LINUX_KERNEL_INTREE_DTS_NAMErockchip/rk3568-evbrockchip_linux这个 defconfig 是 Rockchip 内核自带配置集成了大量驱动和 Rockchip 特有功能。如果你用的是自研板设备树文件要替换成自己的建议把 dts 文件放到内核源码树的arch/arm64/boot/dts/rockchip/目录下然后通过BR2_LINUX_KERNEL_INTREE_DTS_NAME指向它。U-Boot 的配置点如下BR2_TARGET_UBOOTy BR2_TARGET_UBOOT_BOARD_DEFCONFIGevb-rk3568 BR2_TARGET_UBOOT_NEEDS_PYTHON3y BR2_TARGET_UBOOT_NEEDS_PYLIBFDTy BR2_TARGET_UBOOT_FORMAT_IMGyevb-rk3568是 Rockchip 评估板的 U-Boot 默认配置如果你的板子不是公板需要自己在 U-Boot 源码里添加板级 defconfig 和设备树。大多数自研板改动的只是 DDR 参数和外围初始化这部分调试起来比 Buildroot 其他环节要麻烦要有心理准备。ATF 在BR2_TARGET_ARM_TRUSTED_FIRMWAREy时启用RK3568 需要它的 BL31 来配合 U-Boot 的正常启动。注意 ATF 的版本和 U-Boot 同样需要匹配我遇到过 ATF 过新、U-Boot 过老导致启动时在 ATF 阶段直接卡死的问题。保险的做法是三者的 commit 都从 Rockchip 官方同一个发布分支里取。4. 从 defconfig 到可启动镜像分区、设备树和烧录细节4.1 分区表怎么定genimage 怎么改Buildroot 最终通过genimage把内核、U-Boot、rootfs 拼成镜像。RK3568 的 SD 卡/eMMC 分区习惯一般是这样分区起始位置大小内容idbloader32KB 偏移4MBU-Boot TPL/SPLu-boot4MB 偏移4MBU-Boot propermisc8MB 偏移4MB系统恢复标记、OTA 相关信息boot12MB 偏移100MB内核镜像 dtbrootfs112MB 偏移剩余空间Buildroot rootfs 镜像这个布局不是绝对的但有几个原则要守住idbloader必须放在 32KB 偏移处这是 RK3568 BootROM 的硬性要求u-boot紧随其后boot和rootfs的顺序、大小可以改但建议把 boot 放前面方便后续单独更新内核。Buildroot 的board/rockchip/rk3568/genimage.cfg就是做这件事的。你需要根据自己的分区规划修改它尤其是 rootfs 分区大小。默认配置生成的镜像可能只给 rootfs 留几百 MB如果你的业务程序和数据比较大要在genimage.cfg里把 rootfs 分区的大小调整到合理范围。这里我踩过坑直接在genimage.cfg里把 rootfs 分区大小写成一个固定值比如 500MB后来程序要写超过这个大小的日志文件导致整块分区写满系统直接进入“只读”状态。正确做法是让 rootfs 分区尽可能占满 SD 卡剩余空间或者明确预留一个可扩展的数据分区把业务数据单独挂载到那里。4.2 设备树与启动参数的处理设备树是 RK3568 定制里最容易出问题的地方。Buildroot 编译内核时会把BR2_LINUX_KERNEL_INTREE_DTS_NAME指定的各 dts 编译为 dtb放在 boot 分区里。U-Boot 启动时会按它自己匹配到的 dtb 来启动内核所以你需要保证 U-Boot 设备树和内核设备树描述的外设一致性。自研板的设备树一般要改这些点内存节点reg 0x0 0x20000000这样的大小和起始地址DDR 大小不对会导致内核只识别出一部分内存。网口 PHY 地址和复位 GPIORK3568 双网口的配置特别容易踩坑不同底板用的 PHY 芯片和复位引脚不同要在 dts 里逐个对应。UART 配置debug 串口号、波特率、流控调错了就看不到日志。电源域和 regulatorRK3568 的 IO 域和 DVFS 依赖这些节点配置不对会出现外设不稳定、内核启动报 voltage 错误。调试设备树千万别只改 dts 就重新烧整包效率太低。先从 U-Boot 环境里确认 U-Boot 自己是否正常识别到了网卡、DDR 和存储。然后单独编译 dtb通过 U-Boot 的load mmc或 tftp 加载到内存再 boot 内核这样一轮验证只要几秒钟。Bootargs 方面Buildroot 生成镜像时通常会设置一个默认的consolettyS2,1500000 root/dev/mmcblk0p5之类的参数。如果你改了分区布局一定记得同步改 U-Boot 的 bootargs 配置尤其是 root 分区节点。RK3568 的调试串口一般默认是ttyS2波特率 1500000但自研板未必一样启动参数错误最常见的现象就是串口完全没有输出。4.3 烧录介质差异SD 卡、eMMC、RKDevTool烧录方式取决于目标介质。开发阶段我一般直接用 SD 卡sudo dd ifoutput/images/sdcard.img of/dev/sdX bs4M convfsyncsdcard.img 是 Buildroot 通过 genimage 生成的整体镜像dd 完插到板子上就能启动。注意千万不要写错盘符写错一次后悔一天。量产或者开发板焊了 eMMC 的话更常见的做法是用瑞芯微的 RKDevTool通过 USB 烧录。这时候需要把 Buildroot 生成的各部分镜像分别烧到对应分区idbloader、uboot、boot、rootfs 各自对应。eMMC 没有 SD 卡那样现成的分区表所以烧录前要让板子进入 maskrom 或 loader 模式再通过工具分区和烧写。我个人建议开发流程中保持“SD 卡为主、eMMC 为辅”的双轨方案。改代码、调驱动时频繁烧 SD 卡方便功能稳定后烧一版 eMMC验证正式启动流程和断电保护逻辑。两者共用一套 Buildroot 配置只是烧录目标不同Config 里不需要额外改太多。5. 编译、烧录与上板验证的完整链路5.1 首次编译的节奏控制确认 defconfig 正常后我的建议是不要直接make一把梭到底而是分阶段进行方便定位问题make rockchip_rk3568_defconfig make uboot make linux make arm-trusted-firmware make先单独编译 U-Boot、内核和 ATF是为了提前发现工具链或源码版本的兼容性问题。这几个组件编译失败时的日志往往比较长单独编能更快定位。第一次全量编译时Buildroot 会下载大量源码包国内网络环境下有可能很慢。建议先设置好合适的镜像源或者在make menuconfig的 Build options 里配好BR2_PRIMARY_SITE和BR2_BACKUP_SITE让下载过程有兜底。编译过程中有几个实用技巧开启 ccacheBR2_CCACHEy二次编译会快很多。设置BR2_JLEVEL为实际 CPU 核数左右的值别用满否则容易把机器搞到卡死。保留output/build目录不要手动删。Buildroot 的增量编译依赖它删除后只能全量重编。5.2 固件产物解析与烧录实操编译完成之后output/images下大概会看到这样几个文件sdcard.img整体 SD 卡镜像开发阶段直接 dd。idbloader.img、uboot.img、boot.vfat或kernel.img、rootfs.ext2/4分文件的产物用于 RKDevTool 分别烧录。rk3568-evb.dtb编译出来的设备树文件单独调试时可以用。uImage或Image内核镜像文件。用 RKDevTool 烧 eMMC 的流程大致是板子断电USB 连接好按住板上的 recovery/maskrom 按键上电。打开 RKDevTool识别到 loader 设备后在“分区表”里添加或选择对应分区。把 idbloader、uboot、boot、rootfs 分别关联到每个分区。点击执行开始烧录完成后板子重启进入系统。这里我踩过一个大坑开发板的 eMMC 里原本有厂商固件BootROM 会优先从 eMMC 启动导致我明明改了 SD 卡上的 U-Boot上电后还是跑厂商系统。后来才发现要用 BOOT 拨码开关或者按住 maskrom 强制进入烧录模式再擦除 eMMC 中的 idbloader。烧录前先确实确认启动介质选择引脚电平别浪费一上午。5.3 上电启动日志的判读重点板子首次上电串口终端设置好波特率后看到日志的第一件事不是高兴而是检查几个关键点U-Boot 输出里 DDR 初始化是否正常识别到的内存大小对不对。U-Boot 是否尝试从正确的中介读取 boot 分区加载内核映像一个失败会有清晰的标记。内核启动早期日志里Machine model是否指向你的设备树内存节点、串口初始化是否正常。rootfs 挂载是否成功/dev/mmcblk0pX是否正确找不到根文件系统时会报VFS: Unable to mount root fs。启动没问题之后在板子上跑几个基本命令确认系统状态cat /proc/cpuinfo free -h df -h dmesg | grep -i error此时做第一次快照保存把 Buildroot 配置.config、外部树、genimage.cfg、设备树全部提交到 git。后面不管怎么改都有个可以随时回退的基线。6. 二次开发阶段的高频坑与排查思路6.1 内核模块与 rootfs 不同步RK3568 上跑业务经常要加内核模块比如某个 USB 转串口驱动、某个摄像头驱动。Buildroot 里把模块编成.ko后默认会装到 rootfs 的/lib/modules/kernel-version/里。这里有个很隐蔽的坑内核版本号变了modules 目录路径就变了而 udev 或 modprobe 的配置还指向旧路径结果就是模块明明编译进去了却一直加载不了。排查方法很简单在板子上执行find /lib/modules -name *.ko | head -20 uname -r如果两者对不上检查BR2_LINUX_KERNEL_VERSION是否和你实际编的内核源码 commit 对应同时确认 Buildroot 对内核版本的探测是否产生了额外后缀。更稳的做法是把业务模块通过外部树做成了 Buildroot 包指定依赖linux并设置LINUX_MODULES为 y。这样每次内核更新模块都会自动跟随内核版本重新编译并安装到正确路径不需要手工处理。6.2 设备树小错误导致的奇特现象RK3568 的设备树如果写错表现往往不是“完全起不来”而是“部分功能不正常”。我遇到过三个典型问题明明定义了i2c2节点但是i2cdetect扫不到设备对比 U-Boot 设备树和内核设备树的 I2C 总线编号RK3568 的 I2C 控制器可能有别名如果两个阶段配置不一致外设初始化会被跳过。双网口只有一个能 ping 通PHY 的中断引脚或复位 GPIO 错了导致 PHY 芯片没有完成复位驱动探测物理链路失败。用dmesg看 phy 状态是关键。内核启动时随机 hang 在某个驱动往往是 regulator 或 power-domain 配置缺失驱动在访问外设寄存器的时钟被关闭。这种情况最好在 dts 里把对应的assigned-clock-rates和power-domains补齐。调试设备树最常用的工具是fdtdump和内核的CONFIG_OF_*调试选项还有启动阶段的earlycon参数。设备树有问题时earlycon往往能比标准串口驱动更早打印出线索。6.3 包依赖、许可证和版本固定Buildroot 每个软件包都有版本号和哈希校验所以整体上是可复现的。但我还是建议在项目一开始就把所有依赖包的版本固定下来不要用BR2_PACKAGE_*_LATEST这类尝鲜选项。嵌入式产品一旦进入测试阶段源码版本漂移会带来大量隐性回归。另外许可证合规这块容易被忽略。Buildroot 里非常多的包使用 GPL/LGPL 协议你在 menuconfig 里勾选时系统会通过make legal-info生成一份授权信息汇总。做商业产品的朋友务必在交付前导出这份信息避免后面法务找上门再补作业。我在 Buildroot 的 Legalinfo 和output/images/legal-info上栽过跟头一次没留意直接把一个 GPL 协议的库编进了产品之后被客户法务审计出来折腾了一周才把授权文档补全。这个成本比想象中高得多。我个人的经验是在外部树里专门留一个board/my-rk3568-board/legal/目录每次发版前把make legal-info的输出归档进 git并把授权变更记录写进发布说明。这样做既是对自己的保护也是对上游开发者劳动的尊重。建 Buildroot 镜像个把月之后最明显的感觉是整个系统“看得见、摸得着”了。内核配置、文件系统内容、启动流程每一个环节都在自己的掌控范围内不再是一个无从下手的黑盒子。如果你手上正好有 RK3568 的开发任务建议先别急着拖厂商 SDK给 Buildroot 一个机会。哪怕只是编一版最小系统跑起来都会让你对这块芯片的理解提升一个档次。
返回列表