2. 测试环境搭建:嵌入式测试硬件平台选型、软件工具链配置
搭建测试环境,说白了就是给嵌入式软件找个能跑、能测、能复现问题的「家」。我见过不少团队,代码写得漂亮,但环境搭得稀烂,结果一半时间花在跟环境斗智斗勇上。这一章,咱们就把硬件选型、工具链配置、调试器连接这些事掰开揉碎了讲。
2.1 嵌入式测试硬件平台选型
选硬件,先看需求。你想想看,一个跑 RTOS 的传感器节点,跟一个跑 Linux 的工控板,测试重点能一样吗?我个人习惯按下面这张表来快速定位:
| 项目类型 | 推荐 MCU/MPU | 典型 RAM | 调试接口 | 我踩过的坑 |
|---|---|---|---|---|
| 低功耗传感器 | STM32L0 / EFM32 | 16-64 KB | SWD | 忘了测深度睡眠唤醒时序 |
| 实时控制 | STM32F4 / TMS320F28 | 128-512 KB | JTAG / SWD | 中断延迟被 DMA 抢了优先级 |
| 多媒体/网关 | i.MX6 / RK3568 | 512 MB - 2 GB | JTAG + 串口 | DDR 信号完整性翻过车 |
| 功能安全 | TC2xx / RH850 | 2-8 MB | Aurora / DAP | 锁步核测试用例写漏了 |
选型时有三个硬指标:调试接口要够用、RAM 能跑起测试桩、有足够的 GPIO 引出测试点。我曾经在一个项目里选了颗 QFN 封装的芯片,所有调试引脚都被内部电路占用了,最后只能飞线,那叫一个痛苦。
2.2 软件工具链配置
工具链配置,核心就三件事:持续集成、环境一致性、自动化部署。我习惯用 Jenkins + GitLab CI + Docker 这套组合拳。
2.2.1 Jenkins:调度中心
Jenkins 负责跑定时构建、触发测试、收集报告。我个人习惯用 Pipeline as Code,把流程写在 Jenkinsfile 里。
pipeline {
agent any
stages {
stage('Checkout') {
steps { checkout scm }
}
stage('Build') {
steps { sh 'make -j4' }
}
stage('Unit Test') {
steps { sh 'make test' }
}
stage('Deploy to Target') {
steps { sh './flash_target.sh' }
}
}
post {
always { junit 'reports/*.xml' }
}
}
嗯,这里要注意:不要把 Jenkins Master 和 Agent 混用。我见过有人直接在 Master 上编译,结果插件装多了,Master 挂了,所有任务都停了。最好用 Docker Agent,用完即焚。
2.2.2 GitLab CI:代码门禁
GitLab CI 更适合做 Merge Request 前的快速检查。我通常把它配置成:提交代码 → 静态检查 → 编译 → 跑冒烟测试。一旦失败,MR 直接锁住。
stages:
- lint
- build
- smoke_test
lint:
stage: lint
script:
- cppcheck --enable=all src/
build:
stage: build
script:
- docker build -t test_image .
- docker run test_image make
smoke_test:
stage: smoke_test
script:
- python3 smoke_test_runner.py
2.2.3 Docker:环境一致性
Docker 解决的是「在我机器上能跑」的问题。嵌入式环境尤其复杂——编译器版本、库文件、工具链路径,差一点就编译不过。
我一般这么写 Dockerfile:
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y \
gcc-arm-none-eabi \
make \
cmake \
python3-pip \
openocd
RUN pip3 install pytest pyserial
COPY . /workspace
WORKDIR /workspace
然后配合 docker-compose 把 Jenkins Agent 也容器化。这样不管换机器还是换人,环境完全一致。
2.3 目标板与调试器连接
硬件连好了,软件才能跑起来。调试器连接这块,我见过太多人栽在接线和驱动上。
2.3.1 常见调试器对比
| 调试器 | 接口 | 速度 | 适用场景 | 我的评价 |
|---|---|---|---|---|
| J-Link | SWD/JTAG | 最高 50 MHz | ARM 全系列 | 稳定,但贵 |
| ST-Link/V2 | SWD | 最高 4 MHz | STM32 | 够用,性价比高 |
| OpenOCD + FT2232 | JTAG/SWD | 取决于硬件 | 自定义板 | 灵活,但配置麻烦 |
| Lauterbach | JTAG/Aurora | 极高 | 功能安全/复杂 SoC | 专业,但钱包疼 |
2.3.2 接线要点
接线看起来简单,但细节决定成败:
- SWD 只需要 4 根线:SWDIO、SWCLK、GND、VCC(可选,用于电平检测)。
- JTAG 需要 5 根线:TMS、TCK、TDI、TDO、nTRST(可选)。
- 复位线一定要接:很多调试器需要 nSRST 来控制目标板复位,不接的话经常连不上。
- 线长尽量短:超过 20cm 就容易受干扰,尤其是 SWCLK 频率高的时候。
2.3.3 调试器配置示例
以 OpenOCD 为例,连接 STM32F4 的配置:
# stm32f4.cfg
source [find interface/stlink.cfg]
source [find target/stm32f4x.cfg]
adapter speed 4000
reset_config srst_only srst_nogate
启动命令:
openocd -f stm32f4.cfg
然后在 GDB 里连接:
target remote localhost:3333
monitor reset halt
load firmware.elf
continue
嗯,这里有个小技巧:先执行 monitor reset halt,再 load。如果不 halt,芯片还在跑,下载时可能会写坏 Flash。
2.4 整体架构图
下面这张图,把硬件平台、工具链、调试器之间的关系画清楚了。你可以把它贴在工位上,每次搭环境时对照着来。
2.5 环境验证 checklist
环境搭完,别急着写测试用例。先跑一遍验证清单,确保每个环节都通:
- 硬件连接:调试器能识别芯片 IDCODE。
- 编译链:arm-none-eabi-gcc 能正常编译 hello world。
- 下载:能通过调试器把固件烧进 Flash,并复位运行。
- 串口通信:目标板串口能输出日志,PC 端能收到。
- CI 触发:提交代码后,Jenkins/GitLab CI 能自动拉取、编译、部署。
- Docker 环境:在 Docker 容器内编译的结果,跟本地编译结果一致。
环境搭建这事,一次搭好,后面省心。别嫌麻烦,把每一步都走扎实了,后面调试和测试才能顺畅。嗯,就这些,动手去搭吧。