815 lines
19 KiB
C
815 lines
19 KiB
C
/**
|
|
******************************************************************************
|
|
* @file vl53l8cx.c
|
|
* @author IMG SW Application Team
|
|
* @brief This file provides the VL53L8CX ranging sensor component driver
|
|
******************************************************************************
|
|
* @attention
|
|
*
|
|
* Copyright (c) 2022 STMicroelectronics.
|
|
* All rights reserved.
|
|
*
|
|
* This software is licensed under terms that can be found in the LICENSE file
|
|
* in the root directory of this software component.
|
|
* If no LICENSE file comes with this software, it is provided AS-IS.
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "vl53l8cx.h"
|
|
|
|
/** @addtogroup BSP
|
|
* @{
|
|
*/
|
|
|
|
/** @addtogroup Components
|
|
* @{
|
|
*/
|
|
|
|
/** @addtogroup VL53L8CX
|
|
* @brief This file provides a set of functions needed to drive the
|
|
* VL53L8CX ranging sensor.
|
|
* @{
|
|
*/
|
|
|
|
/** @defgroup VL53L8CX_Private_TypesDefinitions Private Types Definitions
|
|
* @{
|
|
*/
|
|
|
|
/* 0x1388 corresponds to 5000 decimal. This will do a timeout of 5 seconds */
|
|
#define V53L8CX_POLL_TIMEOUT (0x1388U)
|
|
#ifndef UNUSED
|
|
#define UNUSED(x) (void)(x)
|
|
#endif
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/** @defgroup VL53L8CX_Private_Variables Private Variables
|
|
* @{
|
|
*/
|
|
|
|
VL53L8CX_RANGING_SENSOR_Drv_t VL53L8CX_RANGING_SENSOR_Driver =
|
|
{
|
|
VL53L8CX_Init,
|
|
VL53L8CX_DeInit,
|
|
VL53L8CX_ReadID,
|
|
VL53L8CX_GetCapabilities,
|
|
VL53L8CX_ConfigProfile,
|
|
VL53L8CX_ConfigROI,
|
|
VL53L8CX_ConfigIT,
|
|
VL53L8CX_GetDistance,
|
|
VL53L8CX_Start,
|
|
VL53L8CX_Stop,
|
|
VL53L8CX_SetAddress,
|
|
VL53L8CX_GetAddress,
|
|
VL53L8CX_SetPowerMode,
|
|
VL53L8CX_GetPowerMode
|
|
};
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
|
|
/** @defgroup VL53L8CX_Private_Functions_Prototypes Private Functions Prototypes
|
|
* @{
|
|
*/
|
|
static int32_t vl53l8cx_poll_for_measurement(VL53L8CX_Object_t *pObj, uint32_t Timeout);
|
|
static int32_t vl53l8cx_get_result(VL53L8CX_Object_t *pObj, VL53L8CX_Result_t *pResult);
|
|
static uint8_t vl53l8cx_map_target_status(uint8_t status);
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @brief Initializes the vl53l8cx context object.
|
|
* @param pObj vl53l8cx context object.
|
|
* @param pIO BSP IO struct.
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_RegisterBusIO(VL53L8CX_Object_t *pObj, VL53L8CX_IO_t *pIO)
|
|
{
|
|
int32_t ret;
|
|
|
|
if ((pObj == NULL) || (pIO == NULL))
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else
|
|
{
|
|
pObj->IO.Init = pIO->Init;
|
|
pObj->IO.DeInit = pIO->DeInit;
|
|
pObj->IO.Address = pIO->Address;
|
|
pObj->IO.WriteReg = pIO->WriteReg;
|
|
pObj->IO.ReadReg = pIO->ReadReg;
|
|
pObj->IO.GetTick = pIO->GetTick;
|
|
|
|
/* fill vl53l8cx platform structure */
|
|
pObj->Dev.platform.address = pIO->Address;
|
|
pObj->Dev.platform.Read = pIO->ReadReg;
|
|
pObj->Dev.platform.Write = pIO->WriteReg;
|
|
pObj->Dev.platform.GetTick = pIO->GetTick;
|
|
|
|
if (pObj->IO.Init != NULL)
|
|
{
|
|
ret = pObj->IO.Init();
|
|
}
|
|
else
|
|
{
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Initializes the vl53l8cx.
|
|
* @param pObj vl53l8cx context object.
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_Init(VL53L8CX_Object_t *pObj)
|
|
{
|
|
int32_t ret;
|
|
|
|
if (pObj == NULL)
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else if (pObj->IsInitialized != 0U)
|
|
{
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
else if (vl53l8cx_init(&pObj->Dev) != VL53L8CX_STATUS_OK)
|
|
{
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
else
|
|
{
|
|
pObj->IsRanging = 0U;
|
|
pObj->IsBlocking = 0U;
|
|
pObj->IsContinuous = 0U;
|
|
pObj->IsAmbientEnabled = 0U;
|
|
pObj->IsSignalEnabled = 0U;
|
|
pObj->IsInitialized = 1U;
|
|
ret = VL53L8CX_OK;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Deinitializes the vl53l8cx.
|
|
* @param pObj vl53l8cx context object.
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_DeInit(VL53L8CX_Object_t *pObj)
|
|
{
|
|
int32_t ret;
|
|
|
|
if (pObj == NULL)
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else if (pObj->IsInitialized == 1U)
|
|
{
|
|
/* De-initialize the vl53l8cx interface */
|
|
if (pObj->IO.DeInit() != 0)
|
|
{
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
else
|
|
{
|
|
ret = VL53L8CX_OK;
|
|
pObj->IsInitialized = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* if device not initialized return error */
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Read the vl53l8cx device ID.
|
|
* @param pObj vl53l8cx context object.
|
|
* @param pId Pointer to the device ID.
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_ReadID(VL53L8CX_Object_t *pObj, uint32_t *pId)
|
|
{
|
|
int32_t ret;
|
|
uint8_t device_id = 0;
|
|
uint8_t revision_id = 0;
|
|
uint8_t status = VL53L8CX_STATUS_OK;
|
|
|
|
if ((pObj == NULL) || (pId == NULL))
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else
|
|
{
|
|
status |= VL53L8CX_WrByte(&pObj->Dev.platform, 0x7fff, 0x00);
|
|
status |= VL53L8CX_RdByte(&pObj->Dev.platform, 0, &device_id);
|
|
status |= VL53L8CX_RdByte(&pObj->Dev.platform, 1, &revision_id);
|
|
status |= VL53L8CX_WrByte(&pObj->Dev.platform, 0x7fff, 0x02);
|
|
|
|
if (status == 0U)
|
|
{
|
|
*pId = ((uint32_t)device_id << 8) + revision_id;
|
|
ret = VL53L8CX_OK;
|
|
}
|
|
else
|
|
{
|
|
*pId = 0;
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the vl53l8cx capabilities.
|
|
* @param pObj vl53l8cx context object.
|
|
* @param pCap Pointer to the vl53l8cx capabilities.
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_GetCapabilities(VL53L8CX_Object_t *pObj, VL53L8CX_Capabilities_t *pCap)
|
|
{
|
|
int32_t ret;
|
|
|
|
if ((pObj == NULL) || (pCap == NULL))
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else
|
|
{
|
|
pCap->NumberOfZones = VL53L8CX_RESOLUTION_8X8;
|
|
pCap->MaxNumberOfTargetsPerZone = VL53L8CX_TARGET_PER_ZONE;
|
|
pCap->CustomROI = 0;
|
|
pCap->ThresholdDetection = 1;
|
|
|
|
ret = VL53L8CX_OK;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Set the ranging configuration profile.
|
|
* @param pObj vl53l8cx context object.
|
|
* @param pConfig Pointer to the new configuration profile to be applied.
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_ConfigProfile(VL53L8CX_Object_t *pObj, VL53L8CX_ProfileConfig_t *pConfig)
|
|
{
|
|
int32_t ret = VL53L8CX_OK;
|
|
|
|
uint8_t profile;
|
|
uint8_t resolution;
|
|
uint8_t ranging_mode;
|
|
uint8_t ranging_frequency;
|
|
uint32_t integration_time;
|
|
|
|
if ((pObj != NULL) && (pConfig != NULL))
|
|
{
|
|
profile = pConfig->RangingProfile;
|
|
integration_time = pConfig->TimingBudget;
|
|
ranging_frequency = (uint8_t)pConfig->Frequency;
|
|
}
|
|
else
|
|
{
|
|
return VL53L8CX_INVALID_PARAM;
|
|
}
|
|
|
|
switch (profile)
|
|
{
|
|
case VL53L8CX_PROFILE_4x4_CONTINUOUS:
|
|
resolution = VL53L8CX_RESOLUTION_4X4;
|
|
ranging_mode = VL53L8CX_RANGING_MODE_CONTINUOUS;
|
|
break;
|
|
case VL53L8CX_PROFILE_4x4_AUTONOMOUS:
|
|
resolution = VL53L8CX_RESOLUTION_4X4;
|
|
ranging_mode = VL53L8CX_RANGING_MODE_AUTONOMOUS;
|
|
break;
|
|
case VL53L8CX_PROFILE_8x8_CONTINUOUS:
|
|
resolution = VL53L8CX_RESOLUTION_8X8;
|
|
ranging_mode = VL53L8CX_RANGING_MODE_CONTINUOUS;
|
|
break;
|
|
case VL53L8CX_PROFILE_8x8_AUTONOMOUS:
|
|
resolution = VL53L8CX_RESOLUTION_8X8;
|
|
ranging_mode = VL53L8CX_RANGING_MODE_AUTONOMOUS;
|
|
break;
|
|
default:
|
|
resolution = 0; /* silence MISRA rule 1.3 warning */
|
|
ranging_mode = 0; /* silence MISRA rule 1.3 warning */
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
break;
|
|
}
|
|
|
|
if (ret != VL53L8CX_OK)
|
|
{
|
|
return ret;
|
|
}
|
|
else if (vl53l8cx_set_resolution(&pObj->Dev, resolution) != VL53L8CX_STATUS_OK)
|
|
{
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
else if (vl53l8cx_set_ranging_mode(&pObj->Dev, ranging_mode) != VL53L8CX_STATUS_OK)
|
|
{
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
else if (vl53l8cx_set_integration_time_ms(&pObj->Dev, integration_time) != VL53L8CX_STATUS_OK)
|
|
{
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
else if (vl53l8cx_set_ranging_frequency_hz(&pObj->Dev, ranging_frequency) != VL53L8CX_STATUS_OK)
|
|
{
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
else
|
|
{
|
|
pObj->IsAmbientEnabled = (pConfig->EnableAmbient == 0U) ? 0U : 1U;
|
|
pObj->IsSignalEnabled = (pConfig->EnableSignal == 0U) ? 0U : 1U;
|
|
|
|
ret = VL53L8CX_OK;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Configure the Region of Interest of the vl53l8cx.
|
|
* @param pObj vl53l8cx context object.
|
|
* @param pROIConfig Pointer to the ROI configuration struct.
|
|
* @note This device does not support this function.
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_ConfigROI(VL53L8CX_Object_t *pObj, VL53L8CX_ROIConfig_t *pROIConfig)
|
|
{
|
|
UNUSED(pObj);
|
|
UNUSED(pROIConfig);
|
|
return VL53L8CX_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/**
|
|
* @brief Configure the IT event generation parameters.
|
|
* @param pObj vl53l8cx context object.
|
|
* @param pITConfig Pointer to the IT configuration struct.
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_ConfigIT(VL53L8CX_Object_t *pObj, VL53L8CX_ITConfig_t *pITConfig)
|
|
{
|
|
int32_t ret;
|
|
uint8_t i;
|
|
uint8_t res; /* current resolution */
|
|
uint8_t status = 0U;
|
|
static VL53L8CX_DetectionThresholds thresholds[VL53L8CX_NB_THRESHOLDS];
|
|
|
|
if ((pObj == NULL) || (pITConfig == NULL))
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else if (pITConfig->Criteria == VL53L8CX_IT_DEFAULT)
|
|
{
|
|
/* disable thresholds detection */
|
|
status |= vl53l8cx_set_detection_thresholds_enable(&pObj->Dev, 0U);
|
|
ret = (status != 0U) ? VL53L8CX_ERROR : VL53L8CX_OK;
|
|
}
|
|
else
|
|
{
|
|
(void)vl53l8cx_get_resolution(&pObj->Dev, &res);
|
|
|
|
/* configure thresholds on each active zone */
|
|
for (i = 0; i < res; i++)
|
|
{
|
|
thresholds[i].zone_num = i;
|
|
thresholds[i].measurement = VL53L8CX_DISTANCE_MM;
|
|
thresholds[i].type = (uint8_t)pITConfig->Criteria;
|
|
thresholds[i].mathematic_operation = VL53L8CX_OPERATION_NONE;
|
|
thresholds[i].param_low_thresh = (int32_t)pITConfig->LowThreshold;
|
|
thresholds[i].param_high_thresh = (int32_t)pITConfig->HighThreshold;
|
|
}
|
|
|
|
/* the last threshold must be clearly indicated */
|
|
thresholds[i].zone_num |= VL53L8CX_LAST_THRESHOLD;
|
|
|
|
/* send array of thresholds to the sensor */
|
|
status |= vl53l8cx_set_detection_thresholds(&pObj->Dev, thresholds);
|
|
|
|
/* enable thresholds detection */
|
|
status |= vl53l8cx_set_detection_thresholds_enable(&pObj->Dev, 1U);
|
|
|
|
ret = (status != 0U) ? VL53L8CX_ERROR : VL53L8CX_OK;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the last distance measurement information.
|
|
* @param pObj vl53l8cx context object.
|
|
* @param pResult Pointer to the result struct.
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_GetDistance(VL53L8CX_Object_t *pObj, VL53L8CX_Result_t *pResult)
|
|
{
|
|
int32_t ret;
|
|
|
|
ret = VL53L8CX_OK;
|
|
if ((pObj == NULL) || (pResult == NULL))
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else if (pObj->IsRanging == 0U)
|
|
{
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
|
|
if (ret == VL53L8CX_OK)
|
|
{
|
|
if (pObj->IsBlocking == 1U)
|
|
{
|
|
ret = vl53l8cx_poll_for_measurement(pObj, V53L8CX_POLL_TIMEOUT);
|
|
}
|
|
else
|
|
{
|
|
ret = vl53l8cx_poll_for_measurement(pObj, 0U);
|
|
}
|
|
}
|
|
|
|
/* a new measure is available if no error is returned by the poll function */
|
|
if (ret == VL53L8CX_OK)
|
|
{
|
|
ret = vl53l8cx_get_result(pObj, pResult);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Start ranging.
|
|
* @param pObj vl53l8cx context object.
|
|
* @param Mode The desired @ref RANGING_SENSOR_Mode_t
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_Start(VL53L8CX_Object_t *pObj, uint32_t Mode)
|
|
{
|
|
int32_t ret;
|
|
|
|
if (pObj == NULL)
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else if (vl53l8cx_start_ranging(&pObj->Dev) == VL53L8CX_STATUS_OK)
|
|
{
|
|
pObj->IsRanging = 1U;
|
|
ret = VL53L8CX_OK;
|
|
|
|
switch (Mode)
|
|
{
|
|
case VL53L8CX_MODE_BLOCKING_CONTINUOUS:
|
|
pObj->IsContinuous = 1U;
|
|
pObj->IsBlocking = 1U;
|
|
break;
|
|
|
|
case VL53L8CX_MODE_BLOCKING_ONESHOT:
|
|
pObj->IsContinuous = 0U;
|
|
pObj->IsBlocking = 1U;
|
|
break;
|
|
|
|
case VL53L8CX_MODE_ASYNC_CONTINUOUS:
|
|
pObj->IsContinuous = 1U;
|
|
pObj->IsBlocking = 0U;
|
|
break;
|
|
|
|
case VL53L8CX_MODE_ASYNC_ONESHOT:
|
|
pObj->IsContinuous = 0U;
|
|
pObj->IsBlocking = 0U;
|
|
break;
|
|
|
|
default:
|
|
pObj->IsRanging = 0U;
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Stop ranging.
|
|
* @param pObj vl53l8cx context object.
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_Stop(VL53L8CX_Object_t *pObj)
|
|
{
|
|
int32_t ret;
|
|
|
|
if (pObj == NULL)
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else if (pObj->IsRanging == 0U)
|
|
{
|
|
/* ranging not started */
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
else if (vl53l8cx_stop_ranging(&pObj->Dev) == VL53L8CX_STATUS_OK)
|
|
{
|
|
pObj->IsRanging = 0U;
|
|
ret = VL53L8CX_OK;
|
|
}
|
|
else
|
|
{
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Set The I2C address of the device.
|
|
* @param pObj vl53l8cx context object.
|
|
* @param Address New I2C address.
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_SetAddress(VL53L8CX_Object_t *pObj, uint32_t Address)
|
|
{
|
|
int32_t ret;
|
|
|
|
if (pObj == NULL)
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else if (vl53l8cx_set_i2c_address(&pObj->Dev, (uint8_t)Address) != VL53L8CX_STATUS_OK)
|
|
{
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
else
|
|
{
|
|
pObj->IO.Address = (uint8_t)(Address & 0xFFU);
|
|
ret = VL53L8CX_OK;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Get The I2C address of the device.
|
|
* @param pObj vl53l8cx context object.
|
|
* @param *pAddress New I2C address.
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_GetAddress(VL53L8CX_Object_t *pObj, uint32_t *pAddress)
|
|
{
|
|
int32_t ret;
|
|
|
|
if ((pObj == NULL) || (pAddress == NULL))
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else
|
|
{
|
|
*pAddress = pObj->IO.Address;
|
|
ret = VL53L8CX_OK;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Set the power mode.
|
|
* @param pObj vl53l8cx context object.
|
|
* @param PowerMode New power mode to be entered.
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_SetPowerMode(VL53L8CX_Object_t *pObj, uint32_t PowerMode)
|
|
{
|
|
int32_t ret;
|
|
|
|
if (pObj == NULL)
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else if ((PowerMode != VL53L8CX_POWER_MODE_SLEEP) &&
|
|
(PowerMode != VL53L8CX_POWER_MODE_WAKEUP))
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else if (vl53l8cx_set_power_mode(&pObj->Dev, (uint8_t)PowerMode) != VL53L8CX_STATUS_OK)
|
|
{
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
else
|
|
{
|
|
ret = VL53L8CX_OK;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the power mode.
|
|
* @param pObj vl53l8cx context object.
|
|
* @param *pPowerMode pointer to variable to be filled with power mode value.
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_GetPowerMode(VL53L8CX_Object_t *pObj, uint32_t *pPowerMode)
|
|
{
|
|
int32_t ret;
|
|
uint8_t powermode;
|
|
|
|
if ((pObj == NULL) || (pPowerMode == NULL))
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else if (vl53l8cx_get_power_mode(&pObj->Dev, &powermode) != VL53L8CX_STATUS_OK)
|
|
{
|
|
*pPowerMode = 0;
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
else
|
|
{
|
|
*pPowerMode = (uint32_t)powermode;
|
|
ret = VL53L8CX_OK;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Perform a xtalk calibration.
|
|
* @param pObj vl53l8cx context object.
|
|
* @param Reflectance Target reflectance in percent (range: 1 - 99 %).
|
|
* @param Distance Target distance in mm (range 600 - 3000 mm).
|
|
* @note The recommended target reflectance value for Xtalk calibration is 3 %.
|
|
* @retval VL53L8CX status
|
|
*/
|
|
int32_t VL53L8CX_XTalkCalibration(VL53L8CX_Object_t *pObj, uint16_t Reflectance, uint16_t Distance)
|
|
{
|
|
int32_t ret;
|
|
uint8_t status;
|
|
|
|
/* Number of data samples used for calibration.
|
|
* A higher number of samples means a higher accuracy,
|
|
* but it increases the calibration time (range 1 - 16). */
|
|
uint8_t nb_samples = 2;
|
|
|
|
status = vl53l8cx_calibrate_xtalk(
|
|
&pObj->Dev,
|
|
Reflectance,
|
|
nb_samples,
|
|
Distance);
|
|
|
|
ret = (status == VL53L8CX_STATUS_OK) ? VL53L8CX_OK : VL53L8CX_ERROR;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/** @defgroup VL53L8CX_Private_Functions Private Functions
|
|
* @{
|
|
*/
|
|
static int32_t vl53l8cx_poll_for_measurement(VL53L8CX_Object_t *pObj, uint32_t Timeout)
|
|
{
|
|
int32_t ret;
|
|
uint32_t TickStart;
|
|
uint8_t NewDataReady = 0;
|
|
|
|
if (pObj == NULL)
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else
|
|
{
|
|
ret = VL53L8CX_TIMEOUT;
|
|
TickStart = pObj->IO.GetTick();
|
|
|
|
do
|
|
{
|
|
(void)vl53l8cx_check_data_ready(&pObj->Dev, &NewDataReady);
|
|
|
|
if (NewDataReady == 1U)
|
|
{
|
|
ret = VL53L8CX_OK;
|
|
break;
|
|
}
|
|
} while ((pObj->IO.GetTick() - TickStart) < Timeout);
|
|
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int32_t vl53l8cx_get_result(VL53L8CX_Object_t *pObj, VL53L8CX_Result_t *pResult)
|
|
{
|
|
int32_t ret;
|
|
uint8_t i, j;
|
|
uint8_t resolution;
|
|
uint8_t target_status;
|
|
static VL53L8CX_ResultsData data;
|
|
|
|
if ((pObj == NULL) || (pResult == NULL))
|
|
{
|
|
ret = VL53L8CX_INVALID_PARAM;
|
|
}
|
|
else if (vl53l8cx_get_resolution(&pObj->Dev, &resolution) != VL53L8CX_STATUS_OK)
|
|
{
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
else if (vl53l8cx_get_ranging_data(&pObj->Dev, &data) != VL53L8CX_STATUS_OK)
|
|
{
|
|
ret = VL53L8CX_ERROR;
|
|
}
|
|
else
|
|
{
|
|
pResult->NumberOfZones = resolution;
|
|
|
|
for (i = 0; i < resolution; i++)
|
|
{
|
|
pResult->ZoneResult[i].NumberOfTargets = data.nb_target_detected[i];
|
|
|
|
for (j = 0; j < data.nb_target_detected[i]; j++)
|
|
{
|
|
pResult->ZoneResult[i].Distance[j] = (uint32_t)data.distance_mm[(VL53L8CX_NB_TARGET_PER_ZONE * i) + j];
|
|
|
|
/* return Ambient value if ambient rate output is enabled */
|
|
if (pObj->IsAmbientEnabled == 1U)
|
|
{
|
|
/* apply ambient value to all targets in a given zone */
|
|
pResult->ZoneResult[i].Ambient[j] = (float_t)data.ambient_per_spad[i];
|
|
}
|
|
else
|
|
{
|
|
pResult->ZoneResult[i].Ambient[j] = 0.0f;
|
|
}
|
|
|
|
/* return Signal value if signal rate output is enabled */
|
|
if (pObj->IsSignalEnabled == 1U)
|
|
{
|
|
pResult->ZoneResult[i].Signal[j] =
|
|
(float_t)data.signal_per_spad[(VL53L8CX_NB_TARGET_PER_ZONE * i) + j];
|
|
}
|
|
else
|
|
{
|
|
pResult->ZoneResult[i].Signal[j] = 0.0f;
|
|
}
|
|
|
|
target_status = data.target_status[(VL53L8CX_NB_TARGET_PER_ZONE * i) + j];
|
|
pResult->ZoneResult[i].Status[j] = vl53l8cx_map_target_status(target_status);
|
|
}
|
|
}
|
|
|
|
ret = VL53L8CX_OK;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static uint8_t vl53l8cx_map_target_status(uint8_t status)
|
|
{
|
|
uint8_t ret;
|
|
|
|
if ((status == 5U) || (status == 9U))
|
|
{
|
|
ret = 0U; /* ranging is OK */
|
|
}
|
|
else if (status == 0U)
|
|
{
|
|
ret = 255U; /* no update */
|
|
}
|
|
else
|
|
{
|
|
ret = status; /* return device status otherwise */
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|