龙芯智能车实战:LoongArch架构下Linux内核编译与逐飞库部署指南 1. 龙芯智能车到底是个什么项目为什么值得折腾第一次听说“龙芯智能车”这个概念很多人脑子里冒出来的第一个问题就是这不就是拿龙芯的芯片替换掉原来智能车上那颗单片机吗能有多复杂我一开始也这么想直到真正把一块龙芯开发板、一套逐飞开源库和一份内核源码摆在桌面上才发现这件事的工程量远比想象中大得多。简单来说这个项目的核心目标是用基于 LoongArch 架构的龙芯处理器作为主控跑完整的 Linux 系统在上面运行逐飞科技提供的开源智能车控制库从而实现摄像头图像采集、赛道元素识别、电机舵机控制等一整套智能车功能。它解决的根本问题是——让智能车从传统的单片机裸机开发模式升级到拥有完整操作系统、支持多任务调度、能跑复杂视觉算法的嵌入式 Linux 平台。适合看这篇内容的人有三类第一类是在准备全国大学生智能车竞赛、想尝试龙芯平台赛道的同学第二类是对 LoongArch 架构感兴趣、想找一个完整项目来练手内核编译和交叉编译的嵌入式爱好者第三类是做嵌入式 Linux 开发、需要一套从内核到应用层完整链路参考的工程师。不管你之前有没有接触过龙芯只要你会基本的 Linux 命令、能看懂 C 语言这篇内容里的步骤和思路你都能跟下来。我踩过的第一个坑就是低估了“内核编译”这四个字的分量。在 x86 上编译内核你随便找台 Ubuntu 机器装几个依赖make defconfig 然后 make -j 就完事了。但龙芯不一样你需要交叉编译工具链、需要匹配的 LoongArch 内核源码树、需要针对智能车外设做设备树裁剪还要把逐飞库依赖的各种驱动模块编进去。这一套流程走下来没有一份靠谱的攻略光靠官方文档能把你绕晕。所以我把整个从零搭建的过程拆成了几个核心环节每个环节都讲清楚为什么这么做、怎么做、做完怎么验证。2. 整体方案设计与核心思路拆解2.1 为什么选龙芯加 Linux 而不是继续用单片机传统智能车方案里主流主控是各种单片机或者 RTOS 平台比如常见的 32 位 MCU。这类方案的好处是实时性强、开发简单、功耗低。但缺点也很明显算力有限跑个简单的图像二值化就到头了想上卷积神经网络或者复杂的赛道元素识别算法基本不可能。龙芯处理器虽然主频不算特别高但它是完整的 64 位架构有 MMU、有 Cache 层级、支持完整的 Linux 内存管理这意味着你可以跑 OpenCV、可以跑轻量级推理框架、可以用多线程做图像处理和控制的并行。另一个关键考量是生态延续性。逐飞开源库本身是跨平台的它把底层硬件操作抽象成了一组统一的接口。你在单片机上用的那些摄像头驱动、电机 PWM 控制、编码器读取函数在 Linux 平台上可以通过逐飞提供的 Linux 适配层来调用。这就意味着你不需要从零写一套控制逻辑而是把精力集中在算法调优和系统集成上。从项目管理的角度看这能省掉至少百分之六十的底层开发时间。2.2 逐飞开源库在龙芯平台上的角色定位逐飞开源库在这个项目里扮演的是“硬件抽象层加算法中间件”的角色。它向下封装了龙芯开发板上各种外设的寄存器操作向上提供了统一的 API 给应用层调用。具体来说它包含几个核心模块摄像头采集模块负责从 MIPI 或者 DVP 接口读取图像数据并转换成灰度或 RGB 格式图像处理模块提供二值化、边缘提取、中线拟合等常用算法控制模块负责把计算出的偏差转换成舵机转向角和电机占空比通信模块则处理调试串口、无线模块的数据收发。这里有一个很重要的设计决策逐飞库在 Linux 下是以字符设备驱动加用户态库的形式存在的。摄像头、电机这些外设的底层操作被写成了内核模块编译进内核或者以 .ko 形式动态加载。用户态则通过 ioctl 或者 mmap 来和驱动交互。这样做的好处是既能保证实时性要求高的操作在内核态完成又能让算法逻辑在用户态灵活修改不用每次改个 PID 参数都重新编译内核。2.3 内核编译在整个链路中的位置很多人会问我能不能直接用龙芯官方提供的预编译内核跳过编译这一步答案是对于点亮开发板、跑个 Hello World 来说可以但对于智能车项目来说不行。原因有三个第一官方内核通常没有开启智能车需要的外设驱动比如特定的 PWM 控制器、正交编码器接口、摄像头传感器驱动第二官方内核的设备树是按照通用开发板配置的引脚复用和时钟树没有针对智能车的 PCB 做优化第三逐飞库的某些内核模块需要特定的内核版本和配置选项才能编译通过。所以内核编译不是可选项而是必选项。你需要拿到龙芯官方的内核源码树打上逐飞提供的补丁用正确的 config 文件配置然后用交叉编译工具链编译出 Image 和 dtb 文件最后烧录到开发板上。这个过程听起来线性但实际操作中每个环节都有坑后面我会逐个拆解。3. 核心细节解析与实操要点3.1 交叉编译工具链的选择与验证龙芯的 LoongArch 架构需要专用的交叉编译工具链。目前主流的选择是龙芯官方维护的 GCC 工具链或者用 crosstool-ng 自己构建。我建议直接用官方预编译好的工具链因为自己构建不仅耗时还容易在 glibc 版本和内核头文件版本上出问题。工具链下载下来之后第一件事是验证它能不能正常工作。你可以写一个最简单的 C 程序用交叉编译器编译然后用 file 命令查看生成的二进制文件架构信息。如果显示的是 LoongArch 相关的标识说明工具链没问题。这一步看似简单但我见过太多人卡在这里原因是环境变量没配好或者下载的工具链版本和内核源码版本不匹配。注意工具链的 glibc 版本必须和根文件系统里的 glibc 版本一致或者兼容。如果你用的根文件系统是 Buildroot 生成的里面用的是 musl libc那你就需要用 musl 版本的交叉工具链否则编译出来的程序在板子上跑不起来。3.2 内核源码树的获取与补丁管理龙芯内核源码可以从官方仓库获取建议选择长期支持版本比如 5.10 或者 6.1 系列。拿到源码后不要急着编译先做两件事第一创建一个独立的分支来管理你的修改这样后续更新或者回滚都方便第二把逐飞提供的补丁文件按顺序打上去。补丁通常包含设备树修改、驱动添加、配置选项调整这几类。打补丁的时候有个技巧用git am而不是patch命令。git am会保留补丁的提交信息方便你追溯每个修改的来源。如果某个补丁打失败了git am会停下来让你手动解决冲突解决完之后git am --continue继续。这比patch命令的体验好太多。3.3 设备树配置的关键参数设备树是 Linux 内核识别硬件的依据对于智能车来说设备树里需要描述的东西包括摄像头接口的引脚复用和时钟频率、PWM 控制器的通道分配、编码器接口的 GPIO 中断配置、串口波特率和引脚映射。这些参数必须和你的硬件原理图一一对应错一个引脚对应的外设就工作不了。我建议的做法是先拿官方开发板的设备树文件作为基础然后对照智能车 PCB 的原理图逐个修改外设节点。修改的时候不要一次改太多改一个外设就编译一次设备树烧录进去用dmesg看内核有没有正确识别。比如你改了摄像头接口烧录后dmesg | grep camera应该能看到摄像头驱动加载成功的日志。如果没有就回去检查引脚复用寄存器的配置。3.4 内核配置选项的取舍内核配置是很多人头疼的地方因为选项太多了。我的策略是以逐飞提供的 defconfig 为基础然后用make menuconfig做微调。必须确认开启的选项包括对应的摄像头传感器驱动、PWM 子系统、GPIO 子系统、I2C 子系统、SPI 子系统、USB 主机支持、网络协议栈、文件系统支持。另外为了调试方便建议把CONFIG_DEBUG_INFO打开这样后续用 gdb 调试内核模块的时候能看符号信息。有一个容易忽略的选项是内核抢占模式。智能车对控制的实时性有要求建议把抢占模式设置为CONFIG_PREEMPT这样内核在大多数地方都可以被抢占能降低控制环路的延迟。但注意不要用CONFIG_PREEMPT_RT因为实时补丁和某些外设驱动可能有兼容性问题而且配置起来更复杂。4. 实操过程与核心环节实现4.1 环境搭建与依赖安装我用的宿主机是 Ubuntu 20.04这个版本比较稳定各种依赖包也齐全。首先安装必要的工具sudo apt update sudo apt install build-essential git flex bison libssl-dev \ libncurses-dev bc rsync kmod cpio python3-dev \ device-tree-compiler u-boot-tools这些包分别对应编译工具链、Git 版本管理、词法语法分析器、SSL 库、菜单配置界面、BC 计算器、文件同步工具、内核模块工具、cpio 归档工具、Python 开发头文件、设备树编译器、U-Boot 工具。缺一个都可能在编译过程中报错。然后把交叉编译工具链解压到/opt目录下并添加到 PATH 环境变量export PATH/opt/loongarch-toolchain/bin:$PATH export CROSS_COMPILEloongarch64-unknown-linux-gnu- export ARCHloongarch这三个环境变量很关键PATH 让系统能找到编译器CROSS_COMPILE 指定编译器前缀ARCH 告诉内核构建系统目标架构是 LoongArch。建议把这些写到~/.bashrc里免得每次开新终端都要重新设置。4.2 内核源码获取与补丁应用从官方仓库克隆内核源码git clone --depth1 -b loongarch-5.10 https://github.com/loongson/linux.git cd linux git checkout -b smartcar然后应用逐飞补丁。假设补丁文件放在~/patches目录下git am ~/patches/0001-add-camera-driver.patch git am ~/patches/0002-add-pwm-driver.patch git am ~/patches/0003-update-devicetree.patch如果某个补丁打失败Git 会提示冲突文件。手动编辑冲突文件解决完之后git add 冲突文件 git am --continue补丁全部应用成功后用git log --oneline看一下提交历史确认每个补丁都正确合入。4.3 内核配置与编译先用逐飞提供的 defconfig 生成基础配置make loongson_smartcar_defconfig然后打开菜单配置做微调make menuconfig在菜单里重点检查这几个地方Device Drivers 下面的 Camera 相关选项、PWM 相关选项、GPIO 相关选项Kernel Features 下面的 Preemption Model 选择 Preemptible KernelFile Systems 下面确保 ext4 和 squashfs 都选上。配置完成后开始编译make -j$(nproc) Image dtbs modules-j$(nproc)表示用所有 CPU 核心并行编译能大幅缩短编译时间。编译完成后在arch/loongarch/boot/目录下会生成Image文件在arch/loongarch/boot/dts/目录下会生成.dtb文件内核模块则分散在各个子目录里。4.4 烧录与启动验证把编译好的 Image 和 dtb 文件拷贝到 TF 卡或者通过 tftp 传输到开发板。具体的烧录方式取决于你的开发板型号常见的有两种一种是通过 USB 烧录工具把镜像写到 eMMC 或者 SPI Flash另一种是把 TF 卡插到读卡器上用 dd 命令写入。烧录完成后上电启动通过串口终端观察启动日志。如果一切正常你会看到内核解压信息、设备树加载信息、各个驱动初始化信息最后进入登录提示符。这时候用dmesg | grep -i error检查有没有报错用ls /dev/video*确认摄像头设备节点是否创建成功用ls /sys/class/pwm/确认 PWM 控制器是否注册。4.5 逐飞库的交叉编译与部署内核跑起来之后下一步是编译逐飞库。逐飞库通常提供一个 CMake 或者 Makefile 构建系统你需要修改里面的交叉编译配置指定 CROSS_COMPILE 和 sysroot 路径。sysroot 就是根文件系统的路径里面包含了目标平台的头文件和库文件。编译完成后把生成的动态库和可执行文件拷贝到开发板的根文件系统里。如果是通过网络文件系统挂载根文件系统的方式直接拷贝到 NFS 共享目录就行。如果是烧录到本地存储需要用 scp 或者 U 盘拷贝。部署完成后运行逐飞库提供的测试程序比如摄像头采集测试、电机转动测试。如果摄像头能出图、电机能转说明整个链路已经打通了。5. 常见问题与排查技巧实录5.1 内核编译报错速查表报错信息可能原因解决方法No rule to make target ImageARCH 环境变量没设置执行export ARCHloongarchCROSS_COMPILE not found工具链路径不对检查 PATH 和 CROSS_COMPILE 变量fatal error: openssl/ssl.h缺少 libssl-devsudo apt install libssl-devdtc: command not found缺少设备树编译器sudo apt install device-tree-compilerundefined reference to ...库版本不匹配检查工具链和 sysroot 的 glibc 版本5.2 设备树配置错误的排查思路设备树配错了最典型的表现是驱动加载了但设备不工作。比如摄像头驱动dmesg里显示 probe 成功但/dev/video0打不开。这时候你需要检查设备树里摄像头节点的status属性是不是okayreg属性里的 I2C 地址对不对pinctrl引用的引脚组有没有定义。另一个常见问题是引脚复用冲突。比如你把某个引脚配成了 PWM 输出但另一个驱动又把它配成了 GPIO 输入结果就是两个驱动都工作不正常。排查方法是查看/sys/kernel/debug/pinctrl/下面的引脚状态确认每个引脚只被一个功能占用。5.3 逐飞库运行时的典型问题逐飞库在 Linux 下运行时最常见的问题是权限不足。比如操作 GPIO 需要 root 权限或者访问/dev/video0需要 video 组的权限。解决方法有两种一种是用sudo运行程序另一种是配置 udev 规则给特定设备节点设置合适的权限和所属组。还有一个问题是实时性不达标。如果你发现控制环路有抖动先检查内核抢占模式是不是PREEMPT然后检查有没有其他高优先级任务在抢 CPU。可以用chrt命令把智能车控制程序设置为实时调度策略比如chrt -f 50 ./smartcar这样能显著降低控制延迟。5.4 实操心得与避坑建议第一个心得每次只改一个变量。不管是改设备树、改内核配置还是改逐飞库的代码每次只改一个地方然后编译、烧录、验证。如果一次改多个地方出了问题你根本不知道是哪个改动导致的。第二个心得保留可回滚的版本。内核源码用 Git 管理根文件系统用镜像备份逐飞库的代码也用 Git 管理。每次验证通过的版本打一个 tag这样出了问题可以快速回滚到上一个稳定版本。第三个心得串口日志是你的最好朋友。把内核的 loglevel 调高让dmesg输出尽可能多的信息。遇到问题先看日志大部分错误日志里都有明确的提示。如果日志不够详细可以在驱动代码里加printk重新编译驱动模块加载测试。第四个心得不要忽视电源问题。智能车上的电机启动瞬间电流很大可能导致龙芯开发板供电不稳表现为系统随机重启或者外设工作异常。建议给核心板和控制板分别供电或者在电源输入端加一个大电容做缓冲。6. 性能调优与后续扩展方向6.1 图像处理流水线的优化摄像头采集回来的原始图像数据量很大如果每帧都做完整的二值化和边缘提取CPU 占用率会很高。优化的思路是把图像处理拆成多个阶段用流水线的方式并行处理。比如第一帧做采集的时候第二帧做二值化第三帧做中线拟合。在 Linux 下可以用多线程实现一个线程负责采集一个线程负责处理线程之间用环形缓冲区传递数据。另一个优化点是降低图像分辨率。智能车赛道识别不需要很高的分辨率把摄像头输出配置成 QVGA 或者更低能大幅减少数据量和处理时间。如果摄像头支持硬件二值化或者 ROI 裁剪一定要用上这比软件处理快得多。6.2 控制环路的实时性保障控制环路的实时性直接决定了智能车能不能跑高速。在 Linux 下保障实时性的手段包括使用PREEMPT内核、把控制线程设置为实时调度策略、用mlockall锁定内存防止换页、关闭不需要的中断和后台服务。实测下来经过这些优化控制环路的抖动可以控制在几百微秒以内对于智能车来说足够了。6.3 从龙芯智能车延伸到其他应用这套龙芯加 Linux 加逐飞库的架构其实不只能用来做智能车。你把摄像头换成其他传感器把电机控制换成其他执行器控制就能快速搭建出各种嵌入式视觉控制项目。比如自动分拣系统、智能云台、巡线机器人等等。核心思路是一样的用 Linux 提供算力和多任务能力用逐飞库提供硬件抽象和算法中间件你只需要关注业务逻辑。我在实际项目中发现龙芯平台的生态虽然不如 ARM 那么丰富但基本的开发工具和库都很齐全。而且 LoongArch 架构的文档比较完善遇到问题查手册基本都能解决。对于想学习嵌入式 Linux 完整开发链路的同学来说龙芯智能车是一个非常好的练手项目因为它涵盖了从内核编译、设备树配置、驱动开发到应用层算法实现的全部环节。