2、环境搭建:开发环境准备、依赖安装、编译工具链配置、示例工程运行
TFLite Micro 的工程实践与常规嵌入式开发有显著差异:它既需要处理交叉编译工具链,又需要管理 TensorFlow 仓库中庞大的依赖关系,还要面对不同硬件平台(MCU、DSP、NPU)的抽象层适配。本章将围绕“从零到可运行示例”这一目标,系统拆解环境搭建的四个核心环节:开发环境选型、依赖安装策略、编译工具链配置、示例工程验证。我们以 Ubuntu 22.04 LTS 作为主开发环境,以 STM32F746G-Discovery 和 ESP32-S3 两个典型平台为例展开说明,帮助读者建立一套可复用的环境搭建方法论。
上图展示了环境搭建的完整链路。四个阶段并非完全串行,实际开发中经常需要回退迭代——例如在编译阶段发现缺少某个 Python 依赖,就需要回到第二阶段补充安装。下面我们逐一深入每个环节的具体操作与关键决策点。
2.1 开发环境准备:主机系统与硬件调试基础设施
核心原理:TFLite Micro 的构建系统基于 Makefile 和 CMake,两者在 Linux 环境下表现最稳定。Windows 原生环境虽然可以运行,但会遇到路径分隔符、符号链接、长路径限制等问题,因此强烈建议使用 Ubuntu 或 WSL2。硬件调试方面,STM32 系列通常依赖 ST-Link,ESP32 系列则通过 USB 转串口进行烧录和日志输出。
操作流程:
- 安装 Ubuntu 22.04 LTS:推荐分配至少 60GB 磁盘空间、8GB 内存。若使用 WSL2,需确保 Windows 11 或 Windows 10 21H2 以上版本。
- 更新系统包:
sudo apt update && sudo apt upgrade -y - 安装基础工具:
sudo apt install -y git make cmake ninja-build python3 python3-pip curl wget - 配置 Git 用户信息:
git config --global user.name "Your Name"和git config --global user.email "your@email.com" - 安装串口工具:
sudo apt install -y minicom screen,并确保当前用户加入dialout组:sudo usermod -aG dialout $USER
usbipd-win 工具来共享 USB 设备,具体命令为 usbipd bind --busid <busid>。
2.2 依赖安装:TensorFlow 仓库与子模块管理
核心原理:TFLite Micro 的代码托管在 TensorFlow 主仓库中,路径为 tensorflow/lite/micro。该目录依赖多个外部组件,包括 CMSIS(Cortex-M 软件接口标准)、Renesas 驱动库、Arduino 库等。这些依赖通过 Git 子模块(submodule)管理,必须显式初始化。
操作流程:
# 克隆 TensorFlow 仓库(使用 --depth=1 减少下载量)
git clone --depth=1 https://github.com/tensorflow/tensorflow.git
cd tensorflow
# 初始化并更新子模块(关键步骤)
git submodule init
git submodule update --init --recursive
# 运行依赖下载脚本(自动拉取缺失的第三方库)
python3 tensorflow/lite/micro/tools/project_generation/rename_cc_outputs.py
make -f tensorflow/lite/micro/tools/make/Makefile third_party_downloads
案例拆解:某开发者在克隆仓库后直接编译,遇到 cmsis_gcc.h: No such file or directory 错误。排查过程如下:
| 排查步骤 | 命令/操作 | 结果 |
|---|---|---|
| 检查子模块状态 | git submodule status | 显示 - 前缀,表示未初始化 |
| 初始化子模块 | git submodule update --init | 下载 CMSIS 等依赖 |
| 重新编译 | make -f tensorflow/lite/micro/tools/make/Makefile hello_world | 编译通过 |
这个案例说明,子模块初始化是环境搭建中最容易遗漏的步骤。建议在克隆仓库后立即执行 git submodule update --init --recursive,不要等到编译报错再处理。
http.postBuffer 参数。如果网络不稳定,可以分多次执行子模块更新,或者使用 git submodule update --depth=1 减少历史记录下载。
2.3 编译工具链配置:交叉编译与平台适配
核心原理:TFLite Micro 的编译工具链分为两部分:主机工具链(用于编译在 PC 上运行的测试程序)和交叉工具链(用于生成目标 MCU 的可执行文件)。交叉工具链的选择取决于目标平台架构:Cortex-M 系列使用 arm-none-eabi-gcc,ESP32-S3 使用 xtensa-esp32s3-elf-gcc。
操作流程(以 STM32F746G 为例):
# 安装 ARM 交叉编译工具链
sudo apt install -y gcc-arm-none-eabi
# 验证安装
arm-none-eabi-gcc --version
# 编译 hello_world 示例(指定目标平台)
make -f tensorflow/lite/micro/tools/make/Makefile \
TARGET=stm32f746g \
TARGET_TOOLCHAIN=arm_gcc \
hello_world
关键参数说明:
TARGET:指定目标平台,如stm32f746g、esp32、sparkfun_edge等。TARGET_TOOLCHAIN:指定工具链,常用arm_gcc或xtensa。BUILD_TYPE:可选debug或release,默认release会启用优化。
案例拆解:ESP32-S3 工具链配置
ESP32-S3 使用乐鑫官方的 ESP-IDF 框架,TFLite Micro 提供了专门的集成脚本:
# 安装 ESP-IDF(版本需 ≥ 4.4)
mkdir -p ~/esp && cd ~/esp
git clone --recursive https://github.com/espressif/esp-idf.git
cd esp-idf
./install.sh esp32s3
source export.sh
# 编译 TFLite Micro 示例
make -f tensorflow/lite/micro/tools/make/Makefile \
TARGET=esp32 \
TARGET_TOOLCHAIN=xtensa \
hello_world
这里需要特别注意:ESP32 的 TARGET 参数是 esp32,但实际编译时会根据 IDF_TARGET 环境变量区分具体芯片型号。在编译前需执行 export IDF_TARGET=esp32s3。
- ARM 工具链由 Arm 官方维护,更新频率稳定,支持 Cortex-M0/M3/M4/M7 全系列。
- Xtensa 工具链由乐鑫维护,与 ESP-IDF 深度绑定,版本升级需同步更新 IDF。
- ARM 工具链可直接通过 apt 安装,Xtensa 工具链必须通过 ESP-IDF 的 install.sh 安装。
2.4 示例工程运行:烧录、调试与验证
核心原理:示例工程编译成功后,生成的可执行文件(.elf 或 .bin)需要烧录到目标板。烧录方式取决于平台:STM32 使用 ST-Link 配合 OpenOCD 或 STM32CubeProgrammer,ESP32 使用 esptool.py。验证环节通过串口输出判断模型推理是否正常。
操作流程(以 STM32F746G 为例):
# 使用 OpenOCD 烧录
openocd -f interface/stlink.cfg -f target/stm32f7x.cfg \
-c "program build/stm32f746g/hello_world/hello_world.elf verify reset exit"
# 查看串口输出(波特率 115200)
minicom -D /dev/ttyUSB0 -b 115200
预期输出:
Hello World! x: 0.000000, y: 0.000000
Hello World! x: 0.100000, y: 0.099833
Hello World! x: 0.200000, y: 0.198669
...
案例拆解:串口无输出的排查过程
某开发者在 STM32F746G 上运行 hello_world,串口无任何输出。排查步骤如下:
| 检查项 | 操作 | 结果 |
|---|---|---|
| 电源指示灯 | 观察板载 LED | LED 亮,供电正常 |
| 烧录是否成功 | OpenOCD 输出 verify OK | 烧录成功 |
| 串口连接 | 检查 /dev/ttyUSB0 权限 | 当前用户不在 dialout 组 |
| 修复权限 | sudo usermod -aG dialout $USER | 重新登录后串口输出正常 |
这个案例揭示了环境搭建中一个常见陷阱:硬件连接正常但权限不足导致无法访问串口。建议在开发前就将用户加入 dialout 组,避免后续调试中断。
2.5 常见误区与总结复盘
误区一:忽略子模块初始化。这是新手最常犯的错误。直接编译会报出各种头文件缺失错误,但根因只有一个——子模块未更新。建议在克隆仓库后立即执行 git submodule update --init --recursive。
误区二:工具链版本不匹配。ARM 工具链版本过旧可能导致编译失败,建议使用 10.3-2021.10 及以上版本。ESP32 工具链则必须与 ESP-IDF 版本严格对应,升级 IDF 后需重新执行 install.sh。
误区三:混淆主机编译与交叉编译。在 x86 主机上直接执行 gcc 编译出的程序无法在 MCU 上运行。必须使用 arm-none-eabi-gcc 或 xtensa-esp32s3-elf-gcc。可以通过 file 命令检查生成文件的架构:file hello_world.elf 应显示 ARM 或 Tensilica 架构。
总结复盘:环境搭建的核心目标是建立一条“源码 → 编译 → 烧录 → 验证”的完整链路。建议读者按照以下顺序自检:
- 主机系统是否满足要求(Ubuntu 22.04 或 WSL2)?
- Git 子模块是否完整?
git submodule status应无-前缀。 - 交叉工具链是否安装?
arm-none-eabi-gcc --version能正常输出。 - 示例工程能否编译通过?
make ... hello_world无报错。 - 烧录后串口是否有预期输出?