generated from hulk/gd32e23x_template_cmake_vscode
feat(VL53L4CD): 添加VL53L4CD测距驱动、I2C 16位寄存器支持与项目文档
This commit is contained in:
+104
@@ -0,0 +1,104 @@
|
|||||||
|
# 变更说明
|
||||||
|
|
||||||
|
本文记录本仓库当前未提交改动的背景、目的和验证结果,方便后续维护时快速了解这次迭代做了什么。
|
||||||
|
|
||||||
|
## 1. I2C 底层支持 16 位寄存器地址
|
||||||
|
|
||||||
|
### 改动
|
||||||
|
|
||||||
|
- `Inc/i2c.h`
|
||||||
|
- `Src/i2c.c`
|
||||||
|
|
||||||
|
`i2c_write()` 和 `i2c_read()` 的 `reg_addr` 参数由 `uint8_t` 改为 `uint16_t`,发送寄存器地址时先发高字节、再发低字节。
|
||||||
|
|
||||||
|
### 目的
|
||||||
|
|
||||||
|
VL53L4CD 的所有寄存器地址都是 16 位,例如:
|
||||||
|
|
||||||
|
- `IDENTIFICATION__MODEL_ID = 0x010F`
|
||||||
|
- `RESULT__RANGE_STATUS = 0x0089`
|
||||||
|
- `RESULT__DISTANCE = 0x0096`
|
||||||
|
|
||||||
|
原来的 `uint8_t` 寄存器地址接口无法直接访问这些寄存器。
|
||||||
|
|
||||||
|
### 兼容性
|
||||||
|
|
||||||
|
对于寄存器地址仍为 8 位的普通 I2C 器件,调用方传入的地址会自动被当作低字节发送,高字节为 `0x00`,因此原有行为不变。
|
||||||
|
|
||||||
|
## 2. 新增 VL53L4CD 驱动
|
||||||
|
|
||||||
|
新增文件:
|
||||||
|
|
||||||
|
- `Inc/VL53L4CD_Driver.h`
|
||||||
|
- `Src/VL53L4CD_Driver.c`
|
||||||
|
|
||||||
|
驱动参考 ST VL53L4CD ULD 和 Pololu Arduino 实现,提供:
|
||||||
|
|
||||||
|
- `vl53l4cd_init()`:读取型号、等待固件启动、写入默认配置、VHV 校准、设置 50ms 时序预算
|
||||||
|
- `vl53l4cd_start_ranging()` / `vl53l4cd_stop_ranging()`:启动/停止连续测距
|
||||||
|
- `vl53l4cd_data_ready()`:查询是否有新结果
|
||||||
|
- `vl53l4cd_clear_interrupt()`:清除测距完成中断
|
||||||
|
- `vl53l4cd_get_result()`:读取并解析 15 字节结果块
|
||||||
|
- `vl53l4cd_set_range_timing()`:设置 10-200ms 时序预算,当前只支持连续模式
|
||||||
|
- `vl53l4cd_read_reg8/16()`、`vl53l4cd_write_reg8/16()`:寄存器调试接口
|
||||||
|
|
||||||
|
结果结构体包含:
|
||||||
|
|
||||||
|
- `distance_mm`
|
||||||
|
- `range_status`
|
||||||
|
- `number_of_spad`
|
||||||
|
- `signal_rate_kcps`
|
||||||
|
- `ambient_rate_kcps`
|
||||||
|
- `signal_per_spad_kcps`
|
||||||
|
- `ambient_per_spad_kcps`
|
||||||
|
- `sigma_mm`
|
||||||
|
|
||||||
|
## 3. main.c 集成
|
||||||
|
|
||||||
|
在 `main.c` 中:
|
||||||
|
|
||||||
|
- 初始化完成后调用 `vl53l4cd_init()`
|
||||||
|
- 成功后调用 `vl53l4cd_start_ranging()`
|
||||||
|
- 主循环每 500ms 检查 `vl53l4cd_data_ready()`
|
||||||
|
- 有结果时清除中断、读取结果,并通过 `printf` 输出距离、状态、信号、环境光和 Sigma
|
||||||
|
|
||||||
|
输出示例:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Distance: 830 mm | status: 0 | signal: 1128 kcps | ambient: 72 kcps | sigma: 3 mm
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 板级配置
|
||||||
|
|
||||||
|
`Inc/board_config.h` 当前状态:
|
||||||
|
|
||||||
|
- `DEBUG_MODE = CFG_DISABLE`:关闭启动横幅,距离输出仍然保留
|
||||||
|
- `DEBUG_VERBOSE = CFG_DISABLE`:关闭 IIC 调试打印和启动 I2C 扫描
|
||||||
|
- `RS485_MODE = CFG_ENABLE`:使用 RS485 串口输出
|
||||||
|
- I2C 使用 PA9/PA10,复用 AF4
|
||||||
|
|
||||||
|
IIC 源码中的调试 `printf` 已恢复并保留在 `DEBUG_VERBOSE` 条件编译中,需要排查 I2C 时可临时打开。
|
||||||
|
|
||||||
|
## 5. 构建系统
|
||||||
|
|
||||||
|
`CMakeLists.txt` 的 `TARGET_SRC` 已添加:
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
Src/VL53L4CD_Driver.c
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 体积与验证
|
||||||
|
|
||||||
|
- MCU:GD32E230,Flash 16K,RAM 4K
|
||||||
|
- Release 编译:`text 14316 / data 116 / bss 2012`
|
||||||
|
- 编译通过,无警告
|
||||||
|
- 已通过 DAPLink/CMSIS-DAP + OpenOCD 烧录
|
||||||
|
- 已在 COM17 @ 115200 验证连续输出,间隔约 500ms
|
||||||
|
- `status: 0` 表示测距有效
|
||||||
|
|
||||||
|
## 7. 当前已知限制
|
||||||
|
|
||||||
|
- 驱动只支持连续测距模式,`inter_measurement_ms` 非 0 会返回失败
|
||||||
|
- 尚未实现距离阈值中断、Offset/Crosstalk 校准、自主低功耗模式、ULP 模式
|
||||||
|
- `DEBUG_VERBOSE` 全开时 IIC 调试打印会让 16K Flash 非常紧张,不建议常开
|
||||||
|
- VL53L4CD 是单区传感器,不是多区测距
|
||||||
+2
-1
@@ -36,6 +36,7 @@ set(TARGET_SRC
|
|||||||
Src/command.c
|
Src/command.c
|
||||||
Src/i2c.c
|
Src/i2c.c
|
||||||
Src/board_config.c
|
Src/board_config.c
|
||||||
|
Src/VL53L4CD_Driver.c
|
||||||
)
|
)
|
||||||
|
|
||||||
# 设置输出目录
|
# 设置输出目录
|
||||||
@@ -92,4 +93,4 @@ add_custom_command(TARGET ${PROJECT_NAME}
|
|||||||
# 1. If you add new source files (e.g. Src/my_module.c), add them to TARGET_SRC above.
|
# 1. If you add new source files (e.g. Src/my_module.c), add them to TARGET_SRC above.
|
||||||
# 2. If you add new header files or directories, add them to target_include_directories above.
|
# 2. If you add new header files or directories, add them to target_include_directories above.
|
||||||
# 3. If you add new SDK modules, use add_subdirectory(SDK/YourModule) and link with target_link_libraries.
|
# 3. If you add new SDK modules, use add_subdirectory(SDK/YourModule) and link with target_link_libraries.
|
||||||
# =========================
|
# =========================
|
||||||
|
|||||||
@@ -0,0 +1,162 @@
|
|||||||
|
/**
|
||||||
|
* @file VL53L4CD_Driver.h
|
||||||
|
* @brief VL53L4CD 测距传感器驱动接口
|
||||||
|
*
|
||||||
|
* 基于 ST VL53L4CD ULD 和 Pololu 参考实现,寄存器地址均为 16 位,
|
||||||
|
* 通过项目现有硬件 I2C0 (PA9/PA10) 访问。
|
||||||
|
*/
|
||||||
|
#ifndef VL53L4CD_DRIVER_H
|
||||||
|
#define VL53L4CD_DRIVER_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* 板载默认 7 位 I2C 地址,VL53L4CD 出厂默认 0x29 */
|
||||||
|
#define VL53L4CD_I2C_ADDR 0x29U
|
||||||
|
|
||||||
|
/* 寄存器地址 */
|
||||||
|
#define VL53L4CD_REG_I2C_SLAVE_DEVICE_ADDRESS 0x0001U
|
||||||
|
#define VL53L4CD_REG_VHV_TIMEOUT_MACROP_LOOP_BOUND 0x0008U
|
||||||
|
#define VL53L4CD_REG_GPIO_HV_MUX_CTRL 0x0030U
|
||||||
|
#define VL53L4CD_REG_GPIO_TIO_HV_STATUS 0x0031U
|
||||||
|
#define VL53L4CD_REG_SYSTEM_INTERRUPT 0x0046U
|
||||||
|
#define VL53L4CD_REG_RANGE_CONFIG_A 0x005EU
|
||||||
|
#define VL53L4CD_REG_RANGE_CONFIG_B 0x0061U
|
||||||
|
#define VL53L4CD_REG_SIGMA_THRESHOLD 0x0064U
|
||||||
|
#define VL53L4CD_REG_MIN_COUNT_RATE_RTN_LIMIT 0x0066U
|
||||||
|
#define VL53L4CD_REG_INTERMEASUREMENT_MS 0x006CU
|
||||||
|
#define VL53L4CD_REG_THRESH_HIGH 0x0072U
|
||||||
|
#define VL53L4CD_REG_THRESH_LOW 0x0074U
|
||||||
|
#define VL53L4CD_REG_SYSTEM_INTERRUPT_CLEAR 0x0086U
|
||||||
|
#define VL53L4CD_REG_SYSTEM_START 0x0087U
|
||||||
|
#define VL53L4CD_REG_RESULT_RANGE_STATUS 0x0089U
|
||||||
|
#define VL53L4CD_REG_RESULT_SPAD_NB 0x008CU
|
||||||
|
#define VL53L4CD_REG_RESULT_SIGNAL_RATE 0x008EU
|
||||||
|
#define VL53L4CD_REG_RESULT_AMBIENT_RATE 0x0090U
|
||||||
|
#define VL53L4CD_REG_RESULT_SIGMA 0x0092U
|
||||||
|
#define VL53L4CD_REG_RESULT_DISTANCE 0x0096U
|
||||||
|
#define VL53L4CD_REG_RESULT_OSC_CALIBRATE_VAL 0x00DEU
|
||||||
|
#define VL53L4CD_REG_FIRMWARE_SYSTEM_STATUS 0x00E5U
|
||||||
|
#define VL53L4CD_REG_IDENTIFICATION_MODEL_ID 0x010FU
|
||||||
|
|
||||||
|
/* 等待固件启动 / 数据就绪的最大时间 */
|
||||||
|
#define VL53L4CD_BOOT_TIMEOUT_MS 200U
|
||||||
|
#define VL53L4CD_DATA_TIMEOUT_MS 500U
|
||||||
|
|
||||||
|
/* 一次结果块读包含的字节数:0x89..0x97 */
|
||||||
|
#define VL53L4CD_RESULT_BLOCK_SIZE 15U
|
||||||
|
|
||||||
|
/* 测距状态码(已由原始状态映射为用户可读状态) */
|
||||||
|
typedef enum {
|
||||||
|
VL53L4CD_STATUS_RANGE_VALID = 0, /* 测距有效 */
|
||||||
|
VL53L4CD_STATUS_SIGMA_FAIL, /* Sigma 超限 */
|
||||||
|
VL53L4CD_STATUS_SIGNAL_FAIL, /* 信号强度不足 */
|
||||||
|
VL53L4CD_STATUS_MIN_RANGE_FAIL, /* 目标过近 */
|
||||||
|
VL53L4CD_STATUS_PHASE_FAIL, /* 相位故障 */
|
||||||
|
VL53L4CD_STATUS_HW_FAIL, /* 硬件故障 */
|
||||||
|
VL53L4CD_STATUS_NO_TARGET, /* 未检测到目标 */
|
||||||
|
VL53L4CD_STATUS_SIGNAL_FAIL_NEAR, /* 近距离信号不足 */
|
||||||
|
VL53L4CD_STATUS_OUT_OF_BOUNDS, /* 超出边界 */
|
||||||
|
VL53L4CD_STATUS_XTALK_SIGNAL_FAIL, /* 串扰信号失败 */
|
||||||
|
VL53L4CD_STATUS_LOW_SIGNAL_FAIL, /* 低信号失败 */
|
||||||
|
VL53L4CD_STATUS_CROSSTALK_SIGNAL_FAIL,/* 串扰信号失败 */
|
||||||
|
VL53L4CD_STATUS_AMBIENT_SIGNAL_FAIL, /* 环境光信号失败 */
|
||||||
|
VL53L4CD_STATUS_SNSPD_AMBIENT_FAIL, /* 单光子雪崩二极管环境光失败 */
|
||||||
|
VL53L4CD_STATUS_UNKNOWN = 255 /* 未知状态 */
|
||||||
|
} vl53l4cd_range_status_t;
|
||||||
|
|
||||||
|
/* 单次测量结果 */
|
||||||
|
typedef struct {
|
||||||
|
uint16_t distance_mm; /* 距离,单位 mm */
|
||||||
|
uint8_t range_status; /* 测距状态码 */
|
||||||
|
uint8_t number_of_spad; /* 有效 SPAD 数 */
|
||||||
|
uint32_t signal_rate_kcps; /* 信号速率,单位 kcps */
|
||||||
|
uint32_t ambient_rate_kcps; /* 环境光速率,单位 kcps */
|
||||||
|
uint32_t signal_per_spad_kcps; /* 每 SPAD 信号速率 */
|
||||||
|
uint32_t ambient_per_spad_kcps; /* 每 SPAD 环境光速率 */
|
||||||
|
uint16_t sigma_mm; /* Sigma,单位 mm */
|
||||||
|
} vl53l4cd_result_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化 VL53L4CD
|
||||||
|
* @param[in] none
|
||||||
|
* @retval true: 初始化成功; false: 初始化失败
|
||||||
|
*/
|
||||||
|
bool vl53l4cd_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 启动连续测距
|
||||||
|
* @param[in] none
|
||||||
|
* @retval true: 启动成功; false: 启动失败
|
||||||
|
*/
|
||||||
|
bool vl53l4cd_start_ranging(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 停止连续测距
|
||||||
|
* @param[in] none
|
||||||
|
* @retval true: 停止成功; false: 停止失败
|
||||||
|
*/
|
||||||
|
bool vl53l4cd_stop_ranging(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查是否有新测距结果
|
||||||
|
* @param[in] none
|
||||||
|
* @retval true: 有新结果; false: 无新结果或读取失败
|
||||||
|
*/
|
||||||
|
bool vl53l4cd_data_ready(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 清除测距完成中断
|
||||||
|
* @param[in] none
|
||||||
|
* @retval true: 清除成功; false: 清除失败
|
||||||
|
*/
|
||||||
|
bool vl53l4cd_clear_interrupt(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取并解析一次测距结果
|
||||||
|
* @param[out] result: 结果结构体指针
|
||||||
|
* @retval true: 读取成功; false: 读取失败
|
||||||
|
*/
|
||||||
|
bool vl53l4cd_get_result(vl53l4cd_result_t *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置测距时序预算和测距周期
|
||||||
|
* @param[in] timing_budget_ms: 10..200 ms
|
||||||
|
* @param[in] inter_measurement_ms: 当前驱动只支持 0(连续模式)
|
||||||
|
* @retval true: 设置成功; false: 参数无效或设置失败
|
||||||
|
*/
|
||||||
|
bool vl53l4cd_set_range_timing(uint8_t timing_budget_ms, uint32_t inter_measurement_ms);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读一个 8 位寄存器
|
||||||
|
* @param[in] reg: 16 位寄存器地址
|
||||||
|
* @param[out] value: 返回值指针
|
||||||
|
* @retval true: 成功; false: 失败
|
||||||
|
*/
|
||||||
|
bool vl53l4cd_read_reg8(uint16_t reg, uint8_t *value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读一个 16 位寄存器
|
||||||
|
* @param[in] reg: 16 位寄存器地址
|
||||||
|
* @param[out] value: 返回值指针
|
||||||
|
* @retval true: 成功; false: 失败
|
||||||
|
*/
|
||||||
|
bool vl53l4cd_read_reg16(uint16_t reg, uint16_t *value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 写一个 8 位寄存器
|
||||||
|
* @param[in] reg: 16 位寄存器地址
|
||||||
|
* @param[in] value: 写入值
|
||||||
|
* @retval true: 成功; false: 失败
|
||||||
|
*/
|
||||||
|
bool vl53l4cd_write_reg8(uint16_t reg, uint8_t value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 写一个 16 位寄存器
|
||||||
|
* @param[in] reg: 16 位寄存器地址
|
||||||
|
* @param[in] value: 写入值
|
||||||
|
* @retval true: 成功; false: 失败
|
||||||
|
*/
|
||||||
|
bool vl53l4cd_write_reg16(uint16_t reg, uint16_t value);
|
||||||
|
|
||||||
|
#endif /* VL53L4CD_DRIVER_H */
|
||||||
+2
-2
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
/* >>>>>>>>>>>>>>>>>>>>[DEBUG MODE]<<<<<<<<<<<<<<<<<<<< */
|
/* >>>>>>>>>>>>>>>>>>>>[DEBUG MODE]<<<<<<<<<<<<<<<<<<<< */
|
||||||
|
|
||||||
#define DEBUG_MODE CFG_ENABLE // CFG_DISABLE: Release Mode; CFG_ENABLE: Debug Mode
|
#define DEBUG_MODE CFG_DISABLE // CFG_DISABLE: Release Mode; CFG_ENABLE: Debug Mode
|
||||||
|
|
||||||
/* >>>>>>>>>>>>>>>>>>>>[COMMAND DEBUG]<<<<<<<<<<<<<<<<<<<< */
|
/* >>>>>>>>>>>>>>>>>>>>[COMMAND DEBUG]<<<<<<<<<<<<<<<<<<<< */
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
/* >>>>>>>>>>>>>>>>>>>>[DEBUG ASSERTIONS DEFINE]<<<<<<<<<<<<<<<<<<<< */
|
/* >>>>>>>>>>>>>>>>>>>>[DEBUG ASSERTIONS DEFINE]<<<<<<<<<<<<<<<<<<<< */
|
||||||
|
|
||||||
#define DEBUG_VERBOSE CFG_ENABLE // CFG_DISABLE: Verbose debug off; CFG_ENABLE: Verbose debug on
|
#define DEBUG_VERBOSE CFG_DISABLE // CFG_DISABLE: Verbose debug off; CFG_ENABLE: Verbose debug on
|
||||||
|
|
||||||
/* >>>>>>>>>>>>>>>>>>>>[SEGGER RTT DETECTION]<<<<<<<<<<<<<<<<<<<< */
|
/* >>>>>>>>>>>>>>>>>>>>[SEGGER RTT DETECTION]<<<<<<<<<<<<<<<<<<<< */
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ void i2c_scan(void);
|
|||||||
/*!
|
/*!
|
||||||
\brief write 16-bit data to I2C device
|
\brief write 16-bit data to I2C device
|
||||||
\param[in] slave_addr: 7-bit slave address
|
\param[in] slave_addr: 7-bit slave address
|
||||||
\param[in] reg_addr: register address
|
\param[in] reg_addr: register address (16-bit, high byte first)
|
||||||
\param[in] data: pointer to 2-byte data array
|
\param[in] data: pointer to 2-byte data array
|
||||||
\param[out] none
|
\param[out] none
|
||||||
\retval i2c_result_t
|
\retval i2c_result_t
|
||||||
@@ -119,17 +119,17 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data
|
|||||||
\param[out] none
|
\param[out] none
|
||||||
\retval i2c_result_t: operation result
|
\retval i2c_result_t: operation result
|
||||||
*/
|
*/
|
||||||
i2c_result_t i2c_write(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length);
|
i2c_result_t i2c_write(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint8_t length);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief read data from I2C device with configurable length
|
\brief read data from I2C device with configurable length
|
||||||
\param[in] slave_addr: slave device address (7-bit)
|
\param[in] slave_addr: slave device address (7-bit)
|
||||||
\param[in] reg_addr: register address
|
\param[in] reg_addr: register address (16-bit, high byte first)
|
||||||
\param[out] data: pointer to data buffer
|
\param[out] data: pointer to data buffer
|
||||||
\param[in] length: number of bytes to read (1-255)
|
\param[in] length: number of bytes to read (1-255)
|
||||||
\retval i2c_result_t: operation result
|
\retval i2c_result_t: operation result
|
||||||
*/
|
*/
|
||||||
i2c_result_t i2c_read(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length);
|
i2c_result_t i2c_read(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint8_t length);
|
||||||
|
|
||||||
/* Pure read response without sub-address phase (for commands that already sent read request parameters) */
|
/* Pure read response without sub-address phase (for commands that already sent read request parameters) */
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
@@ -1,396 +1,214 @@
|
|||||||
# GD32E23x 工程模板
|
# GD32E230 + VL53L4CD 测距项目
|
||||||
|
|
||||||
本仓库为兆易创新 GD32E23x 系列 MCU 的 CMake + VSCode 工程模板,适合嵌入式开发快速上手和团队协作。
|
本仓库是基于 GD32E230 的 VL53L4CD 时间飞行(ToF)测距项目,硬件兼容 Adafruit VL53L4CD 模块。固件通过 I2C 驱动传感器,每 500ms 输出一次距离和测距质量参数。
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 目录
|
## 目录
|
||||||
|
|
||||||
- [适用范围](#适用范围)
|
- [硬件连接](#硬件连接)
|
||||||
- [默认配置](#默认配置)
|
- [功能开关](#功能开关)
|
||||||
- [快速开始](#快速开始)
|
- [编译与烧录](#编译与烧录)
|
||||||
- [工程结构](#工程结构)
|
- [串口输出](#串口输出)
|
||||||
- [板级配置](#板级配置)
|
- [VL53L4CD 驱动](#vl53l4cd-驱动)
|
||||||
- [Flash 偏移配置(配合 Bootloader)](#flash-偏移配置配合-bootloader)
|
- [测距结果字段](#测距结果字段)
|
||||||
- [工具链准备](#工具链准备)
|
- [测距状态码](#测距状态码)
|
||||||
- [使用说明](#使用说明)
|
- [I2C 16 位寄存器说明](#i2c-16-位寄存器说明)
|
||||||
- [时钟配置说明](#时钟配置说明)
|
- [Flash 体积说明](#flash-体积说明)
|
||||||
- [vcpkg 依赖管理(可选)](#vcpkg-依赖管理可选)
|
- [已知限制](#已知限制)
|
||||||
|
- [变更记录](#变更记录)
|
||||||
|
|
||||||
---
|
## 硬件连接
|
||||||
|
|
||||||
## 适用范围
|
### 主控
|
||||||
|
|
||||||
- 适用于兆易创新 GD32E23x 系列 Cortex-M23 内核单片机
|
- MCU:GD32E230 系列,Cortex-M23
|
||||||
- 支持标准外设库开发
|
- 系统时钟:72MHz
|
||||||
- 推荐开发环境:VSCode + CMake + ARM GCC 工具链
|
- Flash:16K(F4)/ 32K(F6)/ 64K(F8),上电自动识别
|
||||||
|
|
||||||
---
|
### VL53L4CD
|
||||||
|
|
||||||
## 默认配置
|
| 信号 | 引脚 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| SCL | PA9 | I2C0 时钟,AF4 |
|
||||||
|
| SDA | PA10 | I2C0 数据,AF4 |
|
||||||
|
| VDD | 3.3V | 模块供电 |
|
||||||
|
| GND | GND | 共地 |
|
||||||
|
|
||||||
- MCU 主频:内部 RC 振荡器,系统时钟配置为 72MHz
|
传感器 7 位 I2C 地址默认为 `0x29`。
|
||||||
- 调试串口:USART0(PA2 TX / PA3 RX),115200 波特率
|
|
||||||
- I2C:默认硬件 I2C0(PF0 SDA / PF1 SCL),可通过 `board_config.h` 切换为软件 I2C
|
|
||||||
|
|
||||||
---
|
### 串口
|
||||||
|
|
||||||
## 快速开始
|
| 信号 | 引脚 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| TX | PA2 | RS485 发送 |
|
||||||
|
| RX | PA3 | RS485 接收 |
|
||||||
|
| DE | PA1 | RS485 方向控制,硬件自动控制 |
|
||||||
|
|
||||||
### 基于模板创建新项目
|
波特率 115200,8N1。
|
||||||
|
|
||||||
1. **克隆或复制本仓库**
|
### 其他
|
||||||
```bash
|
|
||||||
git clone https://gitea.hulk.wang/hulk/gd32e23x_template_cmake_vscode.git my-new-project
|
|
||||||
cd my-new-project
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **修改项目配置** — 编辑 `cmake/project_config.cmake`:
|
- LED:PB1
|
||||||
```cmake
|
- SWD:SWDIO、SWCLK、GND,用于 DAPLink 烧录与调试
|
||||||
set(PROJECT_NAME "MyProject") # 项目名称
|
|
||||||
set(BOARD_TYPE_CODE 20) # 板卡类型码(协议帧中的标识)
|
|
||||||
set(VERSION_MAJOR 1) # 主版本号
|
|
||||||
set(VERSION_MINOR 0) # 次版本号
|
|
||||||
set(VERSION_PATCH 0) # 修订号
|
|
||||||
set(BUILD_VARIANT "APP") # 编译变体
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **添加业务源文件** — 编辑 `CMakeLists.txt`,在 `TARGET_SRC` 中添加你的 `.c` 文件。
|
## 功能开关
|
||||||
|
|
||||||
4. **配置板级引脚** — 编辑 `Inc/board_config.h`,修改 I2C、UART、LED 等引脚定义。
|
所有开关集中在 `Inc/board_config.h`。
|
||||||
|
|
||||||
5. **编译**
|
| 宏 | 当前值 | 作用 |
|
||||||
```bash
|
|---|---|---|
|
||||||
cmake --preset Debug
|
| `DEBUG_MODE` | `CFG_DISABLE` | 关闭 `Hello World` 启动横幅;距离输出仍保留 |
|
||||||
cmake --build build/Debug
|
| `DEBUG_VERBOSE` | `CFG_DISABLE` | 关闭 IIC 调试打印和启动 I2C 扫描 |
|
||||||
```
|
| `COM_DEBUG` | `CFG_DISABLE` | 关闭命令帧调试打印 |
|
||||||
产物在 `build/Debug/` 下,包含 `.elf`、`.hex`、`.bin`、`.map`、`.list`。
|
| `SEGGER_RTT_DETECTION` | `CFG_DISABLE` | 关闭 SEGGER RTT |
|
||||||
|
| `RS485_MODE` | `CFG_ENABLE` | 使用 RS485 串口输出 |
|
||||||
|
| `SOFTWARE_IIC` | `CFG_DISABLE` | 使用硬件 I2C |
|
||||||
|
|
||||||
### 分支说明
|
如果需要临时扫描 I2C 总线或查看 IIC 调试信息,把 `DEBUG_VERBOSE` 改为 `CFG_ENABLE`。注意 16K Flash 下全开会让固件体积非常紧张。
|
||||||
|
|
||||||
| 分支 | 用途 |
|
## 编译与烧录
|
||||||
|------|------|
|
|
||||||
| `template_pc` | **主模板**(推荐),用于桌面端 VSCode 开发 |
|
|
||||||
| `template_xl` | 小琅适配版 |
|
|
||||||
| `main` | 早期版本,不推荐使用 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 工程结构
|
|
||||||
|
|
||||||
```
|
|
||||||
.
|
|
||||||
├── CMakeLists.txt # 主构建文件
|
|
||||||
├── CMakePresets.json # CMake 预设(Debug/Release)
|
|
||||||
├── cmake/
|
|
||||||
│ ├── arm-none-eabi-gcc.cmake # ARM GCC 工具链配置
|
|
||||||
│ ├── project.cmake # 编译选项(-Os/-O0, -mcpu=cortex-m23)
|
|
||||||
│ ├── project_config.cmake # 项目名/版本号/编译变体
|
|
||||||
│ └── version.h.in # 自动生成固件版本头
|
|
||||||
├── Inc/ # 头文件
|
|
||||||
│ ├── board_config.h # 板级引脚定义 + 功能开关
|
|
||||||
│ ├── command.h # 串口命令协议
|
|
||||||
│ ├── i2c.h / led.h / systick.h / uart.h
|
|
||||||
│ └── uart_ring_buffer.h / gd32e23x_it.h / gd32e23x_libopt.h
|
|
||||||
├── Src/ # 源码
|
|
||||||
│ ├── main.c # 入口函数
|
|
||||||
│ ├── command.c # 命令解析处理
|
|
||||||
│ ├── board_config.c # MCU 型号自动检测
|
|
||||||
│ ├── i2c.c / led.c / systick.c / uart.c / uart_ring_buffer.c
|
|
||||||
│ └── gd32e23x_it.c / system_gd32e23x.c / syscalls.c
|
|
||||||
├── SDK/
|
|
||||||
│ ├── CMSIS/ # ARM CMSIS Core (Cortex-M23) + GD 启动文件
|
|
||||||
│ └── GD32E23x_standard_peripheral/ # GD32 标准外设库
|
|
||||||
├── LD/gd32e23x_flash.ld # 链接脚本
|
|
||||||
├── doc/ # 芯片数据手册
|
|
||||||
└── .vscode/ # VSCode 调试/烧录配置
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 板级配置(`Inc/board_config.h`)
|
|
||||||
|
|
||||||
所有功能开关和引脚定义集中在 `Inc/board_config.h`。功能开关均为单行数值宏:将右侧的 `ENABLE` 或 `DISABLE` 改为另一值即可;其中 `ENABLE` 为 `1`,`DISABLE` 为 `0`。以下为完整的宏开关说明和推荐使用方式。
|
|
||||||
|
|
||||||
### 功能开关速查表
|
|
||||||
|
|
||||||
| 宏 | 作用 | 默认值 | Release 建议 |
|
|
||||||
|---|------|:---:|:---:|
|
|
||||||
| `SOFTWARE_IIC` | I2C 实现方式 | `DISABLE`(硬件) | `DISABLE` |
|
|
||||||
| `DEBUG_MODE` | printf 串口输出 | `DISABLE` | `DISABLE` |
|
|
||||||
| `COM_DEBUG` | 命令帧调试打印 | `DISABLE` | `DISABLE` |
|
|
||||||
| `DEBUG_VERBOSE` | 详细调试信息 | `DISABLE` | `DISABLE` |
|
|
||||||
| `SEGGER_RTT_DETECTION` | SEGGER RTT 支持 | `ENABLE` | `DISABLE` |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `SOFTWARE_IIC` — I2C 实现方式
|
|
||||||
|
|
||||||
选择 I2C 使用硬件外设还是软件 GPIO 模拟。
|
|
||||||
|
|
||||||
> 当前工程尚未实现 `SOFTWARE_IIC` 的条件编译驱动选择;该宏已迁移为数值配置,但改值不会在此版本切换 I2C 实现。
|
|
||||||
|
|
||||||
```c
|
|
||||||
#define SOFTWARE_IIC DISABLE // DISABLE: 硬件 I2C(默认);ENABLE: 软件 I2C(GPIO 模拟)
|
|
||||||
```
|
|
||||||
|
|
||||||
| 选项 | 优点 | 缺点 |
|
|
||||||
|------|------|------|
|
|
||||||
| 硬件 I2C | DMA 支持、CPU 占用低 | 仅限固定引脚、调试复杂 |
|
|
||||||
| 软件 I2C | 任意 GPIO、移植方便 | CPU 占用高、速率受限 |
|
|
||||||
|
|
||||||
> 切换后需同步修改下方 I2C 引脚定义。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `DEBUG_MODE` — 调试模式
|
|
||||||
|
|
||||||
开启后 USART0 输出 printf 调试信息。**Release 固件必须关闭。**
|
|
||||||
|
|
||||||
```c
|
|
||||||
#define DEBUG_MODE DISABLE // DISABLE: 关闭(默认);ENABLE: 开启调试输出
|
|
||||||
```
|
|
||||||
|
|
||||||
**影响范围:**
|
|
||||||
- 使能 `USART0` 初始化和 `printf` 重定向到串口
|
|
||||||
- 会占用 PA2/PA3 引脚和 USART0 硬件资源
|
|
||||||
- 增加 ROM 约 2~4KB(取决于 printf 调用量)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `COM_DEBUG` — 命令帧调试打印
|
|
||||||
|
|
||||||
开启后串口命令解析过程打印每帧的详细内容(地址、长度、数据、校验)。**仅调试通信协议时开启。**
|
|
||||||
|
|
||||||
```c
|
|
||||||
#define COM_DEBUG DISABLE // DISABLE: 关闭(默认);ENABLE: 开启命令帧调试
|
|
||||||
```
|
|
||||||
|
|
||||||
**依赖:** 需要先开启 `DEBUG_MODE`,否则输出无法外发。
|
|
||||||
|
|
||||||
**输出示例:**
|
|
||||||
```text
|
|
||||||
[CMD] ADDR=01 LEN=05 DATA: AA BB CC DD EE CHK=OK
|
|
||||||
```
|
|
||||||
|
|
||||||
> ⚠️ Release 必须关闭,否则大量串口输出会严重拖慢主循环。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `DEBUG_VERBOSE` — 详细调试信息
|
|
||||||
|
|
||||||
在 `DEBUG_MODE` 基础上输出更底层的信息,如 I2C 总线扫描结果、MCU 型号识别等。
|
|
||||||
|
|
||||||
```c
|
|
||||||
#define DEBUG_VERBOSE DISABLE // DISABLE: 关闭(默认);ENABLE: 开启详细调试
|
|
||||||
```
|
|
||||||
|
|
||||||
**额外输出:**
|
|
||||||
- 启动时打印 MCU Flash 容量检测结果
|
|
||||||
- I2C 初始化时扫描总线上的设备地址
|
|
||||||
- 其他诊断信息
|
|
||||||
|
|
||||||
> 依赖 `DEBUG_MODE`,开启后 ROM 进一步增加约 1~2KB。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `SEGGER_RTT_DETECTION` — SEGGER RTT 支持
|
|
||||||
|
|
||||||
RTT(Real-Time Transfer)是 SEGGER 的调试通道技术,通过 SWD 接口传输数据,不占用串口引脚,速度远超 UART。
|
|
||||||
|
|
||||||
```c
|
|
||||||
#define SEGGER_RTT_DETECTION ENABLE // DISABLE: 禁用 RTT;ENABLE: 启用 RTT(默认)
|
|
||||||
```
|
|
||||||
|
|
||||||
**启用时:**
|
|
||||||
- 自动包含 `SEGGER_RTT.h`,提供 `RTT_printf` / `RTT_WriteString` / `RTT_PutChar` 宏
|
|
||||||
- `SDK/SEGGER_RTT/` 模块参与编译和链接
|
|
||||||
- 可用 J-Link RTT Viewer 或 VSCode + cortex-debug 查看实时日志
|
|
||||||
|
|
||||||
**禁用时:**
|
|
||||||
- 应用层 RTT 头文件引用与调用代码均在预处理阶段排除
|
|
||||||
- RTT 宏展开为空操作;应用目标不生成 RTT 调用代码
|
|
||||||
- 为保持现有 CMake SDK 加载方式,`SDK/SEGGER_RTT/` 仍会参与构建;静态库中未被引用的对象不会被链接器提取
|
|
||||||
|
|
||||||
> **Release 建议关闭** — RTT 依赖调试器连接,量产固件中无意义且占用 ROM。
|
|
||||||
|
|
||||||
**依赖关系总览:**
|
|
||||||
```
|
|
||||||
COM_DEBUG ──── 依赖 ──→ DEBUG_MODE
|
|
||||||
DEBUG_VERBOSE ─ 依赖 ──→ DEBUG_MODE
|
|
||||||
SEGGER_RTT_DETECTION ─ 独立,与 DEBUG_MODE 并行
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 引脚定义
|
|
||||||
|
|
||||||
所有引脚宏集中在 `board_config.h` 尾部,按需修改:
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* I2C */
|
|
||||||
#define I2C_SCL_PORT GPIOF
|
|
||||||
#define I2C_SCL_PIN GPIO_PIN_1
|
|
||||||
#define I2C_SDA_PORT GPIOF
|
|
||||||
#define I2C_SDA_PIN GPIO_PIN_0
|
|
||||||
|
|
||||||
/* LED */
|
|
||||||
#define LED_RCU RCU_GPIOB
|
|
||||||
#define LED_PORT GPIOB
|
|
||||||
#define LED_PIN GPIO_PIN_1
|
|
||||||
|
|
||||||
/* UART */
|
|
||||||
#define UART_GPIO_PORT GPIOA
|
|
||||||
#define UART_TX_PIN GPIO_PIN_2
|
|
||||||
#define UART_RX_PIN GPIO_PIN_3
|
|
||||||
#define UART_BAUDRATE 115200U
|
|
||||||
```
|
|
||||||
|
|
||||||
### MCU 型号自动检测
|
|
||||||
|
|
||||||
`board_config.c` 中的 `mcu_detect_and_config()` 上电自动识别 GD32E230 的 Flash 容量(F4=16K / F6=32K / F8=64K),结果存入全局变量 `g_mcu_flash_size`,并自动选择对应的 UART 外设(USART0 或 USART1)。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Flash 偏移配置(配合 Bootloader)
|
|
||||||
|
|
||||||
如果固件需要通过 Bootloader 启动(Bootloader 占用 Flash 前部区域),需修改两处:
|
|
||||||
|
|
||||||
**1. 链接脚本** — `LD/gd32e23x_flash.ld` 第 15 行:
|
|
||||||
```c
|
|
||||||
// 默认:从 Flash 起始运行
|
|
||||||
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 16K
|
|
||||||
|
|
||||||
// 配合 Bootloader:前 8KB 留给 Bootloader,App 从 0x08002000 开始
|
|
||||||
FLASH (rx) : ORIGIN = 0x08002000, LENGTH = 8K
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. 向量表偏移** — `Src/system_gd32e23x.c` 第 44 行:
|
|
||||||
```c
|
|
||||||
// 默认
|
|
||||||
#define VECT_TAB_OFFSET (uint32_t)0x00
|
|
||||||
|
|
||||||
// 配合 Bootloader(值 = Flash 偏移量,不含 0x0800 前缀)
|
|
||||||
#define VECT_TAB_OFFSET (uint32_t)0x2000
|
|
||||||
```
|
|
||||||
|
|
||||||
> ⚠️ 两个偏移值必须对应修改:`LD` 中的 `ORIGIN` 减去 `0x08000000` 应等于 `VECT_TAB_OFFSET`。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 工具链准备
|
|
||||||
|
|
||||||
### 1. ARM GCC 工具链
|
|
||||||
|
|
||||||
- **版本**:xpack-arm-none-eabi-gcc-11.3.1-1.1
|
|
||||||
- **建议解压路径**:工程根目录下 `Toolchain/xpack-arm-none-eabi-gcc-11.3.1-1.1`
|
|
||||||
- **官方下载地址**:https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases
|
|
||||||
- **路径自定义**:
|
|
||||||
如需自定义工具链路径,修改 `cmake/arm-none-eabi-gcc.cmake` 中的 `_TOOLCHAIN_CANDIDATES` 列表,或通过 CMake 参数传入:
|
|
||||||
```bash
|
|
||||||
cmake --preset Debug -DTOOLCHAIN_DIRECTORY=/your/path/bin
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. OpenOCD(调试/烧录)
|
|
||||||
|
|
||||||
- **版本**:xpack-openocd-0.11.0-3
|
|
||||||
- **建议解压路径**:任意位置(在 `.vscode/launch.json` 中配置路径)
|
|
||||||
- **获取地址**:https://github.com/burakenez/gd32-tools-xpack-openocd/tree/v0.11.0-3
|
|
||||||
- **说明**:
|
|
||||||
- 本版本提取自 Embedded Builder V1.4.1.23782。
|
|
||||||
- ⚠️ 请勿随意更换版本,因 GD32 MCU 支持有限,推荐严格使用此版本。
|
|
||||||
- **路径自定义**:
|
|
||||||
修改 `.vscode/launch.json` 中 `miDebuggerPath` 和 `serverpath` 指向你的 OpenOCD 路径。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 使用说明
|
|
||||||
|
|
||||||
### 编译
|
### 编译
|
||||||
|
|
||||||
```bash
|
在仓库根目录执行:
|
||||||
# Debug 构建(-O0, -g3)
|
|
||||||
cmake --preset Debug
|
|
||||||
cmake --build build/Debug
|
|
||||||
|
|
||||||
# Release 构建(-Os, -g0)
|
```bash
|
||||||
cmake --preset Release
|
cmake --preset Release
|
||||||
cmake --build build/Release
|
cmake --build Build/Release
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Debug 构建:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake --preset Debug
|
||||||
|
cmake --build Build/Debug
|
||||||
|
```
|
||||||
|
|
||||||
|
产物位于 `Build/Release/Application/`:
|
||||||
|
|
||||||
|
- `Application.elf`
|
||||||
|
- `Application.hex`
|
||||||
|
- `Application.bin`
|
||||||
|
- `Application.map`
|
||||||
|
|
||||||
### 烧录
|
### 烧录
|
||||||
|
|
||||||
通过 VSCode 任务栏运行 `Flash MCU` 任务,或命令行:
|
通过 DAPLink/CMSIS-DAP 烧录:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
openocd -f interface/cmsis-dap.cfg -f target/gd32e23x.cfg -c "program build/Debug/Application.elf verify reset exit"
|
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 任务。
|
||||||
|
|
||||||
编译输出位于 `build/<Config>/`:
|
## 串口输出
|
||||||
|
|
||||||
| 文件 | 说明 |
|
连接串口后使用 115200 8N1 查看,例如 COM17:
|
||||||
|------|------|
|
|
||||||
| `Application.elf` | ELF 固件(调试用) |
|
|
||||||
| `{项目名}_{版本}_{编译条件}_{日期}.hex` | Hex 文件 |
|
|
||||||
| `{项目名}_{版本}_{编译条件}_{日期}.bin` | 二进制文件 |
|
|
||||||
| `{项目名}_{版本}_{编译条件}_{日期}.list` | 反汇编清单 |
|
|
||||||
| `{项目名}_{版本}_{编译条件}_{日期}.map` | 内存映射 |
|
|
||||||
|
|
||||||
---
|
```text
|
||||||
|
Distance: 830 mm | status: 0 | signal: 1128 kcps | ambient: 72 kcps | sigma: 3 mm
|
||||||
|
```
|
||||||
|
|
||||||
## 时钟配置说明
|
默认每 500ms 输出一次。
|
||||||
|
|
||||||
本工程默认系统时钟为内部 IRC8M 振荡器经 PLL 倍频后的 72MHz。
|
## VL53L4CD 驱动
|
||||||
|
|
||||||
如需修改主频或时钟源,请编辑 `Src/system_gd32e23x.c` 文件:
|
驱动文件:
|
||||||
|
|
||||||
1. 查找如下宏定义区:
|
- `Inc/VL53L4CD_Driver.h`
|
||||||
```c
|
- `Src/VL53L4CD_Driver.c`
|
||||||
// #define __SYSTEM_CLOCK_8M_HXTAL (__HXTAL)
|
|
||||||
// #define __SYSTEM_CLOCK_8M_IRC8M (__IRC8M)
|
|
||||||
// #define __SYSTEM_CLOCK_72M_PLL_HXTAL (uint32_t)(72000000)
|
|
||||||
#define __SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2 (uint32_t)(72000000)
|
|
||||||
```
|
|
||||||
2. 取消你需要的时钟方案的注释,并注释掉其它方案。
|
|
||||||
3. 保存后重新编译工程即可生效。
|
|
||||||
|
|
||||||
详细时钟初始化流程可参考 `Src/system_gd32e23x.c` 文件中的 `system_clock_config` 及相关函数实现。
|
### 主要接口
|
||||||
|
|
||||||
---
|
| 函数 | 作用 |
|
||||||
|
|---|---|
|
||||||
|
| `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_read_reg8/16()` | 读 8/16 位寄存器 |
|
||||||
|
| `vl53l4cd_write_reg8/16()` | 写 8/16 位寄存器 |
|
||||||
|
|
||||||
## vcpkg 依赖管理(可选)
|
### 修改时序预算
|
||||||
|
|
||||||
本工程可选支持 vcpkg 作为 C/C++ 工具链和构建工具的自动化依赖管理方案。
|
在 `Src/VL53L4CD_Driver.c` 的 `vl53l4cd_init()` 末尾:
|
||||||
|
|
||||||
- 自动下载和管理如 CMake、Ninja 等构建工具,简化环境配置。
|
```c
|
||||||
- 可扩展用于第三方 C/C++ 库的统一管理。
|
return vl53l4cd_set_range_timing(50U, 0U);
|
||||||
|
```
|
||||||
|
|
||||||
**启用方法**:
|
第一个参数是时序预算,范围 10-200ms。第二个参数当前只能传 `0`,表示连续测距模式。
|
||||||
1. 在项目根目录创建 `vcpkg-configuration.json` 文件,内容如下:
|
|
||||||
|
|
||||||
```json
|
### 修改输出间隔
|
||||||
{
|
|
||||||
"registries": [
|
|
||||||
{
|
|
||||||
"name": "microsoft",
|
|
||||||
"location": "https://aka.ms/vcpkg-ce-default",
|
|
||||||
"kind": "artifact"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "arm",
|
|
||||||
"location": "https://aka.ms/vcpkg-artifacts-arm",
|
|
||||||
"kind": "artifact"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"requires": {
|
|
||||||
"arm:tools/ninja-build/ninja": "^1.12.0",
|
|
||||||
"arm:tools/kitware/cmake": "^3.28.4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
2. 启动 VSCode 或命令行,vcpkg 会自动检测并安装所需工具。
|
在 `Src/main.c` 主循环中:
|
||||||
|
|
||||||
如不需要 vcpkg,可忽略本文件。
|
```c
|
||||||
|
delay_ms(500);
|
||||||
|
```
|
||||||
|
|
||||||
|
改为需要的毫秒数即可。
|
||||||
|
|
||||||
|
## 测距结果字段
|
||||||
|
|
||||||
|
`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 体积说明
|
||||||
|
|
||||||
|
当前 Release 固件约:
|
||||||
|
|
||||||
|
```text
|
||||||
|
text 14316
|
||||||
|
data 116
|
||||||
|
bss 2012
|
||||||
|
```
|
||||||
|
|
||||||
|
16K Flash 下仍有约 2K 余量。保留 `printf` 后体积会增加约 2.5K,因此不建议同时开启全部 IIC 调试打印。
|
||||||
|
|
||||||
|
## 已知限制
|
||||||
|
|
||||||
|
- 驱动只支持连续测距模式
|
||||||
|
- 尚未实现距离阈值中断、Offset/Crosstalk 校准、自主低功耗模式、ULP 模式
|
||||||
|
- VL53L4CD 是单区传感器,不是多区测距
|
||||||
|
- `DEBUG_VERBOSE` 全开时 IIC 调试打印会让 Flash 非常紧张
|
||||||
|
|
||||||
|
## 变更记录
|
||||||
|
|
||||||
|
当前迭代的详细说明见 [CHANGES.md](CHANGES.md)。
|
||||||
|
|||||||
@@ -0,0 +1,283 @@
|
|||||||
|
/**
|
||||||
|
* @file VL53L4CD_Driver.c
|
||||||
|
* @brief VL53L4CD 测距传感器驱动实现
|
||||||
|
*
|
||||||
|
* 初始化配置参考 ST VL53L4CD ULD / Pololu Arduino 库,
|
||||||
|
* 使用 16 位寄存器地址,底层走项目现有硬件 I2C0。
|
||||||
|
*/
|
||||||
|
#include "VL53L4CD_Driver.h"
|
||||||
|
#include "i2c.h"
|
||||||
|
#include "systick.h"
|
||||||
|
|
||||||
|
/* 当前传感器 I2C 地址,默认 0x29 */
|
||||||
|
static uint8_t g_vl53l4cd_addr = VL53L4CD_I2C_ADDR;
|
||||||
|
|
||||||
|
/* VL53L4CD 默认配置,0x30..0x87 共 88 字节,来自 ST ULD */
|
||||||
|
static const uint8_t g_vl53l4cd_default_config[88] = {
|
||||||
|
0x11, 0x02, 0x00, 0x02, 0x08, 0x00, 0x08, 0x10,
|
||||||
|
0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
|
||||||
|
0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0B,
|
||||||
|
0x00, 0x00, 0x02, 0x14, 0x21, 0x00, 0x00, 0x05,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x38,
|
||||||
|
0xFF, 0x01, 0x00, 0x08, 0x00, 0x00, 0x01, 0xCC,
|
||||||
|
0x07, 0x01, 0xF1, 0x05, 0x00, 0xA0, 0x00, 0x80,
|
||||||
|
0x08, 0x38, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x89,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0x07, 0x05, 0x06, 0x06, 0x00, 0x00, 0x02, 0xC7,
|
||||||
|
0xFF, 0x9B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 连续写多个寄存器字节
|
||||||
|
* @param[in] reg: 起始 16 位寄存器地址
|
||||||
|
* @param[in] data: 数据指针
|
||||||
|
* @param[in] length: 字节数
|
||||||
|
* @retval true: 成功; false: 失败
|
||||||
|
*/
|
||||||
|
static bool vl53l4cd_write_regs(uint16_t reg, const uint8_t *data, uint8_t length)
|
||||||
|
{
|
||||||
|
if (data == NULL || length == 0U) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (i2c_write(g_vl53l4cd_addr, reg, (uint8_t *)data, length) == I2C_RESULT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vl53l4cd_read_reg8(uint16_t reg, uint8_t *value)
|
||||||
|
{
|
||||||
|
if (value == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (i2c_read(g_vl53l4cd_addr, reg, value, 1U) == I2C_RESULT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vl53l4cd_read_reg16(uint16_t reg, uint16_t *value)
|
||||||
|
{
|
||||||
|
uint8_t buf[2];
|
||||||
|
|
||||||
|
if (value == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (i2c_read(g_vl53l4cd_addr, reg, buf, 2U) != I2C_RESULT_SUCCESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*value = (uint16_t)(((uint16_t)buf[0] << 8) | buf[1]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vl53l4cd_write_reg8(uint16_t reg, uint8_t value)
|
||||||
|
{
|
||||||
|
return vl53l4cd_write_regs(reg, &value, 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vl53l4cd_write_reg16(uint16_t reg, uint16_t value)
|
||||||
|
{
|
||||||
|
uint8_t buf[2];
|
||||||
|
|
||||||
|
buf[0] = (uint8_t)(value >> 8);
|
||||||
|
buf[1] = (uint8_t)(value & 0xFF);
|
||||||
|
return vl53l4cd_write_regs(reg, buf, 2U);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vl53l4cd_data_ready(void)
|
||||||
|
{
|
||||||
|
uint8_t status = 0U;
|
||||||
|
|
||||||
|
if (!vl53l4cd_read_reg8(VL53L4CD_REG_GPIO_TIO_HV_STATUS, &status)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* 默认中断极性配置下,bit0=0 表示新结果就绪 */
|
||||||
|
return ((status & 0x01U) == 0U);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vl53l4cd_clear_interrupt(void)
|
||||||
|
{
|
||||||
|
return vl53l4cd_write_reg8(VL53L4CD_REG_SYSTEM_INTERRUPT_CLEAR, 0x01U);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vl53l4cd_get_result(vl53l4cd_result_t *result)
|
||||||
|
{
|
||||||
|
static const uint8_t status_rtn[24] = {
|
||||||
|
255, 255, 255, 5, 2, 4, 1, 7, 3, 0,
|
||||||
|
255, 255, 9, 13, 255, 255, 255, 255, 10, 6,
|
||||||
|
255, 255, 11, 12
|
||||||
|
};
|
||||||
|
uint8_t buf[VL53L4CD_RESULT_BLOCK_SIZE];
|
||||||
|
uint8_t raw_status;
|
||||||
|
|
||||||
|
if (result == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (i2c_read(g_vl53l4cd_addr, VL53L4CD_REG_RESULT_RANGE_STATUS,
|
||||||
|
buf, VL53L4CD_RESULT_BLOCK_SIZE) != I2C_RESULT_SUCCESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_status = buf[0] & 0x1FU;
|
||||||
|
result->range_status = (raw_status < 24U) ? status_rtn[raw_status]
|
||||||
|
: (uint8_t)VL53L4CD_STATUS_UNKNOWN;
|
||||||
|
result->number_of_spad = buf[3];
|
||||||
|
result->signal_rate_kcps = ((uint32_t)buf[5] << 8 | buf[6]) * 8U;
|
||||||
|
result->ambient_rate_kcps = ((uint32_t)buf[7] << 8 | buf[8]) * 8U;
|
||||||
|
result->sigma_mm = ((uint16_t)buf[9] << 8 | buf[10]) / 4U;
|
||||||
|
result->distance_mm = (uint16_t)(((uint16_t)buf[13] << 8) | buf[14]);
|
||||||
|
|
||||||
|
if (result->number_of_spad != 0U) {
|
||||||
|
result->signal_per_spad_kcps = result->signal_rate_kcps / result->number_of_spad;
|
||||||
|
result->ambient_per_spad_kcps = result->ambient_rate_kcps / result->number_of_spad;
|
||||||
|
} else {
|
||||||
|
result->signal_per_spad_kcps = 0U;
|
||||||
|
result->ambient_per_spad_kcps = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vl53l4cd_set_range_timing(uint8_t timing_budget_ms, uint32_t inter_measurement_ms)
|
||||||
|
{
|
||||||
|
uint16_t osc_frequency = 0U;
|
||||||
|
uint32_t timing_budget_us;
|
||||||
|
uint32_t macro_period_us;
|
||||||
|
uint32_t tmp;
|
||||||
|
uint16_t ls_byte;
|
||||||
|
uint8_t ms_byte;
|
||||||
|
|
||||||
|
if (timing_budget_ms < 10U || timing_budget_ms > 200U) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (inter_measurement_ms != 0U) {
|
||||||
|
/* 为节省 flash,本版本只支持连续模式 */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!vl53l4cd_read_reg16(0x0006U, &osc_frequency) || osc_frequency == 0U) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
timing_budget_us = (uint32_t)timing_budget_ms * 1000U;
|
||||||
|
macro_period_us = ((uint32_t)2304U * (0x40000000U / osc_frequency)) >> 6U;
|
||||||
|
|
||||||
|
/* 连续模式:测量周期写 0 */
|
||||||
|
{
|
||||||
|
uint8_t zero[4] = {0U, 0U, 0U, 0U};
|
||||||
|
if (!vl53l4cd_write_regs(VL53L4CD_REG_INTERMEASUREMENT_MS, zero, 4U)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timing_budget_us -= 2500U;
|
||||||
|
|
||||||
|
timing_budget_us <<= 12U;
|
||||||
|
|
||||||
|
/* RANGE_CONFIG_A: 基于 16 的宏周期 */
|
||||||
|
tmp = (macro_period_us * 16U) >> 6U;
|
||||||
|
ls_byte = (uint16_t)(((timing_budget_us + (tmp >> 1U)) / tmp) - 1U);
|
||||||
|
ms_byte = 0U;
|
||||||
|
while (ls_byte > 0xFFU) {
|
||||||
|
ls_byte >>= 1U;
|
||||||
|
ms_byte++;
|
||||||
|
}
|
||||||
|
if (!vl53l4cd_write_reg16(VL53L4CD_REG_RANGE_CONFIG_A,
|
||||||
|
(uint16_t)((uint16_t)ms_byte << 8 | ls_byte))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RANGE_CONFIG_B: 基于 12 的宏周期 */
|
||||||
|
tmp = (macro_period_us * 12U) >> 6U;
|
||||||
|
ls_byte = (uint16_t)(((timing_budget_us + (tmp >> 1U)) / tmp) - 1U);
|
||||||
|
ms_byte = 0U;
|
||||||
|
while (ls_byte > 0xFFU) {
|
||||||
|
ls_byte >>= 1U;
|
||||||
|
ms_byte++;
|
||||||
|
}
|
||||||
|
return vl53l4cd_write_reg16(VL53L4CD_REG_RANGE_CONFIG_B,
|
||||||
|
(uint16_t)((uint16_t)ms_byte << 8 | ls_byte));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vl53l4cd_init(void)
|
||||||
|
{
|
||||||
|
uint16_t model_id = 0U;
|
||||||
|
uint8_t firmware_status = 0U;
|
||||||
|
uint32_t elapsed_ms = 0U;
|
||||||
|
uint16_t reg;
|
||||||
|
uint8_t count;
|
||||||
|
|
||||||
|
/* 上电后固件需要一点启动时间,先重试读取型号 */
|
||||||
|
while (elapsed_ms < VL53L4CD_BOOT_TIMEOUT_MS) {
|
||||||
|
if (vl53l4cd_read_reg16(VL53L4CD_REG_IDENTIFICATION_MODEL_ID, &model_id) &&
|
||||||
|
model_id == 0xEBAAU) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
delay_ms(2);
|
||||||
|
elapsed_ms += 2U;
|
||||||
|
}
|
||||||
|
if (model_id != 0xEBAAU) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 等待固件启动完成,FIRMWARE__SYSTEM_STATUS == 0x03 */
|
||||||
|
elapsed_ms = 0U;
|
||||||
|
while (elapsed_ms < VL53L4CD_BOOT_TIMEOUT_MS) {
|
||||||
|
if (vl53l4cd_read_reg8(VL53L4CD_REG_FIRMWARE_SYSTEM_STATUS, &firmware_status) &&
|
||||||
|
firmware_status == 0x03U) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
delay_ms(2);
|
||||||
|
elapsed_ms += 2U;
|
||||||
|
}
|
||||||
|
if (firmware_status != 0x03U) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* I2C/GPIO 上拉配置:本板按 3.3V AVDD 上拉处理 */
|
||||||
|
if (!vl53l4cd_write_reg8(0x002DU, 0x00U) ||
|
||||||
|
!vl53l4cd_write_reg8(0x002EU, 0x00U) ||
|
||||||
|
!vl53l4cd_write_reg8(0x002FU, 0x00U)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 写入 0x30..0x87 默认配置,分 3 次块写 */
|
||||||
|
for (reg = 0x0030U; reg <= 0x0087U; reg += 30U) {
|
||||||
|
uint8_t block[30];
|
||||||
|
count = 0U;
|
||||||
|
while (count < 30U && (reg + count) <= 0x0087U) {
|
||||||
|
block[count] = g_vl53l4cd_default_config[reg + count - 0x0030U];
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if (!vl53l4cd_write_regs(reg, block, count)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 启动 VHV 校准并等待首个结果 */
|
||||||
|
if (!vl53l4cd_write_reg8(VL53L4CD_REG_SYSTEM_START, 0x40U)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
elapsed_ms = 0U;
|
||||||
|
while (!vl53l4cd_data_ready()) {
|
||||||
|
delay_ms(5);
|
||||||
|
elapsed_ms += 5U;
|
||||||
|
if (elapsed_ms >= VL53L4CD_DATA_TIMEOUT_MS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vl53l4cd_clear_interrupt() ||
|
||||||
|
!vl53l4cd_stop_ranging() ||
|
||||||
|
!vl53l4cd_write_reg8(VL53L4CD_REG_VHV_TIMEOUT_MACROP_LOOP_BOUND, 0x09U) ||
|
||||||
|
!vl53l4cd_write_reg8(0x000BU, 0x00U) ||
|
||||||
|
!vl53l4cd_write_reg16(0x0024U, 0x0500U)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 默认 50ms 时序预算,连续模式 */
|
||||||
|
return vl53l4cd_set_range_timing(50U, 0U);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vl53l4cd_start_ranging(void)
|
||||||
|
{
|
||||||
|
/* 本驱动固定使用连续模式 */
|
||||||
|
return vl53l4cd_write_reg8(VL53L4CD_REG_SYSTEM_START, 0x21U);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vl53l4cd_stop_ranging(void)
|
||||||
|
{
|
||||||
|
return vl53l4cd_write_reg8(VL53L4CD_REG_SYSTEM_START, 0x80U);
|
||||||
|
}
|
||||||
@@ -640,13 +640,13 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data
|
|||||||
/*!
|
/*!
|
||||||
\brief write data to I2C device with configurable length
|
\brief write data to I2C device with configurable length
|
||||||
\param[in] slave_addr: slave device address (7-bit)
|
\param[in] slave_addr: slave device address (7-bit)
|
||||||
\param[in] reg_addr: register address
|
\param[in] reg_addr: register address (16-bit, high byte first)
|
||||||
\param[in] data: pointer to data buffer
|
\param[in] data: pointer to data buffer
|
||||||
\param[in] length: number of bytes to write (1-255)
|
\param[in] length: number of bytes to write (1-255)
|
||||||
\param[out] none
|
\param[out] none
|
||||||
\retval i2c_result_t: operation result
|
\retval i2c_result_t: operation result
|
||||||
*/
|
*/
|
||||||
i2c_result_t i2c_write(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length) {
|
i2c_result_t i2c_write(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint8_t length) {
|
||||||
i2c_state_t state = I2C_STATE_START;
|
i2c_state_t state = I2C_STATE_START;
|
||||||
uint16_t timeout = 0;
|
uint16_t timeout = 0;
|
||||||
uint8_t retry_count = 0;
|
uint8_t retry_count = 0;
|
||||||
@@ -727,8 +727,18 @@ i2c_result_t i2c_write(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send register address */
|
/* send register address, high byte first */
|
||||||
i2c_data_transmit(I2C0, reg_addr);
|
if(_i2c_wait_flag_timeout(I2C_FLAG_TBE) != I2C_RESULT_SUCCESS) {
|
||||||
|
state = I2C_STATE_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i2c_data_transmit(I2C0, (uint8_t)(reg_addr >> 8));
|
||||||
|
|
||||||
|
if(_i2c_wait_flag_timeout(I2C_FLAG_TBE) != I2C_RESULT_SUCCESS) {
|
||||||
|
state = I2C_STATE_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i2c_data_transmit(I2C0, (uint8_t)(reg_addr & 0xFF));
|
||||||
state = I2C_STATE_TRANSMIT_DATA;
|
state = I2C_STATE_TRANSMIT_DATA;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -814,12 +824,12 @@ i2c_result_t i2c_write(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint
|
|||||||
/*!
|
/*!
|
||||||
\brief read data from I2C device with configurable length
|
\brief read data from I2C device with configurable length
|
||||||
\param[in] slave_addr: slave device address (7-bit)
|
\param[in] slave_addr: slave device address (7-bit)
|
||||||
\param[in] reg_addr: register address
|
\param[in] reg_addr: register address (16-bit, high byte first)
|
||||||
\param[out] data: pointer to data buffer
|
\param[out] data: pointer to data buffer
|
||||||
\param[in] length: number of bytes to read (1-255)
|
\param[in] length: number of bytes to read (1-255)
|
||||||
\retval i2c_result_t: operation result
|
\retval i2c_result_t: operation result
|
||||||
*/
|
*/
|
||||||
i2c_result_t i2c_read(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length) {
|
i2c_result_t i2c_read(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint8_t length) {
|
||||||
i2c_state_t state = I2C_STATE_START;
|
i2c_state_t state = I2C_STATE_START;
|
||||||
uint16_t timeout = 0;
|
uint16_t timeout = 0;
|
||||||
uint8_t retry_count = 0;
|
uint8_t retry_count = 0;
|
||||||
@@ -937,8 +947,18 @@ i2c_result_t i2c_read(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send register address */
|
/* send register address, high byte first */
|
||||||
i2c_data_transmit(I2C0, reg_addr);
|
if(_i2c_wait_flag_timeout(I2C_FLAG_TBE) != I2C_RESULT_SUCCESS) {
|
||||||
|
state = I2C_STATE_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i2c_data_transmit(I2C0, (uint8_t)(reg_addr >> 8));
|
||||||
|
|
||||||
|
if(_i2c_wait_flag_timeout(I2C_FLAG_TBE) != I2C_RESULT_SUCCESS) {
|
||||||
|
state = I2C_STATE_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i2c_data_transmit(I2C0, (uint8_t)(reg_addr & 0xFF));
|
||||||
state = I2C_STATE_RESTART;
|
state = I2C_STATE_RESTART;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
+24
@@ -41,6 +41,7 @@ OF SUCH DAMAGE.
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "board_config.h"
|
#include "board_config.h"
|
||||||
|
#include "VL53L4CD_Driver.h"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief main function
|
\brief main function
|
||||||
@@ -76,12 +77,35 @@ int main(void)
|
|||||||
i2c_bus_reset();
|
i2c_bus_reset();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (vl53l4cd_init()) {
|
||||||
|
vl53l4cd_start_ranging();
|
||||||
|
printf("VL53L4CD ready\r\n");
|
||||||
|
} else {
|
||||||
|
printf("VL53L4CD init failed\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* ========== Command Testing ========== */
|
/* ========== Command Testing ========== */
|
||||||
|
|
||||||
/* ========== */
|
/* ========== */
|
||||||
|
|
||||||
while(1){
|
while(1){
|
||||||
command_process(); /* Process UART commands */
|
command_process(); /* Process UART commands */
|
||||||
|
|
||||||
|
if (vl53l4cd_data_ready()) {
|
||||||
|
vl53l4cd_result_t result;
|
||||||
|
|
||||||
|
vl53l4cd_clear_interrupt();
|
||||||
|
if (vl53l4cd_get_result(&result)) {
|
||||||
|
printf("Distance: %u mm | status: %u | signal: %lu kcps | ambient: %lu kcps | sigma: %u mm\r\n",
|
||||||
|
result.distance_mm,
|
||||||
|
result.range_status,
|
||||||
|
(unsigned long)result.signal_rate_kcps,
|
||||||
|
(unsigned long)result.ambient_rate_kcps,
|
||||||
|
result.sigma_mm);
|
||||||
|
}
|
||||||
|
delay_ms(500);
|
||||||
|
}
|
||||||
|
|
||||||
delay_ms(10);
|
delay_ms(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user