in boards/STM32L475_Discovery/BSP/Components/vl53l0x/vl53l0x_api_calibration.c [711:973]
VL53L0X_Error VL53L0X_perform_ref_spad_management(VL53L0X_DEV Dev,
uint32_t *refSpadCount,
uint8_t *isApertureSpads)
{
VL53L0X_Error Status = VL53L0X_ERROR_NONE;
uint8_t lastSpadArray[6];
uint8_t startSelect = 0xB4;
uint32_t minimumSpadCount = 3;
uint32_t maxSpadCount = 44;
uint32_t currentSpadIndex = 0;
uint32_t lastSpadIndex = 0;
int32_t nextGoodSpad = 0;
uint16_t targetRefRate = 0x0A00; /* 20 MCPS in 9:7 format */
uint16_t peakSignalRateRef;
uint32_t needAptSpads = 0;
uint32_t index = 0;
uint32_t spadArraySize = 6;
uint32_t signalRateDiff = 0;
uint32_t lastSignalRateDiff = 0;
uint8_t complete = 0;
uint8_t VhvSettings = 0;
uint8_t PhaseCal = 0;
uint32_t refSpadCount_int = 0;
uint8_t isApertureSpads_int = 0;
/*
* The reference SPAD initialization procedure determines the minimum
* amount of reference spads to be enables to achieve a target reference
* signal rate and should be performed once during initialization.
*
* Either aperture or non-aperture spads are applied but never both.
* Firstly non-aperture spads are set, begining with 5 spads, and
* increased one spad at a time until the closest measurement to the
* target rate is achieved.
*
* If the target rate is exceeded when 5 non-aperture spads are enabled,
* initialization is performed instead with aperture spads.
*
* When setting spads, a 'Good Spad Map' is applied.
*
* This procedure operates within a SPAD window of interest of a maximum
* 44 spads.
* The start point is currently fixed to 180, which lies towards the end
* of the non-aperture quadrant and runs in to the adjacent aperture
* quadrant.
*/
targetRefRate = PALDevDataGet(Dev, targetRefRate);
/*
* Initialize Spad arrays.
* Currently the good spad map is initialised to 'All good'.
* This is a short term implementation. The good spad map will be
* provided as an input.
* Note that there are 6 bytes. Only the first 44 bits will be used to
* represent spads.
*/
for (index = 0; index < spadArraySize; index++)
Dev->Data.SpadData.RefSpadEnables[index] = 0;
Status = VL53L0X_WrByte(Dev, 0xFF, 0x01);
if (Status == VL53L0X_ERROR_NONE)
Status = VL53L0X_WrByte(Dev,
VL53L0X_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
if (Status == VL53L0X_ERROR_NONE)
Status = VL53L0X_WrByte(Dev,
VL53L0X_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
if (Status == VL53L0X_ERROR_NONE)
Status = VL53L0X_WrByte(Dev, 0xFF, 0x00);
if (Status == VL53L0X_ERROR_NONE)
Status = VL53L0X_WrByte(Dev,
VL53L0X_REG_GLOBAL_CONFIG_REF_EN_START_SELECT,
startSelect);
if (Status == VL53L0X_ERROR_NONE)
Status = VL53L0X_WrByte(Dev,
VL53L0X_REG_POWER_MANAGEMENT_GO1_POWER_FORCE, 0);
/* Perform ref calibration */
if (Status == VL53L0X_ERROR_NONE)
Status = VL53L0X_perform_ref_calibration(Dev, &VhvSettings,
&PhaseCal, 0);
if (Status == VL53L0X_ERROR_NONE) {
/* Enable Minimum NON-APERTURE Spads */
currentSpadIndex = 0;
lastSpadIndex = currentSpadIndex;
needAptSpads = 0;
Status = enable_ref_spads(Dev,
needAptSpads,
Dev->Data.SpadData.RefGoodSpadMap,
Dev->Data.SpadData.RefSpadEnables,
spadArraySize,
startSelect,
currentSpadIndex,
minimumSpadCount,
&lastSpadIndex);
}
if (Status == VL53L0X_ERROR_NONE) {
currentSpadIndex = lastSpadIndex;
Status = perform_ref_signal_measurement(Dev,
&peakSignalRateRef);
if ((Status == VL53L0X_ERROR_NONE) &&
(peakSignalRateRef > targetRefRate)) {
/* Signal rate measurement too high,
* switch to APERTURE SPADs */
for (index = 0; index < spadArraySize; index++)
Dev->Data.SpadData.RefSpadEnables[index] = 0;
/* Increment to the first APERTURE spad */
while ((is_aperture(startSelect + currentSpadIndex)
== 0) && (currentSpadIndex < maxSpadCount)) {
currentSpadIndex++;
}
needAptSpads = 1;
Status = enable_ref_spads(Dev,
needAptSpads,
Dev->Data.SpadData.RefGoodSpadMap,
Dev->Data.SpadData.RefSpadEnables,
spadArraySize,
startSelect,
currentSpadIndex,
minimumSpadCount,
&lastSpadIndex);
if (Status == VL53L0X_ERROR_NONE) {
currentSpadIndex = lastSpadIndex;
Status = perform_ref_signal_measurement(Dev,
&peakSignalRateRef);
if ((Status == VL53L0X_ERROR_NONE) &&
(peakSignalRateRef > targetRefRate)) {
/* Signal rate still too high after
* setting the minimum number of
* APERTURE spads. Can do no more
* therefore set the min number of
* aperture spads as the result.
*/
isApertureSpads_int = 1;
refSpadCount_int = minimumSpadCount;
}
}
} else {
needAptSpads = 0;
}
}
if ((Status == VL53L0X_ERROR_NONE) &&
(peakSignalRateRef < targetRefRate)) {
/* At this point, the minimum number of either aperture
* or non-aperture spads have been set. Proceed to add
* spads and perform measurements until the target
* reference is reached.
*/
isApertureSpads_int = needAptSpads;
refSpadCount_int = minimumSpadCount;
memcpy(lastSpadArray, Dev->Data.SpadData.RefSpadEnables,
spadArraySize);
lastSignalRateDiff = abs(peakSignalRateRef -
targetRefRate);
complete = 0;
while (!complete) {
get_next_good_spad(
Dev->Data.SpadData.RefGoodSpadMap,
spadArraySize, currentSpadIndex,
&nextGoodSpad);
if (nextGoodSpad == -1) {
Status = VL53L0X_ERROR_REF_SPAD_INIT;
break;
}
(refSpadCount_int)++;
/* Cannot combine Aperture and Non-Aperture spads, so
* ensure the current spad is of the correct type.
*/
if (is_aperture((uint32_t)startSelect + nextGoodSpad) !=
needAptSpads) {
Status = VL53L0X_ERROR_REF_SPAD_INIT;
break;
}
currentSpadIndex = nextGoodSpad;
Status = enable_spad_bit(
Dev->Data.SpadData.RefSpadEnables,
spadArraySize, currentSpadIndex);
if (Status == VL53L0X_ERROR_NONE) {
currentSpadIndex++;
/* Proceed to apply the additional spad and
* perform measurement. */
Status = set_ref_spad_map(Dev,
Dev->Data.SpadData.RefSpadEnables);
}
if (Status != VL53L0X_ERROR_NONE)
break;
Status = perform_ref_signal_measurement(Dev,
&peakSignalRateRef);
if (Status != VL53L0X_ERROR_NONE)
break;
signalRateDiff = abs(peakSignalRateRef - targetRefRate);
if (peakSignalRateRef > targetRefRate) {
/* Select the spad map that provides the
* measurement closest to the target rate,
* either above or below it.
*/
if (signalRateDiff > lastSignalRateDiff) {
/* Previous spad map produced a closer
* measurement, so choose this. */
Status = set_ref_spad_map(Dev,
lastSpadArray);
memcpy(
Dev->Data.SpadData.RefSpadEnables,
lastSpadArray, spadArraySize);
(refSpadCount_int)--;
}
complete = 1;
} else {
/* Continue to add spads */
lastSignalRateDiff = signalRateDiff;
memcpy(lastSpadArray,
Dev->Data.SpadData.RefSpadEnables,
spadArraySize);
}
} /* while */
}
if (Status == VL53L0X_ERROR_NONE) {
*refSpadCount = refSpadCount_int;
*isApertureSpads = isApertureSpads_int;
VL53L0X_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 1);
VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
ReferenceSpadCount, (uint8_t)(*refSpadCount));
VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
ReferenceSpadType, *isApertureSpads);
}
return Status;
}