Statistics
| Branch: | Tag: | Revision:

amiro-lld / include / VL53L0X / v1 / Api_vl53l0x / core / src / vl53l0x_api_calibration.c @ 6ebebd4d

History | View | Annotate | Download (40.818 KB)

1 6ebebd4d Andre Raming
/*******************************************************************************
2
 Copyright � 2016, STMicroelectronics International N.V.
3
 All rights reserved.
4

5
 Redistribution and use in source and binary forms, with or without
6
 modification, are permitted provided that the following conditions are met:
7
 * Redistributions of source code must retain the above copyright
8
 notice, this list of conditions and the following disclaimer.
9
 * Redistributions in binary form must reproduce the above copyright
10
 notice, this list of conditions and the following disclaimer in the
11
 documentation and/or other materials provided with the distribution.
12
 * Neither the name of STMicroelectronics nor the
13
 names of its contributors may be used to endorse or promote products
14
 derived from this software without specific prior written permission.
15

16
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
19
 NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
20
 IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
21
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 ******************************************************************************/
28
29
#include "vl53l0x_api.h"
30
#include "vl53l0x_api_core.h"
31
#include "vl53l0x_api_calibration.h"
32
33
#ifndef __KERNEL__
34
#include <stdlib.h>
35
#endif
36
37
#define LOG_FUNCTION_START(fmt, ...) \
38
    _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
39
#define LOG_FUNCTION_END(status, ...) \
40
    _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
41
#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
42
    _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
43
44
#define REF_ARRAY_SPAD_0  0
45
#define REF_ARRAY_SPAD_5  5
46
#define REF_ARRAY_SPAD_10 10
47
48
uint32_t refArrayQuadrants[4] = {REF_ARRAY_SPAD_10, REF_ARRAY_SPAD_5,
49
        REF_ARRAY_SPAD_0, REF_ARRAY_SPAD_5 };
50
51
VL53L0X_Error VL53L0X_perform_xtalk_calibration(VL53L0X_DEV Dev,
52
            FixPoint1616_t XTalkCalDistance,
53
            FixPoint1616_t *pXTalkCompensationRateMegaCps)
54
{
55
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
56
    uint16_t sum_ranging = 0;
57
    uint16_t sum_spads = 0;
58
    FixPoint1616_t sum_signalRate = 0;
59
    FixPoint1616_t total_count = 0;
60
    uint8_t xtalk_meas = 0;
61
    VL53L0X_RangingMeasurementData_t RangingMeasurementData;
62
    FixPoint1616_t xTalkStoredMeanSignalRate;
63
    FixPoint1616_t xTalkStoredMeanRange;
64
    FixPoint1616_t xTalkStoredMeanRtnSpads;
65
    uint32_t signalXTalkTotalPerSpad;
66
    uint32_t xTalkStoredMeanRtnSpadsAsInt;
67
    uint32_t xTalkCalDistanceAsInt;
68
    FixPoint1616_t XTalkCompensationRateMegaCps;
69
70
    if (XTalkCalDistance <= 0)
71
        Status = VL53L0X_ERROR_INVALID_PARAMS;
72
73
    /* Disable the XTalk compensation */
74
    if (Status == VL53L0X_ERROR_NONE)
75
        Status = VL53L0X_SetXTalkCompensationEnable(Dev, 0);
76
77
    /* Disable the RIT */
78
    if (Status == VL53L0X_ERROR_NONE) {
79
        Status = VL53L0X_SetLimitCheckEnable(Dev,
80
                VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0);
81
    }
82
83
    /* Perform 50 measurements and compute the averages */
84
    if (Status == VL53L0X_ERROR_NONE) {
85
        sum_ranging = 0;
86
        sum_spads = 0;
87
        sum_signalRate = 0;
88
        total_count = 0;
89
        for (xtalk_meas = 0; xtalk_meas < 50; xtalk_meas++) {
90
            Status = VL53L0X_PerformSingleRangingMeasurement(Dev,
91
                &RangingMeasurementData);
92
93
            if (Status != VL53L0X_ERROR_NONE)
94
                break;
95
96
            /* The range is valid when RangeStatus = 0 */
97
            if (RangingMeasurementData.RangeStatus == 0) {
98
                sum_ranging = sum_ranging +
99
                    RangingMeasurementData.RangeMilliMeter;
100
                sum_signalRate = sum_signalRate +
101
                RangingMeasurementData.SignalRateRtnMegaCps;
102
                sum_spads = sum_spads +
103
                RangingMeasurementData.EffectiveSpadRtnCount
104
                    / 256;
105
                total_count = total_count + 1;
106
            }
107
        }
108
109
        /* no valid values found */
110
        if (total_count == 0)
111
            Status = VL53L0X_ERROR_RANGE_ERROR;
112
113
    }
114
115
116
    if (Status == VL53L0X_ERROR_NONE) {
117
        /* FixPoint1616_t / uint16_t = FixPoint1616_t */
118
        xTalkStoredMeanSignalRate = sum_signalRate / total_count;
119
        xTalkStoredMeanRange = (FixPoint1616_t)((uint32_t)(
120
            sum_ranging << 16) / total_count);
121
        xTalkStoredMeanRtnSpads = (FixPoint1616_t)((uint32_t)(
122
            sum_spads << 16) / total_count);
123
124
        /* Round Mean Spads to Whole Number.
125
         * Typically the calculated mean SPAD count is a whole number
126
         * or very close to a whole
127
         * number, therefore any truncation will not result in a
128
         * significant loss in accuracy.
129
         * Also, for a grey target at a typical distance of around
130
         * 400mm, around 220 SPADs will
131
         * be enabled, therefore, any truncation will result in a loss
132
         * of accuracy of less than
133
         * 0.5%.
134
         */
135
        xTalkStoredMeanRtnSpadsAsInt = (xTalkStoredMeanRtnSpads +
136
            0x8000) >> 16;
137
138
        /* Round Cal Distance to Whole Number.
139
         * Note that the cal distance is in mm, therefore no resolution
140
         * is lost.*/
141
         xTalkCalDistanceAsInt = (XTalkCalDistance + 0x8000) >> 16;
142
143
        if (xTalkStoredMeanRtnSpadsAsInt == 0 ||
144
           xTalkCalDistanceAsInt == 0 ||
145
           xTalkStoredMeanRange >= XTalkCalDistance) {
146
            XTalkCompensationRateMegaCps = 0;
147
        } else {
148
            /* Round Cal Distance to Whole Number.
149
               Note that the cal distance is in mm, therefore no
150
               resolution is lost.*/
151
            xTalkCalDistanceAsInt = (XTalkCalDistance +
152
                0x8000) >> 16;
153
154
            /* Apply division by mean spad count early in the
155
             * calculation to keep the numbers small.
156
             * This ensures we can maintain a 32bit calculation.
157
             * Fixed1616 / int := Fixed1616 */
158
            signalXTalkTotalPerSpad = (xTalkStoredMeanSignalRate) /
159
                xTalkStoredMeanRtnSpadsAsInt;
160
161
            /* Complete the calculation for total Signal XTalk per
162
             * SPAD
163
             * Fixed1616 * (Fixed1616 - Fixed1616/int) :=
164
             * (2^16 * Fixed1616)
165
             */
166
            signalXTalkTotalPerSpad *= ((1 << 16) -
167
                (xTalkStoredMeanRange / xTalkCalDistanceAsInt));
168
169
            /* Round from 2^16 * Fixed1616, to Fixed1616. */
170
            XTalkCompensationRateMegaCps = (signalXTalkTotalPerSpad
171
                + 0x8000) >> 16;
172
        }
173
174
        *pXTalkCompensationRateMegaCps = XTalkCompensationRateMegaCps;
175
176
        /* Enable the XTalk compensation */
177
        if (Status == VL53L0X_ERROR_NONE)
178
            Status = VL53L0X_SetXTalkCompensationEnable(Dev, 1);
179
180
        /* Enable the XTalk compensation */
181
        if (Status == VL53L0X_ERROR_NONE)
182
            Status = VL53L0X_SetXTalkCompensationRateMegaCps(Dev,
183
                    XTalkCompensationRateMegaCps);
184
185
    }
186
187
    return Status;
188
}
189
190
VL53L0X_Error VL53L0X_perform_offset_calibration(VL53L0X_DEV Dev,
191
            FixPoint1616_t CalDistanceMilliMeter,
192
            int32_t *pOffsetMicroMeter)
193
{
194
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
195
    uint16_t sum_ranging = 0;
196
    FixPoint1616_t total_count = 0;
197
    VL53L0X_RangingMeasurementData_t RangingMeasurementData;
198
    FixPoint1616_t StoredMeanRange;
199
    uint32_t StoredMeanRangeAsInt;
200
    uint32_t CalDistanceAsInt_mm;
201
    uint8_t SequenceStepEnabled;
202
    int meas = 0;
203
204
    if (CalDistanceMilliMeter <= 0)
205
        Status = VL53L0X_ERROR_INVALID_PARAMS;
206
207
    if (Status == VL53L0X_ERROR_NONE)
208
        Status = VL53L0X_SetOffsetCalibrationDataMicroMeter(Dev, 0);
209
210
211
    /* Get the value of the TCC */
212
    if (Status == VL53L0X_ERROR_NONE)
213
        Status = VL53L0X_GetSequenceStepEnable(Dev,
214
                VL53L0X_SEQUENCESTEP_TCC, &SequenceStepEnabled);
215
216
217
    /* Disable the TCC */
218
    if (Status == VL53L0X_ERROR_NONE)
219
        Status = VL53L0X_SetSequenceStepEnable(Dev,
220
                VL53L0X_SEQUENCESTEP_TCC, 0);
221
222
223
    /* Disable the RIT */
224
    if (Status == VL53L0X_ERROR_NONE)
225
        Status = VL53L0X_SetLimitCheckEnable(Dev,
226
                VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0);
227
228
    /* Perform 50 measurements and compute the averages */
229
    if (Status == VL53L0X_ERROR_NONE) {
230
        sum_ranging = 0;
231
        total_count = 0;
232
        for (meas = 0; meas < 50; meas++) {
233
            Status = VL53L0X_PerformSingleRangingMeasurement(Dev,
234
                    &RangingMeasurementData);
235
236
            if (Status != VL53L0X_ERROR_NONE)
237
                break;
238
239
            /* The range is valid when RangeStatus = 0 */
240
            if (RangingMeasurementData.RangeStatus == 0) {
241
                sum_ranging = sum_ranging +
242
                    RangingMeasurementData.RangeMilliMeter;
243
                total_count = total_count + 1;
244
            }
245
        }
246
247
        /* no valid values found */
248
        if (total_count == 0)
249
            Status = VL53L0X_ERROR_RANGE_ERROR;
250
    }
251
252
253
    if (Status == VL53L0X_ERROR_NONE) {
254
        /* FixPoint1616_t / uint16_t = FixPoint1616_t */
255
        StoredMeanRange = (FixPoint1616_t)((uint32_t)(sum_ranging << 16)
256
            / total_count);
257
258
        StoredMeanRangeAsInt = (StoredMeanRange + 0x8000) >> 16;
259
260
        /* Round Cal Distance to Whole Number.
261
         * Note that the cal distance is in mm, therefore no resolution
262
         * is lost.*/
263
         CalDistanceAsInt_mm = (CalDistanceMilliMeter + 0x8000) >> 16;
264
265
         *pOffsetMicroMeter = (CalDistanceAsInt_mm -
266
                 StoredMeanRangeAsInt) * 1000;
267
268
        /* Apply the calculated offset */
269
        if (Status == VL53L0X_ERROR_NONE) {
270
            VL53L0X_SETPARAMETERFIELD(Dev, RangeOffsetMicroMeters,
271
                    *pOffsetMicroMeter);
272
            Status = VL53L0X_SetOffsetCalibrationDataMicroMeter(Dev,
273
                    *pOffsetMicroMeter);
274
        }
275
276
    }
277
278
    /* Restore the TCC */
279
    if (Status == VL53L0X_ERROR_NONE) {
280
        if (SequenceStepEnabled != 0)
281
            Status = VL53L0X_SetSequenceStepEnable(Dev,
282
                    VL53L0X_SEQUENCESTEP_TCC, 1);
283
    }
284
285
    return Status;
286
}
287
288
289
VL53L0X_Error VL53L0X_set_offset_calibration_data_micro_meter(VL53L0X_DEV Dev,
290
        int32_t OffsetCalibrationDataMicroMeter)
291
{
292
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
293
    int32_t cMaxOffsetMicroMeter = 511000;
294
    int32_t cMinOffsetMicroMeter = -512000;
295
    int16_t cOffsetRange = 4096;
296
    uint32_t encodedOffsetVal;
297
298
    LOG_FUNCTION_START("");
299
300
    if (OffsetCalibrationDataMicroMeter > cMaxOffsetMicroMeter)
301
        OffsetCalibrationDataMicroMeter = cMaxOffsetMicroMeter;
302
    else if (OffsetCalibrationDataMicroMeter < cMinOffsetMicroMeter)
303
        OffsetCalibrationDataMicroMeter = cMinOffsetMicroMeter;
304
305
    /* The offset register is 10.2 format and units are mm
306
     * therefore conversion is applied by a division of
307
     * 250.
308
     */
309
    if (OffsetCalibrationDataMicroMeter >= 0) {
310
        encodedOffsetVal =
311
            OffsetCalibrationDataMicroMeter/250;
312
    } else {
313
        encodedOffsetVal =
314
            cOffsetRange +
315
            OffsetCalibrationDataMicroMeter/250;
316
    }
317
318
    Status = VL53L0X_WrWord(Dev,
319
        VL53L0X_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM,
320
        encodedOffsetVal);
321
322
    LOG_FUNCTION_END(Status);
323
    return Status;
324
}
325
326
VL53L0X_Error VL53L0X_get_offset_calibration_data_micro_meter(VL53L0X_DEV Dev,
327
        int32_t *pOffsetCalibrationDataMicroMeter)
328
{
329
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
330
    uint16_t RangeOffsetRegister;
331
    int16_t cMaxOffset = 2047;
332
    int16_t cOffsetRange = 4096;
333
334
    /* Note that offset has 10.2 format */
335
336
    Status = VL53L0X_RdWord(Dev,
337
                VL53L0X_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM,
338
                &RangeOffsetRegister);
339
340
    if (Status == VL53L0X_ERROR_NONE) {
341
        RangeOffsetRegister = (RangeOffsetRegister & 0x0fff);
342
343
        /* Apply 12 bit 2's compliment conversion */
344
        if (RangeOffsetRegister > cMaxOffset)
345
            *pOffsetCalibrationDataMicroMeter =
346
                (int16_t)(RangeOffsetRegister - cOffsetRange)
347
                    * 250;
348
        else
349
            *pOffsetCalibrationDataMicroMeter =
350
                (int16_t)RangeOffsetRegister * 250;
351
352
    }
353
354
    return Status;
355
}
356
357
358
VL53L0X_Error VL53L0X_apply_offset_adjustment(VL53L0X_DEV Dev)
359
{
360
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
361
    int32_t CorrectedOffsetMicroMeters;
362
    int32_t CurrentOffsetMicroMeters;
363
364
    /* if we run on this function we can read all the NVM info
365
     * used by the API */
366
    Status = VL53L0X_get_info_from_device(Dev, 7);
367
368
    /* Read back current device offset */
369
    if (Status == VL53L0X_ERROR_NONE) {
370
        Status = VL53L0X_GetOffsetCalibrationDataMicroMeter(Dev,
371
                    &CurrentOffsetMicroMeters);
372
    }
373
374
    /* Apply Offset Adjustment derived from 400mm measurements */
375
    if (Status == VL53L0X_ERROR_NONE) {
376
377
        /* Store initial device offset */
378
        PALDevDataSet(Dev, Part2PartOffsetNVMMicroMeter,
379
            CurrentOffsetMicroMeters);
380
381
        CorrectedOffsetMicroMeters = CurrentOffsetMicroMeters +
382
            (int32_t)PALDevDataGet(Dev,
383
                Part2PartOffsetAdjustmentNVMMicroMeter);
384
385
        Status = VL53L0X_SetOffsetCalibrationDataMicroMeter(Dev,
386
                    CorrectedOffsetMicroMeters);
387
388
        /* store current, adjusted offset */
389
        if (Status == VL53L0X_ERROR_NONE) {
390
            VL53L0X_SETPARAMETERFIELD(Dev, RangeOffsetMicroMeters,
391
                    CorrectedOffsetMicroMeters);
392
        }
393
    }
394
395
    return Status;
396
}
397
398
void get_next_good_spad(uint8_t goodSpadArray[], uint32_t size,
399
            uint32_t curr, int32_t *next)
400
{
401
    uint32_t startIndex;
402
    uint32_t fineOffset;
403
    uint32_t cSpadsPerByte = 8;
404
    uint32_t coarseIndex;
405
    uint32_t fineIndex;
406
    uint8_t dataByte;
407
    uint8_t success = 0;
408
409
    /*
410
     * Starting with the current good spad, loop through the array to find
411
     * the next. i.e. the next bit set in the sequence.
412
     *
413
     * The coarse index is the byte index of the array and the fine index is
414
     * the index of the bit within each byte.
415
     */
416
417
    *next = -1;
418
419
    startIndex = curr / cSpadsPerByte;
420
    fineOffset = curr % cSpadsPerByte;
421
422
    for (coarseIndex = startIndex; ((coarseIndex < size) && !success);
423
                coarseIndex++) {
424
        fineIndex = 0;
425
        dataByte = goodSpadArray[coarseIndex];
426
427
        if (coarseIndex == startIndex) {
428
            /* locate the bit position of the provided current
429
             * spad bit before iterating */
430
            dataByte >>= fineOffset;
431
            fineIndex = fineOffset;
432
        }
433
434
        while (fineIndex < cSpadsPerByte) {
435
            if ((dataByte & 0x1) == 1) {
436
                success = 1;
437
                *next = coarseIndex * cSpadsPerByte + fineIndex;
438
                break;
439
            }
440
            dataByte >>= 1;
441
            fineIndex++;
442
        }
443
    }
444
}
445
446
447
uint8_t is_aperture(uint32_t spadIndex)
448
{
449
    /*
450
     * This function reports if a given spad index is an aperture SPAD by
451
     * deriving the quadrant.
452
     */
453
    uint32_t quadrant;
454
    uint8_t isAperture = 1;
455
    quadrant = spadIndex >> 6;
456
    if (refArrayQuadrants[quadrant] == REF_ARRAY_SPAD_0)
457
        isAperture = 0;
458
459
    return isAperture;
460
}
461
462
463
VL53L0X_Error enable_spad_bit(uint8_t spadArray[], uint32_t size,
464
    uint32_t spadIndex)
465
{
466
    VL53L0X_Error status = VL53L0X_ERROR_NONE;
467
    uint32_t cSpadsPerByte = 8;
468
    uint32_t coarseIndex;
469
    uint32_t fineIndex;
470
471
    coarseIndex = spadIndex / cSpadsPerByte;
472
    fineIndex = spadIndex % cSpadsPerByte;
473
    if (coarseIndex >= size)
474
        status = VL53L0X_ERROR_REF_SPAD_INIT;
475
    else
476
        spadArray[coarseIndex] |= (1 << fineIndex);
477
478
    return status;
479
}
480
481
VL53L0X_Error count_enabled_spads(uint8_t spadArray[],
482
        uint32_t byteCount, uint32_t maxSpads,
483
        uint32_t *pTotalSpadsEnabled, uint8_t *pIsAperture)
484
{
485
    VL53L0X_Error status = VL53L0X_ERROR_NONE;
486
    uint32_t cSpadsPerByte = 8;
487
    uint32_t lastByte;
488
    uint32_t lastBit;
489
    uint32_t byteIndex = 0;
490
    uint32_t bitIndex = 0;
491
    uint8_t tempByte;
492
    uint8_t spadTypeIdentified = 0;
493
494
    /* The entire array will not be used for spads, therefore the last
495
     * byte and last bit is determined from the max spads value.
496
     */
497
498
    lastByte = maxSpads / cSpadsPerByte;
499
    lastBit = maxSpads % cSpadsPerByte;
500
501
    /* Check that the max spads value does not exceed the array bounds. */
502
    if (lastByte >= byteCount)
503
        status = VL53L0X_ERROR_REF_SPAD_INIT;
504
505
    *pTotalSpadsEnabled = 0;
506
507
    /* Count the bits enabled in the whole bytes */
508
    for (byteIndex = 0; byteIndex <= (lastByte - 1); byteIndex++) {
509
        tempByte = spadArray[byteIndex];
510
511
        for (bitIndex = 0; bitIndex <= cSpadsPerByte; bitIndex++) {
512
            if ((tempByte & 0x01) == 1) {
513
                (*pTotalSpadsEnabled)++;
514
515
                if (!spadTypeIdentified) {
516
                    *pIsAperture = 1;
517
                    if ((byteIndex < 2) && (bitIndex < 4))
518
                            *pIsAperture = 0;
519
                    spadTypeIdentified = 1;
520
                }
521
            }
522
            tempByte >>= 1;
523
        }
524
    }
525
526
    /* Count the number of bits enabled in the last byte accounting
527
     * for the fact that not all bits in the byte may be used.
528
     */
529
    tempByte = spadArray[lastByte];
530
531
    for (bitIndex = 0; bitIndex <= lastBit; bitIndex++) {
532
        if ((tempByte & 0x01) == 1)
533
            (*pTotalSpadsEnabled)++;
534
    }
535
536
    return status;
537
}
538
539
VL53L0X_Error set_ref_spad_map(VL53L0X_DEV Dev, uint8_t *refSpadArray)
540
{
541
    VL53L0X_Error status = VL53L0X_WriteMulti(Dev,
542
                VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0,
543
                refSpadArray, 6);
544
    return status;
545
}
546
547
VL53L0X_Error get_ref_spad_map(VL53L0X_DEV Dev, uint8_t *refSpadArray)
548
{
549
    VL53L0X_Error status = VL53L0X_ReadMulti(Dev,
550
                VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0,
551
                refSpadArray,
552
                6);
553
    return status;
554
}
555
556
VL53L0X_Error enable_ref_spads(VL53L0X_DEV Dev,
557
                uint8_t apertureSpads,
558
                uint8_t goodSpadArray[],
559
                uint8_t spadArray[],
560
                uint32_t size,
561
                uint32_t start,
562
                uint32_t offset,
563
                uint32_t spadCount,
564
                uint32_t *lastSpad)
565
{
566
    VL53L0X_Error status = VL53L0X_ERROR_NONE;
567
    uint32_t index;
568
    uint32_t i;
569
    int32_t nextGoodSpad = offset;
570
    uint32_t currentSpad;
571
    uint8_t checkSpadArray[6];
572
573
    /*
574
     * This function takes in a spad array which may or may not have SPADS
575
     * already enabled and appends from a given offset a requested number
576
     * of new SPAD enables. The 'good spad map' is applied to
577
     * determine the next SPADs to enable.
578
     *
579
     * This function applies to only aperture or only non-aperture spads.
580
     * Checks are performed to ensure this.
581
     */
582
583
    currentSpad = offset;
584
    for (index = 0; index < spadCount; index++) {
585
        get_next_good_spad(goodSpadArray, size, currentSpad,
586
            &nextGoodSpad);
587
588
        if (nextGoodSpad == -1) {
589
            status = VL53L0X_ERROR_REF_SPAD_INIT;
590
            break;
591
        }
592
593
        /* Confirm that the next good SPAD is non-aperture */
594
        if (is_aperture(start + nextGoodSpad) != apertureSpads) {
595
            /* if we can't get the required number of good aperture
596
             * spads from the current quadrant then this is an error
597
             */
598
            status = VL53L0X_ERROR_REF_SPAD_INIT;
599
            break;
600
        }
601
        currentSpad = (uint32_t)nextGoodSpad;
602
        enable_spad_bit(spadArray, size, currentSpad);
603
        currentSpad++;
604
    }
605
    *lastSpad = currentSpad;
606
607
    if (status == VL53L0X_ERROR_NONE)
608
        status = set_ref_spad_map(Dev, spadArray);
609
610
611
    if (status == VL53L0X_ERROR_NONE) {
612
        status = get_ref_spad_map(Dev, checkSpadArray);
613
614
        i = 0;
615
616
        /* Compare spad maps. If not equal report error. */
617
        while (i < size) {
618
            if (spadArray[i] != checkSpadArray[i]) {
619
                status = VL53L0X_ERROR_REF_SPAD_INIT;
620
                break;
621
            }
622
            i++;
623
        }
624
    }
625
    return status;
626
}
627
628
629
VL53L0X_Error perform_ref_signal_measurement(VL53L0X_DEV Dev,
630
        uint16_t *refSignalRate)
631
{
632
    VL53L0X_Error status = VL53L0X_ERROR_NONE;
633
    VL53L0X_RangingMeasurementData_t rangingMeasurementData;
634
635
    uint8_t SequenceConfig = 0;
636
637
    /* store the value of the sequence config,
638
     * this will be reset before the end of the function
639
     */
640
641
    SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
642
643
    /*
644
     * This function performs a reference signal rate measurement.
645
     */
646
    if (status == VL53L0X_ERROR_NONE)
647
        status = VL53L0X_WrByte(Dev,
648
            VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG, 0xC0);
649
650
    if (status == VL53L0X_ERROR_NONE)
651
        status = VL53L0X_PerformSingleRangingMeasurement(Dev,
652
                &rangingMeasurementData);
653
654
    if (status == VL53L0X_ERROR_NONE)
655
        status = VL53L0X_WrByte(Dev, 0xFF, 0x01);
656
657
    if (status == VL53L0X_ERROR_NONE)
658
        status = VL53L0X_RdWord(Dev,
659
            VL53L0X_REG_RESULT_PEAK_SIGNAL_RATE_REF,
660
            refSignalRate);
661
662
    if (status == VL53L0X_ERROR_NONE)
663
        status = VL53L0X_WrByte(Dev, 0xFF, 0x00);
664
665
    if (status == VL53L0X_ERROR_NONE) {
666
        /* restore the previous Sequence Config */
667
        status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG,
668
                SequenceConfig);
669
        if (status == VL53L0X_ERROR_NONE)
670
            PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
671
    }
672
673
    return status;
674
}
675
676
VL53L0X_Error VL53L0X_perform_ref_spad_management(VL53L0X_DEV Dev,
677
                uint32_t *refSpadCount,
678
                uint8_t *isApertureSpads)
679
{
680
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
681
    uint8_t lastSpadArray[6];
682
    uint8_t startSelect = 0xB4;
683
    uint32_t minimumSpadCount = 3;
684
    uint32_t maxSpadCount = 44;
685
    uint32_t currentSpadIndex = 0;
686
    uint32_t lastSpadIndex = 0;
687
    int32_t nextGoodSpad = 0;
688
    uint16_t targetRefRate = 0x0A00; /* 20 MCPS in 9:7 format */
689
    uint16_t peakSignalRateRef;
690
    uint32_t needAptSpads = 0;
691
    uint32_t index = 0;
692
    uint32_t spadArraySize = 6;
693
    uint32_t signalRateDiff = 0;
694
    uint32_t lastSignalRateDiff = 0;
695
    uint8_t complete = 0;
696
    uint8_t VhvSettings = 0;
697
    uint8_t PhaseCal = 0;
698
    uint32_t refSpadCount_int = 0;
699
    uint8_t         isApertureSpads_int = 0;
700
701
    /*
702
     * The reference SPAD initialization procedure determines the minimum
703
     * amount of reference spads to be enables to achieve a target reference
704
     * signal rate and should be performed once during initialization.
705
     *
706
     * Either aperture or non-aperture spads are applied but never both.
707
     * Firstly non-aperture spads are set, begining with 5 spads, and
708
     * increased one spad at a time until the closest measurement to the
709
     * target rate is achieved.
710
     *
711
     * If the target rate is exceeded when 5 non-aperture spads are enabled,
712
     * initialization is performed instead with aperture spads.
713
     *
714
     * When setting spads, a 'Good Spad Map' is applied.
715
     *
716
     * This procedure operates within a SPAD window of interest of a maximum
717
     * 44 spads.
718
     * The start point is currently fixed to 180, which lies towards the end
719
     * of the non-aperture quadrant and runs in to the adjacent aperture
720
     * quadrant.
721
     */
722
723
724
    targetRefRate = PALDevDataGet(Dev, targetRefRate);
725
726
    /*
727
     * Initialize Spad arrays.
728
     * Currently the good spad map is initialised to 'All good'.
729
     * This is a short term implementation. The good spad map will be
730
     * provided as an input.
731
     * Note that there are 6 bytes. Only the first 44 bits will be used to
732
     * represent spads.
733
     */
734
    for (index = 0; index < spadArraySize; index++)
735
        Dev->Data.SpadData.RefSpadEnables[index] = 0;
736
737
738
    Status = VL53L0X_WrByte(Dev, 0xFF, 0x01);
739
740
    if (Status == VL53L0X_ERROR_NONE)
741
        Status = VL53L0X_WrByte(Dev,
742
            VL53L0X_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
743
744
    if (Status == VL53L0X_ERROR_NONE)
745
        Status = VL53L0X_WrByte(Dev,
746
            VL53L0X_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
747
748
    if (Status == VL53L0X_ERROR_NONE)
749
        Status = VL53L0X_WrByte(Dev, 0xFF, 0x00);
750
751
    if (Status == VL53L0X_ERROR_NONE)
752
        Status = VL53L0X_WrByte(Dev,
753
            VL53L0X_REG_GLOBAL_CONFIG_REF_EN_START_SELECT,
754
            startSelect);
755
756
757
    if (Status == VL53L0X_ERROR_NONE)
758
        Status = VL53L0X_WrByte(Dev,
759
                VL53L0X_REG_POWER_MANAGEMENT_GO1_POWER_FORCE, 0);
760
761
    /* Perform ref calibration */
762
    if (Status == VL53L0X_ERROR_NONE)
763
        Status = VL53L0X_perform_ref_calibration(Dev, &VhvSettings,
764
            &PhaseCal, 0);
765
766
    if (Status == VL53L0X_ERROR_NONE) {
767
        /* Enable Minimum NON-APERTURE Spads */
768
        currentSpadIndex = 0;
769
        lastSpadIndex = currentSpadIndex;
770
        needAptSpads = 0;
771
        Status = enable_ref_spads(Dev,
772
                    needAptSpads,
773
                    Dev->Data.SpadData.RefGoodSpadMap,
774
                    Dev->Data.SpadData.RefSpadEnables,
775
                    spadArraySize,
776
                    startSelect,
777
                    currentSpadIndex,
778
                    minimumSpadCount,
779
                    &lastSpadIndex);
780
    }
781
782
    if (Status == VL53L0X_ERROR_NONE) {
783
        currentSpadIndex = lastSpadIndex;
784
785
        Status = perform_ref_signal_measurement(Dev,
786
            &peakSignalRateRef);
787
        if ((Status == VL53L0X_ERROR_NONE) &&
788
            (peakSignalRateRef > targetRefRate)) {
789
            /* Signal rate measurement too high,
790
             * switch to APERTURE SPADs */
791
792
            for (index = 0; index < spadArraySize; index++)
793
                Dev->Data.SpadData.RefSpadEnables[index] = 0;
794
795
796
            /* Increment to the first APERTURE spad */
797
            while ((is_aperture(startSelect + currentSpadIndex)
798
                == 0) && (currentSpadIndex < maxSpadCount)) {
799
                currentSpadIndex++;
800
            }
801
802
            needAptSpads = 1;
803
804
            Status = enable_ref_spads(Dev,
805
                    needAptSpads,
806
                    Dev->Data.SpadData.RefGoodSpadMap,
807
                    Dev->Data.SpadData.RefSpadEnables,
808
                    spadArraySize,
809
                    startSelect,
810
                    currentSpadIndex,
811
                    minimumSpadCount,
812
                    &lastSpadIndex);
813
814
            if (Status == VL53L0X_ERROR_NONE) {
815
                currentSpadIndex = lastSpadIndex;
816
                Status = perform_ref_signal_measurement(Dev,
817
                        &peakSignalRateRef);
818
819
                if ((Status == VL53L0X_ERROR_NONE) &&
820
                    (peakSignalRateRef > targetRefRate)) {
821
                    /* Signal rate still too high after
822
                     * setting the minimum number of
823
                     * APERTURE spads. Can do no more
824
                     * therefore set the min number of
825
                     * aperture spads as the result.
826
                     */
827
                    isApertureSpads_int = 1;
828
                    refSpadCount_int = minimumSpadCount;
829
                }
830
            }
831
        } else {
832
            needAptSpads = 0;
833
        }
834
    }
835
836
    if ((Status == VL53L0X_ERROR_NONE) &&
837
        (peakSignalRateRef < targetRefRate)) {
838
        /* At this point, the minimum number of either aperture
839
         * or non-aperture spads have been set. Proceed to add
840
         * spads and perform measurements until the target
841
         * reference is reached.
842
         */
843
        isApertureSpads_int = needAptSpads;
844
        refSpadCount_int        = minimumSpadCount;
845
846
        memcpy(lastSpadArray, Dev->Data.SpadData.RefSpadEnables,
847
                spadArraySize);
848
        lastSignalRateDiff = abs(peakSignalRateRef -
849
            targetRefRate);
850
        complete = 0;
851
852
        while (!complete) {
853
            get_next_good_spad(
854
                Dev->Data.SpadData.RefGoodSpadMap,
855
                spadArraySize, currentSpadIndex,
856
                &nextGoodSpad);
857
858
            if (nextGoodSpad == -1) {
859
                Status = VL53L0X_ERROR_REF_SPAD_INIT;
860
                break;
861
            }
862
863
            /* Cannot combine Aperture and Non-Aperture spads, so
864
             * ensure the current spad is of the correct type.
865
             */
866
            if (is_aperture((uint32_t)startSelect + nextGoodSpad) !=
867
                    needAptSpads) {
868
                /* At this point we have enabled the maximum
869
                 * number of Aperture spads.
870
                 */
871
                complete = 1;
872
                break;
873
            }
874
875
            (refSpadCount_int)++;
876
877
            currentSpadIndex = nextGoodSpad;
878
            Status = enable_spad_bit(
879
                    Dev->Data.SpadData.RefSpadEnables,
880
                    spadArraySize, currentSpadIndex);
881
882
            if (Status == VL53L0X_ERROR_NONE) {
883
                currentSpadIndex++;
884
                /* Proceed to apply the additional spad and
885
                 * perform measurement. */
886
                Status = set_ref_spad_map(Dev,
887
                    Dev->Data.SpadData.RefSpadEnables);
888
            }
889
890
            if (Status != VL53L0X_ERROR_NONE)
891
                break;
892
893
            Status = perform_ref_signal_measurement(Dev,
894
                    &peakSignalRateRef);
895
896
            if (Status != VL53L0X_ERROR_NONE)
897
                break;
898
899
            signalRateDiff = abs(peakSignalRateRef - targetRefRate);
900
901
            if (peakSignalRateRef > targetRefRate) {
902
                /* Select the spad map that provides the
903
                 * measurement closest to the target rate,
904
                 * either above or below it.
905
                 */
906
                if (signalRateDiff > lastSignalRateDiff) {
907
                    /* Previous spad map produced a closer
908
                     * measurement, so choose this. */
909
                    Status = set_ref_spad_map(Dev,
910
                            lastSpadArray);
911
                    memcpy(
912
                    Dev->Data.SpadData.RefSpadEnables,
913
                    lastSpadArray, spadArraySize);
914
915
                    (refSpadCount_int)--;
916
                }
917
                complete = 1;
918
            } else {
919
                /* Continue to add spads */
920
                lastSignalRateDiff = signalRateDiff;
921
                memcpy(lastSpadArray,
922
                    Dev->Data.SpadData.RefSpadEnables,
923
                    spadArraySize);
924
            }
925
926
        } /* while */
927
    }
928
929
    if (Status == VL53L0X_ERROR_NONE) {
930
        *refSpadCount = refSpadCount_int;
931
        *isApertureSpads = isApertureSpads_int;
932
933
        VL53L0X_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 1);
934
        VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
935
            ReferenceSpadCount, (uint8_t)(*refSpadCount));
936
        VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
937
            ReferenceSpadType, *isApertureSpads);
938
    }
939
940
    return Status;
941
}
942
943
VL53L0X_Error VL53L0X_set_reference_spads(VL53L0X_DEV Dev,
944
                 uint32_t count, uint8_t isApertureSpads)
945
{
946
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
947
    uint32_t currentSpadIndex = 0;
948
    uint8_t startSelect = 0xB4;
949
    uint32_t spadArraySize = 6;
950
    uint32_t maxSpadCount = 44;
951
    uint32_t lastSpadIndex;
952
    uint32_t index;
953
954
    /*
955
     * This function applies a requested number of reference spads, either
956
     * aperture or
957
     * non-aperture, as requested.
958
     * The good spad map will be applied.
959
     */
960
961
    Status = VL53L0X_WrByte(Dev, 0xFF, 0x01);
962
963
    if (Status == VL53L0X_ERROR_NONE)
964
        Status = VL53L0X_WrByte(Dev,
965
            VL53L0X_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
966
967
    if (Status == VL53L0X_ERROR_NONE)
968
        Status = VL53L0X_WrByte(Dev,
969
            VL53L0X_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
970
971
    if (Status == VL53L0X_ERROR_NONE)
972
        Status = VL53L0X_WrByte(Dev, 0xFF, 0x00);
973
974
    if (Status == VL53L0X_ERROR_NONE)
975
        Status = VL53L0X_WrByte(Dev,
976
            VL53L0X_REG_GLOBAL_CONFIG_REF_EN_START_SELECT,
977
            startSelect);
978
979
    for (index = 0; index < spadArraySize; index++)
980
        Dev->Data.SpadData.RefSpadEnables[index] = 0;
981
982
    if (isApertureSpads) {
983
        /* Increment to the first APERTURE spad */
984
        while ((is_aperture(startSelect + currentSpadIndex) == 0) &&
985
              (currentSpadIndex < maxSpadCount)) {
986
            currentSpadIndex++;
987
        }
988
    }
989
    Status = enable_ref_spads(Dev,
990
                isApertureSpads,
991
                Dev->Data.SpadData.RefGoodSpadMap,
992
                Dev->Data.SpadData.RefSpadEnables,
993
                spadArraySize,
994
                startSelect,
995
                currentSpadIndex,
996
                count,
997
                &lastSpadIndex);
998
999
    if (Status == VL53L0X_ERROR_NONE) {
1000
        VL53L0X_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 1);
1001
        VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
1002
            ReferenceSpadCount, (uint8_t)(count));
1003
        VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
1004
            ReferenceSpadType, isApertureSpads);
1005
    }
1006
1007
    return Status;
1008
}
1009
1010
VL53L0X_Error VL53L0X_get_reference_spads(VL53L0X_DEV Dev,
1011
            uint32_t *pSpadCount, uint8_t *pIsApertureSpads)
1012
{
1013
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1014
    uint8_t refSpadsInitialised;
1015
    uint8_t refSpadArray[6];
1016
    uint32_t cMaxSpadCount = 44;
1017
    uint32_t cSpadArraySize = 6;
1018
    uint32_t spadsEnabled;
1019
    uint8_t isApertureSpads = 0;
1020
1021
    refSpadsInitialised = VL53L0X_GETDEVICESPECIFICPARAMETER(Dev,
1022
                    RefSpadsInitialised);
1023
1024
    if (refSpadsInitialised == 1) {
1025
1026
        *pSpadCount = (uint32_t)VL53L0X_GETDEVICESPECIFICPARAMETER(Dev,
1027
            ReferenceSpadCount);
1028
        *pIsApertureSpads = VL53L0X_GETDEVICESPECIFICPARAMETER(Dev,
1029
            ReferenceSpadType);
1030
    } else {
1031
1032
        /* obtain spad info from device.*/
1033
        Status = get_ref_spad_map(Dev, refSpadArray);
1034
1035
        if (Status == VL53L0X_ERROR_NONE) {
1036
            /* count enabled spads within spad map array and
1037
             * determine if Aperture or Non-Aperture.
1038
             */
1039
            Status = count_enabled_spads(refSpadArray,
1040
                            cSpadArraySize,
1041
                            cMaxSpadCount,
1042
                            &spadsEnabled,
1043
                            &isApertureSpads);
1044
1045
            if (Status == VL53L0X_ERROR_NONE) {
1046
1047
                *pSpadCount = spadsEnabled;
1048
                *pIsApertureSpads = isApertureSpads;
1049
1050
                VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
1051
                    RefSpadsInitialised, 1);
1052
                VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
1053
                    ReferenceSpadCount,
1054
                    (uint8_t)spadsEnabled);
1055
                VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
1056
                    ReferenceSpadType, isApertureSpads);
1057
            }
1058
        }
1059
    }
1060
1061
    return Status;
1062
}
1063
1064
1065
VL53L0X_Error VL53L0X_perform_single_ref_calibration(VL53L0X_DEV Dev,
1066
        uint8_t vhv_init_byte)
1067
{
1068
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1069
1070
    if (Status == VL53L0X_ERROR_NONE)
1071
        Status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSRANGE_START,
1072
                VL53L0X_REG_SYSRANGE_MODE_START_STOP |
1073
                vhv_init_byte);
1074
1075
    if (Status == VL53L0X_ERROR_NONE)
1076
        Status = VL53L0X_measurement_poll_for_completion(Dev);
1077
1078
    if (Status == VL53L0X_ERROR_NONE)
1079
        Status = VL53L0X_ClearInterruptMask(Dev, 0);
1080
1081
    if (Status == VL53L0X_ERROR_NONE)
1082
        Status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSRANGE_START, 0x00);
1083
1084
    return Status;
1085
}
1086
1087
1088
VL53L0X_Error VL53L0X_ref_calibration_io(VL53L0X_DEV Dev, uint8_t read_not_write,
1089
    uint8_t VhvSettings, uint8_t PhaseCal,
1090
    uint8_t *pVhvSettings, uint8_t *pPhaseCal,
1091
    const uint8_t vhv_enable, const uint8_t phase_enable)
1092
{
1093
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1094
    uint8_t PhaseCalint = 0;
1095
1096
    /* Read VHV from device */
1097
    Status |= VL53L0X_WrByte(Dev, 0xFF, 0x01);
1098
    Status |= VL53L0X_WrByte(Dev, 0x00, 0x00);
1099
    Status |= VL53L0X_WrByte(Dev, 0xFF, 0x00);
1100
1101
    if (read_not_write) {
1102
        if (vhv_enable)
1103
            Status |= VL53L0X_RdByte(Dev, 0xCB, pVhvSettings);
1104
        if (phase_enable)
1105
            Status |= VL53L0X_RdByte(Dev, 0xEE, &PhaseCalint);
1106
    } else {
1107
        if (vhv_enable)
1108
            Status |= VL53L0X_WrByte(Dev, 0xCB, VhvSettings);
1109
        if (phase_enable)
1110
            Status |= VL53L0X_UpdateByte(Dev, 0xEE, 0x80, PhaseCal);
1111
    }
1112
1113
    Status |= VL53L0X_WrByte(Dev, 0xFF, 0x01);
1114
    Status |= VL53L0X_WrByte(Dev, 0x00, 0x01);
1115
    Status |= VL53L0X_WrByte(Dev, 0xFF, 0x00);
1116
1117
    *pPhaseCal = (uint8_t)(PhaseCalint&0xEF);
1118
1119
    return Status;
1120
}
1121
1122
1123
VL53L0X_Error VL53L0X_perform_vhv_calibration(VL53L0X_DEV Dev,
1124
    uint8_t *pVhvSettings, const uint8_t get_data_enable,
1125
    const uint8_t restore_config)
1126
{
1127
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1128
    uint8_t SequenceConfig = 0;
1129
    uint8_t VhvSettings = 0;
1130
    uint8_t PhaseCal = 0;
1131
    uint8_t PhaseCalInt = 0;
1132
1133
    /* store the value of the sequence config,
1134
     * this will be reset before the end of the function
1135
     */
1136
1137
    if (restore_config)
1138
        SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
1139
1140
    /* Run VHV */
1141
    Status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG, 0x01);
1142
1143
    if (Status == VL53L0X_ERROR_NONE)
1144
        Status = VL53L0X_perform_single_ref_calibration(Dev, 0x40);
1145
1146
    /* Read VHV from device */
1147
    if ((Status == VL53L0X_ERROR_NONE) && (get_data_enable == 1)) {
1148
        Status = VL53L0X_ref_calibration_io(Dev, 1,
1149
            VhvSettings, PhaseCal, /* Not used here */
1150
            pVhvSettings, &PhaseCalInt,
1151
            1, 0);
1152
    } else
1153
        *pVhvSettings = 0;
1154
1155
1156
    if ((Status == VL53L0X_ERROR_NONE) && restore_config) {
1157
        /* restore the previous Sequence Config */
1158
        Status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG,
1159
                SequenceConfig);
1160
        if (Status == VL53L0X_ERROR_NONE)
1161
            PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
1162
1163
    }
1164
1165
    return Status;
1166
}
1167
1168
VL53L0X_Error VL53L0X_perform_phase_calibration(VL53L0X_DEV Dev,
1169
    uint8_t *pPhaseCal, const uint8_t get_data_enable,
1170
    const uint8_t restore_config)
1171
{
1172
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1173
    uint8_t SequenceConfig = 0;
1174
    uint8_t VhvSettings = 0;
1175
    uint8_t PhaseCal = 0;
1176
    uint8_t VhvSettingsint;
1177
1178
    /* store the value of the sequence config,
1179
     * this will be reset before the end of the function
1180
     */
1181
1182
    if (restore_config)
1183
        SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
1184
1185
    /* Run PhaseCal */
1186
    Status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG, 0x02);
1187
1188
    if (Status == VL53L0X_ERROR_NONE)
1189
        Status = VL53L0X_perform_single_ref_calibration(Dev, 0x0);
1190
1191
    /* Read PhaseCal from device */
1192
    if ((Status == VL53L0X_ERROR_NONE) && (get_data_enable == 1)) {
1193
        Status = VL53L0X_ref_calibration_io(Dev, 1,
1194
            VhvSettings, PhaseCal, /* Not used here */
1195
            &VhvSettingsint, pPhaseCal,
1196
            0, 1);
1197
    } else
1198
        *pPhaseCal = 0;
1199
1200
1201
    if ((Status == VL53L0X_ERROR_NONE) && restore_config) {
1202
        /* restore the previous Sequence Config */
1203
        Status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG,
1204
                SequenceConfig);
1205
        if (Status == VL53L0X_ERROR_NONE)
1206
            PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
1207
1208
    }
1209
1210
    return Status;
1211
}
1212
1213
VL53L0X_Error VL53L0X_perform_ref_calibration(VL53L0X_DEV Dev,
1214
    uint8_t *pVhvSettings, uint8_t *pPhaseCal, uint8_t get_data_enable)
1215
{
1216
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1217
    uint8_t SequenceConfig = 0;
1218
1219
    /* store the value of the sequence config,
1220
     * this will be reset before the end of the function
1221
     */
1222
1223
    SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
1224
1225
    /* In the following function we don't save the config to optimize
1226
     * writes on device. Config is saved and restored only once. */
1227
    Status = VL53L0X_perform_vhv_calibration(
1228
            Dev, pVhvSettings, get_data_enable, 0);
1229
1230
1231
    if (Status == VL53L0X_ERROR_NONE)
1232
        Status = VL53L0X_perform_phase_calibration(
1233
            Dev, pPhaseCal, get_data_enable, 0);
1234
1235
1236
    if (Status == VL53L0X_ERROR_NONE) {
1237
        /* restore the previous Sequence Config */
1238
        Status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG,
1239
                SequenceConfig);
1240
        if (Status == VL53L0X_ERROR_NONE)
1241
            PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
1242
1243
    }
1244
1245
    return Status;
1246
}
1247
1248
VL53L0X_Error VL53L0X_set_ref_calibration(VL53L0X_DEV Dev,
1249
        uint8_t VhvSettings, uint8_t PhaseCal)
1250
{
1251
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1252
    uint8_t pVhvSettings;
1253
    uint8_t pPhaseCal;
1254
1255
    Status = VL53L0X_ref_calibration_io(Dev, 0,
1256
        VhvSettings, PhaseCal,
1257
        &pVhvSettings, &pPhaseCal,
1258
        1, 1);
1259
1260
    return Status;
1261
}
1262
1263
VL53L0X_Error VL53L0X_get_ref_calibration(VL53L0X_DEV Dev,
1264
        uint8_t *pVhvSettings, uint8_t *pPhaseCal)
1265
{
1266
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1267
    uint8_t VhvSettings = 0;
1268
    uint8_t PhaseCal = 0;
1269
1270
    Status = VL53L0X_ref_calibration_io(Dev, 1,
1271
        VhvSettings, PhaseCal,
1272
        pVhvSettings, pPhaseCal,
1273
        1, 1);
1274
1275
    return Status;
1276
}