高通嵌入式Linux开发实战(2):Linux内核编译与裁剪:高通开源内核、Device Tree设备树修改、固件打包
在上一篇里,我们已经把高通边缘硬件平台的基本脉络梳理了一遍:QRB5165、IQ-9075、IQ-9100 这类平台并不是“买一块板子、烧个 Ubuntu”那么简单,它们背后通常包含 SoC、PMIC、电源域、摄像头子系统、DSP/NPU、安全岛、Bootloader、BSP、固件分区等一整套工程体系。
从这一篇开始,我们进入真正的嵌入式 Linux 开发主线。
本篇聚焦三个问题:
-
如何理解高通平台上的 Linux BSP 与开源内核?
-
如何编译、裁剪适合工业场景的 Linux Kernel?
-
如何修改 Device Tree,并把 kernel、dtb、dtbo、modules 打包成可启动固件?
面向的典型场景包括:
-
工业机器人控制器
-
智能相机和机器视觉盒子
-
ROS2 边缘计算节点
-
长时间运行的工业 Linux 网关
-
基于 QRB5165 / IQ 系列平台的整机产品开发
1. 高通嵌入式 Linux 的 BSP 结构
在 x86 PC 上,Linux Kernel 往往可以直接从 kernel.org 拉下来编译运行。但在高通嵌入式平台上,情况会复杂很多。
原因是高通 SoC 内部并不只有 CPU,还包括:
-
Kryo / ARM Cortex-A 系列应用处理器
-
Adreno GPU
-
Hexagon DSP
-
ISP / Camera Subsystem
-
NPU / AI Engine
-
Sensor Hub / Always-on 子系统
-
PMIC 电源管理芯片
-
PCIe / USB / UFS / eMMC / SDIO 控制器
-
MIPI CSI / DSI 接口
-
安全启动、安全岛、看门狗、调试认证模块
这些硬件资源通常需要配套的:
-
Linux Kernel patch
-
Device Tree
-
firmware blob
-
bootloader 配置
-
用户态 HAL / daemon
-
Yocto 或 Ubuntu rootfs 集成脚本
-
分区镜像打包工具
所以在高通平台上,我们讨论“编译 Linux 内核”,实际上通常是在 BSP 体系中编译一个和硬件、固件、启动链强绑定的 kernel。
一个典型 BSP 目录可能类似下面这样:
bsp/
├── bootloader/
│ ├── xbl/
│ ├── abl/
│ └── tools/
├── kernel/
│ └── linux-msm/
├── device-tree/
│ └── qcom/
├── firmware/
│ ├── adsp.mbn
│ ├── cdsp.mbn
│ ├── modem.mbn
│ └── ...
├── yocto/
│ ├── meta-qti/
│ ├── meta-openembedded/
│ └── build/
├── rootfs/
├── out/
└── flash_tools/
不同厂商发布的 BSP 目录结构会有差异。比如 Qualcomm 官方、Thundercomm、Lantronix、Axiomtek 或工业板卡厂商给出的包名和路径可能不同,但核心组成大体一致:
|
组成 |
作用 |
|
|
高通平台 Linux 内核源码 |
|
|
SoC 和开发板 Device Tree |
|
|
DSP、NPU、Camera、Wi-Fi、BT 等固件 |
|
|
BSP 构建规则 |
|
|
启动镜像 |
|
|
Device Tree Overlay 镜像 |
|
|
根文件系统 |
|
|
分区刷写描述 |
实际开发时,不建议一上来就脱离 BSP 单独编 kernel。更推荐先跑通厂商 BSP 的完整编译链路,再逐步拆出 kernel、dtb、modules 的独立编译流程。

2. 高通开源内核与 BSP 内核的关系
高通平台常见的内核来源大致有三类。
2.1 Qualcomm BSP 内核
这是开发板厂商或高通官方 SDK 中附带的 kernel,通常已经包含:
-
SoC bring-up patch
-
PMIC 驱动
-
Camera 驱动框架
-
DSP 通信驱动
-
IOMMU / SMMU 配置
-
NPU / GPU 相关接口
-
板级 dts/dtsi
-
分区和启动相关配置
工业产品开发中,通常以 BSP 内核作为基线,因为它最接近板卡实际硬件。
2.2 CodeLinaro / Qualcomm 开源内核
高通开源代码历史上曾大量发布在 Code Aurora Forum,后来逐步迁移到 CodeLinaro 等平台。开发者可以在公开仓库中找到部分 Qualcomm Linux kernel、Android kernel、firmware loader、device tree 相关内容。
这类代码适合用于:
-
查看驱动实现
-
对比 upstream Linux 差异
-
跟踪高通平台补丁
-
分析某个外设驱动的演进历史
但它不一定能直接替代开发板厂商 BSP,因为工业板卡往往还有额外的 carrier board、接口扩展、电源控制、摄像头模组、CAN、RS485、隔离 IO 等私有修改。
2.3 Mainline Linux
主线 Linux 对 Qualcomm SoC 的支持越来越完善,很多 Snapdragon / QRB 平台的基础外设已经进入 upstream。
但对于工业机器人和智能相机来说,mainline 仍可能缺少:
-
完整 Camera pipeline
-
Hexagon / DSP 低功耗链路
-
商用 NPU 用户态栈
-
板厂自定义接口
-
安全岛相关驱动
-
厂商验证过的功耗和稳定性配置
所以实际产品中常见策略是:
量产用 BSP 内核,研发时参考开源内核,长期维护时逐步吸收 mainline patch。
3. 准备交叉编译环境
高通 QRB / IQ 系列平台通常是 ARM64 架构,因此 kernel 编译需要 AArch64 交叉工具链。
常见工具链包括:
-
aarch64-linux-gnu- -
aarch64-none-linux-gnu- -
Yocto SDK 中导出的交叉编译器
-
Android Clang 工具链,部分 BSP 会要求使用 Clang
如果是普通 Linux kernel 构建,典型环境变量如下:
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
export KERNEL_SRC=$PWD/kernel/linux-msm
export OUT=$PWD/out/kernel
如果 BSP 要求使用 Clang,可能类似:
export ARCH=arm64
export LLVM=1
export LLVM_IAS=1
export CLANG_TRIPLE=aarch64-linux-gnu-
建议优先阅读 BSP 中的编译脚本,例如:
build.sh
build_kernel.sh
setup_env.sh
qti_build.sh
yocto/build.sh
不要一开始就手写完整命令。因为很多 Qualcomm BSP 会额外传入:
-
KCFLAGS -
DTC_FLAGS -
vendor config fragment
-
dtbo build 参数
-
board variant
-
kernel module install path
-
boot image packing 参数
4. 编译高通 Linux Kernel
一个最小化的 kernel 编译流程通常包括:
cd kernel/linux-msm
make O=$OUT qcom_defconfig
make O=$OUT -j$(nproc) Image.gz
make O=$OUT -j$(nproc) dtbs
make O=$OUT -j$(nproc) modules
实际 BSP 中,defconfig 名称可能不是 qcom_defconfig,而是类似:
vendor/qrb5165_defconfig
vendor/sa8155p_defconfig
vendor/qcom_defconfig
qti_defconfig
可以在源码里查看:
ls arch/arm64/configs/
编译完成后,常见产物包括:
out/kernel/arch/arm64/boot/Image
out/kernel/arch/arm64/boot/Image.gz
out/kernel/arch/arm64/boot/dts/qcom/*.dtb
out/kernel/drivers/**/*.ko
out/kernel/vmlinux
out/kernel/System.map
其中最重要的是:
|
文件 |
说明 |
|
|
ARM64 Linux kernel 镜像 |
|
|
编译后的 Device Tree Blob |
|
|
Device Tree Overlay |
|
|
内核模块 |
|
|
未压缩带符号 kernel,调试用 |
|
|
符号地址表,排查 crash 用 |
工业项目里,建议每次发布内核时保留:
Image.gz
dtb/dtbo
所有 .ko
vmlinux
System.map
.config
commit id
编译脚本
否则后续遇到 kernel panic、Oops、watchdog reset 时,很难精确还原问题版本。

5. Yocto BSP 下的 kernel 编译
很多高通嵌入式 Linux BSP 使用 Yocto / OpenEmbedded 构建完整系统。此时不建议直接在 kernel 目录下 make,而是通过 Yocto recipe 编译。
典型流程类似:
source setup-environment build-qti
bitbake virtual/kernel
如果需要进入 kernel 配置界面:
bitbake virtual/kernel -c menuconfig
保存配置后,可以导出 config fragment:
bitbake virtual/kernel -c savedefconfig
或者使用 BSP 提供的方式将 .config 转换成 fragment,并放入对应 layer:
meta-custom/
└── recipes-kernel/
└── linux/
├── linux-qcom_%.bbappend
└── files/
└── industrial_robot.cfg
industrial_robot.cfg 示例:
CONFIG_CAN=y
CONFIG_CAN_RAW=y
CONFIG_CAN_DEV=y
CONFIG_CAN_MCP251X=m
CONFIG_SPI=y
CONFIG_I2C_CHARDEV=y
CONFIG_PREEMPT=y
CONFIG_CGROUPS=y
CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
然后在 .bbappend 中追加:
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI += "file://industrial_robot.cfg"
这种方式比直接修改 .config 更适合长期维护,因为它可以被 git 管理,也方便在不同 BSP 版本之间迁移。
6. 内核裁剪的基本原则
工业嵌入式 Linux 裁剪内核,不是盲目追求“越小越好”,而是在以下目标之间平衡:
-
启动速度
-
内存占用
-
稳定性
-
可维护性
-
外设支持
-
现场调试能力
-
安全性
-
长时间运行可靠性
6.1 可以优先裁剪的部分
如果产品是固定硬件、固定用途,可以考虑关闭:
不使用的文件系统
不使用的网络协议
不使用的 USB Gadget 功能
不使用的 HID / 输入设备
不使用的无线协议
不使用的调试接口
不使用的虚拟化功能
不使用的桌面图形驱动
例如智能相机系统中,如果 rootfs 固定使用 ext4,可以考虑不启用大量冷门文件系统:
CONFIG_BTRFS_FS=n
CONFIG_F2FS_FS=n
CONFIG_XFS_FS=n
CONFIG_JFS_FS=n
CONFIG_REISERFS_FS=n
如果设备不需要蓝牙:
CONFIG_BT=n
如果设备没有 Wi-Fi:
CONFIG_CFG80211=n
CONFIG_MAC80211=n
如果没有 USB 外设模式:
CONFIG_USB_GADGET=n
6.2 不建议过早关闭的部分
早期开发阶段,不建议急着关闭:
CONFIG_PRINTK
CONFIG_KALLSYMS
CONFIG_DEBUG_FS
CONFIG_PROC_FS
CONFIG_SYSFS
CONFIG_DEVTMPFS
CONFIG_MODULES
CONFIG_DYNAMIC_DEBUG
CONFIG_FTRACE
原因很简单:产品初期最重要的是可调试性。
很多现场问题,例如:
-
摄像头偶发打不开
-
CAN 总线通信异常
-
SPI 设备 probe 失败
-
系统运行 72 小时后内存下降
-
某个中断风暴导致 CPU 占用异常
-
watchdog reset 后无法定位原因
都需要依赖这些调试能力。
更合理的做法是分阶段裁剪:
| 阶段 | 策略 |
|---|---|
| Bring-up 阶段 | 保留调试能力,优先跑通硬件 |
| EVT 阶段 | 裁剪明显不用的驱动和协议 |
| DVT 阶段 | 关闭高风险 debug 接口,保留诊断手段 |
| PVT / 量产 | 固化配置,记录 config、符号表和镜像版本 |
6.3 模块还是 built-in?
在工业机器人和智能相机系统中,驱动是编进 kernel 还是做成 module,需要结合启动链路判断。
适合 built-in 的内容:
启动存储驱动
根文件系统驱动
early console
PMIC / regulator
pinctrl
clock controller
关键总线驱动
watchdog
安全相关驱动
适合 module 的内容:
可选外设
不同型号传感器
调试驱动
非启动必需的工业接口
部分 camera sensor driver
例如,如果 rootfs 在 UFS 上,UFS、SCSI、block layer 相关驱动必须在 rootfs 挂载前可用,否则系统无法启动。
如果某个 MIPI 摄像头模组存在多个型号,做成 .ko 可以让同一套 rootfs 支持不同 SKU。
7. Device Tree 在高通平台中的作用
Device Tree 是 ARM Linux 平台描述硬件资源的核心机制。
在高通平台上,Device Tree 通常描述:
-
SoC 外设控制器
-
GPIO / pinctrl
-
I2C / SPI / UART / CAN 控制器
-
regulator 电源
-
clock
-
interrupt
-
reserved memory
-
remoteproc / DSP
-
camera sensor
-
display panel
-
PCIe / USB
-
thermal zone
-
board variant
内核源码中常见路径:
arch/arm64/boot/dts/qcom/
通常会看到三类文件:
soc.dtsi
platform.dtsi
board.dts
可以简单理解为:
| 文件 | 作用 |
|---|---|
*.dtsi | 可复用的 SoC 或板级片段 |
*.dts | 最终板卡入口文件 |
*.dtbo | 可叠加的板级 overlay |
示例结构:
#include "qrb5165.dtsi"
#include "qrb5165-pmic.dtsi"
#include "qrb5165-industrial-carrier.dtsi"
/ {
model = "QRB5165 Industrial Vision Board";
compatible = "vendor,qrb5165-industrial", "qcom,qrb5165";
};

8. 修改 Device Tree:启用一个 SPI 外设
假设我们在 carrier board 上挂了一个 SPI 设备,例如工业 IO 扩展芯片或外部 ADC,需要在 Device Tree 中启用对应 SPI 控制器。
一个简化示例如下:
&spi12 {
status = "okay";
pinctrl-names = "default", "sleep";
pinctrl-0 = <&spi12_default>;
pinctrl-1 = <&spi12_sleep>;
industrial_adc@0 {
compatible = "vendor,industrial-adc";
reg = <0>;
spi-max-frequency = <10000000>;
interrupt-parent = <&tlmm>;
interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
vdd-supply = <&vreg_l11a_1p8>;
};
};
同时需要配置 pinctrl:
&tlmm {
spi12_default: spi12-default-state {
pins = "gpio110", "gpio111", "gpio112", "gpio113";
function = "qup12";
drive-strength = <8>;
bias-disable;
};
spi12_sleep: spi12-sleep-state {
pins = "gpio110", "gpio111", "gpio112", "gpio113";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
};
这里有几个关键点:
-
status = "okay"表示启用该控制器 -
reg = <0>表示 SPI chip select 0 -
spi-max-frequency要结合外设手册、走线长度、EMI 要求设置 -
interrupts要和硬件原理图中的 GPIO 中断脚一致 -
vdd-supply要绑定正确 regulator,否则驱动 probe 时可能上电失败 -
pinctrl的 default 和 sleep 状态会影响功耗表现
在工业场景中,pinctrl 的 sleep 状态很重要。很多板子待机功耗异常,最后发现不是 CPU 没睡下去,而是 GPIO、SPI、I2C、MIPI reset 脚在 suspend 状态下仍然保持高驱动或错误上拉。
9. 修改 Device Tree:启用 CAN-FD
工业机器人和运动控制场景中,CAN-FD 很常见。高通 SoC 本身是否集成 CAN 控制器,要看具体型号和板级设计;很多项目会通过 SPI 外挂 CAN-FD 控制器,例如 MCP2518FD 一类芯片。
Device Tree 示例:
&spi8 {
status = "okay";
canfd0: can@0 {
compatible = "microchip,mcp251xfd";
reg = <0>;
spi-max-frequency = <20000000>;
interrupt-parent = <&tlmm>;
interrupts = <36 IRQ_TYPE_LEVEL_LOW>;
clocks = <&canfd0_osc>;
};
};
canfd0_osc: canfd0-osc {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <40000000>;
};
内核配置需要启用:
CONFIG_CAN=y
CONFIG_CAN_RAW=y
CONFIG_CAN_DEV=y
CONFIG_CAN_MCP251XFD=m
系统启动后可以检查:
dmesg | grep -i can
ip link show
配置 CAN-FD:
ip link set can0 down
ip link set can0 type can bitrate 500000 dbitrate 2000000 fd on
ip link set can0 up
测试收发:
candump can0
cansend can0 123##1122334455667788
如果 dmesg 中出现 probe 失败,优先检查:
-
SPI 控制器是否启用
-
compatible是否匹配驱动 -
中断 GPIO 是否正确
-
外部晶振频率是否正确
-
电源 regulator 是否上电
-
SPI mode 和 max frequency 是否符合芯片要求
10. 修改 Device Tree:MIPI 摄像头的特殊性
智能相机是高通边缘平台的重要方向,但 MIPI 摄像头不是简单加一个 I2C 设备就能工作。
一个摄像头模组通常涉及:
-
I2C 控制通道
-
MIPI CSI-2 data lane
-
MCLK
-
reset GPIO
-
powerdown GPIO
-
AVDD / DVDD / IOVDD 电源
-
regulator 上电时序
-
sensor driver
-
camera clock
-
IOMMU / reserved memory
-
ISP / CSID / VFE / ICP pipeline
-
用户态 camera service 或 GStreamer plugin
简化的 Device Tree 片段可能类似:
&i2c10 {
status = "okay";
camera_sensor0: camera@1a {
compatible = "vendor,imxxxx";
reg = <0x1a>;
reset-gpios = <&tlmm 78 GPIO_ACTIVE_LOW>;
pwdn-gpios = <&tlmm 79 GPIO_ACTIVE_HIGH>;
avdd-supply = <&vreg_l7a_2p8>;
dvdd-supply = <&vreg_l3a_1p1>;
iovdd-supply = <&vreg_l5a_1p8>;
clocks = <&camcc CAM_CC_MCLK0_CLK>;
clock-names = "mclk";
port {
camera0_ep: endpoint {
data-lanes = <0 1 2 3>;
clock-lanes = <4>;
remote-endpoint = <&csiphy0_ep>;
};
};
};
};
实际 Qualcomm Camera Subsystem 的 dts 结构通常更复杂,不同 BSP 差异也比较大。开发时不要只看 sensor 节点,还要同时检查:
-
camcc -
csiphy -
csid -
vfe -
ife -
eeprom -
actuator -
ois -
flash -
camera overlay
-
用户态 camera 配置 XML / JSON
工业智能相机项目里,一个常见做法是:
Device Tree 只描述硬件连接,sensor mode、曝光、帧率、ISP tuning、AI pipeline 放到用户态配置中管理。
这样同一个 kernel 可以支持多个相机 SKU,避免每换一个模组就重刷 kernel。
11. 编译 dtb 和 dtbo
修改 .dts 或 .dtsi 后,需要重新编译 Device Tree。
如果走 kernel make:
make O=$OUT ARCH=arm64 dtbs -j$(nproc)
产物通常在:
out/kernel/arch/arm64/boot/dts/qcom/
如果使用 overlay,需要生成 .dtbo,并进一步打包为 dtbo.img。
常见流程:
make O=$OUT ARCH=arm64 dtbs
然后使用 BSP 提供的工具打包:
mkdtimg create dtbo.img --page_size=4096 board-camera.dtbo board-canfd.dtbo
或通过厂商脚本:
./build_dtbo.sh
不同平台对 dtb/dtbo 的加载方式不同:
| 方式 | 特点 |
|---|---|
| dtb 直接附加到 kernel | 早期或简单启动链常见 |
| boot.img 内包含 dtb | Android boot image 常见 |
| 独立 dtbo 分区 | 支持不同板型 overlay |
| FIT image | U-Boot 场景常见 |
| extlinux.conf 指定 dtb | 通用嵌入式 Linux 常见 |
高通平台上,尤其是 Android-derived BSP,经常会有独立 dtbo 分区。工业 Linux BSP 则可能根据厂商启动链定制。
12. 固件打包:从 kernel 到 boot.img
编译出 Image.gz 和 dtb 后,还不能直接启动。还需要打包成 bootloader 能识别的格式。
在 Qualcomm 平台上,启动链大致可以简化理解为:
PBL -> XBL -> ABL / U-Boot -> Linux Kernel
其中:
-
PBL 是 SoC ROM 内部启动代码
-
XBL 负责早期硬件初始化
-
ABL 或 U-Boot 负责加载 kernel
-
kernel 根据 dtb 初始化硬件并挂载 rootfs
如果平台使用 Android boot image 格式,常见打包产物包括:
boot.img
vendor_boot.img
dtbo.img
rootfs.img
boot.img 通常包含:
kernel
ramdisk
boot header
cmdline
可选 dtb
Android 11 之后的部分启动格式中,vendor ramdisk 和部分硬件相关内容可能被放入:
vendor_boot.img
一个简化打包命令可能类似:
mkbootimg \
--kernel Image.gz \
--ramdisk initramfs.cpio.gz \
--cmdline "console=ttyMSM0,115200n8 root=/dev/sda2 rw" \
--base 0x00000000 \
--pagesize 4096 \
--output boot.img
实际项目中不要照抄这个参数。base、pagesize、header_version、cmdline、dtb、vendor_boot 的设置必须以 BSP 脚本为准。
更安全的方式是复用原 BSP 的打包脚本,例如:
./pack_bootimg.sh \
--kernel out/kernel/arch/arm64/boot/Image.gz \
--dtb out/kernel/arch/arm64/boot/dts/qcom/board.dtb \
--ramdisk out/rootfs/initramfs.cpio.gz \
--output out/images/boot.img
如果 BSP 使用 U-Boot 和 FIT image,流程可能是:
mkimage -f kernel.its fitImage
kernel.its 中会描述:
kernel image
fdt
ramdisk
load address
entry address
hash
signature
如果使用 extlinux,启动分区可能有:
/boot/extlinux/extlinux.conf
/boot/Image.gz
/boot/qcom/board.dtb
extlinux.conf 示例:
LABEL primary
MENU LABEL primary kernel
LINUX /Image.gz
FDT /qcom/board.dtb
APPEND console=ttyMSM0,115200n8 root=/dev/mmcblk0p12 rw rootwait
13. 内核模块安装与 rootfs 集成
编译 kernel modules 后,需要安装到 rootfs 中:
make O=$OUT ARCH=arm64 modules_install INSTALL_MOD_PATH=$ROOTFS
安装后会生成类似目录:
/lib/modules/5.15.XX-qcom/
├── kernel/
├── modules.dep
├── modules.alias
├── modules.symbols
└── ...
如果 rootfs 是单独镜像,需要重新打包:
sudo mount rootfs.img mnt
sudo cp -a lib/modules/5.15.XX-qcom mnt/lib/modules/
sudo umount mnt
或者在 Yocto 中通过 recipe 自动集成。
需要特别注意:kernel image 和 /lib/modules/$(uname -r) 必须匹配。
如果设备启动后出现:
module: version magic '...' should be '...'
说明 .ko 和当前运行 kernel 不是同一次构建产物。
可以在设备上检查:
uname -a
ls /lib/modules/
modinfo your_driver.ko
14. 刷写与验证
如果平台支持 fastboot,常见刷写方式是:
fastboot flash boot boot.img
fastboot flash dtbo dtbo.img
fastboot reboot
如果是 Yocto / 工业 BSP,可能使用厂商刷机工具:
./flash.sh
或者通过 EDL / QDL 模式刷写:
rawprogram.xml
patch.xml
prog_firehose_ddr.elf
刷写后,首先确认内核版本:
uname -a
cat /proc/version
确认 cmdline:
cat /proc/cmdline
确认 Device Tree 是否生效:
ls /proc/device-tree/
cat /proc/device-tree/model
检查某个节点:
ls /proc/device-tree/soc/
检查驱动 probe:
dmesg | grep -i spi
dmesg | grep -i i2c
dmesg | grep -i can
dmesg | grep -i camera
检查模块:
lsmod
modprobe your_driver
检查中断:
cat /proc/interrupts
检查 regulator:
ls /sys/class/regulator/
检查 clock,部分 BSP 需要 debugfs:
mount -t debugfs none /sys/kernel/debug
cat /sys/kernel/debug/clk/clk_summary
15. 工业场景下的裁剪建议
针对工业机器人、智能相机、ROS2 边缘计算这类场景,可以按功能域裁剪。
15.1 工业机器人控制器
建议保留或启用:
CONFIG_PREEMPT
CONFIG_HIGH_RES_TIMERS
CONFIG_CAN
CONFIG_CAN_RAW
CONFIG_NET_SCHED
CONFIG_CGROUPS
CONFIG_CPUSETS
CONFIG_WATCHDOG
CONFIG_HW_RANDOM
CONFIG_PSTORE
CONFIG_PSTORE_RAM
重点关注:
-
调度延迟
-
CAN / EtherCAT / TSN 通信
-
watchdog 恢复
-
电源异常后的日志保留
-
CPU isolation
-
ROS2 节点资源隔离
15.2 智能相机
建议保留或启用:
CONFIG_MEDIA_SUPPORT
CONFIG_VIDEO_V4L2
CONFIG_IOMMU_SUPPORT
CONFIG_DMA_SHARED_BUFFER
CONFIG_DMABUF_HEAPS
CONFIG_CMA
CONFIG_REMOTEPROC
CONFIG_RPMSG
重点关注:
-
MIPI CSI 稳定性
-
DMA buffer 零拷贝
-
ISP / NPU pipeline
-
长时间视频流内存泄漏
-
thermal throttling
-
摄像头异常断流恢复
15.3 ROS2 边缘节点
建议保留或启用:
CONFIG_NAMESPACES
CONFIG_CGROUPS
CONFIG_CGROUP_CPUACCT
CONFIG_CGROUP_DEVICE
CONFIG_MEMCG
CONFIG_OVERLAY_FS
CONFIG_BRIDGE
CONFIG_VETH
CONFIG_NETFILTER
如果后续要跑 Docker 或 containerd,这些配置非常关键。
ROS2 对网络和时间同步也比较敏感,建议关注:
CONFIG_PTP_1588_CLOCK
CONFIG_NETWORK_PHY_TIMESTAMPING
CONFIG_POSIX_TIMERS
CONFIG_HIGH_RES_TIMERS
16. 常见问题排查
16.1 修改 dts 后没有生效
优先检查:
cat /proc/device-tree/model
cat /proc/cmdline
可能原因:
-
刷错分区
-
bootloader 加载的是另一个 dtb
-
dtbo.img 没更新
-
overlay 优先级覆盖了你的修改
-
编译的是 A 板 dts,实际启动的是 B 板 dts
-
secure boot / verified boot 阻止了镜像加载
16.2 驱动没有 probe
检查顺序:
dmesg | grep -i your_driver
ls /sys/bus/platform/devices/
ls /sys/bus/i2c/devices/
ls /sys/bus/spi/devices/
常见原因:
-
compatible字符串和驱动of_match_table不一致 -
status仍然是disabled -
父节点 I2C/SPI 控制器未启用
-
regulator 获取失败
-
clock 获取失败
-
reset GPIO 配错
-
中断号错误
-
pinctrl 状态错误
16.3 kernel 可以启动,但模块加载失败
检查:
uname -r
ls /lib/modules/$(uname -r)
modinfo driver.ko
dmesg | tail
常见原因:
-
modules 和 kernel 不是同一版本
-
CONFIG_MODVERSIONS不一致 -
依赖模块未安装
-
rootfs 中 modules.dep 未更新
-
使用了错误 toolchain 编译外部模块
16.4 系统启动卡在 rootfs 挂载
检查 bootargs:
cat /proc/cmdline
重点关注:
root=
rootwait
rootfstype=
init=
console=
常见原因:
-
UFS/eMMC 驱动未 built-in
-
ext4 驱动被编成 module
-
root 分区号变化
-
initramfs 缺少必要驱动
-
分区表和 bootargs 不一致
17. 推荐的版本管理方式
工业项目中,kernel 和 BSP 的版本管理非常关键。建议建立这样的目录或仓库策略:
product-bsp/
├── kernel/
├── device-tree/
├── config/
│ ├── base_defconfig
│ ├── robot.cfg
│ ├── camera.cfg
│ └── safety.cfg
├── patches/
│ ├── 0001-enable-canfd.patch
│ ├── 0002-add-camera-sensor.patch
│ └── 0003-tune-cpu-freq.patch
├── scripts/
│ ├── build_kernel.sh
│ ├── pack_boot.sh
│ └── flash_kernel.sh
└── release/
└── 2026.07/
├── boot.img
├── dtbo.img
├── modules.tar.gz
├── vmlinux
├── System.map
└── manifest.txt
manifest.txt 建议记录:
Product: IQ9100 Vision System
BSP Version: xxx
Kernel Commit: xxxxxxxx
DTS Commit: xxxxxxxx
Toolchain: gcc/clang version
Build Time: 2026-07-09
Defconfig: vendor_xxx_defconfig + industrial_camera.cfg
Artifacts:
- boot.img
- dtbo.img
- modules.tar.gz
- rootfs.img
这样做的意义是:现场任何一台设备出现问题,都能追溯到明确的 kernel、dtb、modules 和 rootfs 组合。
18. 一个推荐的开发闭环
实际项目中,可以按下面这个闭环推进:
1. 获取官方 BSP
2. 原样编译并刷写
3. 确认开发板能正常启动
4. 固化原始构建脚本
5. 修改 kernel config
6. 修改 Device Tree
7. 编译 Image.gz / dtb / dtbo / modules
8. 打包 boot.img / dtbo.img
9. 刷写验证
10. dmesg / sysfs / debugfs 检查
11. 压测外设和功耗
12. 记录版本和产物
19. 小结
高通嵌入式 Linux 开发的难点,不在于单独执行一次 make Image.gz,而在于理解 kernel、Device Tree、firmware、boot image、rootfs、bootloader 之间的关系。
本篇我们完成了几个关键点:
-
高通 BSP 内核通常比 mainline 更适合量产开发
-
kernel 编译要优先复用 BSP 脚本和 toolchain
-
Device Tree 是板级硬件适配的核心
-
SPI、CAN-FD、MIPI 摄像头的 dts 修改重点不同
-
dtb、dtbo、boot.img、modules 必须成套发布
-
工业项目裁剪内核时,要在体积、稳定性和可调试性之间平衡
-
每次发布都要保留
.config、vmlinux、System.map和 manifest
对工业机器人、智能相机、ROS2 边缘计算来说,内核裁剪不是“删功能”,而是把系统变成一个可控制、可验证、可长期维护的平台。
下一篇我们将进入更具体的外设驱动开发:I2C、SPI、CAN-FD 以及 MIPI 摄像头驱动如何在高通平台上落地,并进一步讨论 Hexagon 侧低功耗外设方案。
更多推荐


所有评论(0)