2. 嵌入式开发环境搭建:交叉编译工具链安装、嵌入式Linux系统烧录、SSH与串口调试

说实话,嵌入式AI算法工程化这件事,第一步往往不是写代码,而是先把开发环境伺候好。我见过太多新手,算法模型在PC上跑得飞起,一上板子就懵了——连个helloworld都编译不过。嗯,这章我们就来把这几个基础环节捋清楚。

2.1 交叉编译工具链:为什么非得“交叉”?

你想想看,你的开发电脑是x86架构,而目标板子通常是ARM或RISC-V。x86上编译出来的二进制,ARM根本认不了。这时候就需要交叉编译工具链——说白了,就是在你的PC上,生成能在目标芯片上跑的程序。

我个人习惯用Linaro提供的GCC工具链,稳定且社区活跃。以ARM Cortex-A72为例,安装步骤其实很简单:

# 下载工具链(以aarch64为例)
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz

# 解压到指定目录
tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz -C /opt/

# 配置环境变量
export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin
小提示:建议把环境变量写到 ~/.bashrc 里,不然每次开终端都得重新 export。我刚开始就吃过这个亏,折腾了半天才发现是环境变量没生效。

验证是否安装成功,跑一下这个命令:

aarch64-linux-gnu-gcc --version

如果能看到版本号,恭喜你,工具链已经就绪。

2.2 嵌入式Linux系统烧录:把系统“灌”进板子

交叉编译环境搭好了,接下来得让板子跑起来。嵌入式Linux系统烧录,说白了就是把bootloader、内核、根文件系统这些玩意儿写到板子的存储介质里(比如eMMC、SD卡、NAND Flash)。

我项目中用得最多的是SD卡烧录方式,因为调试方便。以Rockchip RK3588平台为例,烧录工具是 rkdeveloptool

# 进入Loader模式(按住板子上的RECOVERY键,再上电)
sudo rkdeveloptool db rk3588_loader.bin
sudo rkdeveloptool wl 0x0 uboot.img
sudo rkdeveloptool wl 0x4000 boot.img
sudo rkdeveloptool wl 0x8000 rootfs.img
sudo rkdeveloptool rd
注意:不同芯片厂商的烧录工具不一样。全志用PhoenixCard,NXP用mfgtools,别搞混了。我曾经有一次拿rkdeveloptool去烧全志的板子,结果把板子搞成砖了,还好最后用短接Flash引脚救回来了。

如果你用的是树莓派这类通用板子,用 dd 命令直接写SD卡更省事:

sudo dd if=ubuntu-22.04-preinstalled-server-arm64.img of=/dev/sdb bs=4M status=progress
sync

嗯,这里要注意,/dev/sdb 是你的SD卡设备名,千万别写成系统盘,否则后果你懂的。

2.3 SSH与串口调试:板子跑起来后怎么跟它“说话”?

系统烧录完,板子启动后,你总得跟它交互吧?两种方式:SSH(网络)和串口(物理线缆)。

2.3.1 SSH调试

SSH是最常用的方式,前提是板子和PC在同一个局域网。我一般这样操作:

  1. 板子通过网线连到路由器,或者用USB转网口共享PC网络
  2. 查看板子IP(可以在路由器管理界面找,或者用串口先登录进去 ifconfig
  3. PC端执行:ssh root@192.168.1.100

第一次连接会提示确认指纹,输入 yes 就行。默认密码通常是 rootadmin,具体看你的系统镜像。

避坑指南:我曾经遇到SSH连不上,排查了半天,最后发现是板子的防火墙没关。执行 systemctl stop ufw 就好了。另外,如果板子没有SSH服务,记得先 apt install openssh-server

2.3.2 串口调试

串口是最后的保底手段。哪怕板子网络没配好、系统起不来,只要bootloader还在,串口就能给你输出信息。我习惯用USB转TTL模块,三根线:TX、RX、GND。

接线方式:

  • 板子的TX → 模块的RX
  • 板子的RX → 模块的TX
  • 板子的GND → 模块的GND

PC端用 screenminicom 连接:

# 查看串口设备
ls /dev/ttyUSB*

# 用screen连接(波特率通常115200)
sudo screen /dev/ttyUSB0 115200
警告:千万别把TX和RX接反了!接反了屏幕上啥都没有。我刚开始做嵌入式那会儿,经常犯这个低级错误,后来养成了一个习惯:接好线后先用手碰一下TX引脚,如果串口有乱码输出,说明线接对了。

串口还有一个妙用——查看内核启动日志。当系统起不来时,串口输出的log能告诉你到底是哪里卡住了。比如常见的 Kernel panic - not syncing: VFS: Unable to mount root fs,说明根文件系统没挂载成功,可能是烧录时分区写错了。

2.4 环境验证:跑一个简单的AI推理程序

环境搭好了,总得验证一下。我习惯写一个最简单的TensorFlow Lite程序,在板子上跑个分类任务:

# 交叉编译一个TFLite示例
aarch64-linux-gnu-g++ -o label_image label_image.cc \
  -I/opt/tensorflow -L/opt/tensorflow/lite/tools/make/gen/linux_aarch64/lib \
  -ltensorflow-lite -lpthread -ldl

# 把可执行文件和模型推送到板子
scp label_image root@192.168.1.100:/root/
scp mobilenet_v1_1.0_224.tflite root@192.168.1.100:/root/

# SSH登录板子执行
ssh root@192.168.1.100
./label_image -i cat.jpg -m mobilenet_v1_1.0_224.tflite

如果能看到输出 tabby cat: 0.875 之类的结果,说明整个环境——交叉编译、系统烧录、SSH调试——全部打通了。

核心要点:嵌入式AI开发环境搭建,本质上就是三件事:
1. 让PC能编译ARM代码(交叉工具链)
2. 让板子能跑系统(烧录)
3. 让PC和板子能通信(SSH/串口)
这三件事搞定了,后面的事情就顺了。

嗯,这一章的内容就到这里。下一章我们会深入嵌入式Linux内核的裁剪与编译,到时候会用到今天搭好的环境。记得把工具链和烧录流程练熟,后面很多操作都依赖这些基础。