feat(VL53L4CD): 添加VL53L4CD测距驱动、I2C 16位寄存器支持与项目文档

This commit is contained in:
2026-08-06 00:52:32 +08:00
parent 6eb9f304d3
commit 782fe2b2b0
9 changed files with 774 additions and 362 deletions
+104
View File
@@ -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. 体积与验证
- MCUGD32E230Flash 16KRAM 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 是单区传感器,不是多区测距
+1
View File
@@ -36,6 +36,7 @@ set(TARGET_SRC
Src/command.c
Src/i2c.c
Src/board_config.c
Src/VL53L4CD_Driver.c
)
# 设置输出目录
+162
View File
@@ -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
View File
@@ -23,7 +23,7 @@
/* >>>>>>>>>>>>>>>>>>>>[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]<<<<<<<<<<<<<<<<<<<< */
@@ -31,7 +31,7 @@
/* >>>>>>>>>>>>>>>>>>>>[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]<<<<<<<<<<<<<<<<<<<< */
+4 -4
View File
@@ -93,7 +93,7 @@ void i2c_scan(void);
/*!
\brief write 16-bit data to I2C device
\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[out] none
\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
\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
\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[in] length: number of bytes to read (1-255)
\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) */
/*!
+170 -352
View File
@@ -1,396 +1,214 @@
# GD32E23x 工程模板
# GD32E230 + VL53L4CD 测距项目
本仓库为兆易创新 GD32E23x 系列 MCU 的 CMake + VSCode 工程模板,适合嵌入式开发快速上手和团队协作
---
本仓库是基于 GD32E230 的 VL53L4CD 时间飞行(ToF)测距项目,硬件兼容 Adafruit VL53L4CD 模块。固件通过 I2C 驱动传感器,每 500ms 输出一次距离和测距质量参数
## 目录
- [适用范围](#适用范围)
- [默认配置](#默认配置)
- [快速开始](#快速开始)
- [工程结构](#工程结构)
- [板级配置](#板级配置)
- [Flash 偏移配置(配合 Bootloader](#flash-偏移配置配合-bootloader)
- [工具链准备](#工具链准备)
- [使用说明](#使用说明)
- [时钟配置说明](#时钟配置说明)
- [vcpkg 依赖管理(可选)](#vcpkg-依赖管理可选)
- [硬件连接](#硬件连接)
- [功能开关](#功能开关)
- [编译与烧录](#编译与烧录)
- [串口输出](#串口输出)
- [VL53L4CD 驱动](#vl53l4cd-驱动)
- [测距结果字段](#测距结果字段)
- [测距状态码](#测距状态码)
- [I2C 16 位寄存器说明](#i2c-16-位寄存器说明)
- [Flash 体积说明](#flash-体积说明)
- [已知限制](#已知限制)
- [变更记录](#变更记录)
---
## 硬件连接
## 适用范围
### 主控
- 适用于兆易创新 GD32E23x 系列 Cortex-M23 内核单片机
- 支持标准外设库开发
- 推荐开发环境:VSCode + CMake + ARM GCC 工具链
- MCUGD32E230 系列Cortex-M23
- 系统时钟:72MHz
- Flash16KF4/ 32KF6/ 64KF8),上电自动识别
---
### VL53L4CD
## 默认配置
| 信号 | 引脚 | 说明 |
|---|---|---|
| SCL | PA9 | I2C0 时钟,AF4 |
| SDA | PA10 | I2C0 数据,AF4 |
| VDD | 3.3V | 模块供电 |
| GND | GND | 共地 |
- MCU 主频:内部 RC 振荡器,系统时钟配置为 72MHz
- 调试串口:USART0PA2 TX / PA3 RX),115200 波特率
- I2C:默认硬件 I2C0PF0 SDA / PF1 SCL),可通过 `board_config.h` 切换为软件 I2C
传感器 7 位 I2C 地址默认为 `0x29`
---
### 串口
## 快速开始
| 信号 | 引脚 | 说明 |
|---|---|---|
| TX | PA2 | RS485 发送 |
| RX | PA3 | RS485 接收 |
| DE | PA1 | RS485 方向控制,硬件自动控制 |
### 基于模板创建新项目
波特率 1152008N1。
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`
```cmake
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") # 编译变体
```
- LEDPB1
- SWDSWDIO、SWCLK、GND,用于 DAPLink 烧录与调试
3. **添加业务源文件** — 编辑 `CMakeLists.txt`,在 `TARGET_SRC` 中添加你的 `.c` 文件。
## 功能开关
4. **配置板级引脚** — 编辑 `Inc/board_config.h`,修改 I2C、UART、LED 等引脚定义
所有开关集中在 `Inc/board_config.h`
5. **编译**
```bash
cmake --preset Debug
cmake --build build/Debug
```
产物在 `build/Debug/` 下,包含 `.elf`、`.hex`、`.bin`、`.map`、`.list`。
| 宏 | 当前值 | 作用 |
|---|---|---|
| `DEBUG_MODE` | `CFG_DISABLE` | 关闭 `Hello World` 启动横幅;距离输出仍保留 |
| `DEBUG_VERBOSE` | `CFG_DISABLE` | 关闭 IIC 调试打印和启动 I2C 扫描 |
| `COM_DEBUG` | `CFG_DISABLE` | 关闭命令帧调试打印 |
| `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: 软件 I2CGPIO 模拟)
```
| 选项 | 优点 | 缺点 |
|------|------|------|
| 硬件 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 支持
RTTReal-Time Transfer)是 SEGGER 的调试通道技术,通过 SWD 接口传输数据,不占用串口引脚,速度远超 UART。
```c
#define SEGGER_RTT_DETECTION ENABLE // DISABLE: 禁用 RTTENABLE: 启用 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 留给 BootloaderApp 从 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 --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
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>/`
## 串口输出
| 文件 | 说明 |
|------|------|
| `Application.elf` | ELF 固件(调试用) |
| `{项目名}_{版本}_{编译条件}_{日期}.hex` | Hex 文件 |
| `{项目名}_{版本}_{编译条件}_{日期}.bin` | 二进制文件 |
| `{项目名}_{版本}_{编译条件}_{日期}.list` | 反汇编清单 |
| `{项目名}_{版本}_{编译条件}_{日期}.map` | 内存映射 |
连接串口后使用 115200 8N1 查看,例如 COM17
---
```text
Distance: 830 mm | status: 0 | signal: 1128 kcps | ambient: 72 kcps | sigma: 3 mm
```
## 时钟配置说明
默认每 500ms 输出一次。
本工程默认系统时钟为内部 IRC8M 振荡器经 PLL 倍频后的 72MHz。
## VL53L4CD 驱动
如需修改主频或时钟源,请编辑 `Src/system_gd32e23x.c` 文件:
驱动文件:
- `Inc/VL53L4CD_Driver.h`
- `Src/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_read_reg8/16()` | 读 8/16 位寄存器 |
| `vl53l4cd_write_reg8/16()` | 写 8/16 位寄存器 |
### 修改时序预算
`Src/VL53L4CD_Driver.c``vl53l4cd_init()` 末尾:
1. 查找如下宏定义区:
```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` 及相关函数实现。
---
## vcpkg 依赖管理(可选)
本工程可选支持 vcpkg 作为 C/C++ 工具链和构建工具的自动化依赖管理方案。
- 自动下载和管理如 CMake、Ninja 等构建工具,简化环境配置。
- 可扩展用于第三方 C/C++ 库的统一管理。
**启用方法**
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"
}
}
return vl53l4cd_set_range_timing(50U, 0U);
```
2. 启动 VSCode 或命令行,vcpkg 会自动检测并安装所需工具
第一个参数是时序预算,范围 10-200ms。第二个参数当前只能传 `0`,表示连续测距模式
如不需要 vcpkg,可忽略本文件。
### 修改输出间隔
`Src/main.c` 主循环中:
```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)。
+283
View File
@@ -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);
}
+28 -8
View File
@@ -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
\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] length: number of bytes to write (1-255)
\param[out] none
\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;
uint16_t timeout = 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;
}
/* send register address */
i2c_data_transmit(I2C0, reg_addr);
/* send register address, high byte first */
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;
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
\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[in] length: number of bytes to read (1-255)
\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;
uint16_t timeout = 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;
}
/* send register address */
i2c_data_transmit(I2C0, reg_addr);
/* send register address, high byte first */
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;
break;
+24
View File
@@ -41,6 +41,7 @@ OF SUCH DAMAGE.
#include <stdio.h>
#include "i2c.h"
#include "board_config.h"
#include "VL53L4CD_Driver.h"
/*!
\brief main function
@@ -76,12 +77,35 @@ int main(void)
i2c_bus_reset();
#endif
if (vl53l4cd_init()) {
vl53l4cd_start_ranging();
printf("VL53L4CD ready\r\n");
} else {
printf("VL53L4CD init failed\r\n");
}
/* ========== Command Testing ========== */
/* ========== */
while(1){
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);
}
}