The VL53L1CB proximity sensor, based on ST’s FlightSense™, Time-of-Flight technology.
Dependencies: X_NUCLEO_COMMON ST_INTERFACES
Dependents: VL53L1CB_noshield_1sensor_polls_auton VL53L1CB_noshield_1sensor_interrupt_auton X_NUCLEO_53L1A2
Based on VL53L1 library, this is a library for the VL53L1CB ToF chip.
src/vl53l1_core.c
- Committer:
- charlesmn
- Date:
- 2020-11-06
- Revision:
- 0:3ac96e360672
- Child:
- 7:1add29d51e72
File content as of revision 0:3ac96e360672:
/******************************************************************************* * Copyright (c) 2020, STMicroelectronics - All Rights Reserved This file is part of VL53L1 Core and is dual licensed, either 'STMicroelectronics Proprietary license' or 'BSD 3-clause "New" or "Revised" License' , at your option. ******************************************************************************** 'STMicroelectronics Proprietary license' ******************************************************************************** License terms: STMicroelectronics Proprietary in accordance with licensing terms at www.st.com/sla0081 STMicroelectronics confidential Reproduction and Communication of this document is strictly prohibited unless specifically authorized in writing by STMicroelectronics. ******************************************************************************** Alternatively, VL53L1 Core may be distributed under the terms of 'BSD 3-clause "New" or "Revised" License', in which case the following provisions apply instead of the ones mentioned above : ******************************************************************************** License terms: BSD 3-clause "New" or "Revised" License. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************** */ #include "vl53l1_ll_def.h" #include "vl53l1_ll_device.h" #include "vl53l1_platform.h" #include "vl53l1_register_map.h" #include "vl53l1_register_funcs.h" #include "vl53l1_register_settings.h" #include "vl53l1_hist_structs.h" #include "vl53l1_api_preset_modes.h" #include "vl53l1_core.h" #include "vl53l1_tuning_parm_defaults.h" #define LOG_FUNCTION_START(fmt, ...) \ _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) #define LOG_FUNCTION_END(status, ...) \ _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) #define LOG_FUNCTION_END_FMT(status, fmt, ...) \ _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, \ status, fmt, ##__VA_ARGS__) #define trace_print(level, ...) \ _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) void VL53L1_init_version( VL53L1_DEV Dev) { VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); pdev->version.ll_major = VL53L1_LL_API_IMPLEMENTATION_VER_MAJOR; pdev->version.ll_minor = VL53L1_LL_API_IMPLEMENTATION_VER_MINOR; pdev->version.ll_build = VL53L1_LL_API_IMPLEMENTATION_VER_SUB; pdev->version.ll_revision = VL53L1_LL_API_IMPLEMENTATION_VER_REVISION; } void VL53L1_init_ll_driver_state( VL53L1_DEV Dev, VL53L1_DeviceState device_state) { VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); pstate->cfg_device_state = device_state; pstate->cfg_stream_count = 0; pstate->cfg_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; pstate->cfg_timing_status = 0; pstate->cfg_zone_id = 0; pstate->rd_device_state = device_state; pstate->rd_stream_count = 0; pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; pstate->rd_timing_status = 0; pstate->rd_zone_id = 0; } VL53L1_Error VL53L1_update_ll_driver_rd_state( VL53L1_DEV Dev) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); LOG_FUNCTION_START(""); if ((pdev->sys_ctrl.system__mode_start & VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK) == 0x00) { pstate->rd_device_state = VL53L1_DEVICESTATE_SW_STANDBY; pstate->rd_stream_count = 0; pstate->rd_internal_stream_count = 0; pstate->rd_internal_stream_count_val = 0; pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; pstate->rd_timing_status = 0; pstate->rd_zone_id = 0; } else { if (pstate->rd_stream_count == 0xFF) pstate->rd_stream_count = 0x80; else pstate->rd_stream_count++; status = VL53L1_update_internal_stream_counters(Dev, pstate->rd_stream_count, &(pstate->rd_internal_stream_count), &(pstate->rd_internal_stream_count_val)); pstate->rd_gph_id ^= VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; switch (pstate->rd_device_state) { case VL53L1_DEVICESTATE_SW_STANDBY: if ((pdev->dyn_cfg.system__grouped_parameter_hold & VL53L1_GROUPEDPARAMETERHOLD_ID_MASK) > 0) { pstate->rd_device_state = VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC; } else { if (pstate->rd_zone_id >= pdev->zone_cfg.active_zones) pstate->rd_device_state = VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; else pstate->rd_device_state = VL53L1_DEVICESTATE_RANGING_GATHER_DATA; } pstate->rd_stream_count = 0; pstate->rd_internal_stream_count = 0; pstate->rd_internal_stream_count_val = 0; pstate->rd_timing_status = 0; pstate->rd_zone_id = 0; break; case VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC: pstate->rd_stream_count = 0; pstate->rd_internal_stream_count = 0; pstate->rd_internal_stream_count_val = 0; pstate->rd_zone_id = 0; if (pstate->rd_zone_id >= pdev->zone_cfg.active_zones) pstate->rd_device_state = VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; else pstate->rd_device_state = VL53L1_DEVICESTATE_RANGING_GATHER_DATA; break; case VL53L1_DEVICESTATE_RANGING_GATHER_DATA: pstate->rd_zone_id++; if (pstate->rd_zone_id >= pdev->zone_cfg.active_zones) pstate->rd_device_state = VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; else pstate->rd_device_state = VL53L1_DEVICESTATE_RANGING_GATHER_DATA; break; case VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA: pstate->rd_zone_id = 0; pstate->rd_timing_status ^= 0x01; if (pstate->rd_zone_id >= pdev->zone_cfg.active_zones) pstate->rd_device_state = VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; else pstate->rd_device_state = VL53L1_DEVICESTATE_RANGING_GATHER_DATA; break; default: pstate->rd_device_state = VL53L1_DEVICESTATE_SW_STANDBY; pstate->rd_stream_count = 0; pstate->rd_internal_stream_count = 0; pstate->rd_internal_stream_count_val = 0; pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; pstate->rd_timing_status = 0; pstate->rd_zone_id = 0; break; } } LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_check_ll_driver_rd_state( VL53L1_DEV Dev) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); VL53L1_system_results_t *psys_results = &(pdev->sys_results); VL53L1_histogram_bin_data_t *phist_data = &(pdev->hist_data); VL53L1_zone_private_dyn_cfgs_t *pZ = &(pres->zone_dyn_cfgs); uint8_t device_range_status = 0; uint8_t device_stream_count = 0; uint8_t device_gph_id = 0; uint8_t histogram_mode = 0; uint8_t expected_stream_count = 0; uint8_t expected_gph_id = 0; LOG_FUNCTION_START(""); device_range_status = psys_results->result__range_status & VL53L1_RANGE_STATUS__RANGE_STATUS_MASK; device_stream_count = psys_results->result__stream_count; histogram_mode = (pdev->sys_ctrl.system__mode_start & VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) == VL53L1_DEVICESCHEDULERMODE_HISTOGRAM; device_gph_id = (psys_results->result__interrupt_status & VL53L1_INTERRUPT_STATUS__GPH_ID_INT_STATUS_MASK) >> 4; if (histogram_mode) device_gph_id = (phist_data->result__interrupt_status & VL53L1_INTERRUPT_STATUS__GPH_ID_INT_STATUS_MASK) >> 4; if (!((pdev->sys_ctrl.system__mode_start & VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK) == VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK)) goto ENDFUNC; if (pstate->rd_device_state == VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) { if (histogram_mode == 0) { if (device_range_status != VL53L1_DEVICEERROR_GPHSTREAMCOUNT0READY) status = VL53L1_ERROR_GPH_SYNC_CHECK_FAIL; } } else { if (pstate->rd_stream_count != device_stream_count) status = VL53L1_ERROR_STREAM_COUNT_CHECK_FAIL; if (pstate->rd_gph_id != device_gph_id) status = VL53L1_ERROR_GPH_ID_CHECK_FAIL; expected_stream_count = pZ->VL53L1_p_002[pstate->rd_zone_id].expected_stream_count; expected_gph_id = pZ->VL53L1_p_002[pstate->rd_zone_id].expected_gph_id; if (expected_stream_count != device_stream_count) { if (!((pdev->zone_cfg.active_zones == 0) && (device_stream_count == 255))) status = VL53L1_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL; } if (expected_gph_id != device_gph_id) status = VL53L1_ERROR_ZONE_GPH_ID_CHECK_FAIL; } ENDFUNC: LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_update_ll_driver_cfg_state( VL53L1_DEV Dev) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); VL53L1_zone_private_dyn_cfgs_t *pZ = &(pres->zone_dyn_cfgs); uint8_t prev_cfg_zone_id; uint8_t prev_cfg_gph_id; uint8_t prev_cfg_stream_count; LOG_FUNCTION_START(""); if ((pdev->sys_ctrl.system__mode_start & VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK) == 0x00) { pstate->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY; pstate->cfg_stream_count = 0; pstate->cfg_internal_stream_count = 0; pstate->cfg_internal_stream_count_val = 0; pstate->cfg_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; pstate->cfg_timing_status = 0; pstate->cfg_zone_id = 0; prev_cfg_zone_id = 0; prev_cfg_gph_id = 0; prev_cfg_stream_count = 0; } else { prev_cfg_gph_id = pstate->cfg_gph_id; prev_cfg_zone_id = pstate->cfg_zone_id; prev_cfg_stream_count = pstate->cfg_stream_count; if (pstate->cfg_stream_count == 0xFF) pstate->cfg_stream_count = 0x80; else pstate->cfg_stream_count++; status = VL53L1_update_internal_stream_counters( Dev, pstate->cfg_stream_count, &(pstate->cfg_internal_stream_count), &(pstate->cfg_internal_stream_count_val)); pstate->cfg_gph_id ^= VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; switch (pstate->cfg_device_state) { case VL53L1_DEVICESTATE_SW_STANDBY: pstate->cfg_zone_id = 1; if (pstate->cfg_zone_id > pdev->zone_cfg.active_zones) { pstate->cfg_zone_id = 0; pstate->cfg_timing_status ^= 0x01; } pstate->cfg_stream_count = 1; if (pdev->gen_cfg.global_config__stream_divider == 0) { pstate->cfg_internal_stream_count = 1; pstate->cfg_internal_stream_count_val = 0; } else { pstate->cfg_internal_stream_count = 0; pstate->cfg_internal_stream_count_val = 1; } pstate->cfg_device_state = VL53L1_DEVICESTATE_RANGING_DSS_AUTO; break; case VL53L1_DEVICESTATE_RANGING_DSS_AUTO: pstate->cfg_zone_id++; if (pstate->cfg_zone_id > pdev->zone_cfg.active_zones) { pstate->cfg_zone_id = 0; pstate->cfg_timing_status ^= 0x01; if (pdev->zone_cfg.active_zones > 0) { pstate->cfg_device_state = VL53L1_DEVICESTATE_RANGING_DSS_MANUAL; } } break; case VL53L1_DEVICESTATE_RANGING_DSS_MANUAL: pstate->cfg_zone_id++; if (pstate->cfg_zone_id > pdev->zone_cfg.active_zones) { pstate->cfg_zone_id = 0; pstate->cfg_timing_status ^= 0x01; } break; default: pstate->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY; pstate->cfg_stream_count = 0; pstate->cfg_internal_stream_count = 0; pstate->cfg_internal_stream_count_val = 0; pstate->cfg_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; pstate->cfg_timing_status = 0; pstate->cfg_zone_id = 0; break; } } if (pdev->zone_cfg.active_zones == 0) { pZ->VL53L1_p_002[prev_cfg_zone_id].expected_stream_count = prev_cfg_stream_count - 1; pZ->VL53L1_p_002[pstate->rd_zone_id].expected_gph_id = prev_cfg_gph_id ^ VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; } else { pZ->VL53L1_p_002[prev_cfg_zone_id].expected_stream_count = prev_cfg_stream_count; pZ->VL53L1_p_002[prev_cfg_zone_id].expected_gph_id = prev_cfg_gph_id; } LOG_FUNCTION_END(status); return status; } void VL53L1_copy_rtn_good_spads_to_buffer( VL53L1_nvm_copy_data_t *pdata, uint8_t *pbuffer) { *(pbuffer + 0) = pdata->global_config__spad_enables_rtn_0; *(pbuffer + 1) = pdata->global_config__spad_enables_rtn_1; *(pbuffer + 2) = pdata->global_config__spad_enables_rtn_2; *(pbuffer + 3) = pdata->global_config__spad_enables_rtn_3; *(pbuffer + 4) = pdata->global_config__spad_enables_rtn_4; *(pbuffer + 5) = pdata->global_config__spad_enables_rtn_5; *(pbuffer + 6) = pdata->global_config__spad_enables_rtn_6; *(pbuffer + 7) = pdata->global_config__spad_enables_rtn_7; *(pbuffer + 8) = pdata->global_config__spad_enables_rtn_8; *(pbuffer + 9) = pdata->global_config__spad_enables_rtn_9; *(pbuffer + 10) = pdata->global_config__spad_enables_rtn_10; *(pbuffer + 11) = pdata->global_config__spad_enables_rtn_11; *(pbuffer + 12) = pdata->global_config__spad_enables_rtn_12; *(pbuffer + 13) = pdata->global_config__spad_enables_rtn_13; *(pbuffer + 14) = pdata->global_config__spad_enables_rtn_14; *(pbuffer + 15) = pdata->global_config__spad_enables_rtn_15; *(pbuffer + 16) = pdata->global_config__spad_enables_rtn_16; *(pbuffer + 17) = pdata->global_config__spad_enables_rtn_17; *(pbuffer + 18) = pdata->global_config__spad_enables_rtn_18; *(pbuffer + 19) = pdata->global_config__spad_enables_rtn_19; *(pbuffer + 20) = pdata->global_config__spad_enables_rtn_20; *(pbuffer + 21) = pdata->global_config__spad_enables_rtn_21; *(pbuffer + 22) = pdata->global_config__spad_enables_rtn_22; *(pbuffer + 23) = pdata->global_config__spad_enables_rtn_23; *(pbuffer + 24) = pdata->global_config__spad_enables_rtn_24; *(pbuffer + 25) = pdata->global_config__spad_enables_rtn_25; *(pbuffer + 26) = pdata->global_config__spad_enables_rtn_26; *(pbuffer + 27) = pdata->global_config__spad_enables_rtn_27; *(pbuffer + 28) = pdata->global_config__spad_enables_rtn_28; *(pbuffer + 29) = pdata->global_config__spad_enables_rtn_29; *(pbuffer + 30) = pdata->global_config__spad_enables_rtn_30; *(pbuffer + 31) = pdata->global_config__spad_enables_rtn_31; } void VL53L1_init_system_results( VL53L1_system_results_t *pdata) { pdata->result__interrupt_status = 0xFF; pdata->result__range_status = 0xFF; pdata->result__report_status = 0xFF; pdata->result__stream_count = 0xFF; pdata->result__dss_actual_effective_spads_sd0 = 0xFFFF; pdata->result__peak_signal_count_rate_mcps_sd0 = 0xFFFF; pdata->result__ambient_count_rate_mcps_sd0 = 0xFFFF; pdata->result__sigma_sd0 = 0xFFFF; pdata->result__phase_sd0 = 0xFFFF; pdata->result__final_crosstalk_corrected_range_mm_sd0 = 0xFFFF; pdata->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = 0xFFFF; pdata->result__mm_inner_actual_effective_spads_sd0 = 0xFFFF; pdata->result__mm_outer_actual_effective_spads_sd0 = 0xFFFF; pdata->result__avg_signal_count_rate_mcps_sd0 = 0xFFFF; pdata->result__dss_actual_effective_spads_sd1 = 0xFFFF; pdata->result__peak_signal_count_rate_mcps_sd1 = 0xFFFF; pdata->result__ambient_count_rate_mcps_sd1 = 0xFFFF; pdata->result__sigma_sd1 = 0xFFFF; pdata->result__phase_sd1 = 0xFFFF; pdata->result__final_crosstalk_corrected_range_mm_sd1 = 0xFFFF; pdata->result__spare_0_sd1 = 0xFFFF; pdata->result__spare_1_sd1 = 0xFFFF; pdata->result__spare_2_sd1 = 0xFFFF; pdata->result__spare_3_sd1 = 0xFF; } void V53L1_init_zone_results_structure( uint8_t active_zones, VL53L1_zone_results_t *pdata) { uint8_t z = 0; VL53L1_zone_objects_t *pobjects; pdata->max_zones = VL53L1_MAX_USER_ZONES; pdata->active_zones = active_zones; for (z = 0; z < pdata->max_zones; z++) { pobjects = &(pdata->VL53L1_p_002[z]); pobjects->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY; pobjects->rd_device_state = VL53L1_DEVICESTATE_SW_STANDBY; pobjects->max_objects = VL53L1_MAX_RANGE_RESULTS; pobjects->active_objects = 0; } } void V53L1_init_zone_dss_configs( VL53L1_DEV Dev) { VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); uint8_t z = 0; uint8_t max_zones = VL53L1_MAX_USER_ZONES; VL53L1_zone_private_dyn_cfgs_t *pdata = &(pres->zone_dyn_cfgs); for (z = 0; z < max_zones; z++) { pdata->VL53L1_p_002[z].dss_mode = VL53L1_DSS_CONTROL__MODE_TARGET_RATE; pdata->VL53L1_p_002[z].dss_requested_effective_spad_count = 0; } } void VL53L1_init_histogram_config_structure( uint8_t even_bin0, uint8_t even_bin1, uint8_t even_bin2, uint8_t even_bin3, uint8_t even_bin4, uint8_t even_bin5, uint8_t odd_bin0, uint8_t odd_bin1, uint8_t odd_bin2, uint8_t odd_bin3, uint8_t odd_bin4, uint8_t odd_bin5, VL53L1_histogram_config_t *pdata) { pdata->histogram_config__low_amb_even_bin_0_1 = (even_bin1 << 4) + even_bin0; pdata->histogram_config__low_amb_even_bin_2_3 = (even_bin3 << 4) + even_bin2; pdata->histogram_config__low_amb_even_bin_4_5 = (even_bin5 << 4) + even_bin4; pdata->histogram_config__low_amb_odd_bin_0_1 = (odd_bin1 << 4) + odd_bin0; pdata->histogram_config__low_amb_odd_bin_2_3 = (odd_bin3 << 4) + odd_bin2; pdata->histogram_config__low_amb_odd_bin_4_5 = (odd_bin5 << 4) + odd_bin4; pdata->histogram_config__mid_amb_even_bin_0_1 = pdata->histogram_config__low_amb_even_bin_0_1; pdata->histogram_config__mid_amb_even_bin_2_3 = pdata->histogram_config__low_amb_even_bin_2_3; pdata->histogram_config__mid_amb_even_bin_4_5 = pdata->histogram_config__low_amb_even_bin_4_5; pdata->histogram_config__mid_amb_odd_bin_0_1 = pdata->histogram_config__low_amb_odd_bin_0_1; pdata->histogram_config__mid_amb_odd_bin_2 = odd_bin2; pdata->histogram_config__mid_amb_odd_bin_3_4 = (odd_bin4 << 4) + odd_bin3; pdata->histogram_config__mid_amb_odd_bin_5 = odd_bin5; pdata->histogram_config__user_bin_offset = 0x00; pdata->histogram_config__high_amb_even_bin_0_1 = pdata->histogram_config__low_amb_even_bin_0_1; pdata->histogram_config__high_amb_even_bin_2_3 = pdata->histogram_config__low_amb_even_bin_2_3; pdata->histogram_config__high_amb_even_bin_4_5 = pdata->histogram_config__low_amb_even_bin_4_5; pdata->histogram_config__high_amb_odd_bin_0_1 = pdata->histogram_config__low_amb_odd_bin_0_1; pdata->histogram_config__high_amb_odd_bin_2_3 = pdata->histogram_config__low_amb_odd_bin_2_3; pdata->histogram_config__high_amb_odd_bin_4_5 = pdata->histogram_config__low_amb_odd_bin_4_5; pdata->histogram_config__amb_thresh_low = 0xFFFF; pdata->histogram_config__amb_thresh_high = 0xFFFF; pdata->histogram_config__spad_array_selection = 0x00; } void VL53L1_init_histogram_multizone_config_structure( uint8_t even_bin0, uint8_t even_bin1, uint8_t even_bin2, uint8_t even_bin3, uint8_t even_bin4, uint8_t even_bin5, uint8_t odd_bin0, uint8_t odd_bin1, uint8_t odd_bin2, uint8_t odd_bin3, uint8_t odd_bin4, uint8_t odd_bin5, VL53L1_histogram_config_t *pdata) { pdata->histogram_config__low_amb_even_bin_0_1 = (even_bin1 << 4) + even_bin0; pdata->histogram_config__low_amb_even_bin_2_3 = (even_bin3 << 4) + even_bin2; pdata->histogram_config__low_amb_even_bin_4_5 = (even_bin5 << 4) + even_bin4; pdata->histogram_config__low_amb_odd_bin_0_1 = pdata->histogram_config__low_amb_even_bin_0_1; pdata->histogram_config__low_amb_odd_bin_2_3 = pdata->histogram_config__low_amb_even_bin_2_3; pdata->histogram_config__low_amb_odd_bin_4_5 = pdata->histogram_config__low_amb_even_bin_4_5; pdata->histogram_config__mid_amb_even_bin_0_1 = pdata->histogram_config__low_amb_even_bin_0_1; pdata->histogram_config__mid_amb_even_bin_2_3 = pdata->histogram_config__low_amb_even_bin_2_3; pdata->histogram_config__mid_amb_even_bin_4_5 = pdata->histogram_config__low_amb_even_bin_4_5; pdata->histogram_config__mid_amb_odd_bin_0_1 = pdata->histogram_config__low_amb_odd_bin_0_1; pdata->histogram_config__mid_amb_odd_bin_2 = odd_bin2; pdata->histogram_config__mid_amb_odd_bin_3_4 = (odd_bin4 << 4) + odd_bin3; pdata->histogram_config__mid_amb_odd_bin_5 = odd_bin5; pdata->histogram_config__user_bin_offset = 0x00; pdata->histogram_config__high_amb_even_bin_0_1 = (odd_bin1 << 4) + odd_bin0; pdata->histogram_config__high_amb_even_bin_2_3 = (odd_bin3 << 4) + odd_bin2; pdata->histogram_config__high_amb_even_bin_4_5 = (odd_bin5 << 4) + odd_bin4; pdata->histogram_config__high_amb_odd_bin_0_1 = pdata->histogram_config__high_amb_even_bin_0_1; pdata->histogram_config__high_amb_odd_bin_2_3 = pdata->histogram_config__high_amb_even_bin_2_3; pdata->histogram_config__high_amb_odd_bin_4_5 = pdata->histogram_config__high_amb_even_bin_4_5; pdata->histogram_config__amb_thresh_low = 0xFFFF; pdata->histogram_config__amb_thresh_high = 0xFFFF; pdata->histogram_config__spad_array_selection = 0x00; } void VL53L1_init_xtalk_bin_data_struct( uint32_t bin_value, uint16_t VL53L1_p_024, VL53L1_xtalk_histogram_shape_t *pdata) { uint16_t i = 0; pdata->zone_id = 0; pdata->time_stamp = 0; pdata->VL53L1_p_022 = 0; pdata->VL53L1_p_023 = VL53L1_XTALK_HISTO_BINS; pdata->VL53L1_p_024 = (uint8_t)VL53L1_p_024; pdata->phasecal_result__reference_phase = 0; pdata->phasecal_result__vcsel_start = 0; pdata->cal_config__vcsel_start = 0; pdata->vcsel_width = 0; pdata->VL53L1_p_019 = 0; pdata->zero_distance_phase = 0; for (i = 0; i < VL53L1_XTALK_HISTO_BINS; i++) { if (i < VL53L1_p_024) pdata->bin_data[i] = bin_value; else pdata->bin_data[i] = 0; } } void VL53L1_i2c_encode_uint16_t( uint16_t ip_value, uint16_t count, uint8_t *pbuffer) { uint16_t i = 0; uint16_t VL53L1_p_002 = 0; VL53L1_p_002 = ip_value; for (i = 0; i < count; i++) { pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); VL53L1_p_002 = VL53L1_p_002 >> 8; } } uint16_t VL53L1_i2c_decode_uint16_t( uint16_t count, uint8_t *pbuffer) { uint16_t value = 0x00; while (count-- > 0) value = (value << 8) | (uint16_t)*pbuffer++; return value; } void VL53L1_i2c_encode_int16_t( int16_t ip_value, uint16_t count, uint8_t *pbuffer) { uint16_t i = 0; int16_t VL53L1_p_002 = 0; VL53L1_p_002 = ip_value; for (i = 0; i < count; i++) { pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); VL53L1_p_002 = VL53L1_p_002 >> 8; } } int16_t VL53L1_i2c_decode_int16_t( uint16_t count, uint8_t *pbuffer) { int16_t value = 0x00; if (*pbuffer >= 0x80) value = 0xFFFF; while (count-- > 0) value = (value << 8) | (int16_t)*pbuffer++; return value; } void VL53L1_i2c_encode_uint32_t( uint32_t ip_value, uint16_t count, uint8_t *pbuffer) { uint16_t i = 0; uint32_t VL53L1_p_002 = 0; VL53L1_p_002 = ip_value; for (i = 0; i < count; i++) { pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); VL53L1_p_002 = VL53L1_p_002 >> 8; } } uint32_t VL53L1_i2c_decode_uint32_t( uint16_t count, uint8_t *pbuffer) { uint32_t value = 0x00; while (count-- > 0) value = (value << 8) | (uint32_t)*pbuffer++; return value; } uint32_t VL53L1_i2c_decode_with_mask( uint16_t count, uint8_t *pbuffer, uint32_t bit_mask, uint32_t down_shift, uint32_t offset) { uint32_t value = 0x00; while (count-- > 0) value = (value << 8) | (uint32_t)*pbuffer++; value = value & bit_mask; if (down_shift > 0) value = value >> down_shift; value = value + offset; return value; } void VL53L1_i2c_encode_int32_t( int32_t ip_value, uint16_t count, uint8_t *pbuffer) { uint16_t i = 0; int32_t VL53L1_p_002 = 0; VL53L1_p_002 = ip_value; for (i = 0; i < count; i++) { pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); VL53L1_p_002 = VL53L1_p_002 >> 8; } } int32_t VL53L1_i2c_decode_int32_t( uint16_t count, uint8_t *pbuffer) { int32_t value = 0x00; if (*pbuffer >= 0x80) value = 0xFFFFFFFF; while (count-- > 0) value = (value << 8) | (int32_t)*pbuffer++; return value; } VL53L1_Error VL53L1_start_test( VL53L1_DEV Dev, uint8_t test_mode__ctrl) { VL53L1_Error status = VL53L1_ERROR_NONE; LOG_FUNCTION_START(""); if (status == VL53L1_ERROR_NONE) { status = VL53L1_WrByte( Dev, VL53L1_TEST_MODE__CTRL, test_mode__ctrl); } LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_set_firmware_enable_register( VL53L1_DEV Dev, uint8_t value) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); pdev->sys_ctrl.firmware__enable = value; status = VL53L1_WrByte( Dev, VL53L1_FIRMWARE__ENABLE, pdev->sys_ctrl.firmware__enable); return status; } VL53L1_Error VL53L1_enable_firmware( VL53L1_DEV Dev) { VL53L1_Error status = VL53L1_ERROR_NONE; LOG_FUNCTION_START(""); status = VL53L1_set_firmware_enable_register(Dev, 0x01); LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_disable_firmware( VL53L1_DEV Dev) { VL53L1_Error status = VL53L1_ERROR_NONE; LOG_FUNCTION_START(""); status = VL53L1_set_firmware_enable_register(Dev, 0x00); LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_set_powerforce_register( VL53L1_DEV Dev, uint8_t value) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); pdev->sys_ctrl.power_management__go1_power_force = value; status = VL53L1_WrByte( Dev, VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE, pdev->sys_ctrl.power_management__go1_power_force); return status; } VL53L1_Error VL53L1_enable_powerforce( VL53L1_DEV Dev) { VL53L1_Error status = VL53L1_ERROR_NONE; LOG_FUNCTION_START(""); status = VL53L1_set_powerforce_register(Dev, 0x01); LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_disable_powerforce( VL53L1_DEV Dev) { VL53L1_Error status = VL53L1_ERROR_NONE; LOG_FUNCTION_START(""); status = VL53L1_set_powerforce_register(Dev, 0x00); LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_clear_interrupt( VL53L1_DEV Dev) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); LOG_FUNCTION_START(""); pdev->sys_ctrl.system__interrupt_clear = VL53L1_CLEAR_RANGE_INT; status = VL53L1_WrByte( Dev, VL53L1_SYSTEM__INTERRUPT_CLEAR, pdev->sys_ctrl.system__interrupt_clear); LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_force_shadow_stream_count_to_zero( VL53L1_DEV Dev) { VL53L1_Error status = VL53L1_ERROR_NONE; if (status == VL53L1_ERROR_NONE) status = VL53L1_disable_firmware(Dev); if (status == VL53L1_ERROR_NONE) { status = VL53L1_WrByte( Dev, VL53L1_SHADOW_RESULT__STREAM_COUNT, 0x00); } if (status == VL53L1_ERROR_NONE) status = VL53L1_enable_firmware(Dev); return status; } uint32_t VL53L1_calc_macro_period_us( uint16_t fast_osc_frequency, uint8_t VL53L1_p_009) { uint32_t pll_period_us = 0; uint8_t VL53L1_p_031 = 0; uint32_t macro_period_us = 0; LOG_FUNCTION_START(""); pll_period_us = VL53L1_calc_pll_period_us(fast_osc_frequency); VL53L1_p_031 = VL53L1_decode_vcsel_period(VL53L1_p_009); macro_period_us = (uint32_t)VL53L1_MACRO_PERIOD_VCSEL_PERIODS * pll_period_us; macro_period_us = macro_period_us >> 6; macro_period_us = macro_period_us * (uint32_t)VL53L1_p_031; macro_period_us = macro_period_us >> 6; LOG_FUNCTION_END(0); return macro_period_us; } uint16_t VL53L1_calc_range_ignore_threshold( uint32_t central_rate, int16_t x_gradient, int16_t y_gradient, uint8_t rate_mult) { int32_t range_ignore_thresh_int = 0; uint16_t range_ignore_thresh_kcps = 0; int32_t central_rate_int = 0; int16_t x_gradient_int = 0; int16_t y_gradient_int = 0; LOG_FUNCTION_START(""); central_rate_int = ((int32_t)central_rate * (1 << 4)) / (1000); if (x_gradient < 0) x_gradient_int = x_gradient * -1; if (y_gradient < 0) y_gradient_int = y_gradient * -1; range_ignore_thresh_int = (8 * x_gradient_int * 4) + (8 * y_gradient_int * 4); range_ignore_thresh_int = range_ignore_thresh_int / 1000; range_ignore_thresh_int = range_ignore_thresh_int + central_rate_int; range_ignore_thresh_int = (int32_t)rate_mult * range_ignore_thresh_int; range_ignore_thresh_int = (range_ignore_thresh_int + (1<<4)) / (1<<5); if (range_ignore_thresh_int > 0xFFFF) range_ignore_thresh_kcps = 0xFFFF; else range_ignore_thresh_kcps = (uint16_t)range_ignore_thresh_int; LOG_FUNCTION_END(0); return range_ignore_thresh_kcps; } uint32_t VL53L1_calc_timeout_mclks( uint32_t timeout_us, uint32_t macro_period_us) { uint32_t timeout_mclks = 0; LOG_FUNCTION_START(""); timeout_mclks = ((timeout_us << 12) + (macro_period_us>>1)) / macro_period_us; LOG_FUNCTION_END(0); return timeout_mclks; } uint16_t VL53L1_calc_encoded_timeout( uint32_t timeout_us, uint32_t macro_period_us) { uint32_t timeout_mclks = 0; uint16_t timeout_encoded = 0; LOG_FUNCTION_START(""); timeout_mclks = VL53L1_calc_timeout_mclks(timeout_us, macro_period_us); timeout_encoded = VL53L1_encode_timeout(timeout_mclks); LOG_FUNCTION_END(0); return timeout_encoded; } uint32_t VL53L1_calc_timeout_us( uint32_t timeout_mclks, uint32_t macro_period_us) { uint32_t timeout_us = 0; uint64_t tmp = 0; LOG_FUNCTION_START(""); tmp = (uint64_t)timeout_mclks * (uint64_t)macro_period_us; tmp += 0x00800; tmp = tmp >> 12; timeout_us = (uint32_t)tmp; LOG_FUNCTION_END(0); return timeout_us; } uint32_t VL53L1_calc_crosstalk_plane_offset_with_margin( uint32_t plane_offset_kcps, int16_t margin_offset_kcps) { uint32_t plane_offset_with_margin = 0; int32_t plane_offset_kcps_temp = 0; LOG_FUNCTION_START(""); plane_offset_kcps_temp = (int32_t)plane_offset_kcps + (int32_t)margin_offset_kcps; if (plane_offset_kcps_temp < 0) plane_offset_kcps_temp = 0; else if (plane_offset_kcps_temp > 0x3FFFF) plane_offset_kcps_temp = 0x3FFFF; plane_offset_with_margin = (uint32_t) plane_offset_kcps_temp; LOG_FUNCTION_END(0); return plane_offset_with_margin; } uint32_t VL53L1_calc_decoded_timeout_us( uint16_t timeout_encoded, uint32_t macro_period_us) { uint32_t timeout_mclks = 0; uint32_t timeout_us = 0; LOG_FUNCTION_START(""); timeout_mclks = VL53L1_decode_timeout(timeout_encoded); timeout_us = VL53L1_calc_timeout_us(timeout_mclks, macro_period_us); LOG_FUNCTION_END(0); return timeout_us; } uint16_t VL53L1_encode_timeout(uint32_t timeout_mclks) { uint16_t encoded_timeout = 0; uint32_t ls_byte = 0; uint16_t ms_byte = 0; if (timeout_mclks > 0) { ls_byte = timeout_mclks - 1; while ((ls_byte & 0xFFFFFF00) > 0) { ls_byte = ls_byte >> 1; ms_byte++; } encoded_timeout = (ms_byte << 8) + (uint16_t) (ls_byte & 0x000000FF); } return encoded_timeout; } uint32_t VL53L1_decode_timeout(uint16_t encoded_timeout) { uint32_t timeout_macro_clks = 0; timeout_macro_clks = ((uint32_t) (encoded_timeout & 0x00FF) << (uint32_t) ((encoded_timeout & 0xFF00) >> 8)) + 1; return timeout_macro_clks; } VL53L1_Error VL53L1_calc_timeout_register_values( uint32_t phasecal_config_timeout_us, uint32_t mm_config_timeout_us, uint32_t range_config_timeout_us, uint16_t fast_osc_frequency, VL53L1_general_config_t *pgeneral, VL53L1_timing_config_t *ptiming) { VL53L1_Error status = VL53L1_ERROR_NONE; uint32_t macro_period_us = 0; uint32_t timeout_mclks = 0; uint16_t timeout_encoded = 0; LOG_FUNCTION_START(""); if (fast_osc_frequency == 0) { status = VL53L1_ERROR_DIVISION_BY_ZERO; } else { macro_period_us = VL53L1_calc_macro_period_us( fast_osc_frequency, ptiming->range_config__vcsel_period_a); timeout_mclks = VL53L1_calc_timeout_mclks( phasecal_config_timeout_us, macro_period_us); if (timeout_mclks > 0xFF) timeout_mclks = 0xFF; pgeneral->phasecal_config__timeout_macrop = (uint8_t)timeout_mclks; timeout_encoded = VL53L1_calc_encoded_timeout( mm_config_timeout_us, macro_period_us); ptiming->mm_config__timeout_macrop_a_hi = (uint8_t)((timeout_encoded & 0xFF00) >> 8); ptiming->mm_config__timeout_macrop_a_lo = (uint8_t) (timeout_encoded & 0x00FF); timeout_encoded = VL53L1_calc_encoded_timeout( range_config_timeout_us, macro_period_us); ptiming->range_config__timeout_macrop_a_hi = (uint8_t)((timeout_encoded & 0xFF00) >> 8); ptiming->range_config__timeout_macrop_a_lo = (uint8_t) (timeout_encoded & 0x00FF); macro_period_us = VL53L1_calc_macro_period_us( fast_osc_frequency, ptiming->range_config__vcsel_period_b); timeout_encoded = VL53L1_calc_encoded_timeout( mm_config_timeout_us, macro_period_us); ptiming->mm_config__timeout_macrop_b_hi = (uint8_t)((timeout_encoded & 0xFF00) >> 8); ptiming->mm_config__timeout_macrop_b_lo = (uint8_t) (timeout_encoded & 0x00FF); timeout_encoded = VL53L1_calc_encoded_timeout( range_config_timeout_us, macro_period_us); ptiming->range_config__timeout_macrop_b_hi = (uint8_t)((timeout_encoded & 0xFF00) >> 8); ptiming->range_config__timeout_macrop_b_lo = (uint8_t) (timeout_encoded & 0x00FF); } LOG_FUNCTION_END(0); return status; } uint8_t VL53L1_encode_vcsel_period(uint8_t VL53L1_p_031) { uint8_t vcsel_period_reg = 0; vcsel_period_reg = (VL53L1_p_031 >> 1) - 1; return vcsel_period_reg; } uint32_t VL53L1_decode_unsigned_integer( uint8_t *pbuffer, uint8_t no_of_bytes) { uint8_t i = 0; uint32_t decoded_value = 0; for (i = 0; i < no_of_bytes; i++) decoded_value = (decoded_value << 8) + (uint32_t)pbuffer[i]; return decoded_value; } void VL53L1_encode_unsigned_integer( uint32_t ip_value, uint8_t no_of_bytes, uint8_t *pbuffer) { uint8_t i = 0; uint32_t VL53L1_p_002 = 0; VL53L1_p_002 = ip_value; for (i = 0; i < no_of_bytes; i++) { pbuffer[no_of_bytes-i-1] = VL53L1_p_002 & 0x00FF; VL53L1_p_002 = VL53L1_p_002 >> 8; } } VL53L1_Error VL53L1_hist_copy_and_scale_ambient_info( VL53L1_zone_hist_info_t *pidata, VL53L1_histogram_bin_data_t *podata) { VL53L1_Error status = VL53L1_ERROR_NONE; int64_t evts = 0; int64_t tmpi = 0; int64_t tmpo = 0; LOG_FUNCTION_START(""); if (pidata->result__dss_actual_effective_spads == 0) { status = VL53L1_ERROR_DIVISION_BY_ZERO; } else { if (pidata->number_of_ambient_bins > 0 && podata->number_of_ambient_bins == 0) { tmpo = 1 + (int64_t)podata->total_periods_elapsed; tmpo *= (int64_t)podata->result__dss_actual_effective_spads; tmpi = 1 + (int64_t)pidata->total_periods_elapsed; tmpi *= (int64_t)pidata->result__dss_actual_effective_spads; evts = tmpo * (int64_t)pidata->ambient_events_sum; evts += (tmpi/2); if (tmpi != 0) evts = do_division_s(evts, tmpi); podata->ambient_events_sum = (int32_t)evts; podata->VL53L1_p_004 = podata->ambient_events_sum; podata->VL53L1_p_004 += ((int32_t)pidata->number_of_ambient_bins / 2); podata->VL53L1_p_004 /= (int32_t)pidata->number_of_ambient_bins; } } LOG_FUNCTION_END(0); return status; } void VL53L1_hist_get_bin_sequence_config( VL53L1_DEV Dev, VL53L1_histogram_bin_data_t *pdata) { VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); int32_t amb_thresh_low = 0; int32_t amb_thresh_high = 0; uint8_t i = 0; LOG_FUNCTION_START(""); amb_thresh_low = 1024 * (int32_t)pdev->hist_cfg.histogram_config__amb_thresh_low; amb_thresh_high = 1024 * (int32_t)pdev->hist_cfg.histogram_config__amb_thresh_high; if ((pdev->ll_state.rd_stream_count & 0x01) == 0) { pdata->bin_seq[5] = pdev->hist_cfg.histogram_config__mid_amb_even_bin_4_5 >> 4; pdata->bin_seq[4] = pdev->hist_cfg.histogram_config__mid_amb_even_bin_4_5 & 0x0F; pdata->bin_seq[3] = pdev->hist_cfg.histogram_config__mid_amb_even_bin_2_3 >> 4; pdata->bin_seq[2] = pdev->hist_cfg.histogram_config__mid_amb_even_bin_2_3 & 0x0F; pdata->bin_seq[1] = pdev->hist_cfg.histogram_config__mid_amb_even_bin_0_1 >> 4; pdata->bin_seq[0] = pdev->hist_cfg.histogram_config__mid_amb_even_bin_0_1 & 0x0F; if (pdata->ambient_events_sum > amb_thresh_high) { pdata->bin_seq[5] = pdev->hist_cfg.histogram_config__high_amb_even_bin_4_5 >> 4; pdata->bin_seq[4] = pdev->hist_cfg.histogram_config__high_amb_even_bin_4_5 & 0x0F; pdata->bin_seq[3] = pdev->hist_cfg.histogram_config__high_amb_even_bin_2_3 >> 4; pdata->bin_seq[2] = pdev->hist_cfg.histogram_config__high_amb_even_bin_2_3 & 0x0F; pdata->bin_seq[1] = pdev->hist_cfg.histogram_config__high_amb_even_bin_0_1 >> 4; pdata->bin_seq[0] = pdev->hist_cfg.histogram_config__high_amb_even_bin_0_1 & 0x0F; } if (pdata->ambient_events_sum < amb_thresh_low) { pdata->bin_seq[5] = pdev->hist_cfg.histogram_config__low_amb_even_bin_4_5 >> 4; pdata->bin_seq[4] = pdev->hist_cfg.histogram_config__low_amb_even_bin_4_5 & 0x0F; pdata->bin_seq[3] = pdev->hist_cfg.histogram_config__low_amb_even_bin_2_3 >> 4; pdata->bin_seq[2] = pdev->hist_cfg.histogram_config__low_amb_even_bin_2_3 & 0x0F; pdata->bin_seq[1] = pdev->hist_cfg.histogram_config__low_amb_even_bin_0_1 >> 4; pdata->bin_seq[0] = pdev->hist_cfg.histogram_config__low_amb_even_bin_0_1 & 0x0F; } } else { pdata->bin_seq[5] = pdev->hist_cfg.histogram_config__mid_amb_odd_bin_5 & 0x0F; pdata->bin_seq[4] = pdev->hist_cfg.histogram_config__mid_amb_odd_bin_3_4 & 0x0F; pdata->bin_seq[3] = pdev->hist_cfg.histogram_config__mid_amb_odd_bin_3_4 >> 4; pdata->bin_seq[2] = pdev->hist_cfg.histogram_config__mid_amb_odd_bin_2 & 0x0F; pdata->bin_seq[1] = pdev->hist_cfg.histogram_config__mid_amb_odd_bin_0_1 >> 4; pdata->bin_seq[0] = pdev->hist_cfg.histogram_config__mid_amb_odd_bin_0_1 & 0x0F; if (pdata->ambient_events_sum > amb_thresh_high) { pdata->bin_seq[5] = pdev->hist_cfg.histogram_config__high_amb_odd_bin_4_5 >> 4; pdata->bin_seq[4] = pdev->hist_cfg.histogram_config__high_amb_odd_bin_4_5 & 0x0F; pdata->bin_seq[3] = pdev->hist_cfg.histogram_config__high_amb_odd_bin_2_3 >> 4; pdata->bin_seq[2] = pdev->hist_cfg.histogram_config__high_amb_odd_bin_2_3 & 0x0F; pdata->bin_seq[1] = pdev->hist_cfg.histogram_config__high_amb_odd_bin_0_1 >> 4; pdata->bin_seq[0] = pdev->hist_cfg.histogram_config__high_amb_odd_bin_0_1 & 0x0F; } if (pdata->ambient_events_sum < amb_thresh_low) { pdata->bin_seq[5] = pdev->hist_cfg.histogram_config__low_amb_odd_bin_4_5 >> 4; pdata->bin_seq[4] = pdev->hist_cfg.histogram_config__low_amb_odd_bin_4_5 & 0x0F; pdata->bin_seq[3] = pdev->hist_cfg.histogram_config__low_amb_odd_bin_2_3 >> 4; pdata->bin_seq[2] = pdev->hist_cfg.histogram_config__low_amb_odd_bin_2_3 & 0x0F; pdata->bin_seq[1] = pdev->hist_cfg.histogram_config__low_amb_odd_bin_0_1 >> 4; pdata->bin_seq[0] = pdev->hist_cfg.histogram_config__low_amb_odd_bin_0_1 & 0x0F; } } for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) pdata->bin_rep[i] = 1; LOG_FUNCTION_END(0); } VL53L1_Error VL53L1_hist_phase_consistency_check( VL53L1_DEV Dev, VL53L1_zone_hist_info_t *phist_prev, VL53L1_zone_objects_t *prange_prev, VL53L1_range_results_t *prange_curr) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); uint8_t lc = 0; uint8_t p = 0; uint16_t phase_delta = 0; uint16_t phase_tolerance = 0; int32_t events_delta = 0; int32_t events_tolerance = 0; uint8_t event_sigma; uint16_t event_min_spad_count; uint16_t min_max_tolerance; uint8_t pht; VL53L1_DeviceError range_status = 0; LOG_FUNCTION_START(""); event_sigma = pdev->histpostprocess.algo__consistency_check__event_sigma; event_min_spad_count = pdev->histpostprocess.algo__consistency_check__event_min_spad_count; min_max_tolerance = pdev->histpostprocess.algo__consistency_check__min_max_tolerance; pht = pdev->histpostprocess.algo__consistency_check__phase_tolerance; phase_tolerance = (uint16_t)pht; phase_tolerance = phase_tolerance << 8; if (prange_prev->rd_device_state != VL53L1_DEVICESTATE_RANGING_GATHER_DATA && prange_prev->rd_device_state != VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA) return status; if (phase_tolerance == 0) return status; for (lc = 0; lc < prange_curr->active_results; lc++) { if (!((prange_curr->VL53L1_p_002[lc].range_status == VL53L1_DEVICEERROR_RANGECOMPLETE) || (prange_curr->VL53L1_p_002[lc].range_status == VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK))) continue; if (prange_prev->active_objects == 0) prange_curr->VL53L1_p_002[lc].range_status = VL53L1_DEVICEERROR_PREV_RANGE_NO_TARGETS; else prange_curr->VL53L1_p_002[lc].range_status = VL53L1_DEVICEERROR_PHASECONSISTENCY; for (p = 0; p < prange_prev->active_objects; p++) { if (prange_curr->VL53L1_p_002[lc].VL53L1_p_014 > prange_prev->VL53L1_p_002[p].VL53L1_p_014) { phase_delta = prange_curr->VL53L1_p_002[lc].VL53L1_p_014 - prange_prev->VL53L1_p_002[p].VL53L1_p_014; } else { phase_delta = prange_prev->VL53L1_p_002[p].VL53L1_p_014 - prange_curr->VL53L1_p_002[lc].VL53L1_p_014; } if (phase_delta < phase_tolerance) { if (status == VL53L1_ERROR_NONE) status = VL53L1_hist_events_consistency_check( event_sigma, event_min_spad_count, phist_prev, &(prange_prev->VL53L1_p_002[p]), &(prange_curr->VL53L1_p_002[lc]), &events_tolerance, &events_delta, &range_status); if (status == VL53L1_ERROR_NONE && range_status == VL53L1_DEVICEERROR_RANGECOMPLETE) status = VL53L1_hist_merged_pulse_check( min_max_tolerance, &(prange_curr->VL53L1_p_002[lc]), &range_status); prange_curr->VL53L1_p_002[lc].range_status = range_status; } } } LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_hist_events_consistency_check( uint8_t event_sigma, uint16_t min_effective_spad_count, VL53L1_zone_hist_info_t *phist_prev, VL53L1_object_data_t *prange_prev, VL53L1_range_data_t *prange_curr, int32_t *pevents_tolerance, int32_t *pevents_delta, VL53L1_DeviceError *prange_status) { VL53L1_Error status = VL53L1_ERROR_NONE; int64_t tmpp = 0; int64_t tmpc = 0; int64_t events_scaler = 0; int64_t events_scaler_sq = 0; int64_t c_signal_events = 0; int64_t c_sig_noise_sq = 0; int64_t c_amb_noise_sq = 0; int64_t p_amb_noise_sq = 0; int32_t p_signal_events = 0; uint32_t noise_sq_sum = 0; if (event_sigma == 0) { *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE; return status; } tmpp = 1 + (int64_t)phist_prev->total_periods_elapsed; tmpp *= (int64_t)phist_prev->result__dss_actual_effective_spads; tmpc = 1 + (int64_t)prange_curr->total_periods_elapsed; tmpc *= (int64_t)prange_curr->VL53L1_p_006; events_scaler = tmpp * 4096; events_scaler += (tmpc/2); if (tmpc != 0) events_scaler = do_division_s(events_scaler, tmpc); events_scaler_sq = events_scaler * events_scaler; events_scaler_sq += 2048; events_scaler_sq /= 4096; c_signal_events = (int64_t)prange_curr->VL53L1_p_021; c_signal_events -= (int64_t)prange_curr->VL53L1_p_020; c_signal_events *= (int64_t)events_scaler; c_signal_events += 2048; c_signal_events /= 4096; c_sig_noise_sq = (int64_t)events_scaler_sq; c_sig_noise_sq *= (int64_t)prange_curr->VL53L1_p_021; c_sig_noise_sq += 2048; c_sig_noise_sq /= 4096; c_amb_noise_sq = (int64_t)events_scaler_sq; c_amb_noise_sq *= (int64_t)prange_curr->VL53L1_p_020; c_amb_noise_sq += 2048; c_amb_noise_sq /= 4096; c_amb_noise_sq += 2; c_amb_noise_sq /= 4; p_amb_noise_sq = (int64_t)prange_prev->VL53L1_p_020; p_amb_noise_sq += 2; p_amb_noise_sq /= 4; noise_sq_sum = (uint32_t)prange_prev->VL53L1_p_021 + (uint32_t)c_sig_noise_sq + (uint32_t)p_amb_noise_sq + (uint32_t)c_amb_noise_sq; *pevents_tolerance = (int32_t)VL53L1_isqrt(noise_sq_sum * 16); *pevents_tolerance *= (int32_t)event_sigma; *pevents_tolerance += 32; *pevents_tolerance /= 64; p_signal_events = (int32_t)prange_prev->VL53L1_p_021; p_signal_events -= (int32_t)prange_prev->VL53L1_p_020; if ((int32_t)c_signal_events > p_signal_events) *pevents_delta = (int32_t)c_signal_events - p_signal_events; else *pevents_delta = p_signal_events - (int32_t)c_signal_events; if (*pevents_delta > *pevents_tolerance && prange_curr->VL53L1_p_006 > min_effective_spad_count) *prange_status = VL53L1_DEVICEERROR_EVENTCONSISTENCY; else *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE; return status; } VL53L1_Error VL53L1_hist_merged_pulse_check( int16_t min_max_tolerance_mm, VL53L1_range_data_t *pdata, VL53L1_DeviceError *prange_status) { VL53L1_Error status = VL53L1_ERROR_NONE; int16_t delta_mm = 0; if (pdata->max_range_mm > pdata->min_range_mm) delta_mm = pdata->max_range_mm - pdata->min_range_mm; else delta_mm = pdata->min_range_mm - pdata->max_range_mm; if (min_max_tolerance_mm > 0 && delta_mm > min_max_tolerance_mm) *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE_MERGED_PULSE; else *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE; return status; } VL53L1_Error VL53L1_hist_xmonitor_consistency_check( VL53L1_DEV Dev, VL53L1_zone_hist_info_t *phist_prev, VL53L1_zone_objects_t *prange_prev, VL53L1_range_data_t *prange_curr) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); int32_t events_delta = 0; int32_t events_tolerance = 0; uint8_t event_sigma; uint16_t min_spad_count; event_sigma = pdev->histpostprocess.algo__crosstalk_detect_event_sigma; min_spad_count = pdev->histpostprocess.algo__consistency_check__event_min_spad_count; if (prange_curr->range_status == VL53L1_DEVICEERROR_RANGECOMPLETE || prange_curr->range_status == VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK || prange_curr->range_status == VL53L1_DEVICEERROR_EVENTCONSISTENCY) { if (prange_prev->xmonitor.range_status == VL53L1_DEVICEERROR_RANGECOMPLETE || prange_prev->xmonitor.range_status == VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK || prange_prev->xmonitor.range_status == VL53L1_DEVICEERROR_EVENTCONSISTENCY) { prange_curr->range_status = VL53L1_DEVICEERROR_RANGECOMPLETE; status = VL53L1_hist_events_consistency_check( event_sigma, min_spad_count, phist_prev, &(prange_prev->xmonitor), prange_curr, &events_tolerance, &events_delta, &(prange_curr->range_status)); } } return status; } VL53L1_Error VL53L1_hist_wrap_dmax( VL53L1_hist_post_process_config_t *phistpostprocess, VL53L1_histogram_bin_data_t *pcurrent, int16_t *pwrap_dmax_mm) { VL53L1_Error status = VL53L1_ERROR_NONE; uint32_t pll_period_mm = 0; uint32_t wrap_dmax_phase = 0; uint32_t range_mm = 0; LOG_FUNCTION_START(""); *pwrap_dmax_mm = 0; if (pcurrent->VL53L1_p_019 != 0) { pll_period_mm = VL53L1_calc_pll_period_mm( pcurrent->VL53L1_p_019); wrap_dmax_phase = (uint32_t)phistpostprocess->valid_phase_high << 8; range_mm = wrap_dmax_phase * pll_period_mm; range_mm = (range_mm + (1<<14)) >> 15; *pwrap_dmax_mm = (int16_t)range_mm; } LOG_FUNCTION_END(status); return status; } void VL53L1_hist_combine_mm1_mm2_offsets( int16_t mm1_offset_mm, int16_t mm2_offset_mm, uint8_t encoded_mm_roi_centre, uint8_t encoded_mm_roi_size, uint8_t encoded_zone_centre, uint8_t encoded_zone_size, VL53L1_additional_offset_cal_data_t *pcal_data, uint8_t *pgood_spads, uint16_t aperture_attenuation, int16_t *prange_offset_mm) { uint16_t max_mm_inner_effective_spads = 0; uint16_t max_mm_outer_effective_spads = 0; uint16_t mm_inner_effective_spads = 0; uint16_t mm_outer_effective_spads = 0; uint32_t scaled_mm1_peak_rate_mcps = 0; uint32_t scaled_mm2_peak_rate_mcps = 0; int32_t tmp0 = 0; int32_t tmp1 = 0; VL53L1_calc_mm_effective_spads( encoded_mm_roi_centre, encoded_mm_roi_size, 0xC7, 0xFF, pgood_spads, aperture_attenuation, &max_mm_inner_effective_spads, &max_mm_outer_effective_spads); if ((max_mm_inner_effective_spads == 0) || (max_mm_outer_effective_spads == 0)) goto FAIL; VL53L1_calc_mm_effective_spads( encoded_mm_roi_centre, encoded_mm_roi_size, encoded_zone_centre, encoded_zone_size, pgood_spads, aperture_attenuation, &mm_inner_effective_spads, &mm_outer_effective_spads); scaled_mm1_peak_rate_mcps = (uint32_t)pcal_data->result__mm_inner_peak_signal_count_rtn_mcps; scaled_mm1_peak_rate_mcps *= (uint32_t)mm_inner_effective_spads; scaled_mm1_peak_rate_mcps /= (uint32_t)max_mm_inner_effective_spads; scaled_mm2_peak_rate_mcps = (uint32_t)pcal_data->result__mm_outer_peak_signal_count_rtn_mcps; scaled_mm2_peak_rate_mcps *= (uint32_t)mm_outer_effective_spads; scaled_mm2_peak_rate_mcps /= (uint32_t)max_mm_outer_effective_spads; tmp0 = ((int32_t)mm1_offset_mm * (int32_t)scaled_mm1_peak_rate_mcps); tmp0 += ((int32_t)mm2_offset_mm * (int32_t)scaled_mm2_peak_rate_mcps); tmp1 = (int32_t)scaled_mm1_peak_rate_mcps + (int32_t)scaled_mm2_peak_rate_mcps; if (tmp1 != 0) tmp0 = (tmp0 * 4) / tmp1; FAIL: *prange_offset_mm = (int16_t)tmp0; } VL53L1_Error VL53L1_hist_xtalk_extract_calc_window( int16_t target_distance_mm, uint16_t target_width_oversize, VL53L1_histogram_bin_data_t *phist_bins, VL53L1_hist_xtalk_extract_data_t *pxtalk_data) { VL53L1_Error status = VL53L1_ERROR_NONE; LOG_FUNCTION_START(""); pxtalk_data->pll_period_mm = VL53L1_calc_pll_period_mm(phist_bins->VL53L1_p_019); pxtalk_data->xtalk_width_phase = (int32_t)phist_bins->vcsel_width * 128; pxtalk_data->target_width_phase = pxtalk_data->xtalk_width_phase + (int32_t)target_width_oversize * 128; pxtalk_data->xtalk_start_phase = (int32_t)phist_bins->zero_distance_phase - (pxtalk_data->xtalk_width_phase / 2); pxtalk_data->xtalk_end_phase = (int32_t)pxtalk_data->xtalk_start_phase + pxtalk_data->xtalk_width_phase; if (pxtalk_data->xtalk_start_phase < 0) pxtalk_data->xtalk_start_phase = 0; pxtalk_data->VL53L1_p_015 = (uint8_t)(pxtalk_data->xtalk_start_phase / 2048); pxtalk_data->VL53L1_p_016 = (uint8_t)((pxtalk_data->xtalk_end_phase + 2047) / 2048); pxtalk_data->target_start_phase = (int32_t)target_distance_mm * 2048 * 16; pxtalk_data->target_start_phase += ((int32_t)pxtalk_data->pll_period_mm / 2); pxtalk_data->target_start_phase /= (int32_t)pxtalk_data->pll_period_mm; pxtalk_data->target_start_phase += (int32_t)phist_bins->zero_distance_phase; pxtalk_data->target_start_phase -= (pxtalk_data->target_width_phase / 2); pxtalk_data->target_end_phase = (int32_t)pxtalk_data->target_start_phase + pxtalk_data->target_width_phase; if (pxtalk_data->target_start_phase < 0) pxtalk_data->target_start_phase = 0; pxtalk_data->target_start = (uint8_t)(pxtalk_data->target_start_phase / 2048); if (pxtalk_data->VL53L1_p_016 > (pxtalk_data->target_start-1)) pxtalk_data->VL53L1_p_016 = pxtalk_data->target_start-1; pxtalk_data->effective_width = (2048 * ((int32_t)pxtalk_data->VL53L1_p_016+1)); pxtalk_data->effective_width -= pxtalk_data->xtalk_start_phase; if (pxtalk_data->effective_width > pxtalk_data->xtalk_width_phase) pxtalk_data->effective_width = pxtalk_data->xtalk_width_phase; if (pxtalk_data->effective_width < 1) pxtalk_data->effective_width = 1; pxtalk_data->event_scaler = pxtalk_data->xtalk_width_phase * 1000; pxtalk_data->event_scaler += (pxtalk_data->effective_width / 2); pxtalk_data->event_scaler /= pxtalk_data->effective_width; if (pxtalk_data->event_scaler < 1000) pxtalk_data->event_scaler = 1000; if (pxtalk_data->event_scaler > 4000) pxtalk_data->event_scaler = 4000; pxtalk_data->event_scaler_sum += pxtalk_data->event_scaler; pxtalk_data->peak_duration_us_sum += (uint32_t)phist_bins->peak_duration_us; pxtalk_data->effective_spad_count_sum += (uint32_t)phist_bins->result__dss_actual_effective_spads; pxtalk_data->zero_distance_phase_sum += (uint32_t)phist_bins->zero_distance_phase; LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_hist_xtalk_extract_calc_event_sums( VL53L1_histogram_bin_data_t *phist_bins, VL53L1_hist_xtalk_extract_data_t *pxtalk_data) { VL53L1_Error status = VL53L1_ERROR_NONE; uint8_t lb = 0; uint8_t i = 0; LOG_FUNCTION_START(""); for (lb = pxtalk_data->VL53L1_p_015; lb <= pxtalk_data->VL53L1_p_016; lb++) { i = (lb + phist_bins->number_of_ambient_bins + phist_bins->VL53L1_p_024) % phist_bins->VL53L1_p_024; pxtalk_data->signal_events_sum += phist_bins->bin_data[i]; pxtalk_data->signal_events_sum -= phist_bins->VL53L1_p_004; } for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS && lb < phist_bins->VL53L1_p_024; lb++) { i = (lb + phist_bins->number_of_ambient_bins + phist_bins->VL53L1_p_024) % phist_bins->VL53L1_p_024; pxtalk_data->bin_data_sums[lb] += phist_bins->bin_data[i]; pxtalk_data->bin_data_sums[lb] -= phist_bins->VL53L1_p_004; } pxtalk_data->sample_count += 1; LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_hist_xtalk_extract_calc_rate_per_spad( VL53L1_hist_xtalk_extract_data_t *pxtalk_data) { VL53L1_Error status = VL53L1_ERROR_NONE; uint64_t tmp64_0 = 0; uint64_t tmp64_1 = 0; uint64_t xtalk_per_spad = 0; LOG_FUNCTION_START(""); if (pxtalk_data->signal_events_sum > 0) { tmp64_0 = ((uint64_t)pxtalk_data->signal_events_sum * (uint64_t)pxtalk_data->sample_count * (uint64_t)pxtalk_data->event_scaler_avg * 256U) << 9U; tmp64_1 = (uint64_t)pxtalk_data->effective_spad_count_sum * (uint64_t)pxtalk_data->peak_duration_us_sum; if (tmp64_1 > 0U) { tmp64_0 = tmp64_0 + (tmp64_1 >> 1U); xtalk_per_spad = do_division_u(tmp64_0, tmp64_1); } else { xtalk_per_spad = (uint64_t)tmp64_0; } } else { status = VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL; } pxtalk_data->xtalk_rate_kcps_per_spad = (uint32_t)xtalk_per_spad; LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_hist_xtalk_extract_calc_shape( VL53L1_hist_xtalk_extract_data_t *pxtalk_data, VL53L1_xtalk_histogram_shape_t *pxtalk_shape) { VL53L1_Error status = VL53L1_ERROR_NONE; int32_t lb = 0; uint64_t total_events = 0U; uint64_t tmp64_0 = 0U; int32_t remaining_area = 1024; LOG_FUNCTION_START(""); pxtalk_shape->VL53L1_p_022 = 0; pxtalk_shape->VL53L1_p_023 = VL53L1_XTALK_HISTO_BINS; pxtalk_shape->VL53L1_p_024 = VL53L1_XTALK_HISTO_BINS; pxtalk_shape->zero_distance_phase = (uint16_t)pxtalk_data->zero_distance_phase_avg; pxtalk_shape->phasecal_result__reference_phase = (uint16_t)pxtalk_data->zero_distance_phase_avg + (3*2048); if (pxtalk_data->signal_events_sum > 0) total_events = (uint64_t)pxtalk_data->signal_events_sum * (uint64_t)pxtalk_data->event_scaler_avg; else total_events = 1; if (total_events == 0) total_events = 1; remaining_area = 1024; pxtalk_data->max_shape_value = 0; for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS; lb++) { if ((lb < (int32_t)pxtalk_data->VL53L1_p_015 || lb > (int32_t)pxtalk_data->VL53L1_p_016) || pxtalk_data->bin_data_sums[lb] < 0) { if (remaining_area > 0 && remaining_area < 1024) { if (remaining_area > pxtalk_data->max_shape_value) { pxtalk_shape->bin_data[lb] = (uint32_t)pxtalk_data->max_shape_value; remaining_area -= pxtalk_data->max_shape_value; } else { pxtalk_shape->bin_data[lb] = (uint32_t)remaining_area; remaining_area = 0; } } else { pxtalk_shape->bin_data[lb] = 0; } } else { tmp64_0 = (uint64_t)pxtalk_data->bin_data_sums[lb] * 1024U * 1000U; tmp64_0 += (total_events >> 1); tmp64_0 = do_division_u(tmp64_0, total_events); if (tmp64_0 > 0xFFFFU) tmp64_0 = 0xFFFFU; pxtalk_shape->bin_data[lb] = (uint32_t)tmp64_0; if ((int32_t)pxtalk_shape->bin_data[lb] > pxtalk_data->max_shape_value) pxtalk_data->max_shape_value = (int32_t)pxtalk_shape->bin_data[lb]; remaining_area -= (int32_t)pxtalk_shape->bin_data[lb]; } } LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_hist_xtalk_shape_model( uint16_t events_per_bin, uint16_t pulse_centre, uint16_t pulse_width, VL53L1_xtalk_histogram_shape_t *pxtalk_shape) { VL53L1_Error status = VL53L1_ERROR_NONE; uint32_t phase_start = 0; uint32_t phase_stop = 0; uint32_t phase_bin = 0; uint32_t bin_start = 0; uint32_t bin_stop = 0; uint32_t lb = 0; uint16_t VL53L1_p_008 = 0; LOG_FUNCTION_START(""); pxtalk_shape->VL53L1_p_022 = 0; pxtalk_shape->VL53L1_p_023 = VL53L1_XTALK_HISTO_BINS; pxtalk_shape->VL53L1_p_024 = VL53L1_XTALK_HISTO_BINS; pxtalk_shape->zero_distance_phase = pulse_centre; pxtalk_shape->phasecal_result__reference_phase = pulse_centre + (3*2048); if (pulse_centre > (pulse_width >> 1)) phase_start = (uint32_t)pulse_centre - ((uint32_t)pulse_width >> 1); else phase_start = 0; phase_stop = (uint32_t)pulse_centre + ((uint32_t)pulse_width >> 1); bin_start = (phase_start / 2048); bin_stop = (phase_stop / 2048); for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS; lb++) { VL53L1_p_008 = 0; if (lb == bin_start && lb == bin_stop) { VL53L1_p_008 = VL53L1_hist_xtalk_shape_model_interp( events_per_bin, phase_stop - phase_start); } else if (lb > bin_start && lb < bin_stop) { VL53L1_p_008 = events_per_bin; } else if (lb == bin_start) { phase_bin = (lb + 1) * 2048; VL53L1_p_008 = VL53L1_hist_xtalk_shape_model_interp( events_per_bin, (phase_bin - phase_start)); } else if (lb == bin_stop) { phase_bin = lb * 2048; VL53L1_p_008 = VL53L1_hist_xtalk_shape_model_interp( events_per_bin, (phase_stop - phase_bin)); } pxtalk_shape->bin_data[lb] = VL53L1_p_008; } LOG_FUNCTION_END(status); return status; } uint16_t VL53L1_hist_xtalk_shape_model_interp( uint16_t events_per_bin, uint32_t phase_delta) { uint32_t VL53L1_p_008 = 0; LOG_FUNCTION_START(""); VL53L1_p_008 = (uint32_t)events_per_bin * phase_delta; VL53L1_p_008 += 1024; VL53L1_p_008 /= 2048; if (VL53L1_p_008 > 0xFFFFU) VL53L1_p_008 = 0xFFFFU; LOG_FUNCTION_END(0); return (uint16_t)VL53L1_p_008; } void VL53L1_spad_number_to_byte_bit_index( uint8_t spad_number, uint8_t *pbyte_index, uint8_t *pbit_index, uint8_t *pbit_mask) { *pbyte_index = spad_number >> 3; *pbit_index = spad_number & 0x07; *pbit_mask = 0x01 << *pbit_index; } void VL53L1_encode_row_col( uint8_t row, uint8_t col, uint8_t *pspad_number) { if (row > 7) *pspad_number = 128 + (col << 3) + (15-row); else *pspad_number = ((15-col) << 3) + row; } void VL53L1_decode_zone_size( uint8_t encoded_xy_size, uint8_t *pwidth, uint8_t *pheight) { *pheight = encoded_xy_size >> 4; *pwidth = encoded_xy_size & 0x0F; } void VL53L1_encode_zone_size( uint8_t width, uint8_t height, uint8_t *pencoded_xy_size) { *pencoded_xy_size = (height << 4) + width; } void VL53L1_decode_zone_limits( uint8_t encoded_xy_centre, uint8_t encoded_xy_size, int16_t *px_ll, int16_t *py_ll, int16_t *px_ur, int16_t *py_ur) { uint8_t x_centre = 0; uint8_t y_centre = 0; uint8_t width = 0; uint8_t height = 0; VL53L1_decode_row_col( encoded_xy_centre, &y_centre, &x_centre); VL53L1_decode_zone_size( encoded_xy_size, &width, &height); *px_ll = (int16_t)x_centre - ((int16_t)width + 1) / 2; if (*px_ll < 0) *px_ll = 0; *px_ur = *px_ll + (int16_t)width; if (*px_ur > (VL53L1_SPAD_ARRAY_WIDTH-1)) *px_ur = VL53L1_SPAD_ARRAY_WIDTH-1; *py_ll = (int16_t)y_centre - ((int16_t)height + 1) / 2; if (*py_ll < 0) *py_ll = 0; *py_ur = *py_ll + (int16_t)height; if (*py_ur > (VL53L1_SPAD_ARRAY_HEIGHT-1)) *py_ur = VL53L1_SPAD_ARRAY_HEIGHT-1; } uint8_t VL53L1_is_aperture_location( uint8_t row, uint8_t col) { uint8_t is_aperture = 0; uint8_t mod_row = row % 4; uint8_t mod_col = col % 4; if (mod_row == 0 && mod_col == 2) is_aperture = 1; if (mod_row == 2 && mod_col == 0) is_aperture = 1; return is_aperture; } void VL53L1_calc_max_effective_spads( uint8_t encoded_zone_centre, uint8_t encoded_zone_size, uint8_t *pgood_spads, uint16_t aperture_attenuation, uint16_t *pmax_effective_spads) { int16_t x = 0; int16_t y = 0; int16_t zone_x_ll = 0; int16_t zone_y_ll = 0; int16_t zone_x_ur = 0; int16_t zone_y_ur = 0; uint8_t spad_number = 0; uint8_t byte_index = 0; uint8_t bit_index = 0; uint8_t bit_mask = 0; uint8_t is_aperture = 0; VL53L1_decode_zone_limits( encoded_zone_centre, encoded_zone_size, &zone_x_ll, &zone_y_ll, &zone_x_ur, &zone_y_ur); *pmax_effective_spads = 0; for (y = zone_y_ll; y <= zone_y_ur; y++) { for (x = zone_x_ll; x <= zone_x_ur; x++) { VL53L1_encode_row_col( (uint8_t)y, (uint8_t)x, &spad_number); VL53L1_spad_number_to_byte_bit_index( spad_number, &byte_index, &bit_index, &bit_mask); if ((pgood_spads[byte_index] & bit_mask) > 0) { is_aperture = VL53L1_is_aperture_location( (uint8_t)y, (uint8_t)x); if (is_aperture > 0) *pmax_effective_spads += aperture_attenuation; else *pmax_effective_spads += 0x0100; } } } } void VL53L1_calc_mm_effective_spads( uint8_t encoded_mm_roi_centre, uint8_t encoded_mm_roi_size, uint8_t encoded_zone_centre, uint8_t encoded_zone_size, uint8_t *pgood_spads, uint16_t aperture_attenuation, uint16_t *pmm_inner_effective_spads, uint16_t *pmm_outer_effective_spads) { int16_t x = 0; int16_t y = 0; int16_t mm_x_ll = 0; int16_t mm_y_ll = 0; int16_t mm_x_ur = 0; int16_t mm_y_ur = 0; int16_t zone_x_ll = 0; int16_t zone_y_ll = 0; int16_t zone_x_ur = 0; int16_t zone_y_ur = 0; uint8_t spad_number = 0; uint8_t byte_index = 0; uint8_t bit_index = 0; uint8_t bit_mask = 0; uint8_t is_aperture = 0; uint16_t spad_attenuation = 0; VL53L1_decode_zone_limits( encoded_mm_roi_centre, encoded_mm_roi_size, &mm_x_ll, &mm_y_ll, &mm_x_ur, &mm_y_ur); VL53L1_decode_zone_limits( encoded_zone_centre, encoded_zone_size, &zone_x_ll, &zone_y_ll, &zone_x_ur, &zone_y_ur); *pmm_inner_effective_spads = 0; *pmm_outer_effective_spads = 0; for (y = zone_y_ll; y <= zone_y_ur; y++) { for (x = zone_x_ll; x <= zone_x_ur; x++) { VL53L1_encode_row_col( (uint8_t)y, (uint8_t)x, &spad_number); VL53L1_spad_number_to_byte_bit_index( spad_number, &byte_index, &bit_index, &bit_mask); if ((pgood_spads[byte_index] & bit_mask) > 0) { is_aperture = VL53L1_is_aperture_location( (uint8_t)y, (uint8_t)x); if (is_aperture > 0) spad_attenuation = aperture_attenuation; else spad_attenuation = 0x0100; if (x >= mm_x_ll && x <= mm_x_ur && y >= mm_y_ll && y <= mm_y_ur) *pmm_inner_effective_spads += spad_attenuation; else *pmm_outer_effective_spads += spad_attenuation; } } } } void VL53L1_hist_copy_results_to_sys_and_core( VL53L1_histogram_bin_data_t *pbins, VL53L1_range_results_t *phist, VL53L1_system_results_t *psys, VL53L1_core_results_t *pcore) { uint8_t i = 0; VL53L1_range_data_t *pdata; LOG_FUNCTION_START(""); VL53L1_init_system_results(psys); psys->result__interrupt_status = pbins->result__interrupt_status; psys->result__range_status = phist->active_results; psys->result__report_status = pbins->result__report_status; psys->result__stream_count = pbins->result__stream_count; pdata = &(phist->VL53L1_p_002[0]); for (i = 0; i < phist->active_results; i++) { switch (i) { case 0: psys->result__dss_actual_effective_spads_sd0 = pdata->VL53L1_p_006; psys->result__peak_signal_count_rate_mcps_sd0 = pdata->peak_signal_count_rate_mcps; psys->result__avg_signal_count_rate_mcps_sd0 = pdata->avg_signal_count_rate_mcps; psys->result__ambient_count_rate_mcps_sd0 = pdata->ambient_count_rate_mcps; psys->result__sigma_sd0 = pdata->VL53L1_p_005; psys->result__phase_sd0 = pdata->VL53L1_p_014; psys->result__final_crosstalk_corrected_range_mm_sd0 = (uint16_t)pdata->median_range_mm; psys->result__phase_sd1 = pdata->zero_distance_phase; pcore->result_core__ranging_total_events_sd0 = pdata->VL53L1_p_021; pcore->result_core__signal_total_events_sd0 = pdata->VL53L1_p_013; pcore->result_core__total_periods_elapsed_sd0 = pdata->total_periods_elapsed; pcore->result_core__ambient_window_events_sd0 = pdata->VL53L1_p_020; break; case 1: psys->result__dss_actual_effective_spads_sd1 = pdata->VL53L1_p_006; psys->result__peak_signal_count_rate_mcps_sd1 = pdata->peak_signal_count_rate_mcps; psys->result__ambient_count_rate_mcps_sd1 = pdata->ambient_count_rate_mcps; psys->result__sigma_sd1 = pdata->VL53L1_p_005; psys->result__phase_sd1 = pdata->VL53L1_p_014; psys->result__final_crosstalk_corrected_range_mm_sd1 = (uint16_t)pdata->median_range_mm; pcore->result_core__ranging_total_events_sd1 = pdata->VL53L1_p_021; pcore->result_core__signal_total_events_sd1 = pdata->VL53L1_p_013; pcore->result_core__total_periods_elapsed_sd1 = pdata->total_periods_elapsed; pcore->result_core__ambient_window_events_sd1 = pdata->VL53L1_p_020; break; } pdata++; } LOG_FUNCTION_END(0); } VL53L1_Error VL53L1_sum_histogram_data( VL53L1_histogram_bin_data_t *phist_input, VL53L1_histogram_bin_data_t *phist_output) { VL53L1_Error status = VL53L1_ERROR_NONE; uint8_t i = 0; uint8_t smallest_bin_num = 0; LOG_FUNCTION_START(""); if (status == VL53L1_ERROR_NONE) { if (phist_output->VL53L1_p_024 >= phist_input->VL53L1_p_024) smallest_bin_num = phist_input->VL53L1_p_024; else smallest_bin_num = phist_output->VL53L1_p_024; } if (status == VL53L1_ERROR_NONE) for (i = 0; i < smallest_bin_num; i++) phist_output->bin_data[i] += phist_input->bin_data[i]; if (status == VL53L1_ERROR_NONE) phist_output->VL53L1_p_004 += phist_input->VL53L1_p_004; LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_avg_histogram_data( uint8_t no_of_samples, VL53L1_histogram_bin_data_t *phist_sum, VL53L1_histogram_bin_data_t *phist_avg) { VL53L1_Error status = VL53L1_ERROR_NONE; uint8_t i = 0; LOG_FUNCTION_START(""); if (status == VL53L1_ERROR_NONE) { for (i = 0; i < phist_sum->VL53L1_p_024; i++) { if (no_of_samples > 0) phist_avg->bin_data[i] = phist_sum->bin_data[i] / (int32_t)no_of_samples; else phist_avg->bin_data[i] = phist_sum->bin_data[i]; } } if (status == VL53L1_ERROR_NONE) { if (no_of_samples > 0) phist_avg->VL53L1_p_004 = phist_sum->VL53L1_p_004 / (int32_t)no_of_samples; else phist_avg->VL53L1_p_004 = phist_sum->VL53L1_p_004; } LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_save_cfg_data( VL53L1_DEV Dev) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg; VL53L1_dynamic_config_t *pdynamic = &(pdev->dyn_cfg); LOG_FUNCTION_START(""); pzone_dyn_cfg = &(pres->zone_dyn_cfgs.VL53L1_p_002[pdev->ll_state.cfg_zone_id]); pzone_dyn_cfg->expected_stream_count = pdev->ll_state.cfg_stream_count; pzone_dyn_cfg->expected_gph_id = pdev->ll_state.cfg_gph_id; pzone_dyn_cfg->roi_config__user_roi_centre_spad = pdynamic->roi_config__user_roi_centre_spad; pzone_dyn_cfg->roi_config__user_roi_requested_global_xy_size = pdynamic->roi_config__user_roi_requested_global_xy_size; LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_dynamic_zone_update( VL53L1_DEV Dev, VL53L1_range_results_t *presults) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); VL53L1_zone_private_dyn_cfgs_t *pZ = &(pres->zone_dyn_cfgs); uint8_t zone_id = pdev->ll_state.rd_zone_id; uint8_t i; uint16_t max_total_rate_per_spads; uint16_t target_rate = pdev->stat_cfg.dss_config__target_total_rate_mcps; uint32_t temp = 0xFFFF; #ifdef VL53L1_LOG_ENABLE uint16_t eff_spad_cnt = pZ->VL53L1_p_002[zone_id].dss_requested_effective_spad_count; #endif LOG_FUNCTION_START(""); pZ->VL53L1_p_002[zone_id].dss_requested_effective_spad_count = 0; trace_print(VL53L1_TRACE_LEVEL_DEBUG, " DYNZONEUPDATE: peak signal count rate mcps:"); trace_print(VL53L1_TRACE_LEVEL_DEBUG, "%u actual effective spads: %u\n", presults->VL53L1_p_002[0].peak_signal_count_rate_mcps, presults->VL53L1_p_002[0].VL53L1_p_006); trace_print(VL53L1_TRACE_LEVEL_DEBUG, " DYNZONEUPDATE: active results: %u\n", presults->active_results); max_total_rate_per_spads = presults->VL53L1_p_002[0].total_rate_per_spad_mcps; trace_print(VL53L1_TRACE_LEVEL_DEBUG, " DYNZONEUPDATE: max total rate per spad at start: %u\n", max_total_rate_per_spads); for (i = 1; i < presults->active_results; i++) { trace_print(VL53L1_TRACE_LEVEL_DEBUG, " DYNZONEUPDATE: zone total rate per spad: zone_id: %u,", i); trace_print(VL53L1_TRACE_LEVEL_DEBUG, "total rate per spad: %u\n", presults->VL53L1_p_002[i].total_rate_per_spad_mcps); if (presults->VL53L1_p_002[i].total_rate_per_spad_mcps > max_total_rate_per_spads) max_total_rate_per_spads = presults->VL53L1_p_002[i].total_rate_per_spad_mcps; } if (max_total_rate_per_spads == 0) { temp = 0xFFFF; } else { temp = target_rate << 14; trace_print(VL53L1_TRACE_LEVEL_DEBUG, " DYNZONEUPDATE: 1: temp: %u\n", temp); temp = temp / max_total_rate_per_spads; trace_print(VL53L1_TRACE_LEVEL_DEBUG, " DYNZONEUPDATE: 2: temp: %u\n", temp); if (temp > 0xFFFF) temp = 0xFFFF; trace_print(VL53L1_TRACE_LEVEL_DEBUG, " DYNZONEUPDATE: 3: temp: %u\n", temp); } pZ->VL53L1_p_002[zone_id].dss_requested_effective_spad_count = (uint16_t)temp; trace_print(VL53L1_TRACE_LEVEL_DEBUG, " DYNZONEUPDATE: zone_id: %u, target_rate: %u,", zone_id, target_rate); trace_print(VL53L1_TRACE_LEVEL_DEBUG, "max_total_rate_per_spads: %u, requested_spads: %u\n", max_total_rate_per_spads, eff_spad_cnt); LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_multizone_hist_bins_update( VL53L1_DEV Dev) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); VL53L1_zone_config_t *pzone_cfg = &(pdev->zone_cfg); VL53L1_histogram_config_t *phist_cfg = &(pdev->hist_cfg); VL53L1_histogram_config_t *pmulti_hist = &(pzone_cfg->multizone_hist_cfg); uint8_t next_range_is_odd_timing = (pstate->cfg_stream_count) % 2; LOG_FUNCTION_START(""); if (pzone_cfg->bin_config[pdev->ll_state.cfg_zone_id] == VL53L1_ZONECONFIG_BINCONFIG__LOWAMB) { if (!next_range_is_odd_timing) { trace_print (VL53L1_TRACE_LEVEL_DEBUG, " HISTBINCONFIGUPDATE: Setting LOWAMB EVEN timing\n"); phist_cfg->histogram_config__low_amb_even_bin_0_1 = pmulti_hist->histogram_config__low_amb_even_bin_0_1; phist_cfg->histogram_config__low_amb_even_bin_2_3 = pmulti_hist->histogram_config__low_amb_even_bin_2_3; phist_cfg->histogram_config__low_amb_even_bin_4_5 = pmulti_hist->histogram_config__low_amb_even_bin_4_5; } if (next_range_is_odd_timing) { trace_print (VL53L1_TRACE_LEVEL_DEBUG, " HISTBINCONFIGUPDATE: Setting LOWAMB ODD timing\n"); phist_cfg->histogram_config__low_amb_odd_bin_0_1 = pmulti_hist->histogram_config__low_amb_even_bin_0_1; phist_cfg->histogram_config__low_amb_odd_bin_2_3 = pmulti_hist->histogram_config__low_amb_even_bin_2_3; phist_cfg->histogram_config__low_amb_odd_bin_4_5 = pmulti_hist->histogram_config__low_amb_even_bin_4_5; } } else if (pzone_cfg->bin_config[pdev->ll_state.cfg_zone_id] == VL53L1_ZONECONFIG_BINCONFIG__MIDAMB) { trace_print (VL53L1_TRACE_LEVEL_DEBUG, " HISTBINCONFIGUPDATE: Setting MIDAMB timing\n"); if (!next_range_is_odd_timing) { trace_print(VL53L1_TRACE_LEVEL_DEBUG, " HISTBINCONFIGUPDATE: Setting MIDAMB EVEN timing\n"); phist_cfg->histogram_config__low_amb_even_bin_0_1 = pmulti_hist->histogram_config__mid_amb_even_bin_0_1; phist_cfg->histogram_config__low_amb_even_bin_2_3 = pmulti_hist->histogram_config__mid_amb_even_bin_2_3; phist_cfg->histogram_config__low_amb_even_bin_4_5 = pmulti_hist->histogram_config__mid_amb_even_bin_4_5; } if (next_range_is_odd_timing) { trace_print (VL53L1_TRACE_LEVEL_DEBUG, " HISTBINCONFIGUPDATE: Setting MIDAMB ODD timing\n"); phist_cfg->histogram_config__low_amb_odd_bin_0_1 = pmulti_hist->histogram_config__mid_amb_even_bin_0_1; phist_cfg->histogram_config__low_amb_odd_bin_2_3 = pmulti_hist->histogram_config__mid_amb_even_bin_2_3; phist_cfg->histogram_config__low_amb_odd_bin_4_5 = pmulti_hist->histogram_config__mid_amb_even_bin_4_5; } } else if (pzone_cfg->bin_config[pdev->ll_state.cfg_zone_id] == VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB) { if (!next_range_is_odd_timing) { trace_print (VL53L1_TRACE_LEVEL_DEBUG, " HISTBINCONFIGUPDATE: Setting HIGHAMB EVEN timing\n" ); phist_cfg->histogram_config__low_amb_even_bin_0_1 = pmulti_hist->histogram_config__high_amb_even_bin_0_1; phist_cfg->histogram_config__low_amb_even_bin_2_3 = pmulti_hist->histogram_config__high_amb_even_bin_2_3; phist_cfg->histogram_config__low_amb_even_bin_4_5 = pmulti_hist->histogram_config__high_amb_even_bin_4_5; } if (next_range_is_odd_timing) { trace_print (VL53L1_TRACE_LEVEL_DEBUG, " HISTBINCONFIGUPDATE: Setting HIGHAMB ODD timing\n"); phist_cfg->histogram_config__low_amb_odd_bin_0_1 = pmulti_hist->histogram_config__high_amb_even_bin_0_1; phist_cfg->histogram_config__low_amb_odd_bin_2_3 = pmulti_hist->histogram_config__high_amb_even_bin_2_3; phist_cfg->histogram_config__low_amb_odd_bin_4_5 = pmulti_hist->histogram_config__high_amb_even_bin_4_5; } } if (status == VL53L1_ERROR_NONE) { VL53L1_copy_hist_bins_to_static_cfg( phist_cfg, &(pdev->stat_cfg), &(pdev->tim_cfg)); } LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_update_internal_stream_counters( VL53L1_DEV Dev, uint8_t external_stream_count, uint8_t *pinternal_stream_count, uint8_t *pinternal_stream_count_val) { VL53L1_Error status = VL53L1_ERROR_NONE; uint8_t stream_divider; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); LOG_FUNCTION_START(""); stream_divider = pdev->gen_cfg.global_config__stream_divider; if (stream_divider == 0) { *pinternal_stream_count = external_stream_count; } else if (*pinternal_stream_count_val == (stream_divider-1)) { if (*pinternal_stream_count == 0xFF) *pinternal_stream_count = 0x80; else *pinternal_stream_count = *pinternal_stream_count + 1; *pinternal_stream_count_val = 0; } else { *pinternal_stream_count_val = *pinternal_stream_count_val + 1; } trace_print(VL53L1_TRACE_LEVEL_DEBUG, "UPDINTSTREAMCOUNT internal_steam_count: %d,", *pinternal_stream_count); trace_print(VL53L1_TRACE_LEVEL_DEBUG, "internal_stream_count_val: %d, divider: %d\n", *pinternal_stream_count_val, stream_divider); LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_set_histogram_multizone_initial_bin_config( VL53L1_zone_config_t *pzone_cfg, VL53L1_histogram_config_t *phist_cfg, VL53L1_histogram_config_t *pmulti_hist) { VL53L1_Error status = VL53L1_ERROR_NONE; LOG_FUNCTION_START(""); if (pzone_cfg->bin_config[0] == VL53L1_ZONECONFIG_BINCONFIG__LOWAMB) { phist_cfg->histogram_config__low_amb_even_bin_0_1 = pmulti_hist->histogram_config__low_amb_even_bin_0_1; phist_cfg->histogram_config__low_amb_even_bin_2_3 = pmulti_hist->histogram_config__low_amb_even_bin_2_3; phist_cfg->histogram_config__low_amb_even_bin_4_5 = pmulti_hist->histogram_config__low_amb_even_bin_4_5; phist_cfg->histogram_config__low_amb_odd_bin_0_1 = pmulti_hist->histogram_config__low_amb_even_bin_0_1; phist_cfg->histogram_config__low_amb_odd_bin_2_3 = pmulti_hist->histogram_config__low_amb_even_bin_2_3; phist_cfg->histogram_config__low_amb_odd_bin_4_5 = pmulti_hist->histogram_config__low_amb_even_bin_4_5; } else if (pzone_cfg->bin_config[0] == VL53L1_ZONECONFIG_BINCONFIG__MIDAMB) { phist_cfg->histogram_config__low_amb_even_bin_0_1 = pmulti_hist->histogram_config__mid_amb_even_bin_0_1; phist_cfg->histogram_config__low_amb_even_bin_2_3 = pmulti_hist->histogram_config__mid_amb_even_bin_2_3; phist_cfg->histogram_config__low_amb_even_bin_4_5 = pmulti_hist->histogram_config__mid_amb_even_bin_4_5; phist_cfg->histogram_config__low_amb_odd_bin_0_1 = pmulti_hist->histogram_config__mid_amb_even_bin_0_1; phist_cfg->histogram_config__low_amb_odd_bin_2_3 = pmulti_hist->histogram_config__mid_amb_even_bin_2_3; phist_cfg->histogram_config__low_amb_odd_bin_4_5 = pmulti_hist->histogram_config__mid_amb_even_bin_4_5; } else if (pzone_cfg->bin_config[0] == VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB) { phist_cfg->histogram_config__low_amb_even_bin_0_1 = pmulti_hist->histogram_config__high_amb_even_bin_0_1; phist_cfg->histogram_config__low_amb_even_bin_2_3 = pmulti_hist->histogram_config__high_amb_even_bin_2_3; phist_cfg->histogram_config__low_amb_even_bin_4_5 = pmulti_hist->histogram_config__high_amb_even_bin_4_5; phist_cfg->histogram_config__low_amb_odd_bin_0_1 = pmulti_hist->histogram_config__high_amb_even_bin_0_1; phist_cfg->histogram_config__low_amb_odd_bin_2_3 = pmulti_hist->histogram_config__high_amb_even_bin_2_3; phist_cfg->histogram_config__low_amb_odd_bin_4_5 = pmulti_hist->histogram_config__high_amb_even_bin_4_5; } LOG_FUNCTION_END(status); return status; } uint8_t VL53L1_encode_GPIO_interrupt_config( VL53L1_GPIO_interrupt_config_t *pintconf) { uint8_t system__interrupt_config; system__interrupt_config = pintconf->intr_mode_distance; system__interrupt_config |= ((pintconf->intr_mode_rate) << 2); system__interrupt_config |= ((pintconf->intr_new_measure_ready) << 5); system__interrupt_config |= ((pintconf->intr_no_target) << 6); system__interrupt_config |= ((pintconf->intr_combined_mode) << 7); return system__interrupt_config; } VL53L1_GPIO_interrupt_config_t VL53L1_decode_GPIO_interrupt_config( uint8_t system__interrupt_config) { VL53L1_GPIO_interrupt_config_t intconf; intconf.intr_mode_distance = system__interrupt_config & 0x03; intconf.intr_mode_rate = (system__interrupt_config >> 2) & 0x03; intconf.intr_new_measure_ready = (system__interrupt_config >> 5) & 0x01; intconf.intr_no_target = (system__interrupt_config >> 6) & 0x01; intconf.intr_combined_mode = (system__interrupt_config >> 7) & 0x01; intconf.threshold_rate_low = 0; intconf.threshold_rate_high = 0; intconf.threshold_distance_low = 0; intconf.threshold_distance_high = 0; return intconf; } VL53L1_Error VL53L1_set_GPIO_distance_threshold( VL53L1_DEV Dev, uint16_t threshold_high, uint16_t threshold_low) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); LOG_FUNCTION_START(""); pdev->dyn_cfg.system__thresh_high = threshold_high; pdev->dyn_cfg.system__thresh_low = threshold_low; LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_set_GPIO_rate_threshold( VL53L1_DEV Dev, uint16_t threshold_high, uint16_t threshold_low) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); LOG_FUNCTION_START(""); pdev->gen_cfg.system__thresh_rate_high = threshold_high; pdev->gen_cfg.system__thresh_rate_low = threshold_low; LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_set_GPIO_thresholds_from_struct( VL53L1_DEV Dev, VL53L1_GPIO_interrupt_config_t *pintconf) { VL53L1_Error status = VL53L1_ERROR_NONE; LOG_FUNCTION_START(""); status = VL53L1_set_GPIO_distance_threshold( Dev, pintconf->threshold_distance_high, pintconf->threshold_distance_low); if (status == VL53L1_ERROR_NONE) { status = VL53L1_set_GPIO_rate_threshold( Dev, pintconf->threshold_rate_high, pintconf->threshold_rate_low); } LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_set_ref_spad_char_config( VL53L1_DEV Dev, uint8_t vcsel_period_a, uint32_t phasecal_timeout_us, uint16_t total_rate_target_mcps, uint16_t max_count_rate_rtn_limit_mcps, uint16_t min_count_rate_rtn_limit_mcps, uint16_t fast_osc_frequency) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); uint8_t buffer[2]; uint32_t macro_period_us = 0; uint32_t timeout_mclks = 0; LOG_FUNCTION_START(""); macro_period_us = VL53L1_calc_macro_period_us( fast_osc_frequency, vcsel_period_a); timeout_mclks = phasecal_timeout_us << 12; timeout_mclks = timeout_mclks + (macro_period_us>>1); timeout_mclks = timeout_mclks / macro_period_us; if (timeout_mclks > 0xFF) pdev->gen_cfg.phasecal_config__timeout_macrop = 0xFF; else pdev->gen_cfg.phasecal_config__timeout_macrop = (uint8_t)timeout_mclks; pdev->tim_cfg.range_config__vcsel_period_a = vcsel_period_a; if (status == VL53L1_ERROR_NONE) status = VL53L1_WrByte( Dev, VL53L1_PHASECAL_CONFIG__TIMEOUT_MACROP, pdev->gen_cfg.phasecal_config__timeout_macrop); if (status == VL53L1_ERROR_NONE) status = VL53L1_WrByte( Dev, VL53L1_RANGE_CONFIG__VCSEL_PERIOD_A, pdev->tim_cfg.range_config__vcsel_period_a); buffer[0] = pdev->tim_cfg.range_config__vcsel_period_a; buffer[1] = pdev->tim_cfg.range_config__vcsel_period_a; if (status == VL53L1_ERROR_NONE) status = VL53L1_WriteMulti( Dev, VL53L1_SD_CONFIG__WOI_SD0, buffer, 2); pdev->customer.ref_spad_char__total_rate_target_mcps = total_rate_target_mcps; if (status == VL53L1_ERROR_NONE) status = VL53L1_WrWord( Dev, VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS, total_rate_target_mcps); if (status == VL53L1_ERROR_NONE) status = VL53L1_WrWord( Dev, VL53L1_RANGE_CONFIG__SIGMA_THRESH, max_count_rate_rtn_limit_mcps); if (status == VL53L1_ERROR_NONE) status = VL53L1_WrWord( Dev, VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS, min_count_rate_rtn_limit_mcps); LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_set_ssc_config( VL53L1_DEV Dev, VL53L1_ssc_config_t *pssc_cfg, uint16_t fast_osc_frequency) { VL53L1_Error status = VL53L1_ERROR_NONE; uint8_t buffer[5]; uint32_t macro_period_us = 0; uint16_t timeout_encoded = 0; LOG_FUNCTION_START(""); macro_period_us = VL53L1_calc_macro_period_us( fast_osc_frequency, pssc_cfg->VL53L1_p_009); timeout_encoded = VL53L1_calc_encoded_timeout( pssc_cfg->timeout_us, macro_period_us); if (status == VL53L1_ERROR_NONE) status = VL53L1_WrByte( Dev, VL53L1_CAL_CONFIG__VCSEL_START, pssc_cfg->vcsel_start); if (status == VL53L1_ERROR_NONE) status = VL53L1_WrByte( Dev, VL53L1_GLOBAL_CONFIG__VCSEL_WIDTH, pssc_cfg->vcsel_width); buffer[0] = (uint8_t)((timeout_encoded & 0x0000FF00) >> 8); buffer[1] = (uint8_t) (timeout_encoded & 0x000000FF); buffer[2] = pssc_cfg->VL53L1_p_009; buffer[3] = (uint8_t)((pssc_cfg->rate_limit_mcps & 0x0000FF00) >> 8); buffer[4] = (uint8_t) (pssc_cfg->rate_limit_mcps & 0x000000FF); if (status == VL53L1_ERROR_NONE) status = VL53L1_WriteMulti( Dev, VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_B_HI, buffer, 5); buffer[0] = pssc_cfg->VL53L1_p_009; buffer[1] = pssc_cfg->VL53L1_p_009; if (status == VL53L1_ERROR_NONE) status = VL53L1_WriteMulti( Dev, VL53L1_SD_CONFIG__WOI_SD0, buffer, 2); if (status == VL53L1_ERROR_NONE) status = VL53L1_WrByte( Dev, VL53L1_NVM_BIST__CTRL, pssc_cfg->array_select); LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_get_spad_rate_data( VL53L1_DEV Dev, VL53L1_spad_rate_data_t *pspad_rates) { VL53L1_Error status = VL53L1_ERROR_NONE; int i = 0; uint8_t VL53L1_p_002[512]; uint8_t *pdata = &VL53L1_p_002[0]; LOG_FUNCTION_START(""); if (status == VL53L1_ERROR_NONE) status = VL53L1_disable_firmware(Dev); if (status == VL53L1_ERROR_NONE) status = VL53L1_ReadMulti( Dev, VL53L1_PRIVATE__PATCH_BASE_ADDR_RSLV, pdata, 512); pdata = &VL53L1_p_002[0]; for (i = 0; i < VL53L1_NO_OF_SPAD_ENABLES; i++) { pspad_rates->rate_data[i] = (uint16_t)VL53L1_decode_unsigned_integer(pdata, 2); pdata += 2; } pspad_rates->VL53L1_p_023 = VL53L1_NO_OF_SPAD_ENABLES; pspad_rates->no_of_values = VL53L1_NO_OF_SPAD_ENABLES; pspad_rates->fractional_bits = 15; if (status == VL53L1_ERROR_NONE) status = VL53L1_enable_firmware(Dev); LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_required_samples( VL53L1_DEV Dev ) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); VL53L1_smudge_corrector_config_t *pconfig = &(pdev->smudge_correct_config); VL53L1_smudge_corrector_internals_t *pint = &(pdev->smudge_corrector_internals); VL53L1_range_results_t *presults = &(pres->range_results); VL53L1_range_data_t *pxmonitor = &(presults->xmonitor); uint32_t peak_duration_us = pxmonitor->peak_duration_us; uint64_t temp64a; uint64_t temp64z; LOG_FUNCTION_START(""); if (peak_duration_us == 0) peak_duration_us = 1000; temp64a = pxmonitor->VL53L1_p_021 + pxmonitor->VL53L1_p_020; temp64a = do_division_u((temp64a * 1000), peak_duration_us); temp64a = do_division_u((temp64a * 1000), peak_duration_us); temp64z = pconfig->noise_margin * pxmonitor->VL53L1_p_006; if (temp64z == 0) temp64z = 1; temp64a = temp64a * 1000 * 256; temp64a = do_division_u(temp64a, temp64z); temp64a = temp64a * 1000 * 256; temp64a = do_division_u(temp64a, temp64z); pint->required_samples = (uint32_t)temp64a; if (pint->required_samples < 2) pint->required_samples = 2; LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_new_xtalk( VL53L1_DEV Dev, uint32_t xtalk_offset_out, VL53L1_smudge_corrector_config_t *pconfig, VL53L1_smudge_corrector_data_t *pout, uint8_t add_smudge, uint8_t soft_update ) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); int16_t x_gradient_scaler; int16_t y_gradient_scaler; uint32_t orig_xtalk_offset; int16_t orig_x_gradient; int16_t orig_y_gradient; uint8_t histo_merge_nb; uint8_t i; int32_t itemp32; uint32_t SmudgeFactor; VL53L1_xtalk_config_t *pX = &(pdev->xtalk_cfg); VL53L1_xtalk_calibration_results_t *pC = &(pdev->xtalk_cal); uint32_t *pcpo; uint32_t max, nXtalk, cXtalk; uint8_t merge_enabled; LOG_FUNCTION_START(""); merge_enabled = (pdev->tuning_parms.tp_hist_merge == 1) && (VL53L1DevDataGet(Dev, CurrentParameters.PresetMode) == VL53L1_PRESETMODE_RANGING); if (add_smudge == 1) { pout->algo__crosstalk_compensation_plane_offset_kcps = (uint32_t)xtalk_offset_out + (uint32_t)pconfig->smudge_margin; } else { pout->algo__crosstalk_compensation_plane_offset_kcps = (uint32_t)xtalk_offset_out; } orig_xtalk_offset = pX->nvm_default__crosstalk_compensation_plane_offset_kcps; orig_x_gradient = pX->nvm_default__crosstalk_compensation_x_plane_gradient_kcps; orig_y_gradient = pX->nvm_default__crosstalk_compensation_y_plane_gradient_kcps; if (((pconfig->user_scaler_set == 0) || (pconfig->scaler_calc_method == 1)) && (pC->algo__crosstalk_compensation_plane_offset_kcps != 0)) { VL53L1_compute_histo_merge_nb(Dev, &histo_merge_nb); if (histo_merge_nb == 0) histo_merge_nb = 1; if (!merge_enabled) orig_xtalk_offset = pC->algo__crosstalk_compensation_plane_offset_kcps; else orig_xtalk_offset = pC->algo__xtalk_cpo_HistoMerge_kcps[histo_merge_nb-1]; orig_x_gradient = pC->algo__crosstalk_compensation_x_plane_gradient_kcps; orig_y_gradient = pC->algo__crosstalk_compensation_y_plane_gradient_kcps; } if ((pconfig->user_scaler_set == 0) && (orig_x_gradient == 0)) pout->gradient_zero_flag |= 0x01; if ((pconfig->user_scaler_set == 0) && (orig_y_gradient == 0)) pout->gradient_zero_flag |= 0x02; if (orig_xtalk_offset == 0) orig_xtalk_offset = 1; if (pconfig->user_scaler_set == 1) { x_gradient_scaler = pconfig->x_gradient_scaler; y_gradient_scaler = pconfig->y_gradient_scaler; } else { x_gradient_scaler = (int16_t)do_division_s( (((int32_t)orig_x_gradient) << 6), orig_xtalk_offset); pconfig->x_gradient_scaler = x_gradient_scaler; y_gradient_scaler = (int16_t)do_division_s( (((int32_t)orig_y_gradient) << 6), orig_xtalk_offset); pconfig->y_gradient_scaler = y_gradient_scaler; } if (pconfig->scaler_calc_method == 0) { itemp32 = (int32_t)( pout->algo__crosstalk_compensation_plane_offset_kcps * x_gradient_scaler); itemp32 = itemp32 >> 6; if (itemp32 > 0xFFFF) itemp32 = 0xFFFF; pout->algo__crosstalk_compensation_x_plane_gradient_kcps = (int16_t)itemp32; itemp32 = (int32_t)( pout->algo__crosstalk_compensation_plane_offset_kcps * y_gradient_scaler); itemp32 = itemp32 >> 6; if (itemp32 > 0xFFFF) itemp32 = 0xFFFF; pout->algo__crosstalk_compensation_y_plane_gradient_kcps = (int16_t)itemp32; } else if (pconfig->scaler_calc_method == 1) { itemp32 = (int32_t)(orig_xtalk_offset - pout->algo__crosstalk_compensation_plane_offset_kcps); itemp32 = (int32_t)(do_division_s(itemp32, 16)); itemp32 = itemp32 << 2; itemp32 = itemp32 + (int32_t)(orig_x_gradient); if (itemp32 > 0xFFFF) itemp32 = 0xFFFF; pout->algo__crosstalk_compensation_x_plane_gradient_kcps = (int16_t)itemp32; itemp32 = (int32_t)(orig_xtalk_offset - pout->algo__crosstalk_compensation_plane_offset_kcps); itemp32 = (int32_t)(do_division_s(itemp32, 80)); itemp32 = itemp32 << 2; itemp32 = itemp32 + (int32_t)(orig_y_gradient); if (itemp32 > 0xFFFF) itemp32 = 0xFFFF; pout->algo__crosstalk_compensation_y_plane_gradient_kcps = (int16_t)itemp32; } if (pconfig->smudge_corr_apply_enabled == 1 && (soft_update != 1)) { pout->new_xtalk_applied_flag = 1; nXtalk = pout->algo__crosstalk_compensation_plane_offset_kcps; VL53L1_compute_histo_merge_nb(Dev, &histo_merge_nb); max = pdev->tuning_parms.tp_hist_merge_max_size; pcpo = &(pC->algo__xtalk_cpo_HistoMerge_kcps[0]); if ((histo_merge_nb > 0) && merge_enabled && (nXtalk != 0)) { cXtalk = pC->algo__xtalk_cpo_HistoMerge_kcps[histo_merge_nb-1]; SmudgeFactor = cXtalk * 1000 / nXtalk; if (SmudgeFactor >= pconfig->max_smudge_factor) pout->new_xtalk_applied_flag = 0; else if (SmudgeFactor > 0) for (i = 0; i < max; i++) { *pcpo *= 1000; *pcpo /= SmudgeFactor; pcpo++; } } if (pout->new_xtalk_applied_flag) { pX->algo__crosstalk_compensation_plane_offset_kcps = pout->algo__crosstalk_compensation_plane_offset_kcps; pX->algo__crosstalk_compensation_x_plane_gradient_kcps = pout->algo__crosstalk_compensation_x_plane_gradient_kcps; pX->algo__crosstalk_compensation_y_plane_gradient_kcps = pout->algo__crosstalk_compensation_y_plane_gradient_kcps; if (pconfig->smudge_corr_single_apply == 1) { pconfig->smudge_corr_apply_enabled = 0; pconfig->smudge_corr_single_apply = 0; } } } if (soft_update != 1) pout->smudge_corr_valid = 1; LOG_FUNCTION_END(status); return status; } #define CONT_CONTINUE 0 #define CONT_NEXT_LOOP 1 #define CONT_RESET 2 VL53L1_Error VL53L1_dynamic_xtalk_correction_corrector( VL53L1_DEV Dev ) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); VL53L1_smudge_corrector_config_t *pconfig = &(pdev->smudge_correct_config); VL53L1_smudge_corrector_internals_t *pint = &(pdev->smudge_corrector_internals); VL53L1_smudge_corrector_data_t *pout = &(pres->range_results.smudge_corrector_data); VL53L1_range_results_t *pR = &(pres->range_results); VL53L1_xtalk_config_t *pX = &(pdev->xtalk_cfg); uint8_t run_smudge_detection = 0; uint8_t merging_complete = 0; uint8_t run_nodetect = 0; uint8_t ambient_check = 0; int32_t itemp32 = 0; uint64_t utemp64 = 0; uint8_t continue_processing = CONT_CONTINUE; uint32_t xtalk_offset_out = 0; uint32_t xtalk_offset_in = 0; uint32_t current_xtalk = 0; uint32_t smudge_margin_adjusted = 0; uint8_t i = 0; uint8_t nodetect_index = 0; uint16_t amr; uint32_t cco; uint8_t histo_merge_nb; uint8_t merge_enabled; LOG_FUNCTION_START(""); merge_enabled = (pdev->tuning_parms.tp_hist_merge == 1) && (VL53L1DevDataGet(Dev, CurrentParameters.PresetMode) == VL53L1_PRESETMODE_RANGING); VL53L1_compute_histo_merge_nb(Dev, &histo_merge_nb); if ((histo_merge_nb == 0) || (!merge_enabled)) histo_merge_nb = 1; VL53L1_dynamic_xtalk_correction_output_init(pres); ambient_check = (pconfig->smudge_corr_ambient_threshold == 0) || ((pconfig->smudge_corr_ambient_threshold * histo_merge_nb) > ((uint32_t)pR->xmonitor.ambient_count_rate_mcps)); merging_complete = ((!merge_enabled) || (histo_merge_nb == pdev->tuning_parms.tp_hist_merge_max_size)); run_smudge_detection = (pconfig->smudge_corr_enabled == 1) && ambient_check && (pR->xmonitor.range_status == VL53L1_DEVICEERROR_RANGECOMPLETE) && merging_complete; if ((pR->xmonitor.range_status != VL53L1_DEVICEERROR_RANGECOMPLETE) && (pconfig->smudge_corr_enabled == 1)) { run_nodetect = 2; for (i = 0; i < pR->active_results; i++) { if (pR->VL53L1_p_002[i].range_status == VL53L1_DEVICEERROR_RANGECOMPLETE) { if (pR->VL53L1_p_002[i].median_range_mm <= pconfig->nodetect_min_range_mm) { run_nodetect = 0; } else { if (run_nodetect == 2) { run_nodetect = 1; nodetect_index = i; } } } } if (run_nodetect == 2) run_nodetect = 0; amr = pR->VL53L1_p_002[nodetect_index].ambient_count_rate_mcps; if (run_nodetect == 1) { utemp64 = 1000 * ((uint64_t)amr); utemp64 = utemp64 << 9; if (utemp64 < pconfig->nodetect_ambient_threshold) run_nodetect = 1; else run_nodetect = 0; } } if (run_smudge_detection) { pint->nodetect_counter = 0; VL53L1_dynamic_xtalk_correction_calc_required_samples(Dev); xtalk_offset_in = pR->xmonitor.VL53L1_p_012; cco = pX->algo__crosstalk_compensation_plane_offset_kcps; current_xtalk = ((uint32_t)cco) << 2; smudge_margin_adjusted = ((uint32_t)(pconfig->smudge_margin)) << 2; itemp32 = xtalk_offset_in - current_xtalk + smudge_margin_adjusted; if (itemp32 < 0) itemp32 = itemp32 * (-1); if (itemp32 > ((int32_t)pconfig->single_xtalk_delta)) { if ((int32_t)xtalk_offset_in > ((int32_t)current_xtalk - (int32_t)smudge_margin_adjusted)) { pout->single_xtalk_delta_flag = 1; } else { pout->single_xtalk_delta_flag = 2; } } pint->current_samples = pint->current_samples + 1; if (pint->current_samples > pconfig->sample_limit) { pout->sample_limit_exceeded_flag = 1; continue_processing = CONT_RESET; } else { pint->accumulator = pint->accumulator + xtalk_offset_in; } if (pint->current_samples < pint->required_samples) continue_processing = CONT_NEXT_LOOP; xtalk_offset_out = (uint32_t)(do_division_u(pint->accumulator, pint->current_samples)); itemp32 = xtalk_offset_out - current_xtalk + smudge_margin_adjusted; if (itemp32 < 0) itemp32 = itemp32 * (-1); if (continue_processing == CONT_CONTINUE && (itemp32 >= ((int32_t)(pconfig->averaged_xtalk_delta))) ) { if ((int32_t)xtalk_offset_out > ((int32_t)current_xtalk - (int32_t)smudge_margin_adjusted)) pout->averaged_xtalk_delta_flag = 1; else pout->averaged_xtalk_delta_flag = 2; } if (continue_processing == CONT_CONTINUE && (itemp32 < ((int32_t)(pconfig->averaged_xtalk_delta))) ) continue_processing = CONT_RESET; pout->smudge_corr_clipped = 0; if ((continue_processing == CONT_CONTINUE) && (pconfig->smudge_corr_clip_limit != 0)) { if (xtalk_offset_out > (pconfig->smudge_corr_clip_limit * histo_merge_nb)) { pout->smudge_corr_clipped = 1; continue_processing = CONT_RESET; } } if (pconfig->user_xtalk_offset_limit_hi && (xtalk_offset_out > pconfig->user_xtalk_offset_limit)) xtalk_offset_out = pconfig->user_xtalk_offset_limit; if ((pconfig->user_xtalk_offset_limit_hi == 0) && (xtalk_offset_out < pconfig->user_xtalk_offset_limit)) xtalk_offset_out = pconfig->user_xtalk_offset_limit; xtalk_offset_out = xtalk_offset_out >> 2; if (xtalk_offset_out > 0x3FFFF) xtalk_offset_out = 0x3FFFF; if (continue_processing == CONT_CONTINUE) { VL53L1_dynamic_xtalk_correction_calc_new_xtalk( Dev, xtalk_offset_out, pconfig, pout, 1, 0 ); continue_processing = CONT_RESET; } else { VL53L1_dynamic_xtalk_correction_calc_new_xtalk( Dev, xtalk_offset_out, pconfig, pout, 1, 1 ); } if (continue_processing == CONT_RESET) { pint->accumulator = 0; pint->current_samples = 0; pint->nodetect_counter = 0; } } continue_processing = CONT_CONTINUE; if (run_nodetect == 1) { pint->nodetect_counter += 1; if (pint->nodetect_counter < pconfig->nodetect_sample_limit) continue_processing = CONT_NEXT_LOOP; xtalk_offset_out = (uint32_t)(pconfig->nodetect_xtalk_offset); if (continue_processing == CONT_CONTINUE) { VL53L1_dynamic_xtalk_correction_calc_new_xtalk( Dev, xtalk_offset_out, pconfig, pout, 0, 0 ); pout->smudge_corr_valid = 2; continue_processing = CONT_RESET; } else { VL53L1_dynamic_xtalk_correction_calc_new_xtalk( Dev, xtalk_offset_out, pconfig, pout, 0, 1 ); } if (continue_processing == CONT_RESET) { pint->accumulator = 0; pint->current_samples = 0; pint->nodetect_counter = 0; } } LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_dynamic_xtalk_correction_data_init( VL53L1_DEV Dev ) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); LOG_FUNCTION_START(""); pdev->smudge_correct_config.smudge_corr_enabled = 1; pdev->smudge_correct_config.smudge_corr_apply_enabled = 1; pdev->smudge_correct_config.smudge_corr_single_apply = VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY_DEFAULT; pdev->smudge_correct_config.smudge_margin = VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN_DEFAULT; pdev->smudge_correct_config.noise_margin = VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN_DEFAULT; pdev->smudge_correct_config.user_xtalk_offset_limit = VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_DEFAULT; pdev->smudge_correct_config.user_xtalk_offset_limit_hi = VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI_DEFAULT; pdev->smudge_correct_config.sample_limit = VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT_DEFAULT; pdev->smudge_correct_config.single_xtalk_delta = VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA_DEFAULT; pdev->smudge_correct_config.averaged_xtalk_delta = VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA_DEFAULT; pdev->smudge_correct_config.smudge_corr_clip_limit = VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT_DEFAULT; pdev->smudge_correct_config.smudge_corr_ambient_threshold = VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD_DEFAULT; pdev->smudge_correct_config.scaler_calc_method = 0; pdev->smudge_correct_config.x_gradient_scaler = VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER_DEFAULT; pdev->smudge_correct_config.y_gradient_scaler = VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER_DEFAULT; pdev->smudge_correct_config.user_scaler_set = VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET_DEFAULT; pdev->smudge_correct_config.nodetect_ambient_threshold = VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS_DEFAULT; pdev->smudge_correct_config.nodetect_sample_limit = VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT_DEFAULT; pdev->smudge_correct_config.nodetect_xtalk_offset = VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS_DEFAULT; pdev->smudge_correct_config.nodetect_min_range_mm = VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM_DEFAULT; pdev->smudge_correct_config.max_smudge_factor = VL53L1_TUNINGPARM_DYNXTALK_MAX_SMUDGE_FACTOR_DEFAULT; pdev->smudge_corrector_internals.current_samples = 0; pdev->smudge_corrector_internals.required_samples = 0; pdev->smudge_corrector_internals.accumulator = 0; pdev->smudge_corrector_internals.nodetect_counter = 0; VL53L1_dynamic_xtalk_correction_output_init(pres); LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_dynamic_xtalk_correction_output_init( VL53L1_LLDriverResults_t *pres ) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_smudge_corrector_data_t *pdata; LOG_FUNCTION_START(""); pdata = &(pres->range_results.smudge_corrector_data); pdata->smudge_corr_valid = 0; pdata->smudge_corr_clipped = 0; pdata->single_xtalk_delta_flag = 0; pdata->averaged_xtalk_delta_flag = 0; pdata->sample_limit_exceeded_flag = 0; pdata->gradient_zero_flag = 0; pdata->new_xtalk_applied_flag = 0; pdata->algo__crosstalk_compensation_plane_offset_kcps = 0; pdata->algo__crosstalk_compensation_x_plane_gradient_kcps = 0; pdata->algo__crosstalk_compensation_y_plane_gradient_kcps = 0; LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_xtalk_cal_data_init( VL53L1_DEV Dev ) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); LOG_FUNCTION_START(""); pdev->xtalk_cal.algo__crosstalk_compensation_plane_offset_kcps = 0; pdev->xtalk_cal.algo__crosstalk_compensation_x_plane_gradient_kcps = 0; pdev->xtalk_cal.algo__crosstalk_compensation_y_plane_gradient_kcps = 0; memset(&pdev->xtalk_cal.algo__xtalk_cpo_HistoMerge_kcps[0], 0, sizeof(pdev->xtalk_cal.algo__xtalk_cpo_HistoMerge_kcps)); LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_low_power_auto_data_init( VL53L1_DEV Dev ) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); LOG_FUNCTION_START(""); pdev->low_power_auto_data.vhv_loop_bound = VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND_DEFAULT; pdev->low_power_auto_data.is_low_power_auto_mode = 0; pdev->low_power_auto_data.low_power_auto_range_count = 0; pdev->low_power_auto_data.saved_interrupt_config = 0; pdev->low_power_auto_data.saved_vhv_init = 0; pdev->low_power_auto_data.saved_vhv_timeout = 0; pdev->low_power_auto_data.first_run_phasecal_result = 0; pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = 0; pdev->low_power_auto_data.dss__required_spads = 0; LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_low_power_auto_data_stop_range( VL53L1_DEV Dev ) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); LOG_FUNCTION_START(""); pdev->low_power_auto_data.low_power_auto_range_count = 0xFF; pdev->low_power_auto_data.first_run_phasecal_result = 0; pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = 0; pdev->low_power_auto_data.dss__required_spads = 0; if (pdev->low_power_auto_data.saved_vhv_init != 0) pdev->stat_nvm.vhv_config__init = pdev->low_power_auto_data.saved_vhv_init; if (pdev->low_power_auto_data.saved_vhv_timeout != 0) pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = pdev->low_power_auto_data.saved_vhv_timeout; pdev->gen_cfg.phasecal_config__override = 0x00; LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_config_low_power_auto_mode( VL53L1_general_config_t *pgeneral, VL53L1_dynamic_config_t *pdynamic, VL53L1_low_power_auto_data_t *plpadata ) { VL53L1_Error status = VL53L1_ERROR_NONE; LOG_FUNCTION_START(""); plpadata->is_low_power_auto_mode = 1; plpadata->low_power_auto_range_count = 0; pdynamic->system__sequence_config = VL53L1_SEQUENCE_VHV_EN | VL53L1_SEQUENCE_PHASECAL_EN | VL53L1_SEQUENCE_DSS1_EN | VL53L1_SEQUENCE_RANGE_EN; pgeneral->dss_config__manual_effective_spads_select = 200 << 8; pgeneral->dss_config__roi_mode_control = VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_low_power_auto_setup_manual_calibration( VL53L1_DEV Dev) { VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); VL53L1_Error status = VL53L1_ERROR_NONE; LOG_FUNCTION_START(""); pdev->low_power_auto_data.saved_vhv_init = pdev->stat_nvm.vhv_config__init; pdev->low_power_auto_data.saved_vhv_timeout = pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound; pdev->stat_nvm.vhv_config__init &= 0x7F; pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = (pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound & 0x03) + (pdev->low_power_auto_data.vhv_loop_bound << 2); pdev->gen_cfg.phasecal_config__override = 0x01; pdev->low_power_auto_data.first_run_phasecal_result = pdev->dbg_results.phasecal_result__vcsel_start; pdev->gen_cfg.cal_config__vcsel_start = pdev->low_power_auto_data.first_run_phasecal_result; LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_low_power_auto_update_DSS( VL53L1_DEV Dev) { VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); VL53L1_system_results_t *pS = &(pdev->sys_results); VL53L1_Error status = VL53L1_ERROR_NONE; uint32_t utemp32a; LOG_FUNCTION_START(""); utemp32a = pS->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 + pS->result__ambient_count_rate_mcps_sd0; if (utemp32a > 0xFFFF) utemp32a = 0xFFFF; utemp32a = utemp32a << 16; if (pdev->sys_results.result__dss_actual_effective_spads_sd0 == 0) status = VL53L1_ERROR_DIVISION_BY_ZERO; else { utemp32a = utemp32a / pdev->sys_results.result__dss_actual_effective_spads_sd0; pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = utemp32a; utemp32a = pdev->stat_cfg.dss_config__target_total_rate_mcps << 16; if (pdev->low_power_auto_data.dss__total_rate_per_spad_mcps == 0) status = VL53L1_ERROR_DIVISION_BY_ZERO; else { utemp32a = utemp32a / pdev->low_power_auto_data.dss__total_rate_per_spad_mcps; if (utemp32a > 0xFFFF) utemp32a = 0xFFFF; pdev->low_power_auto_data.dss__required_spads = (uint16_t)utemp32a; pdev->gen_cfg.dss_config__manual_effective_spads_select = pdev->low_power_auto_data.dss__required_spads; pdev->gen_cfg.dss_config__roi_mode_control = VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; } } if (status == VL53L1_ERROR_DIVISION_BY_ZERO) { pdev->low_power_auto_data.dss__required_spads = 0x8000; pdev->gen_cfg.dss_config__manual_effective_spads_select = pdev->low_power_auto_data.dss__required_spads; pdev->gen_cfg.dss_config__roi_mode_control = VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; status = VL53L1_ERROR_NONE; } LOG_FUNCTION_END(status); return status; } VL53L1_Error VL53L1_compute_histo_merge_nb( VL53L1_DEV Dev, uint8_t *histo_merge_nb) { VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); VL53L1_Error status = VL53L1_ERROR_NONE; uint8_t i, timing; uint8_t sum = 0; timing = (pdev->hist_data.bin_seq[0] == 7 ? 1 : 0); for (i = 0; i < VL53L1_BIN_REC_SIZE; i++) if (pdev->multi_bins_rec[i][timing][7] > 0) sum++; *histo_merge_nb = sum; return status; }