Files
GD32E230_VL53L4CD/Src/VL53L4CD_Driver.c
T

284 lines
8.4 KiB
C

/**
* @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);
}