
1. 龙芯智能车到底是个什么项目为什么值得折腾第一次听说“龙芯智能车”这个概念是在一个做嵌入式的朋友那里。他当时正在准备智能车竞赛的赛道聊到主控选型的时候提了一嘴今年想试试龙芯的方案用逐飞的开源库来搭。我当时的第一反应是——龙芯做智能车能跑得动摄像头图像处理吗后来自己上手折腾了一轮才发现这条路虽然比传统方案要陡一些但走通了之后确实有意思。先把话说清楚龙芯智能车指的是以龙芯中科推出的LoongArch架构处理器作为主控芯片配合逐飞科技提供的开源库和工具链搭建一台能够自主循迹、识别赛道元素的智能车系统。它和传统用STM32、GD32或者TC264的方案最大的区别在于——指令集架构完全不同。LoongArch是龙芯自主设计的指令集不是ARM也不是x86这意味着你没法直接拿现成的ARM工程来改从编译器到内核到外设驱动整条链路都需要重新走一遍。那为什么还要折腾它我的体会是三个层面的原因。第一智能车竞赛这几年在往国产化方向引导用国产主控本身就是一种技术储备第二龙芯的LoongArch架构在嵌入式领域的生态正在快速补齐逐飞开源库已经把常用的外设驱动、图像处理、控制算法做了适配你不需要从寄存器开始写起第三从学习价值来看走一遍完整的交叉编译、内核裁剪、驱动适配流程对理解嵌入式Linux系统的全貌帮助极大这是单纯调STM32 HAL库给不了的经验。这篇文章适合谁看如果你已经有一点Linux基础会用命令行知道什么是交叉编译那就可以直接跟着走。如果你连make和gcc都没怎么用过建议先补一下Linux的基本操作再来。整篇文章我会按照实际操作的顺序来写从环境搭建、工具链配置、逐飞库的获取和编译到内核的裁剪和编译再到烧录和上电验证每一步都会说清楚为什么这么做以及我踩过的坑。注意龙芯智能车的开发环境搭建涉及交叉编译工具链、内核源码、设备树等多个环节任何一个环节版本不匹配都可能导致编译失败。建议在开始之前先确认你手头的硬件版本和逐飞库的版本对应关系。2. 开发环境搭建与工具链配置2.1 为什么不能直接用系统自带的gcc这是新手最容易犯的错误。你在Ubuntu上敲gcc --version看到的是x86_64的编译器它生成的二进制代码是给x86处理器跑的。而龙芯智能车的主控是LoongArch架构指令集完全不一样。你需要的是交叉编译器——在x86的宿主机上生成能在LoongArch上运行的代码。逐飞科技为龙芯智能车提供的工具链通常是一个预编译好的压缩包里面包含了loongarch64-linux-gnu-gcc、loongarch64-linux-gnu-ld、loongarch64-linux-gnu-objcopy等工具。拿到工具链之后第一步是解压到一个合适的路径比如/opt/toolchain/然后把它加到PATH环境变量里。# 解压工具链到指定目录 sudo tar -xzf loongarch-toolchain.tar.gz -C /opt/toolchain/ # 编辑环境变量把工具链路径加进去 echo export PATH/opt/toolchain/loongarch64-linux-gnu/bin:$PATH ~/.bashrc source ~/.bashrc # 验证工具链是否可用 loongarch64-linux-gnu-gcc --version如果输出了版本信息说明工具链配置成功。如果提示command not found检查一下路径是不是写错了或者压缩包解压后的目录结构和预期不一致。提示不同版本的逐飞库可能对应不同版本的交叉编译器。如果你用的是逐飞官方提供的SDK包里面通常会附带推荐的工具链版本。不要随意混用版本否则可能出现链接错误或者运行时异常。2.2 宿主机环境的选择与准备宿主机用什么系统我实测下来Ubuntu 20.04和Ubuntu 22.04都可以推荐用20.04因为很多嵌入式工具链对glibc版本有要求太新的系统反而容易出兼容性问题。如果你用的是Windows建议装一个WSL2或者直接跑虚拟机不要试图在Windows原生环境下做交叉编译各种路径和权限问题会让你崩溃。除了工具链还需要安装一些基础的构建工具sudo apt update sudo apt install -y build-essential git cmake ninja-build \ libncurses-dev bison flex libssl-dev libelf-dev \ u-boot-tools device-tree-compiler这几个包分别对应编译工具、版本管理、构建系统、内核配置界面依赖、设备树编译工具。少一个都可能在后续步骤中报错。2.3 逐飞开源库的获取与目录结构解读逐飞的开源库通常以Git仓库或者压缩包的形式发布。拿到之后先别急着编译花十分钟把目录结构看清楚能省掉后面很多盲目搜索的时间。典型的逐飞龙芯智能车库目录结构是这样的seeking_loongarch_sdk/ ├── libraries/ # 外设驱动库 │ ├── zf_common/ # 通用函数、类型定义 │ ├── zf_driver/ # 底层驱动GPIO、UART、PWM、ADC等 │ ├── zf_device/ # 外设器件驱动摄像头、IMU、屏幕等 │ └── zf_components/ # 组件层图像处理、控制算法 ├── project/ # 示例工程 │ ├── user/ # 用户代码入口 │ └── ... ├── tools/ # 烧录工具、脚本 └── doc/ # 文档关键要理解的是libraries和project的关系。libraries是逐飞封装好的驱动和算法你一般不需要改project是你的主战场main函数、中断服务函数、赛道元素处理逻辑都在这里写。编译的时候构建系统会把libraries编译成静态库然后和project里的代码链接在一起。注意逐飞的库有多个版本分支分别对应不同的主控和竞赛年份。拿到库之后先看README或者doc目录下的说明确认这个版本是不是对应你手上的龙芯主控型号。版本不对后面全是白费功夫。3. 内核编译从配置到生成镜像的完整流程3.1 为什么智能车也需要编译内核很多人会问智能车不就是跑个裸机程序吗为什么还要编译Linux内核这个问题问得好。传统的STM32智能车确实是裸机或者RTOS但龙芯智能车的方案通常是跑一个精简的Linux系统原因有几个一是龙芯的LoongArch处理器本身定位偏应用处理跑Linux更能发挥性能二是逐飞的库很多功能依赖Linux的用户空间接口比如文件操作、网络通信、多线程三是用Linux可以方便地做图像处理和算法调试开发效率比裸机高很多。所以内核编译是绕不过去的一步。你需要根据智能车的硬件配置裁剪出一个体积小、启动快、驱动齐全的内核镜像。3.2 内核源码的获取与版本选择龙芯的内核源码通常从龙芯官方的Git仓库获取或者逐飞会提供一个已经适配好的内核源码包。我建议优先用逐飞提供的版本因为里面已经包含了智能车外设的驱动补丁比如摄像头的MIPI接口驱动、IMU的SPI驱动等。如果你从龙芯官方仓库拉最新版这些驱动可能还没有合并进去需要自己打补丁。# 假设逐飞提供的内核源码包是 linux-loongarch-seekfree.tar.gz tar -xzf linux-loongarch-seekfree.tar.gz cd linux-loongarch-seekfree # 查看当前内核版本 make kernelversion记下这个版本号后面配置和编译都会用到。3.3 内核配置哪些必须开哪些可以关内核配置是整个编译过程中最考验经验的一步。配置项有上千个全开会导致镜像巨大、启动慢关多了又会导致驱动缺失、外设不工作。我的策略是以逐飞提供的默认配置文件为基础只改必须改的。# 先看看有没有现成的配置文件 ls arch/loongarch/configs/ # 通常会有一个类似 seekfree_defconfig 的文件 # 用它作为基础配置 make ARCHloongarch seekfree_defconfig # 然后打开菜单配置界面做微调 make ARCHloongarch menuconfig在menuconfig里重点检查这几个部分CPU类型和特性确认选中的是龙芯对应的处理器型号浮点单元、向量指令等按需开启。设备驱动串口、SPI、I2C、GPIO、PWM、ADC这些必须开摄像头接口MIPI CSI和显示接口按实际硬件选。文件系统智能车一般用initramfs或者UBIFS如果用的是eMMC或者SD卡启动要开对应的块设备驱动和文件系统支持。网络协议如果智能车需要无线调试或者图传TCP/IP协议栈要开纯本地跑的话可以裁掉。提示每次改完配置保存的时候会生成一个新的.config文件。建议把这个文件备份一份后面如果编译出问题可以快速回退到已知可用的配置。3.4 编译过程与常见报错处理配置好了就可以开始编译。编译命令本身很简单make ARCHloongarch CROSS_COMPILEloongarch64-linux-gnu- -j$(nproc)-j$(nproc)是让make用满所有CPU核心并行编译能显著缩短时间。但并行编译也会让报错信息变得混乱如果第一次编译就报错建议先用-j1单线程跑一遍看清楚第一个错误是什么。常见的报错有这么几类第一类工具链找不到。报错信息通常是loongarch64-linux-gnu-gcc: command not found。这说明PATH没配好或者工具链的命名前缀和CROSS_COMPILE参数不一致。回去检查工具链的实际文件名确认前缀。第二类头文件缺失。比如fatal error: openssl/ssl.h: No such file or directory。这是宿主机缺少开发库按照前面2.2节的包列表补装即可。第三类配置冲突。某些配置项之间有依赖关系你开了一个但没开它依赖的另一个编译到一半就会报错。这种错误在menuconfig里通常会有提示回去把依赖项补上。第四类设备树编译错误。如果设备树源文件.dts里有语法错误或者引用了不存在的节点dtc会报错。仔细看报错的行号对照设备树语法检查。编译成功后会在arch/loongarch/boot/目录下生成内核镜像文件通常是vmlinuz或者Image格式。同时设备树二进制文件.dtb也会在arch/loongarch/boot/dts/下生成。3.5 内核镜像的打包与烧录拿到内核镜像和设备树之后还需要把它们打包成智能车能识别的启动格式。逐飞通常会提供一个打包脚本把内核、设备树、根文件系统打包成一个可烧录的镜像文件。# 假设逐飞提供了打包脚本 mkimage.sh ./tools/mkimage.sh \ --kernel arch/loongarch/boot/vmlinuz \ --dtb arch/loongarch/boot/dts/loongson_seekfree.dtb \ --rootfs rootfs.cpio.gz \ --output seekfree_loongarch.img烧录通常通过USB或者TF卡进行。如果是TF卡启动直接用dd命令把镜像写到卡里sudo dd ifseekfree_loongarch.img of/dev/sdX bs4M statusprogress sync/dev/sdX要替换成你实际的TF卡设备名千万别写错了写错会把你的硬盘数据抹掉。写完之后拔卡插到智能车上上电。4. 逐飞库的编译与工程配置4.1 库的编译方式静态库还是源码集成逐飞的库有两种使用方式一种是编译成静态库.a文件然后在工程里链接另一种是把源码直接加到工程里一起编译。两种方式各有优劣。静态库的优点是编译快、工程干净适合库代码稳定不常改的情况。缺点是调试不方便如果库里有bug你没法直接改源码得重新编译库。源码集成则相反灵活但编译慢。我个人的习惯是开发阶段用源码集成方便调试和改代码最终版本用静态库减少编译时间。逐飞的构建系统通常两种方式都支持通过一个配置开关来切换。4.2 工程配置中的关键参数逐飞的工程通常用一个Makefile或者CMakeLists.txt来管理构建。有几个参数必须根据你的实际情况改工具链前缀CROSS_COMPILE要设成loongarch64-linux-gnu-。目标架构ARCH设成loongarch。优化等级调试阶段用-O0 -g方便定位问题发布阶段用-O2或-Os减小体积、提高速度。链接脚本如果工程涉及裸机或者特殊内存布局链接脚本.ld文件要对应修改。# 典型的工程Makefile片段 CROSS_COMPILE loongarch64-linux-gnu- CC $(CROSS_COMPILE)gcc ARCH loongarch CFLAGS -O2 -Wall -I./libraries/zf_common -I./libraries/zf_driver LDFLAGS -L./libraries -lzf_driver -lzf_device4.3 摄像头与图像处理的适配要点智能车的核心是摄像头图像处理。逐飞的库对常见的摄像头模组比如总钻风、凌瞳等都有驱动支持但在龙芯平台上有几个点需要特别注意。第一DMA缓冲区对齐。LoongArch架构对DMA缓冲区的地址对齐有要求如果不对齐摄像头数据可能出现错位或者丢帧。逐飞的驱动通常会处理这个问题但如果你自己写采集代码记得用posix_memalign或者memalign来分配对齐的内存。第二图像格式转换。摄像头输出的原始数据可能是RGB565、YUV或者灰度图逐飞的图像处理库通常期望灰度图输入。如果格式不匹配需要在采集后做一次转换。这个转换在龙芯上可以用向量指令加速但逐飞的库可能还没做这个优化需要自己补。第三帧率与处理耗时的平衡。龙芯的处理能力比STM32强但比桌面CPU弱。摄像头帧率设太高处理不过来会丢帧设太低赛道元素识别不及时。我的经验是先测一下单帧图像的处理耗时然后根据这个耗时来设帧率留出20%的余量。注意图像处理算法的参数比如二值化阈值、边缘检测阈值需要根据实际赛道的光照条件来调。实验室调好的参数到了比赛现场可能完全不能用。建议在代码里留一个参数调整接口方便现场快速修改。5. 上电调试与常见问题排查5.1 第一次上电串口终端能看到什么烧录完成后把智能车接上串口线打开终端软件比如minicom或者picocom波特率通常设成115200。上电之后你应该能看到内核的启动日志。# 用picocom连接串口 picocom -b 115200 /dev/ttyUSB0启动日志会依次显示Bootloader加载信息、内核解压信息、设备树解析、驱动初始化、根文件系统挂载。如果卡在某一步不动了那一步就是问题所在。5.2 常见问题速查表现象可能原因排查方法上电后串口无输出供电不足、串口线接错、波特率不对万用表测电压确认TX/RX交叉连接换波特率试试内核启动卡在“Starting kernel...”设备树不匹配、内核镜像损坏换一个已知可用的设备树重新烧录内核启动后找不到根文件系统根文件系统分区没挂上、文件系统类型不支持检查内核配置里的文件系统选项确认分区表正确摄像头无图像驱动没加载、MIPI接口配置错误dmesg看驱动加载日志检查设备树里的摄像头节点图像有但花屏DMA对齐问题、时钟频率不对检查内存分配对齐调整摄像头时钟程序运行一段时间后死机内存泄漏、散热问题用free看内存变化摸一下主控温度5.3 调试技巧怎么快速定位问题嵌入式调试最怕的就是“没反应”。我的经验是把问题范围缩小到最小可复现单元。比如摄像头不出图先别管图像处理算法先确认摄像头驱动有没有加载、I2C通信是否正常、MIPI时钟有没有输出。逐飞的库通常提供了底层的测试函数可以单独调用这些函数来验证硬件。另一个技巧是善用GPIO翻转。在关键代码路径上加一句GPIO翻转用示波器或者逻辑分析仪看波形能直观地判断代码有没有执行到那里、执行了多长时间。这个方法比打印日志更精确也不会干扰实时性。提示龙芯智能车的调试串口和程序输出串口可能是同一个如果程序里大量打印日志会拖慢运行速度。建议调试阶段用高波特率发布阶段把日志关掉或者降到最低等级。6. 从能跑到跑得好性能优化与实战建议6.1 启动速度优化智能车比赛从发车到跑完时间是以秒计的。如果系统启动就要十几秒那比赛就不用比了。优化启动速度有几个方向裁剪内核把不需要的驱动、文件系统、网络协议全部去掉内核镜像能小很多。用initramfs代替完整根文件系统initramfs直接打包进内核省去了挂载根文件系统的步骤。延迟加载非关键驱动摄像头、屏幕这些不是启动必须的驱动可以做成模块启动后再加载。关闭内核调试信息printk的输出很耗时发布版本把日志等级调高。我实测过一个裁剪得当的龙芯智能车内核从Bootloader到应用程序启动可以控制在3秒以内。6.2 图像处理算法的加速龙芯的LoongArch架构支持向量指令LSX/LASX如果图像处理算法能用上这些指令速度会有明显提升。但逐飞的库不一定都做了向量化优化你可以自己针对热点函数做优化。比如二值化操作用标量指令是逐像素判断用向量指令可以一次处理16个或32个像素。边缘检测的卷积操作也是类似。不过向量化编程有门槛需要对LoongArch的向量指令集比较熟悉。如果时间紧可以先不做向量化优先保证算法逻辑正确。6.3 比赛现场的准备清单根据我自己的经验比赛现场最容易出问题的不是代码而是环境和硬件。建议出发前准备好这些东西备用主控板烧录好的、验证过能跑的备用板万一主控烧了可以快速替换。备用摄像头摄像头是易损件多带一个。串口线和USB转串口模块现场调试必备。充电宝和稳压电源确保供电稳定。烧录工具和镜像文件存在U盘里带两份。参数记录本把实验室调好的参数记下来现场微调时有参考。注意比赛现场的电磁环境比实验室复杂得多摄像头可能受到干扰电磁组的传感器读数也可能漂移。建议在代码里留一个“现场校准”模式上电后先跑一段校准程序再进入正式比赛。7. 我踩过的几个坑和最后的建议第一个坑是工具链版本不匹配。我一开始用的是龙芯官方最新的工具链结果逐飞的库编译报了一堆链接错误。后来换成逐飞SDK包里附带的工具链版本问题就消失了。所以再强调一遍用逐飞推荐的版本不要自己追新。第二个坑是设备树里的引脚配置和实际硬件不对应。逐飞的示例设备树是针对他们的标准板写的如果你用的是自己画的板子引脚定义肯定不一样。这个错误的表现是驱动加载成功但外设不工作排查起来很费时间。建议拿到新板子后先对照原理图把设备树里的GPIO、I2C、SPI节点全部核对一遍。第三个坑是内核配置里开了太多调试选项。CONFIG_DEBUG_*系列的选项在开发阶段有用但会让内核变大、变慢。发布版本一定要关掉。最后一个建议不要等到比赛前一周才开始搭环境。龙芯智能车的开发链路比传统方案长从工具链到内核到驱动每个环节都可能卡住。留出至少一个月的缓冲时间把环境搭稳、把驱动调通、把算法跑顺。真正到了比赛现场你才有精力去应对那些预料之外的问题。这个方案后续还可以往几个方向扩展一是把图像处理算法做成硬件加速用LoongArch的向量指令或者外挂NPU二是把控制算法从PID升级到模型预测控制提高高速循迹的稳定性三是把调试接口做成无线的方便现场快速改参数。这些我都还在摸索有进展再分享。