/** * @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); } /** * @brief 等待新的测距结果就绪 * @param[in] timeout_ms: 超时时间,单位 ms * @retval true: 结果就绪; false: 超时或读取失败 */ static bool vl53l4cd_wait_for_data_ready(uint32_t timeout_ms) { uint32_t elapsed_ms = 0U; while (elapsed_ms < timeout_ms) { if (vl53l4cd_data_ready()) { return true; } delay_ms(1); elapsed_ms++; } return false; } 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_set_offset(int16_t offset_mm) { uint16_t reg_value; reg_value = (uint16_t)((int16_t)offset_mm * 4); return vl53l4cd_write_reg16(VL53L4CD_REG_RANGE_OFFSET_MM, reg_value) && vl53l4cd_write_reg16(VL53L4CD_REG_INNER_OFFSET_MM, 0U) && vl53l4cd_write_reg16(VL53L4CD_REG_OUTER_OFFSET_MM, 0U); } bool vl53l4cd_get_offset(int16_t *offset_mm) { uint16_t reg_value; int16_t raw; if (offset_mm == NULL) { return false; } if (!vl53l4cd_read_reg16(VL53L4CD_REG_RANGE_OFFSET_MM, ®_value)) { return false; } raw = (int16_t)reg_value; *offset_mm = (int16_t)(raw / 4); return true; } bool vl53l4cd_calibrate_offset(uint16_t target_distance_mm, uint16_t num_samples, int16_t *measured_offset_mm) { vl53l4cd_result_t result; int32_t distance_sum = 0; uint16_t valid_samples = 0; uint16_t i; int16_t average_distance; int16_t offset; if (measured_offset_mm == NULL || target_distance_mm < 10U || target_distance_mm > 1000U || num_samples < 5U || num_samples > 255U) { return false; } if (!vl53l4cd_stop_ranging() || !vl53l4cd_set_offset(0) || !vl53l4cd_start_ranging()) { return false; } /* 热机 10 帧,丢弃 */ for (i = 0U; i < 10U; i++) { if (!vl53l4cd_wait_for_data_ready(VL53L4CD_DATA_TIMEOUT_MS)) { return false; } (void)vl53l4cd_clear_interrupt(); (void)vl53l4cd_get_result(&result); } /* 统计有效测距样本 */ for (i = 0U; i < num_samples; i++) { if (!vl53l4cd_wait_for_data_ready(VL53L4CD_DATA_TIMEOUT_MS)) { return false; } (void)vl53l4cd_clear_interrupt(); if (vl53l4cd_get_result(&result) && result.range_status == VL53L4CD_STATUS_RANGE_VALID) { distance_sum += (int32_t)result.distance_mm; valid_samples++; } } (void)vl53l4cd_stop_ranging(); if (valid_samples == 0U) { return false; } average_distance = (int16_t)(distance_sum / (int32_t)valid_samples); offset = (int16_t)((int16_t)target_distance_mm - average_distance); if (!vl53l4cd_set_offset(offset)) { return false; } *measured_offset_mm = offset; return true; } bool vl53l4cd_set_xtalk(uint16_t xtalk_kcps) { /* ST 固件上限:127 kcps(65536/512),寄存器值单位为 1/512 kcps */ if (xtalk_kcps > 127U) { return false; } if (!vl53l4cd_write_reg16(VL53L4CD_REG_XTALK_X_PLANE_GRADIENT_KCPS, 0U) || !vl53l4cd_write_reg16(VL53L4CD_REG_XTALK_Y_PLANE_GRADIENT_KCPS, 0U)) { return false; } return vl53l4cd_write_reg16(VL53L4CD_REG_XTALK_PLANE_OFFSET_KCPS, (uint16_t)(xtalk_kcps << 9)); } bool vl53l4cd_get_xtalk(uint16_t *xtalk_kcps) { uint16_t reg_value; if (xtalk_kcps == NULL) { return false; } if (!vl53l4cd_read_reg16(VL53L4CD_REG_XTALK_PLANE_OFFSET_KCPS, ®_value)) { return false; } *xtalk_kcps = (uint16_t)(reg_value >> 9); return true; } bool vl53l4cd_calibrate_xtalk(uint16_t target_distance_mm, uint16_t num_samples, uint16_t *measured_xtalk_kcps) { vl53l4cd_result_t result; uint32_t distance_sum = 0U; uint32_t signal_sum = 0U; uint32_t spad_sum = 0U; uint32_t valid_samples = 0U; uint16_t avg_distance; uint32_t avg_signal; uint32_t avg_spad; uint32_t signal_ratio; uint16_t xtalk_kcps; uint16_t i; if (measured_xtalk_kcps == NULL || target_distance_mm < 10U || target_distance_mm > 5000U || num_samples < 5U || num_samples > 255U) { return false; } /* 先禁用串扰补偿再采样 */ if (!vl53l4cd_set_xtalk(0U)) { return false; } if (!vl53l4cd_stop_ranging() || !vl53l4cd_start_ranging()) { return false; } /* 热机 10 帧,丢弃 */ for (i = 0U; i < 10U; i++) { if (!vl53l4cd_wait_for_data_ready(VL53L4CD_DATA_TIMEOUT_MS)) { (void)vl53l4cd_stop_ranging(); return false; } (void)vl53l4cd_clear_interrupt(); (void)vl53l4cd_get_result(&result); } /* 统计有效测距样本(ST 参考实现:跳过首个采样帧) */ for (i = 0U; i < num_samples; i++) { if (!vl53l4cd_wait_for_data_ready(VL53L4CD_DATA_TIMEOUT_MS)) { (void)vl53l4cd_stop_ranging(); return false; } (void)vl53l4cd_clear_interrupt(); if (i > 0U && vl53l4cd_get_result(&result) && result.range_status == VL53L4CD_STATUS_RANGE_VALID) { distance_sum += result.distance_mm; signal_sum += result.signal_rate_kcps; spad_sum += result.number_of_spad; valid_samples++; } } (void)vl53l4cd_stop_ranging(); if (valid_samples == 0U) { return false; } /* 定点数计算 xtalk = (1 - 平均距离/目标距离) * 平均信号/平均SPAD数 */ avg_distance = (uint16_t)(distance_sum / valid_samples); avg_signal = signal_sum / valid_samples; avg_spad = spad_sum / valid_samples; if (avg_spad == 0U || avg_distance >= target_distance_mm) { return false; } /* 乘法上界安全:avg_signal<=524280, (target-avg_distance)<=4990, 乘积 < 2^32 */ signal_ratio = (uint32_t)((avg_signal * (uint32_t)(target_distance_mm - avg_distance)) / target_distance_mm); xtalk_kcps = (uint16_t)((signal_ratio + (avg_spad / 2U)) / avg_spad); if (xtalk_kcps > 127U) { /* 超出传感器固件支持的最大串扰值,判定为校准失败 */ return false; } if (!vl53l4cd_set_xtalk(xtalk_kcps)) { return false; } *measured_xtalk_kcps = xtalk_kcps; return true; } 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); }