海思SS928开发板环境搭建全攻略:从交叉编译到NFS/TFTP高效调试

发布时间:2026/9/20 12:42:48
海思SS928开发板环境搭建全攻略:从交叉编译到NFS/TFTP高效调试 拿到了海思SS928开发板第一步不是急着点灯也不是翻手册而是先把开发环境弄得顺手。这块芯片是海思SD3403系列的工业/安防向SoC跑Linux系统带NPU算力光看参数挺唬人但真到了动手阶段交叉编译工具链、SDK目录、板卡网络、NFS/TFTP这些环节任何一个没配好都会让你在“Hello World”之前就先耗掉一整天。这篇文章是我的系列第二篇主题就一个把SS928的开发环境从零到一真正搭起来并且搭得高效。所谓高效不只是能编译、能烧录而是你改完代码能在最短时间内跑到板子上日志能顺畅地回到PC出问题能快速定位是环境问题还是代码问题。这篇内容基于我实际踩坑后的完整记录适合刚拿到板子的开发人员也适合准备从海思其它平台切到SS928的工程师做参考。1. 整体思路与方案选型先想清楚再动手1.1 这块板子的特殊之处在哪里SS928这颗芯片从开发视角看和海思早年的Hi3516系列、Hi3559系列有相似之处但也有明显差异。相似的地方在于它仍然是典型的Arm SoC开发模式PC端装交叉编译工具链通过串口连接开发板的调试串口通过网线进行数据传输和挂载文件系统。差异则体现在几个方面芯片标配了较大的DDR容量和更高频率的CPU对64位系统支持更完整工具链需要采用aarch64版本SDK包体积也更大内容涵盖U-Boot、内核、rootfs、DDK驱动开发套件和算力相关的组件解压后占用的磁盘空间和路径规划都需要提前考虑。这里要先说一个理念层面的问题环境搭建不只是一次性的安装动作它决定了你后续每天的开发流程是否顺畅。很多人在这一步图省事文件乱放、网络乱配后面每编一次固件、每烧一次板子都在为当初的草率买单。所以我下面讲的每一个环节都带着“为后续长期使用服务”这个目标来设计。1.2 环境方案虚拟机还是实体机先说宿主机系统。SS928的SDK和交叉编译工具链都是基于Linux的Windows下确实也能通过WSL或者Cygwin折腾但从我用过的几个海思平台来看老老实实装一台Ubuntu虚拟机或者直接用实体Linux机器是效率最高的选择。虚拟机的好处是快照备份方便装坏了回滚就行这对环境搭建初期尤其友好。比如你在配置NFS、TFTP的时候改坏了系统配置文件一条命令没写好整个服务起不来有快照就能迅速回到正常状态。实体机的优势是磁盘IO和网络性能更好如果你经常做全量编译或者大数据量的固件打包实体机优势明显。我个人在实际使用中倾向于虚拟机。原因很简单SS928的SDK编译并不像编译Android那样动辄占满几十个核跑半小时虚拟机分配的CPU和内存基本够用。而且开发板通过网线直连PC时VMware和VirtualBox的桥接网络模式都能很好处理不构成瓶颈。你真正需要关注的是磁盘空间整个SS928 SDK解压后大约20GB到30GB再加交叉编译工具链、根文件系统、内核源码和日常编译产物建议给虚拟机预留至少150GB的磁盘空间。1.3 目录规划与版本管理很多工程师习惯把SDK解压到桌面或者随意建个文件夹这是我在这个系列里第一个要纠正的习惯。嵌入式开发中路径深度、路径空格、权限问题都会成为后期莫名其妙的编译报错来源。我建议在Ubuntu的根目录下建立固定工作区例如/data/project/在这个目录下再细分mkdir -p /data/project/sdk # 存放SS928 SDK mkdir -p /data/project/toolchain # 存放交叉编译工具链 mkdir -p /data/project/nfs # NFS根文件系统目录 mkdir -p /data/project/tftp # TFTP下载目录 mkdir -p /data/project/output # 编译产物输出目录规划完顺便做一件事把版本管理意识从第一天就建立起来。SDK包里的U-Boot和内核源码建议用git管理。海思官方SDK解压出来通常自带.git目录或至少是一份完整代码树你可以在此基础上建自己的分支每次修改都提交记录。这样万一代码改坏了可以对比回滚而不是靠人肉备注“这个文件改过”。2. 基础环境准备从虚拟机到开发板连通2.1 Ubuntu版本与基础软件包安装SS928的SDK对Ubuntu版本没有特别严格的要求我分别用18.04和20.04都编译通过过。新版本的Ubuntu 22.04理论上也可以但有个别旧版SDK脚本依赖Python 2或者老的库建议优先用20.04兼容性最稳。系统装好后先把基础软件包装齐这些都是编译内核、U-Boot和应用程序时的公共依赖sudo apt update sudo apt install -y build-essential git vim curl wget \ libncurses5-dev libncursesw5-dev \ u-boot-tools device-tree-compiler \ lzop liblz4-tool gcc-multilib g-multilib \ nfs-kernel-server tftpd-hpa \ minicom picocom net-tools这里特别说下libncurses5-dev这个是内核menuconfig配置界面依赖的库。Ubuntu 20.04的软件源里默认提供的是libncurses6如果你在配置内核时提示找不到ncurses可以手动装libncurses5-dev。这是一个很容易被忽略的坑。2.2 串口终端与USB网卡开发板拿到手第一件事不是装SDK而是先把调试串口打通。SS928开发板通常会提供一个调试串口接口形式可能是4针插针或者Type-C板卡资料里都有标注。你需要一根USB转TTL串口线注意电平是3.3V千万别用5V的模块去接否则可能烧掉板子上的串口芯片。串口参数是固定的波特率1152008位数据位1位停止位无校验无硬件流控。Windows下用SecureCRT或MobaXterm都可以Linux下我用picocom比较多因为它轻量且依赖少sudo picocom -b 115200 /dev/ttyUSB0如果插上USB转串口线后没有/dev/ttyUSB0设备节点先检查驱动。市面上常见的CH340、CP2102、FT232在Ubuntu下都免驱或只需装一个简单驱动模块。网络方面SS928开发板一般带一个千兆网口。我的连接方式是开发板网口直连PC的有线网口虚拟机的网络模式设置为桥接。这样PC、虚拟机、开发板三者形成一个局域网虚拟机通过桥接网卡直接与开发板通信传输速度和稳定性都很好。2.3 主机、虚拟机与开发板之间的网络拓扑网络拓扑看起来简单但IP地址规划做不好后面会很头疼。我的规划如下虚拟机Ubuntu192.168.1.10开发板192.168.1.99PC物理机有线网卡192.168.1.100用于与虚拟机桥接通信三个地址都在同一个192.168.1.0/24网段确保互相能ping通。这里注意一点虚拟机使用桥接模式时需要把VMware或VirtualBox的虚拟网卡对应到PC的物理有线网卡上不是默认的自动桥接。如果你PC同时连着Wi-Fi和有线自动桥接可能选错网卡导致虚拟机与开发板不在同一链路。开发板端在U-Boot阶段就可以设置IP进入系统后也可以临时配置ifconfig eth0 192.168.1.99 netmask 255.255.255.0 up网络通了以后建议在你的开发主机上配置好SSH免密登录把PC的公钥放到开发板的root用户下。这块板子跑的系统默认有时只开串口登录SSH可选但强烈建议开启因为后面挂载NFS、拷贝文件、远程调试都靠它整天插着串口线操作太难受了。3. 工具链、SDK与交叉编译环境3.1 SDK目录结构解析拿到海思官方SDK后通常是一个压缩包解压后第一层目录一般有docs、osdrv、mpp、smp等。osdrv里包含了U-Boot、内核以及对应的编译脚本mpp里是媒体处理平台相关的库和头文件smp里则是双系统或AMP相关的组件。对于SS928来说重点先看osdrv目录。里面会有一个Makefile通过make命令可以一键编译U-Boot和内核。不过第一次编译建议不要直接全量make先看README和docs目录下的编译指导文档确认工具链版本要求。SS928是64位芯片U-Boot和内核都是aarch64架构工具链必须使用64位版本这跟早年海思的arm920t、armv7工具链完全不同。3.2 交叉编译工具链安装与验证交叉编译工具链建议使用海思SDK自带的版本在SDK的toolchain目录下通常能找到或者使用官方文档指定的Linaro GCC版本。以常见的aarch64工具链为例解压到/data/project/toolchain目录后把bin目录添加到PATHexport PATH/data/project/toolchain/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin:$PATH为了不让每次开终端都手工export我习惯把这行写到~/.bashrc里。然后验证工具链是否可用aarch64-none-linux-gnu-gcc -v看到gcc version信息就说明工具链已经就位。这里有个小细节工具链名称不同厂家也不一样有的是aarch64-linux-gnu-有的是aarch64-none-linux-gnu-前缀不同但作用一样编译时对应的CROSS_COMPILE变量值也不同注意看SDK文档里的说明。3.3 第一个交叉编译程序工具链装好之后写一个最简单的程序验证整个链路。在/data/project/output目录下新建hello.c#include stdio.h int main(void) { printf(Hello SS928!\n); return 0; }用交叉工具链编译aarch64-none-linux-gnu-gcc -o hello hello.c file hellofile命令输出的结果应该是“ELF 64-bit LSB executable, ARM aarch64”看到这个就说明编译架构正确。把这个文件通过NFS拷贝到开发板上运行或者在开发板上通过U盘、TFTP传到本地运行屏幕上打印出“Hello SS928!”那一刻交叉环境就算真正打通了。3.4 环境变量与编译脚本的约定交叉编译环境搭建中还有一个影响效率的细节环境变量。除了PATH还有ARCH和CROSS_COMPILE这两个环境变量在编译内核和U-Boot时至关重要export ARCHarm64 export CROSS_COMPILEaarch64-none-linux-gnu-这两个变量可以写到~/.bashrc里但注意如果你在同一台机器上交叉编译多个不同平台的项目全局设置ARCH和CROSS_COMPILE会导致切换平台时踩坑。我在实践中更推荐在SDK根目录下做一个env.sh脚本每次进入项目目录时source它相当于为这个项目单独锁定一套编译环境。这个习惯在多项目并行的时候节省的时间非常可观。# /data/project/sdk/env.sh export PATH/data/project/toolchain/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin:$PATH export ARCHarm64 export CROSS_COMPILEaarch64-none-linux-gnu-用的时候cd /data/project/sdk source env.sh这个做法的好处是环境隔离不同项目间互不干扰也不会因为全局环境变量污染导致编译时选了错误的架构。4. NFS与TFTP打通“改完就能跑”的链路4.1 为什么要用NFS和TFTP嵌入式开发中代码改完到板子上运行验证中间的数据通路越短越好。两种最常见的通路TFTP负责把内核镜像和U-Boot传到开发板内存或存储介质NFS则让开发板直接挂载PC上的目录作为根文件系统或应用目录。这样你在PC上编译出的可执行文件放到了NFS目录里开发板上立刻就能看到、立刻就能执行免去反复烧写Flash或拷贝SD卡的步骤。SS928也支持从SD卡、eMMC启动但日常开发阶段NFS是最快的迭代方式。改一行代码交叉编译拷贝到NFS共享目录在板子上重新运行整个过程几十秒。如果是烧写eMMC方案一次烧写加重启可能就要几分钟效率差别非常大。4.2 NFS服务配置实操Ubuntu下配置NFS服务端先安装nfs-kernel-server然后编辑/etc/exportssudo vim /etc/exports加入一行/data/project/nfs *(rw,sync,no_root_squash,no_subtree_check)这里解释几个关键参数rw是允许读写sync表示同步写入保证数据一致性no_root_squash允许开发板的root用户远程拥有root权限这个对嵌入式开发很重要否则板子上以root身份访问NFS目录时会被映射成nobody用户权限问题一堆no_subtree_check是为了避免目录结构检查带来的性能损耗和某些特殊场景下的权限异常。配置完重启NFS服务sudo systemctl restart nfs-kernel-server在开发板端挂载mount -t nfs -o nolock,nfsvers3 192.168.1.10:/data/project/nfs /mnt/nfs注意开发板上的内核通常不启用NFSv4相关的锁机制所以挂载时加-nolock参数更稳妥。还有一点如果开发板rootfs里没有mount.nfs命令可能是内核配置或busybox选项没开NFS支持需要在编译内核时检查CONFIG_NFS_FS和CONFIG_ROOT_NFS相关配置。根文件系统整体走NFS的方式是在U-Boot里设置bootargs时指定root/dev/nfs和nfsroot192.168.1.10:/data/project/nfs。这样开发板开机后直接从PC的NFS目录启动系统完全不用把rootfs烧进板载存储。这种方式适合频繁改动文件系统或库文件的阶段等系统稳定后再把rootfs打包烧录到板载存储。4.3 TFTP服务与U-Boot配合TFTP在U-Boot阶段的作用是下载内核镜像。配置过程中有两个需要注意的地方一是tftpd-hpa服务的根目录二是U-Boot里的serverip环境变量。Ubuntu下安装tftpd-hpa后配置文件在/etc/default/tftpd-hpa默认根目录是/srv/tftp我把TFTP根目录改成自己规划的/data/project/tftpsudo vim /etc/default/tftpd-hpa内容修改为TFTP_USERNAMEtftp TFTP_DIRECTORY/data/project/tftp TFTP_ADDRESS0.0.0.0:69 TFTP_OPTIONS--secure -cTFTP_OPTIONS里的-c参数允许上传文件这在某些调试场景下非常有用虽然TFTP本身不是一个安全协议但在隔离的开发网络里完全够用。修改完后重启服务sudo systemctl restart tftpd-hpa然后在开发板的U-Boot命令行里设置setenv serverip 192.168.1.10 setenv ipaddr 192.168.1.99 saveenvU-Boot里下载内核tftp 0x40000000 uImage等待传输完成后继续设置启动参数并bootm整个烧录和启动流程就串起来了。实际操作中TFTP传大文件偶尔会超时可以先确认PC防火墙是否拦截了UDP 69端口和临时数据端口Ubuntu的ufw防火墙如果开启需要放行。5. 烧录、启动与基本调试5.1 烧录方式与启动流程SS928的启动流程和大多数海思平台一致芯片上电后先从内部ROM加载BootROM然后根据拨码或eMMC、SPI Flash等启动介质加载U-BootU-Boot再加载内核内核挂载根文件系统。开发初期板卡出厂时一般已经烧录了可用的U-Boot你只需要通过网络或串口把编译好的内核和文件系统传进去。烧录U-Boot本身时SS928官方工具或uboot下的烧写命令都可以完成具体要看板卡原理图和SDK文档确认启动介质。如果板卡已经有U-Boot且网络通最稳妥的方式是先不烧U-Boot只在U-Boot里通过TFTP下载内核和rootfs来测试确认没问题后再整体烧录。U-Boot一旦刷成砖恢复需要依赖串口或专用烧录工具比较麻烦。我最初拿到板子的时候先做的是在U-Boot命令行下ping开发主机确认网络链路正常ping 192.168.1.10这个命令能通说明后续TFTP下载、NFS挂载的前提都成立了。如果ping不通优先检查网线连接、PC防火墙和虚拟机的桥接网卡设置而不是急着查烧录命令。5.2 串口调试与常用命令串口是嵌入式开发最底层的调试通道哪怕网络完全不通只要有串口就能看到系统输出。SS928的U-Boot和内核日志都默认输出到调试串口波特率115200。进入Linux系统后查看系统信息、确认硬件状态这几个命令是每天的必修课cat /proc/cpuinfo # 查看CPU信息 cat /proc/meminfo # 查看内存信息 free -m # 查看可用内存 ifconfig eth0 # 查看网络状态 dmesg | tail -50 # 查看最近内核日志另外在开发阶段建议在U-Boot里延长bootdelay默认的1秒或者2秒等你手忙脚乱找键盘时早过去了。改成5秒给自己留出足够时间按任意键进入U-Boot命令行setenv bootdelay 5 saveenv这个细节看似很小但在频繁调试启动参数的阶段非常实用。5.3 日志与崩溃现场分析内核启动过程中如果出现panic或者卡死日志是唯一的线索。所以从环境搭建阶段就要保证串口日志完整记录。我用的是picocom可以把串口输出同时记录到文件里sudo picocom -b 115200 --logfile /data/project/output/serial_log.txt /dev/ttyUSB0这样每次上电后的完整日志都会落盘排查问题时可以回翻。还有一个习惯建议在PC上单独建一个logs目录按日期命名日志文件比如serial_log_20250120.txt方便后续对比不同版本的启动日志差异。如果内核崩溃发生在挂载根文件系统之前通常是内核命令行参数、设备树或者驱动初始化的问题如果崩溃发生在挂载rootfs之后多半是文件系统内容或权限问题。这两个阶段的分界线是内核日志里出现“VFS: Mounted root”提示判断清楚阶段能省下大量排查时间。6. 常见问题与排查技巧实录6.1 工具链相关的典型报错交叉编译SS928的U-Boot或内核时最常见的报错是“gcc: error: unrecognized command-line option”这类问题一般是工具链版本太老不支持代码中用到的编译选项。比如内核代码用到了-moutline-atomics之类的选项老版本的aarch64工具链就会报错换用较新的Linaro工具链或海思SDK指定版本即可。另一个典型的报错是“/bin/sh: 1: bison: not found”或者“flex: command not found”这类是宿主机缺少编译依赖回到第2.1节把基础软件包装全就能解决。还有“mkimage”命令找不到是u-boot-tools没装同样的道理。6.2 NFS挂载失败排查开发板挂载NFS失败表现通常是卡在“nfs: server 192.168.1.10 not responding, still trying”或者直接报“Permission denied”。排查顺序我一般是这样的第一步确认PC上“showmount -e 192.168.1.10”能看到共享目录看不到说明/etc/exports配置有误或nfs服务没起来。第二步确认防火墙ufw status看看是否放行NFS端口。第三步检查挂载参数换用“mount -t nfs -o nolock,vers3 192.168.1.10:/data/project/nfs /mnt/nfs”试一次。第四步看PC端/var/log/syslog里有没有NFS相关报错有些问题在板端看不出来但服务端日志里写得一清二楚。如果开发板要作为根文件系统启动NFS内核配置里必须开启CONFIG_ROOT_NFS这个在内核的File systems - Network File Systems下不开启的话启动到挂载rootfs阶段必然失败。6.3 TFTP下载超时或中断TFTP下载过程中进度条卡住不动或者传了一部分就超时优先检查网络质量。开发板直连PC网线时注意网线的线序和接口速率协商劣质网线或者接触不良会造成大量丢包。其次关闭PC上的防火墙或者明确放行UDP的69端口以及后续的数据端口。TFTP默认使用69端口协商但数据传输会切换到随机高位端口防火墙规则如果写得太死会造成“握手成功但数据传输失败”的诡异现象。还有一点在U-Boot里使用tftp命令时有的固件对内存地址有对齐要求我遇到过用0x41000000地址下载没问题、用0x41000001就报错的情况这种情况把地址改回对齐地址即可。6.4 电源与电平问题最后说一个很多人容易忽略的硬件层面的问题。SS928开发板功耗不低尤其外接了摄像头、屏幕或USB设备后对电源质量很敏感。我在调试过程中遇到过几次板子毫无征兆地重启或死机排查很久发现是USB供电的转串口模块导致的地电平不稳。换用独立供电的串口模块或者给开发板接更稳定的电源适配器后问题消失。这种问题不会每次复现排查难度大一旦遇到不要只盯软件先把硬件供电和连接可靠性排查一遍。U-Boot阶段无法进入命令行串口无输出先用示波器或万用表确认串口TX引脚的信号状态再确认串口线接的是不是调试串口。有些开发板上同时有多个串口插座调试串口可能不是离电源最近的那个务必对照板卡原理图确认。在我实际操作中环境搭建最忌一步到位的心态。很多人以为照着文档敲完命令就算完事结果后面每个环节都在返工。真正高效的做法是每配置好一个环节就用最小的验证动作确认它确实可用。工具链装完马上编个hello程序NFS配好马上挂载试读写TFTP配好马上用uboot下载一个小文件。每个验证动作只需要一两分钟但这几分钟能帮你把后面几天的时间都省回来。最后再分享一个技巧把你配好的虚拟机做一次快照最好是所有验证都通过之后立刻做。这样后续SDK编译、内核配置再怎么折腾随时可以恢复到一个确定可用的环境状态。这个习惯在多人共用一台编译服务器的时候尤其重要别人改坏的环境不会拖住你的开发进度。