12 KiB
GD32E230 + VL53L4CD 测距项目
本仓库是基于 GD32E230 的 VL53L4CD 时间飞行(ToF)测距项目,硬件兼容 Adafruit VL53L4CD 模块。固件通过 I2C 驱动传感器,每 500ms 输出一次距离和测距质量参数。
目录
- 硬件连接
- 功能开关
- 编译与烧录
- 串口命令(Mx)
- 串口输出
- VL53L4CD 驱动
- 测距结果字段
- 测距状态码
- 偏移校准
- 透过玻璃测距(Crosstalk)
- 校准数据 Flash 存储
- I2C 16 位寄存器说明
- Flash 体积说明
- 已知限制
- 变更记录
硬件连接
主控
- MCU:GD32E230 系列,Cortex-M23
- 系统时钟:72MHz
- Flash:16K(F4)/ 32K(F6)/ 64K(F8),上电自动识别
VL53L4CD
| 信号 | 引脚 | 说明 |
|---|---|---|
| SCL | PA9 | I2C0 时钟,AF4 |
| SDA | PA10 | I2C0 数据,AF4 |
| VDD | 3.3V | 模块供电 |
| GND | GND | 共地 |
传感器 7 位 I2C 地址默认为 0x29。
串口
| 信号 | 引脚 | 说明 |
|---|---|---|
| TX | PA2 | RS485 发送 |
| RX | PA3 | RS485 接收 |
| DE | PA1 | RS485 方向控制,硬件自动控制 |
波特率 115200,8N1。
其他
- LED:PB1
- SWD:SWDIO、SWCLK、GND,用于 DAPLink 烧录与调试
功能开关
所有开关集中在 Inc/board_config.h。
| 宏 | 当前值 | 作用 |
|---|---|---|
DEBUG_MODE |
CFG_DISABLE |
关闭 Hello World 启动横幅;距离输出仍保留 |
DEBUG_VERBOSE |
CFG_DISABLE |
关闭 IIC 调试打印和启动 I2C 扫描 |
COM_DEBUG |
CFG_DISABLE |
关闭命令帧调试打印 |
SEGGER_RTT_DETECTION |
CFG_DISABLE |
关闭 SEGGER RTT |
VL53L4CD_CALIB_TARGET_MM |
44 |
当前安装位置的目标实际距离 |
VL53L4CD_CALIB_SAMPLES |
20 |
校准采样次数 |
VL53L4CD_AUTO_CALIB |
CFG_DISABLE |
开机自动校准开关 |
VL53L4CD_CALIB_OFFSET_MM |
-9 |
当前固定的距离偏移量 |
VL53L4CD_GLASS_XTALK |
CFG_DISABLE |
透过玻璃测距:开机写入串扰补偿 |
VL53L4CD_GLASS_XTALK_KCPS |
20 |
编译期固定串扰值,单位 kcps,0..127 |
VL53L4CD_XTALK_CALIB_TARGET_MM |
500 |
M104 串扰校准默认目标距离(玻璃后方) |
VL53L4CD_XTALK_CALIB_SAMPLES |
20 |
M104 串扰校准默认采样次数 |
VL53L4CD_PERSIST_CALIB |
CFG_ENABLE |
开机优先从 Flash 末页加载校准数据 |
RS485_MODE |
CFG_ENABLE |
使用 RS485 串口输出 |
SOFTWARE_IIC |
CFG_DISABLE |
使用硬件 I2C |
如果需要临时扫描 I2C 总线或查看 IIC 调试信息,把 DEBUG_VERBOSE 改为 CFG_ENABLE。注意 16K Flash 下全开会让固件体积非常紧张。
编译与烧录
编译
在仓库根目录执行:
cmake --preset Release
cmake --build Build/Release
Debug 构建:
cmake --preset Debug
cmake --build Build/Debug
产物位于 Build/Release/Application/:
Application.elfApplication.hexApplication.binApplication.map
烧录
通过 DAPLink/CMSIS-DAP 烧录:
D:/toolchain/openocd/bin/openocd.exe \
-s D:/toolchain/openocd/scripts \
-f interface/cmsis-dap.cfg \
-f target/gd32e23x.cfg \
-c "reset_config srst_only connect_assert_srst; init; reset halt; flash write_image erase Build/Release/Application/Application.elf; reset; exit"
也可以在 VSCode 中使用已配置的 Flash 任务。
串口命令(Mx)
命令帧格式 D5 01 LEN [命令] CRC(LEN 为命令字节数,CRC 为帧内累加和),响应帧 B5 TYPE LEN [数据] CRC,TYPE=0xF0 表示成功。波特率 115200,8N1。
基础命令
| 命令 | 功能 | 成功响应 |
|---|---|---|
M1 |
开启测距上报,LED 亮 | ok |
M2 |
关闭测距上报,LED 灭 | ok |
M3 |
立即返回最近一帧结果(上报关闭时也可查询) | d=830;s=0 |
M888 |
软件重启 | ok 后复位 |
M999 |
输出固件版本号 | v20.0.0.1 |
M9999 |
复位进入 OTA/Bootloader | 复位 |
校准命令
| 命令 | 功能 | 成功响应 |
|---|---|---|
M101 |
读取当前偏移量 | o=-9 |
M101S<mm> |
写入偏移量并立即生效,如 M101S-9 |
o=-9 |
M102S<mm> |
执行偏移校准,S 为目标实际距离(默认 44) |
o=-9 |
M103 |
读取当前串扰补偿值 | x=12 |
M103S<kcps> |
写入串扰补偿值 0..127,如 M103S12 |
x=12 |
M104S<mm> |
执行串扰校准,S 为玻璃后方目标距离(默认 500) |
x=12 |
M105 |
保存当前偏移+串扰到 Flash(掉电保持) | ok |
M106 |
从 Flash 读取并应用校准数据 | o=-9 |
M107 |
擦除 Flash 校准数据,偏移/串扰清零 | ok |
说明:
M102/M104为阻塞执行,耗时约 2 秒,期间连续上报暂停。M101S/M103S/M102/M104只改寄存器,掉电丢失;需要掉电保持时接一条M105。- 参数错误返回
0xFD,未知命令返回0xFE,校准/Flash 失败返回0xFF。
串口输出
连接串口后使用 115200 8N1 查看,例如 COM17:
Distance: 830 mm | status: 0 | signal: 1128 kcps | ambient: 72 kcps | sigma: 3 mm
默认每 500ms 输出一次。
VL53L4CD 驱动
驱动文件:
Inc/VL53L4CD_Driver.hSrc/VL53L4CD_Driver.c
主要接口
| 函数 | 作用 |
|---|---|
vl53l4cd_init() |
初始化传感器,写入默认配置,默认 50ms 时序预算 |
vl53l4cd_start_ranging() |
启动连续测距 |
vl53l4cd_stop_ranging() |
停止连续测距 |
vl53l4cd_data_ready() |
查询是否有新结果 |
vl53l4cd_clear_interrupt() |
清除测距完成中断 |
vl53l4cd_get_result() |
读取并解析测距结果 |
vl53l4cd_set_range_timing() |
设置 10-200ms 时序预算,当前仅支持连续模式 |
vl53l4cd_set_offset(offset_mm) |
写入手动指定的距离偏移量 |
vl53l4cd_get_offset(&offset_mm) |
读取当前生效的距离偏移量 |
vl53l4cd_calibrate_offset(target_mm, samples, &offset) |
对当前目标执行偏移校准并写回 |
vl53l4cd_set_xtalk(xtalk_kcps) |
写入串扰补偿值(透过玻璃),0..127 kcps |
vl53l4cd_get_xtalk(&xtalk_kcps) |
读取当前串扰补偿值 |
vl53l4cd_calibrate_xtalk(target_mm, samples, &xtalk) |
执行串扰校准并写回 |
vl53l4cd_read_reg8/16() |
读 8/16 位寄存器 |
vl53l4cd_write_reg8/16() |
写 8/16 位寄存器 |
偏移校准
VL53L4CD 出厂带有默认偏移,但器件之间存在差异,固定安装场景建议做一次单点校准。
当前安装位置的目标距离为 44mm,已通过 20 帧有效采样完成校准,校准得到的偏移量为 -9mm。固件在 vl53l4cd_init() 后调用 vl53l4cd_set_offset(VL53L4CD_CALIB_OFFSET_MM) 写回,因此每次上电都会保持校准结果。
需要重新校准时:
- 把目标放在已知距离,例如 44mm。
- 将
Inc/board_config.h中VL53L4CD_AUTO_CALIB改为CFG_ENABLE。 - 上电后串口会打印
VL53L4CD offset calibrated: X mm。 - 把打印出的
X填入VL53L4CD_CALIB_OFFSET_MM,再将VL53L4CD_AUTO_CALIB改回CFG_DISABLE。
也可以不发固件、直接用串口命令在线校准:目标放好后依次发送 M102S44(校准)、M105(保存到 Flash)。M101 可随时读回当前偏移。
也可以直接调用 vl53l4cd_calibrate_offset(),该函数会先清零偏移、热机 10 帧,再统计有效测距样本并计算 offset = 实际距离 - 平均距离,最后写入 RANGE_OFFSET_MM (0x001E)。
注意:单点偏移只修正当前固定距离的绝对误差。近距离高反射金属目标存在非线性,建议使用哑光目标。
透过玻璃测距(Crosstalk)
传感器透过盖板玻璃测距时,玻璃上下表面的反射会产生串扰(crosstalk),表现为读数偏小、近距离出现固定虚假目标。VL53L4CD 通过 XTALK 寄存器组(0x0016..0x001D)做信号级补偿。
固件按 ST ULD 官方算法(vl53l4cd_calibration.c)实现,并改为定点数运算以省 Flash:
xtalk = (1 - 平均距离/目标距离) * 平均信号速率/平均SPAD数
上限 127 kcps,超出判定为校准失败;寄存器值为 xtalk_kcps * 512。
使用方式
方式一:编译期固定值(不使用串口)
- 测得或校准出串扰值后,打开
VL53L4CD_GLASS_XTALK,把值填入VL53L4CD_GLASS_XTALK_KCPS。 - Flash 中无校准数据时,开机自动写入该值。
方式二:串口命令(推荐)
- 装上玻璃,目标放在玻璃后方已知距离(如 500mm),确保目标与玻璃之间无遮挡。
- 先完成偏移校准:
M102S44。 - 执行串扰校准:
M104S500,返回如x=12。 M105保存到 Flash,掉电不丢。M103可随时读回当前串扰值。
注意:偏移校准与串扰校准相互影响,重新校准其中一项后建议两项都重新校准并再次 M105 保存。
校准数据 Flash 存储
校准数据(偏移 + 串扰)保存在主 Flash 的最后一页(1KB),由 Src/calib_store.c 管理:
| 器件 | 校准页地址 |
|---|---|
| 16K(F4) | 0x0800 3C00 |
| 32K(F6) | 0x0800 7C00 |
| 64K(F8) | 0x0800 FC00 |
- 页地址按上电检测到的 Flash 容量动态计算,一份固件适配三种容量。
- 记录 16 字节,含魔数
CVL4、版本号、累加和校验;空白 Flash(全0xFF)不会误判。 - 链接脚本代码区已缩至 15K,避免代码长入校准页;擦写通过 GD32 SDK 的
fmc_page_erase()/fmc_doubleword_program()完成,操作期间短暂暂停串口接收中断。 - 上电加载顺序(
VL53L4CD_PERSIST_CALIB = CFG_ENABLE时):Flash 有有效数据 → 用 Flash 值;否则用VL53L4CD_CALIB_OFFSET_MM(及开启VL53L4CD_GLASS_XTALK时的固定串扰值)。
修改时序预算
在 Src/VL53L4CD_Driver.c 的 vl53l4cd_init() 末尾:
return vl53l4cd_set_range_timing(50U, 0U);
第一个参数是时序预算,范围 10-200ms。第二个参数当前只能传 0,表示连续测距模式。
修改输出间隔
在 Src/main.c 主循环中:
delay_ms(500);
改为需要的毫秒数即可。
I2C 16 位寄存器说明
测距结果字段
vl53l4cd_get_result() 返回 vl53l4cd_result_t:
| 字段 | 含义 |
|---|---|
distance_mm |
距离,单位 mm |
range_status |
测距状态码 |
number_of_spad |
有效 SPAD 数 |
signal_rate_kcps |
目标反射信号强度 |
ambient_rate_kcps |
环境光/背景噪声强度 |
signal_per_spad_kcps |
每个 SPAD 的信号强度 |
ambient_per_spad_kcps |
每个 SPAD 的环境光强度 |
sigma_mm |
测距噪声/不确定度,单位 mm |
测距状态码
| 状态码 | 含义 |
|---|---|
| 0 | 测距有效 |
| 1 | Sigma 超限,结果不稳定 |
| 2 | 信号太弱,目标太远、太黑或反射率低 |
| 3 | 目标过近 |
| 4 | 相位故障 |
| 5 | 硬件故障 |
| 6 | 未检测到目标 |
| 7 | 近距离信号不足 |
| 255 | 未知状态 |
I2C 16 位寄存器说明
VL53L4CD 的寄存器地址是 16 位。本项目的 i2c_read() / i2c_write() 已改为支持 uint16_t 寄存器地址,发送时先发高字节、再发低字节。
对原有 8 位寄存器地址的 I2C 器件仍然兼容:地址高字节为 0x00,发送序列与原来一致。
Flash 体积说明
链接脚本代码区为 15K(16K 容量器件预留最后 1KB 页存放校准数据)。当前 Release 固件约:
text 12908
data 24
bss 1704
15K 内仍有约 2.4K 余量。为省体积,主循环测距上报与启动信息改为手写格式化输出(不再链接 vfprintf,省约 2.7K),输出格式与旧版本逐字节一致。Debug 构建优化等级由 -O0 调整为 -Og(-O0 已无法放下),text 约 14876。保留 printf 会增加约 2.5K,因此 DEBUG_VERBOSE 全开仍会让 Flash 非常紧张。
已知限制
- 驱动只支持连续测距模式
- 距离阈值中断、自主低功耗模式、ULP 模式尚未实现
- VL53L4CD 是单区传感器,不是多区测距
- 串扰补偿为单区平面补偿(梯度寄存器清零),玻璃需正对传感器且尽量平行
DEBUG_VERBOSE全开时 IIC 调试打印会让 Flash 非常紧张
变更记录
当前迭代的详细说明见 CHANGES.md。