blob: 6824c02c5262bcce5c36fd57850d8bcc95881016 [file] [log] [blame]
shaoxingc0dbf642018-03-20 19:43:05 +08001/*
2 * vl53l0x_api_core.c - Linux kernel modules for
3 * STM VL53L0 FlightSense TOF sensor
4 *
5 * Copyright (C) 2016 STMicroelectronics Imaging Division.
6 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19#include "vl53l0x_api.h"
20#include "vl53l0x_api_core.h"
21#include "vl53l0x_api_calibration.h"
22
23
24#ifndef __KERNEL__
25#include <stdlib.h>
26#endif
27#define LOG_FUNCTION_START(fmt, ...) \
28 _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
29#define LOG_FUNCTION_END(status, ...) \
30 _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
31#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
32 _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
33
34int8_t VL_reverse_bytes(uint8_t *data, uint32_t size)
35{
36 int8_t Status = VL_ERROR_NONE;
37 uint8_t tempData;
38 uint32_t mirrorIndex;
39 uint32_t middle = size/2;
40 uint32_t index;
41
42 for (index = 0; index < middle; index++) {
43 mirrorIndex = size - index - 1;
44 tempData = data[index];
45 data[index] = data[mirrorIndex];
46 data[mirrorIndex] = tempData;
47 }
48 return Status;
49}
50
51int8_t VL_measurement_poll_for_completion(struct vl_data *Dev)
52{
53 int8_t Status = VL_ERROR_NONE;
54 uint8_t NewDataReady = 0;
55 uint32_t LoopNb;
56
57 LOG_FUNCTION_START("");
58
59 LoopNb = 0;
60
61 do {
62 Status = VL_GetMeasurementDataReady(Dev, &NewDataReady);
63 if (Status != 0)
64 break; /* the error is set */
65
66 if (NewDataReady == 1)
67 break; /* done note that status == 0 */
68
69 LoopNb++;
70 if (LoopNb >= VL_DEFAULT_MAX_LOOP) {
71 Status = VL_ERROR_TIME_OUT;
72 break;
73 }
74
75 VL_PollingDelay(Dev);
76 } while (1);
77
78 LOG_FUNCTION_END(Status);
79
80 return Status;
81}
82
83
84uint8_t VL_decode_vcsel_period(uint8_t vcsel_period_reg)
85{
86 /*!
87 * Converts the encoded VCSEL period register value into the real
88 * period in PLL clocks
89 */
90
91 uint8_t vcsel_period_pclks = 0;
92
93 vcsel_period_pclks = (vcsel_period_reg + 1) << 1;
94
95 return vcsel_period_pclks;
96}
97
98uint8_t VL_encode_vcsel_period(uint8_t vcsel_period_pclks)
99{
100 /*!
101 * Converts the encoded VCSEL period register value into the real period
102 * in PLL clocks
103 */
104
105 uint8_t vcsel_period_reg = 0;
106
107 vcsel_period_reg = (vcsel_period_pclks >> 1) - 1;
108
109 return vcsel_period_reg;
110}
111
112
113uint32_t VL_isqrt(uint32_t num)
114{
115 /*
116 * Implements an integer square root
117 *
118 * From: http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
119 */
120
121 uint32_t res = 0;
122 uint32_t bit = 1 << 30;
123 /* The second-to-top bit is set: */
124 /* 1 << 14 for 16-bits, 1 << 30 for 32 bits */
125
126 /* "bit" starts at the highest power of four <= the argument. */
127 while (bit > num)
128 bit >>= 2;
129
130
131 while (bit != 0) {
132 if (num >= res + bit) {
133 num -= res + bit;
134 res = (res >> 1) + bit;
135 } else
136 res >>= 1;
137
138 bit >>= 2;
139 }
140
141 return res;
142}
143
144
145uint32_t VL_quadrature_sum(uint32_t a, uint32_t b)
146{
147 /*
148 * Implements a quadrature sum
149 *
150 * rea = sqrt(a^2 + b^2)
151 *
152 * Trap overflow case max input value is 65535 (16-bit value)
153 * as internal calc are 32-bit wide
154 *
155 * If overflow then seta output to maximum
156 */
157 uint32_t res = 0;
158
159 if (a > 65535 || b > 65535)
160 res = 65535;
161 else
162 res = VL_isqrt(a * a + b * b);
163
164 return res;
165}
166
167
168int8_t VL_device_read_strobe(struct vl_data *Dev)
169{
170 int8_t Status = VL_ERROR_NONE;
171 uint8_t strobe;
172 uint32_t LoopNb;
173
174 LOG_FUNCTION_START("");
175
176 Status |= VL_WrByte(Dev, 0x83, 0x00);
177
178 /* polling use timeout to avoid deadlock*/
179 if (Status == VL_ERROR_NONE) {
180 LoopNb = 0;
181 do {
182 Status = VL_RdByte(Dev, 0x83, &strobe);
183 if ((strobe != 0x00) || Status != VL_ERROR_NONE)
184 break;
zhaochen85671562018-06-13 17:48:56 +0800185 LoopNb = LoopNb + 1;
shaoxingc0dbf642018-03-20 19:43:05 +0800186 } while (LoopNb < VL_DEFAULT_MAX_LOOP);
187
188 if (LoopNb >= VL_DEFAULT_MAX_LOOP)
189 Status = VL_ERROR_TIME_OUT;
190
191 }
192
193 Status |= VL_WrByte(Dev, 0x83, 0x01);
194
195 LOG_FUNCTION_END(Status);
196 return Status;
197
198}
199
200int8_t VL_get_info_from_device(struct vl_data *Dev, uint8_t option)
201{
202
203 int8_t Status = VL_ERROR_NONE;
204 uint8_t byte;
205 uint32_t TmpDWord;
206 uint8_t ModuleId;
207 uint8_t Revision;
208 uint8_t ReferenceSpadCount = 0;
209 uint8_t ReferenceSpadType = 0;
210 uint32_t PartUIDUpper = 0;
211 uint32_t PartUIDLower = 0;
212 uint32_t OffsetFixed1104_mm = 0;
213 int16_t OffsetMicroMeters = 0;
214 uint32_t DistMeasTgtFixed1104_mm = 400 << 4;
215 uint32_t DistMeasFixed1104_400_mm = 0;
216 uint32_t SignalRateMeasFixed1104_400_mm = 0;
217 char ProductId[19];
218 char *ProductId_tmp;
219 uint8_t ReadDataFromDeviceDone;
220 unsigned int SignalRateMeasFixed400mmFix = 0;
221 uint8_t NvmRefGoodSpadMap[VL_REF_SPAD_BUFFER_SIZE];
222 int i;
223
224
225 LOG_FUNCTION_START("");
226
227 ReadDataFromDeviceDone = VL_GETDEVICESPECIFICPARAMETER(Dev,
228 ReadDataFromDeviceDone);
229
230 /* This access is done only once after that a GetDeviceInfo or */
231 /* datainit is done*/
232 if (ReadDataFromDeviceDone != 7) {
233
234 Status |= VL_WrByte(Dev, 0x80, 0x01);
235 Status |= VL_WrByte(Dev, 0xFF, 0x01);
236 Status |= VL_WrByte(Dev, 0x00, 0x00);
237
238 Status |= VL_WrByte(Dev, 0xFF, 0x06);
239 Status |= VL_RdByte(Dev, 0x83, &byte);
240 Status |= VL_WrByte(Dev, 0x83, byte|4);
241 Status |= VL_WrByte(Dev, 0xFF, 0x07);
242 Status |= VL_WrByte(Dev, 0x81, 0x01);
243
244 Status |= VL_PollingDelay(Dev);
245
246 Status |= VL_WrByte(Dev, 0x80, 0x01);
247
248 if (((option & 1) == 1) &&
249 ((ReadDataFromDeviceDone & 1) == 0)) {
250 Status |= VL_WrByte(Dev, 0x94, 0x6b);
251 Status |= VL_device_read_strobe(Dev);
252 Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
253
254 ReferenceSpadCount = (uint8_t)((TmpDWord >> 8) & 0x07f);
255 ReferenceSpadType = (uint8_t)((TmpDWord >> 15) & 0x01);
256
257 Status |= VL_WrByte(Dev, 0x94, 0x24);
258 Status |= VL_device_read_strobe(Dev);
259 Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
260
261
262 NvmRefGoodSpadMap[0] = (uint8_t)((TmpDWord >> 24)
263 & 0xff);
264 NvmRefGoodSpadMap[1] = (uint8_t)((TmpDWord >> 16)
265 & 0xff);
266 NvmRefGoodSpadMap[2] = (uint8_t)((TmpDWord >> 8)
267 & 0xff);
268 NvmRefGoodSpadMap[3] = (uint8_t)(TmpDWord & 0xff);
269
270 Status |= VL_WrByte(Dev, 0x94, 0x25);
271 Status |= VL_device_read_strobe(Dev);
272 Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
273
274 NvmRefGoodSpadMap[4] = (uint8_t)((TmpDWord >> 24)
275 & 0xff);
276 NvmRefGoodSpadMap[5] = (uint8_t)((TmpDWord >> 16)
277 & 0xff);
278 }
279
280 if (((option & 2) == 2) &&
281 ((ReadDataFromDeviceDone & 2) == 0)) {
282
283 Status |= VL_WrByte(Dev, 0x94, 0x02);
284 Status |= VL_device_read_strobe(Dev);
285 Status |= VL_RdByte(Dev, 0x90, &ModuleId);
286
287 Status |= VL_WrByte(Dev, 0x94, 0x7B);
288 Status |= VL_device_read_strobe(Dev);
289 Status |= VL_RdByte(Dev, 0x90, &Revision);
290
291 Status |= VL_WrByte(Dev, 0x94, 0x77);
292 Status |= VL_device_read_strobe(Dev);
293 Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
294
295 ProductId[0] = (char)((TmpDWord >> 25) & 0x07f);
296 ProductId[1] = (char)((TmpDWord >> 18) & 0x07f);
297 ProductId[2] = (char)((TmpDWord >> 11) & 0x07f);
298 ProductId[3] = (char)((TmpDWord >> 4) & 0x07f);
299
300 byte = (uint8_t)((TmpDWord & 0x00f) << 3);
301
302 Status |= VL_WrByte(Dev, 0x94, 0x78);
303 Status |= VL_device_read_strobe(Dev);
304 Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
305
306 ProductId[4] = (char)(byte +
307 ((TmpDWord >> 29) & 0x07f));
308 ProductId[5] = (char)((TmpDWord >> 22) & 0x07f);
309 ProductId[6] = (char)((TmpDWord >> 15) & 0x07f);
310 ProductId[7] = (char)((TmpDWord >> 8) & 0x07f);
311 ProductId[8] = (char)((TmpDWord >> 1) & 0x07f);
312
313 byte = (uint8_t)((TmpDWord & 0x001) << 6);
314
315 Status |= VL_WrByte(Dev, 0x94, 0x79);
316
317 Status |= VL_device_read_strobe(Dev);
318
319 Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
320
321 ProductId[9] = (char)(byte +
322 ((TmpDWord >> 26) & 0x07f));
323 ProductId[10] = (char)((TmpDWord >> 19) & 0x07f);
324 ProductId[11] = (char)((TmpDWord >> 12) & 0x07f);
325 ProductId[12] = (char)((TmpDWord >> 5) & 0x07f);
326
327 byte = (uint8_t)((TmpDWord & 0x01f) << 2);
328
329 Status |= VL_WrByte(Dev, 0x94, 0x7A);
330
331 Status |= VL_device_read_strobe(Dev);
332
333 Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
334
335 ProductId[13] = (char)(byte +
336 ((TmpDWord >> 30) & 0x07f));
337 ProductId[14] = (char)((TmpDWord >> 23) & 0x07f);
338 ProductId[15] = (char)((TmpDWord >> 16) & 0x07f);
339 ProductId[16] = (char)((TmpDWord >> 9) & 0x07f);
340 ProductId[17] = (char)((TmpDWord >> 2) & 0x07f);
341 ProductId[18] = '\0';
342
343 }
344
345 if (((option & 4) == 4) &&
346 ((ReadDataFromDeviceDone & 4) == 0)) {
347
348 Status |= VL_WrByte(Dev, 0x94, 0x7B);
349 Status |= VL_device_read_strobe(Dev);
350 Status |= VL_RdDWord(Dev, 0x90, &PartUIDUpper);
351
352 Status |= VL_WrByte(Dev, 0x94, 0x7C);
353 Status |= VL_device_read_strobe(Dev);
354 Status |= VL_RdDWord(Dev, 0x90, &PartUIDLower);
355
356 Status |= VL_WrByte(Dev, 0x94, 0x73);
357 Status |= VL_device_read_strobe(Dev);
358 Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
359
360 SignalRateMeasFixed1104_400_mm = (TmpDWord &
361 0x0000000ff) << 8;
362
363 Status |= VL_WrByte(Dev, 0x94, 0x74);
364 Status |= VL_device_read_strobe(Dev);
365 Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
366
367 SignalRateMeasFixed1104_400_mm |= ((TmpDWord &
368 0xff000000) >> 24);
369
370 Status |= VL_WrByte(Dev, 0x94, 0x75);
371 Status |= VL_device_read_strobe(Dev);
372 Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
373
374 DistMeasFixed1104_400_mm = (TmpDWord & 0x0000000ff)
375 << 8;
376
377 Status |= VL_WrByte(Dev, 0x94, 0x76);
378 Status |= VL_device_read_strobe(Dev);
379 Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
380
381 DistMeasFixed1104_400_mm |= ((TmpDWord & 0xff000000)
382 >> 24);
383 }
384
385 Status |= VL_WrByte(Dev, 0x81, 0x00);
386 Status |= VL_WrByte(Dev, 0xFF, 0x06);
387 Status |= VL_RdByte(Dev, 0x83, &byte);
388 Status |= VL_WrByte(Dev, 0x83, byte&0xfb);
389 Status |= VL_WrByte(Dev, 0xFF, 0x01);
390 Status |= VL_WrByte(Dev, 0x00, 0x01);
391
392 Status |= VL_WrByte(Dev, 0xFF, 0x00);
393 Status |= VL_WrByte(Dev, 0x80, 0x00);
394 }
395
396 if ((Status == VL_ERROR_NONE) &&
397 (ReadDataFromDeviceDone != 7)) {
398 /* Assign to variable if status is ok */
399 if (((option & 1) == 1) &&
400 ((ReadDataFromDeviceDone & 1) == 0)) {
401 VL_SETDEVICESPECIFICPARAMETER(Dev,
402 ReferenceSpadCount, ReferenceSpadCount);
403
404 VL_SETDEVICESPECIFICPARAMETER(Dev,
405 ReferenceSpadType, ReferenceSpadType);
406
407 for (i = 0; i < VL_REF_SPAD_BUFFER_SIZE; i++) {
408 Dev->Data.SpadData.RefGoodSpadMap[i] =
409 NvmRefGoodSpadMap[i];
410 }
411 }
412
413 if (((option & 2) == 2) &&
414 ((ReadDataFromDeviceDone & 2) == 0)) {
415 VL_SETDEVICESPECIFICPARAMETER(Dev,
416 ModuleId, ModuleId);
417
418 VL_SETDEVICESPECIFICPARAMETER(Dev,
419 Revision, Revision);
420
421 ProductId_tmp = VL_GETDEVICESPECIFICPARAMETER(Dev,
422 ProductId);
423 VL_COPYSTRING(ProductId_tmp, ProductId);
424
425 }
426
427 if (((option & 4) == 4) &&
428 ((ReadDataFromDeviceDone & 4) == 0)) {
429 VL_SETDEVICESPECIFICPARAMETER(Dev,
430 PartUIDUpper, PartUIDUpper);
431
432 VL_SETDEVICESPECIFICPARAMETER(Dev,
433 PartUIDLower, PartUIDLower);
434
435 SignalRateMeasFixed400mmFix =
436 VL_FIXPOINT97TOFIXPOINT1616(
437 SignalRateMeasFixed1104_400_mm);
438
439 VL_SETDEVICESPECIFICPARAMETER(Dev,
440 SignalRateMeasFixed400mm,
441 SignalRateMeasFixed400mmFix);
442
443 OffsetMicroMeters = 0;
444 if (DistMeasFixed1104_400_mm != 0) {
445 OffsetFixed1104_mm = DistMeasFixed1104_400_mm -
446 DistMeasTgtFixed1104_mm;
447 OffsetMicroMeters = (OffsetFixed1104_mm
448 * 1000) >> 4;
449 OffsetMicroMeters *= -1;
450 }
451
452 PALDevDataSet(Dev,
453 Part2PartOffsetAdjustmentNVMMicroMeter,
454 OffsetMicroMeters);
455 }
456 byte = (uint8_t)(ReadDataFromDeviceDone|option);
457 VL_SETDEVICESPECIFICPARAMETER(Dev, ReadDataFromDeviceDone,
458 byte);
459 }
460
461 LOG_FUNCTION_END(Status);
462 return Status;
463}
464
465
466uint32_t VL_calc_macro_period_ps(struct vl_data *Dev,
467 uint8_t vcsel_period_pclks)
468{
469 uint64_t PLL_period_ps;
470 uint32_t macro_period_vclks;
471 uint32_t macro_period_ps;
472
473 LOG_FUNCTION_START("");
474
475 /* The above calculation will produce rounding errors, */
476 /* therefore set fixed value */
477 PLL_period_ps = 1655;
478
479 macro_period_vclks = 2304;
480 macro_period_ps = (uint32_t)(macro_period_vclks
481 * vcsel_period_pclks * PLL_period_ps);
482
483 LOG_FUNCTION_END("");
484 return macro_period_ps;
485}
486
487uint16_t VL_encode_timeout(uint32_t timeout_macro_clks)
488{
489 /*!
490 * Encode timeout in macro periods in (LSByte * 2^MSByte) + 1 format
491 */
492
493 uint16_t encoded_timeout = 0;
494 uint32_t ls_byte = 0;
495 uint16_t ms_byte = 0;
496
497 if (timeout_macro_clks > 0) {
498 ls_byte = timeout_macro_clks - 1;
499
500 while ((ls_byte & 0xFFFFFF00) > 0) {
501 ls_byte = ls_byte >> 1;
502 ms_byte++;
503 }
504
505 encoded_timeout = (ms_byte << 8)
506 + (uint16_t) (ls_byte & 0x000000FF);
507 }
508
509 return encoded_timeout;
510
511}
512
513uint32_t VL_decode_timeout(uint16_t encoded_timeout)
514{
515 /*!
516 * Decode 16-bit timeout register value - format (LSByte * 2^MSByte) + 1
517 */
518
519 uint32_t timeout_macro_clks = 0;
520
521 timeout_macro_clks = ((uint32_t) (encoded_timeout & 0x00FF)
522 << (uint32_t) ((encoded_timeout & 0xFF00) >> 8)) + 1;
523
524 return timeout_macro_clks;
525}
526
527
528/* To convert ms into register value */
529uint32_t VL_calc_timeout_mclks(struct vl_data *Dev,
530 uint32_t timeout_period_us,
531 uint8_t vcsel_period_pclks)
532{
533 uint32_t macro_period_ps;
534 uint32_t macro_period_ns;
535 uint32_t timeout_period_mclks = 0;
536
537 macro_period_ps = VL_calc_macro_period_ps(Dev, vcsel_period_pclks);
538 macro_period_ns = (macro_period_ps + 500) / 1000;
539
540 timeout_period_mclks =
541 (uint32_t) (((timeout_period_us * 1000)
542 + (macro_period_ns / 2)) / macro_period_ns);
543
544 return timeout_period_mclks;
545}
546
547/* To convert register value into us */
548uint32_t VL_calc_timeout_us(struct vl_data *Dev,
549 uint16_t timeout_period_mclks,
550 uint8_t vcsel_period_pclks)
551{
552 uint32_t macro_period_ps;
553 uint32_t macro_period_ns;
554 uint32_t actual_timeout_period_us = 0;
555
556 macro_period_ps = VL_calc_macro_period_ps(Dev, vcsel_period_pclks);
557 macro_period_ns = (macro_period_ps + 500) / 1000;
558
559 actual_timeout_period_us =
560 ((timeout_period_mclks * macro_period_ns) + 500) / 1000;
561
562 return actual_timeout_period_us;
563}
564
565
566int8_t get_sequence_step_timeout(struct vl_data *Dev,
567 uint8_t SequenceStepId,
568 uint32_t *pTimeOutMicroSecs)
569{
570 int8_t Status = VL_ERROR_NONE;
571 uint8_t CurrentVCSELPulsePeriodPClk;
572 uint8_t EncodedTimeOutByte = 0;
573 uint32_t TimeoutMicroSeconds = 0;
574 uint16_t PreRangeEncodedTimeOut = 0;
575 uint16_t MsrcTimeOutMClks;
576 uint16_t PreRangeTimeOutMClks;
577 uint16_t FinalRangeTimeOutMClks = 0;
578 uint16_t FinalRangeEncodedTimeOut;
579 struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps;
580
581 if ((SequenceStepId == VL_SEQUENCESTEP_TCC) ||
582 (SequenceStepId == VL_SEQUENCESTEP_DSS) ||
583 (SequenceStepId == VL_SEQUENCESTEP_MSRC)) {
584
585 Status = VL_GetVcselPulsePeriod(Dev,
586 VL_VCSEL_PERIOD_PRE_RANGE,
587 &CurrentVCSELPulsePeriodPClk);
588 if (Status == VL_ERROR_NONE) {
589 Status = VL_RdByte(Dev,
590 VL_REG_MSRC_CONFIG_TIMEOUT_MACROP,
591 &EncodedTimeOutByte);
592 }
593 MsrcTimeOutMClks = VL_decode_timeout(EncodedTimeOutByte);
594
595 TimeoutMicroSeconds = VL_calc_timeout_us(Dev,
596 MsrcTimeOutMClks,
597 CurrentVCSELPulsePeriodPClk);
598 } else if (SequenceStepId == VL_SEQUENCESTEP_PRE_RANGE) {
599 /* Retrieve PRE-RANGE VCSEL Period */
600 Status = VL_GetVcselPulsePeriod(Dev,
601 VL_VCSEL_PERIOD_PRE_RANGE,
602 &CurrentVCSELPulsePeriodPClk);
603
604 /* Retrieve PRE-RANGE Timeout in Macro periods (MCLKS) */
605 if (Status == VL_ERROR_NONE) {
606
607 /* Retrieve PRE-RANGE VCSEL Period */
608 Status = VL_GetVcselPulsePeriod(Dev,
609 VL_VCSEL_PERIOD_PRE_RANGE,
610 &CurrentVCSELPulsePeriodPClk);
611
612 if (Status == VL_ERROR_NONE) {
613 Status = VL_RdWord(Dev,
614 VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
615 &PreRangeEncodedTimeOut);
616 }
617
618 PreRangeTimeOutMClks = VL_decode_timeout(
619 PreRangeEncodedTimeOut);
620
621 TimeoutMicroSeconds = VL_calc_timeout_us(Dev,
622 PreRangeTimeOutMClks,
623 CurrentVCSELPulsePeriodPClk);
624 }
625 } else if (SequenceStepId == VL_SEQUENCESTEP_FINAL_RANGE) {
626
627 VL_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps);
628 PreRangeTimeOutMClks = 0;
629
630 if (SchedulerSequenceSteps.PreRangeOn) {
631 /* Retrieve PRE-RANGE VCSEL Period */
632 Status = VL_GetVcselPulsePeriod(Dev,
633 VL_VCSEL_PERIOD_PRE_RANGE,
634 &CurrentVCSELPulsePeriodPClk);
635
636 /* Retrieve PRE-RANGE Timeout in Macro periods */
637 /* (MCLKS) */
638 if (Status == VL_ERROR_NONE) {
639 Status = VL_RdWord(Dev,
640 VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
641 &PreRangeEncodedTimeOut);
642 PreRangeTimeOutMClks = VL_decode_timeout(
643 PreRangeEncodedTimeOut);
644 }
645 }
646
647 if (Status == VL_ERROR_NONE) {
648 /* Retrieve FINAL-RANGE VCSEL Period */
649 Status = VL_GetVcselPulsePeriod(Dev,
650 VL_VCSEL_PERIOD_FINAL_RANGE,
651 &CurrentVCSELPulsePeriodPClk);
652 }
653
654 /* Retrieve FINAL-RANGE Timeout in Macro periods (MCLKS) */
655 if (Status == VL_ERROR_NONE) {
656 Status = VL_RdWord(Dev,
657 VL_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI,
658 &FinalRangeEncodedTimeOut);
659 FinalRangeTimeOutMClks = VL_decode_timeout(
660 FinalRangeEncodedTimeOut);
661 }
662
663 FinalRangeTimeOutMClks -= PreRangeTimeOutMClks;
664 TimeoutMicroSeconds = VL_calc_timeout_us(Dev,
665 FinalRangeTimeOutMClks,
666 CurrentVCSELPulsePeriodPClk);
667 }
668
669 *pTimeOutMicroSecs = TimeoutMicroSeconds;
670
671 return Status;
672}
673
674
675int8_t set_sequence_step_timeout(struct vl_data *Dev,
676 uint8_t SequenceStepId,
677 uint32_t TimeOutMicroSecs)
678{
679 int8_t Status = VL_ERROR_NONE;
680 uint8_t CurrentVCSELPulsePeriodPClk;
681 uint8_t MsrcEncodedTimeOut;
682 uint16_t PreRangeEncodedTimeOut;
683 uint16_t PreRangeTimeOutMClks;
684 uint16_t MsrcRangeTimeOutMClks;
685 uint32_t FinalRangeTimeOutMClks;
686 uint16_t FinalRangeEncodedTimeOut;
687 struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps;
688
689 if ((SequenceStepId == VL_SEQUENCESTEP_TCC) ||
690 (SequenceStepId == VL_SEQUENCESTEP_DSS) ||
691 (SequenceStepId == VL_SEQUENCESTEP_MSRC)) {
692
693 Status = VL_GetVcselPulsePeriod(Dev,
694 VL_VCSEL_PERIOD_PRE_RANGE,
695 &CurrentVCSELPulsePeriodPClk);
696
697 if (Status == VL_ERROR_NONE) {
698 MsrcRangeTimeOutMClks = VL_calc_timeout_mclks(Dev,
699 TimeOutMicroSecs,
700 (uint8_t)CurrentVCSELPulsePeriodPClk);
701
702 if (MsrcRangeTimeOutMClks > 256)
703 MsrcEncodedTimeOut = 255;
704 else
705 MsrcEncodedTimeOut =
706 (uint8_t)MsrcRangeTimeOutMClks - 1;
707
708 VL_SETDEVICESPECIFICPARAMETER(Dev,
709 LastEncodedTimeout,
710 MsrcEncodedTimeOut);
711 }
712
713 if (Status == VL_ERROR_NONE) {
714 Status = VL_WrByte(Dev,
715 VL_REG_MSRC_CONFIG_TIMEOUT_MACROP,
716 MsrcEncodedTimeOut);
717 }
718 } else {
719
720 if (SequenceStepId == VL_SEQUENCESTEP_PRE_RANGE) {
721
722 if (Status == VL_ERROR_NONE) {
723 Status = VL_GetVcselPulsePeriod(Dev,
724 VL_VCSEL_PERIOD_PRE_RANGE,
725 &CurrentVCSELPulsePeriodPClk);
726 PreRangeTimeOutMClks =
727 VL_calc_timeout_mclks(Dev,
728 TimeOutMicroSecs,
729 (uint8_t)CurrentVCSELPulsePeriodPClk);
730 PreRangeEncodedTimeOut = VL_encode_timeout(
731 PreRangeTimeOutMClks);
732
733 VL_SETDEVICESPECIFICPARAMETER(Dev,
734 LastEncodedTimeout,
735 PreRangeEncodedTimeOut);
736 }
737
738 if (Status == VL_ERROR_NONE) {
739 Status = VL_WrWord(Dev,
740 VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
741 PreRangeEncodedTimeOut);
742 }
743
744 if (Status == VL_ERROR_NONE) {
745 VL_SETDEVICESPECIFICPARAMETER(
746 Dev,
747 PreRangeTimeoutMicroSecs,
748 TimeOutMicroSecs);
749 }
750 } else if (SequenceStepId == VL_SEQUENCESTEP_FINAL_RANGE) {
751
752 /* For the final range timeout, the pre-range timeout
753 * must be added. To do this both final and pre-range
754 * timeouts must be expressed in macro periods MClks
755 * because they have different vcsel periods.
756 */
757
758 VL_GetSequenceStepEnables(Dev,
759 &SchedulerSequenceSteps);
760 PreRangeTimeOutMClks = 0;
761 if (SchedulerSequenceSteps.PreRangeOn) {
762
763 /* Retrieve PRE-RANGE VCSEL Period */
764 Status = VL_GetVcselPulsePeriod(Dev,
765 VL_VCSEL_PERIOD_PRE_RANGE,
766 &CurrentVCSELPulsePeriodPClk);
767
768 /* Retrieve PRE-RANGE Timeout in Macro */
769 /* periods (MCLKS) */
770 if (Status == VL_ERROR_NONE) {
771 Status = VL_RdWord(Dev, 0x51,
772 &PreRangeEncodedTimeOut);
773 PreRangeTimeOutMClks =
774 VL_decode_timeout(
775 PreRangeEncodedTimeOut);
776 }
777 }
778
779 /* Calculate FINAL RANGE Timeout in Macro Periods */
780 /* (MCLKS) and add PRE-RANGE value */
781 if (Status == VL_ERROR_NONE) {
782
783 Status = VL_GetVcselPulsePeriod(Dev,
784 VL_VCSEL_PERIOD_FINAL_RANGE,
785 &CurrentVCSELPulsePeriodPClk);
786 }
787 if (Status == VL_ERROR_NONE) {
788
789 FinalRangeTimeOutMClks =
790 VL_calc_timeout_mclks(Dev,
791 TimeOutMicroSecs,
792 (uint8_t) CurrentVCSELPulsePeriodPClk);
793
794 FinalRangeTimeOutMClks += PreRangeTimeOutMClks;
795
796 FinalRangeEncodedTimeOut =
797 VL_encode_timeout(FinalRangeTimeOutMClks);
798
799 if (Status == VL_ERROR_NONE) {
800 Status = VL_WrWord(Dev, 0x71,
801 FinalRangeEncodedTimeOut);
802 }
803
804 if (Status == VL_ERROR_NONE) {
805 VL_SETDEVICESPECIFICPARAMETER(
806 Dev,
807 FinalRangeTimeoutMicroSecs,
808 TimeOutMicroSecs);
809 }
810 }
811 } else
812 Status = VL_ERROR_INVALID_PARAMS;
813
814 }
815 return Status;
816}
817
818int8_t VL_set_vcsel_pulse_period(struct vl_data *Dev,
819 uint8_t VcselPeriodType, uint8_t VCSELPulsePeriodPCLK)
820{
821 int8_t Status = VL_ERROR_NONE;
822 uint8_t vcsel_period_reg;
823 uint8_t MinPreVcselPeriodPCLK = 12;
824 uint8_t MaxPreVcselPeriodPCLK = 18;
825 uint8_t MinFinalVcselPeriodPCLK = 8;
826 uint8_t MaxFinalVcselPeriodPCLK = 14;
827 uint32_t MeasurementTimingBudgetMicroSeconds;
828 uint32_t FinalRangeTimeoutMicroSeconds;
829 uint32_t PreRangeTimeoutMicroSeconds;
830 uint32_t MsrcTimeoutMicroSeconds;
831 uint8_t PhaseCalInt = 0;
832
833 /* Check if valid clock period requested */
834
835 if ((VCSELPulsePeriodPCLK % 2) != 0) {
836 /* Value must be an even number */
837 Status = VL_ERROR_INVALID_PARAMS;
838 } else if (VcselPeriodType == VL_VCSEL_PERIOD_PRE_RANGE &&
839 (VCSELPulsePeriodPCLK < MinPreVcselPeriodPCLK ||
840 VCSELPulsePeriodPCLK > MaxPreVcselPeriodPCLK)) {
841 Status = VL_ERROR_INVALID_PARAMS;
842 } else if (VcselPeriodType == VL_VCSEL_PERIOD_FINAL_RANGE &&
843 (VCSELPulsePeriodPCLK < MinFinalVcselPeriodPCLK ||
844 VCSELPulsePeriodPCLK > MaxFinalVcselPeriodPCLK)) {
845
846 Status = VL_ERROR_INVALID_PARAMS;
847 }
848
849 /* Apply specific settings for the requested clock period */
850
851 if (Status != VL_ERROR_NONE)
852 return Status;
853
854
855 if (VcselPeriodType == VL_VCSEL_PERIOD_PRE_RANGE) {
856
857 /* Set phase check limits */
858 if (VCSELPulsePeriodPCLK == 12) {
859
860 Status = VL_WrByte(Dev,
861 VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
862 0x18);
863 Status = VL_WrByte(Dev,
864 VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
865 0x08);
866 } else if (VCSELPulsePeriodPCLK == 14) {
867
868 Status = VL_WrByte(Dev,
869 VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
870 0x30);
871 Status = VL_WrByte(Dev,
872 VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
873 0x08);
874 } else if (VCSELPulsePeriodPCLK == 16) {
875
876 Status = VL_WrByte(Dev,
877 VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
878 0x40);
879 Status = VL_WrByte(Dev,
880 VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
881 0x08);
882 } else if (VCSELPulsePeriodPCLK == 18) {
883
884 Status = VL_WrByte(Dev,
885 VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
886 0x50);
887 Status = VL_WrByte(Dev,
888 VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
889 0x08);
890 }
891 } else if (VcselPeriodType == VL_VCSEL_PERIOD_FINAL_RANGE) {
892
893 if (VCSELPulsePeriodPCLK == 8) {
894
895 Status = VL_WrByte(Dev,
896 VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
897 0x10);
898 Status = VL_WrByte(Dev,
899 VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
900 0x08);
901
902 Status |= VL_WrByte(Dev,
903 VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x02);
904 Status |= VL_WrByte(Dev,
905 VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x0C);
906
907 Status |= VL_WrByte(Dev, 0xff, 0x01);
908 Status |= VL_WrByte(Dev,
909 VL_REG_ALGO_PHASECAL_LIM,
910 0x30);
911 Status |= VL_WrByte(Dev, 0xff, 0x00);
912 } else if (VCSELPulsePeriodPCLK == 10) {
913
914 Status = VL_WrByte(Dev,
915 VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
916 0x28);
917 Status = VL_WrByte(Dev,
918 VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
919 0x08);
920
921 Status |= VL_WrByte(Dev,
922 VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
923 Status |= VL_WrByte(Dev,
924 VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x09);
925
926 Status |= VL_WrByte(Dev, 0xff, 0x01);
927 Status |= VL_WrByte(Dev,
928 VL_REG_ALGO_PHASECAL_LIM,
929 0x20);
930 Status |= VL_WrByte(Dev, 0xff, 0x00);
931 } else if (VCSELPulsePeriodPCLK == 12) {
932
933 Status = VL_WrByte(Dev,
934 VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
935 0x38);
936 Status = VL_WrByte(Dev,
937 VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
938 0x08);
939
940 Status |= VL_WrByte(Dev,
941 VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
942 Status |= VL_WrByte(Dev,
943 VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x08);
944
945 Status |= VL_WrByte(Dev, 0xff, 0x01);
946 Status |= VL_WrByte(Dev,
947 VL_REG_ALGO_PHASECAL_LIM,
948 0x20);
949 Status |= VL_WrByte(Dev, 0xff, 0x00);
950 } else if (VCSELPulsePeriodPCLK == 14) {
951
952 Status = VL_WrByte(Dev,
953 VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
954 0x048);
955 Status = VL_WrByte(Dev,
956 VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
957 0x08);
958
959 Status |= VL_WrByte(Dev,
960 VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
961 Status |= VL_WrByte(Dev,
962 VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x07);
963
964 Status |= VL_WrByte(Dev, 0xff, 0x01);
965 Status |= VL_WrByte(Dev,
966 VL_REG_ALGO_PHASECAL_LIM,
967 0x20);
968 Status |= VL_WrByte(Dev, 0xff, 0x00);
969 }
970 }
971
972
973 /* Re-calculate and apply timeouts, in macro periods */
974
975 if (Status == VL_ERROR_NONE) {
976 vcsel_period_reg = VL_encode_vcsel_period((uint8_t)
977 VCSELPulsePeriodPCLK);
978
979 /* When the VCSEL period for the pre or final range is changed, */
980 /* the corresponding timeout must be read from the device using */
981 /* the current VCSEL period, then the new VCSEL period can be */
982 /* applied. The timeout then must be written back to the device */
983 /* using the new VCSEL period. */
984 /* For the MSRC timeout, the same applies - this timeout being */
985 /* dependent on the pre-range vcsel period. */
986 switch (VcselPeriodType) {
987 case VL_VCSEL_PERIOD_PRE_RANGE:
988 Status = get_sequence_step_timeout(Dev,
989 VL_SEQUENCESTEP_PRE_RANGE,
990 &PreRangeTimeoutMicroSeconds);
991
992 if (Status == VL_ERROR_NONE)
993 Status = get_sequence_step_timeout(Dev,
994 VL_SEQUENCESTEP_MSRC,
995 &MsrcTimeoutMicroSeconds);
996
997 if (Status == VL_ERROR_NONE)
998 Status = VL_WrByte(Dev,
999 VL_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,
1000 vcsel_period_reg);
1001
1002
1003 if (Status == VL_ERROR_NONE)
1004 Status = set_sequence_step_timeout(Dev,
1005 VL_SEQUENCESTEP_PRE_RANGE,
1006 PreRangeTimeoutMicroSeconds);
1007
1008
1009 if (Status == VL_ERROR_NONE)
1010 Status = set_sequence_step_timeout(Dev,
1011 VL_SEQUENCESTEP_MSRC,
1012 MsrcTimeoutMicroSeconds);
1013
1014 VL_SETDEVICESPECIFICPARAMETER(
1015 Dev,
1016 PreRangeVcselPulsePeriod,
1017 VCSELPulsePeriodPCLK);
1018 break;
1019 case VL_VCSEL_PERIOD_FINAL_RANGE:
1020 Status = get_sequence_step_timeout(Dev,
1021 VL_SEQUENCESTEP_FINAL_RANGE,
1022 &FinalRangeTimeoutMicroSeconds);
1023
1024 if (Status == VL_ERROR_NONE)
1025 Status = VL_WrByte(Dev,
1026 VL_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,
1027 vcsel_period_reg);
1028
1029
1030 if (Status == VL_ERROR_NONE)
1031 Status = set_sequence_step_timeout(Dev,
1032 VL_SEQUENCESTEP_FINAL_RANGE,
1033 FinalRangeTimeoutMicroSeconds);
1034
1035 VL_SETDEVICESPECIFICPARAMETER(
1036 Dev,
1037 FinalRangeVcselPulsePeriod,
1038 VCSELPulsePeriodPCLK);
1039 break;
1040 default:
1041 Status = VL_ERROR_INVALID_PARAMS;
1042 }
1043 }
1044
1045 /* Finally, the timing budget must be re-applied */
1046 if (Status == VL_ERROR_NONE) {
1047 VL_GETPARAMETERFIELD(Dev,
1048 MeasurementTimingBudgetMicroSeconds,
1049 MeasurementTimingBudgetMicroSeconds);
1050
1051 Status = VL_SetMeasurementTimingBudgetMicroSeconds(Dev,
1052 MeasurementTimingBudgetMicroSeconds);
1053 }
1054
1055 /* Perform the phase calibration. This is needed after changing on */
1056 /* vcsel period. */
1057 /* get_data_enable = 0, restore_config = 1 */
1058 if (Status == VL_ERROR_NONE)
1059 Status = VL_perform_phase_calibration(
1060 Dev, &PhaseCalInt, 0, 1);
1061
1062 return Status;
1063}
1064
1065int8_t VL_get_vcsel_pulse_period(struct vl_data *Dev,
1066 uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK)
1067{
1068 int8_t Status = VL_ERROR_NONE;
1069 uint8_t vcsel_period_reg;
1070
1071 switch (VcselPeriodType) {
1072 case VL_VCSEL_PERIOD_PRE_RANGE:
1073 Status = VL_RdByte(Dev,
1074 VL_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,
1075 &vcsel_period_reg);
1076 break;
1077 case VL_VCSEL_PERIOD_FINAL_RANGE:
1078 Status = VL_RdByte(Dev,
1079 VL_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,
1080 &vcsel_period_reg);
1081 break;
1082 default:
1083 Status = VL_ERROR_INVALID_PARAMS;
1084 }
1085
1086 if (Status == VL_ERROR_NONE)
1087 *pVCSELPulsePeriodPCLK =
1088 VL_decode_vcsel_period(vcsel_period_reg);
1089
1090 return Status;
1091}
1092
1093
1094
1095int8_t VL_set_measurement_timing_budget_micro_seconds(
1096 struct vl_data *Dev, uint32_t MeasurementTimingBudgetMicroSeconds)
1097{
1098 int8_t Status = VL_ERROR_NONE;
1099 uint32_t FinalRangeTimingBudgetMicroSeconds;
1100 struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps;
1101 uint32_t MsrcDccTccTimeoutMicroSeconds = 2000;
1102 uint32_t StartOverheadMicroSeconds = 1910;
1103 uint32_t EndOverheadMicroSeconds = 960;
1104 uint32_t MsrcOverheadMicroSeconds = 660;
1105 uint32_t TccOverheadMicroSeconds = 590;
1106 uint32_t DssOverheadMicroSeconds = 690;
1107 uint32_t PreRangeOverheadMicroSeconds = 660;
1108 uint32_t FinalRangeOverheadMicroSeconds = 550;
1109 uint32_t PreRangeTimeoutMicroSeconds = 0;
1110 uint32_t cMinTimingBudgetMicroSeconds = 20000;
1111 uint32_t SubTimeout = 0;
1112
1113 LOG_FUNCTION_START("");
1114
1115 if (MeasurementTimingBudgetMicroSeconds
1116 < cMinTimingBudgetMicroSeconds) {
1117 Status = VL_ERROR_INVALID_PARAMS;
1118 return Status;
1119 }
1120
1121 FinalRangeTimingBudgetMicroSeconds =
1122 MeasurementTimingBudgetMicroSeconds -
1123 (StartOverheadMicroSeconds + EndOverheadMicroSeconds);
1124
1125 Status = VL_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps);
1126
1127 if (Status == VL_ERROR_NONE &&
1128 (SchedulerSequenceSteps.TccOn ||
1129 SchedulerSequenceSteps.MsrcOn ||
1130 SchedulerSequenceSteps.DssOn)) {
1131
1132 /* TCC, MSRC and DSS all share the same timeout */
1133 Status = get_sequence_step_timeout(Dev,
1134 VL_SEQUENCESTEP_MSRC,
1135 &MsrcDccTccTimeoutMicroSeconds);
1136
1137 /* Subtract the TCC, MSRC and DSS timeouts if they are */
1138 /* enabled. */
1139
1140 if (Status != VL_ERROR_NONE)
1141 return Status;
1142
1143 /* TCC */
1144 if (SchedulerSequenceSteps.TccOn) {
1145
1146 SubTimeout = MsrcDccTccTimeoutMicroSeconds
1147 + TccOverheadMicroSeconds;
1148
1149 if (SubTimeout <
1150 FinalRangeTimingBudgetMicroSeconds) {
1151 FinalRangeTimingBudgetMicroSeconds -=
1152 SubTimeout;
1153 } else {
1154 /* Requested timeout too big. */
1155 Status = VL_ERROR_INVALID_PARAMS;
1156 }
1157 }
1158
1159 if (Status != VL_ERROR_NONE) {
1160 LOG_FUNCTION_END(Status);
1161 return Status;
1162 }
1163
1164 /* DSS */
1165 if (SchedulerSequenceSteps.DssOn) {
1166
1167 SubTimeout = 2 * (MsrcDccTccTimeoutMicroSeconds +
1168 DssOverheadMicroSeconds);
1169
1170 if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) {
1171 FinalRangeTimingBudgetMicroSeconds
1172 -= SubTimeout;
1173 } else {
1174 /* Requested timeout too big. */
1175 Status = VL_ERROR_INVALID_PARAMS;
1176 }
1177 } else if (SchedulerSequenceSteps.MsrcOn) {
1178 /* MSRC */
1179 SubTimeout = MsrcDccTccTimeoutMicroSeconds +
1180 MsrcOverheadMicroSeconds;
1181
1182 if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) {
1183 FinalRangeTimingBudgetMicroSeconds
1184 -= SubTimeout;
1185 } else {
1186 /* Requested timeout too big. */
1187 Status = VL_ERROR_INVALID_PARAMS;
1188 }
1189 }
1190
1191 }
1192
1193 if (Status != VL_ERROR_NONE) {
1194 LOG_FUNCTION_END(Status);
1195 return Status;
1196 }
1197
1198 if (SchedulerSequenceSteps.PreRangeOn) {
1199
1200 /* Subtract the Pre-range timeout if enabled. */
1201
1202 Status = get_sequence_step_timeout(Dev,
1203 VL_SEQUENCESTEP_PRE_RANGE,
1204 &PreRangeTimeoutMicroSeconds);
1205
1206 SubTimeout = PreRangeTimeoutMicroSeconds +
1207 PreRangeOverheadMicroSeconds;
1208
1209 if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) {
1210 FinalRangeTimingBudgetMicroSeconds -= SubTimeout;
1211 } else {
1212 /* Requested timeout too big. */
1213 Status = VL_ERROR_INVALID_PARAMS;
1214 }
1215 }
1216
1217
1218 if (Status == VL_ERROR_NONE &&
1219 SchedulerSequenceSteps.FinalRangeOn) {
1220
1221 FinalRangeTimingBudgetMicroSeconds -=
1222 FinalRangeOverheadMicroSeconds;
1223
1224 /* Final Range Timeout
1225 * Note that the final range timeout is determined by the timing
1226 * budget and the sum of all other timeouts within the sequence.
1227 * If there is no room for the final range timeout,then an error
1228 * will be set. Otherwise the remaining time will be applied to
1229 * the final range.
1230 */
1231 Status = set_sequence_step_timeout(Dev,
1232 VL_SEQUENCESTEP_FINAL_RANGE,
1233 FinalRangeTimingBudgetMicroSeconds);
1234
1235 VL_SETPARAMETERFIELD(Dev,
1236 MeasurementTimingBudgetMicroSeconds,
1237 MeasurementTimingBudgetMicroSeconds);
1238 }
1239
1240 LOG_FUNCTION_END(Status);
1241
1242 return Status;
1243}
1244
1245int8_t VL_get_measurement_timing_budget_micro_seconds(
1246 struct vl_data *Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds)
1247{
1248 int8_t Status = VL_ERROR_NONE;
1249 struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps;
1250 uint32_t FinalRangeTimeoutMicroSeconds;
1251 uint32_t MsrcDccTccTimeoutMicroSeconds = 2000;
1252 uint32_t StartOverheadMicroSeconds = 1910;
1253 uint32_t EndOverheadMicroSeconds = 960;
1254 uint32_t MsrcOverheadMicroSeconds = 660;
1255 uint32_t TccOverheadMicroSeconds = 590;
1256 uint32_t DssOverheadMicroSeconds = 690;
1257 uint32_t PreRangeOverheadMicroSeconds = 660;
1258 uint32_t FinalRangeOverheadMicroSeconds = 550;
1259 uint32_t PreRangeTimeoutMicroSeconds = 0;
1260
1261 LOG_FUNCTION_START("");
1262
1263 /* Start and end overhead times always present */
1264 *pMeasurementTimingBudgetMicroSeconds
1265 = StartOverheadMicroSeconds + EndOverheadMicroSeconds;
1266
1267 Status = VL_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps);
1268
1269 if (Status != VL_ERROR_NONE) {
1270 LOG_FUNCTION_END(Status);
1271 return Status;
1272 }
1273
1274
1275 if (SchedulerSequenceSteps.TccOn ||
1276 SchedulerSequenceSteps.MsrcOn ||
1277 SchedulerSequenceSteps.DssOn) {
1278
1279 Status = get_sequence_step_timeout(Dev,
1280 VL_SEQUENCESTEP_MSRC,
1281 &MsrcDccTccTimeoutMicroSeconds);
1282
1283 if (Status == VL_ERROR_NONE) {
1284 if (SchedulerSequenceSteps.TccOn) {
1285 *pMeasurementTimingBudgetMicroSeconds +=
1286 MsrcDccTccTimeoutMicroSeconds +
1287 TccOverheadMicroSeconds;
1288 }
1289
1290 if (SchedulerSequenceSteps.DssOn) {
1291 *pMeasurementTimingBudgetMicroSeconds +=
1292 2 * (MsrcDccTccTimeoutMicroSeconds +
1293 DssOverheadMicroSeconds);
1294 } else if (SchedulerSequenceSteps.MsrcOn) {
1295 *pMeasurementTimingBudgetMicroSeconds +=
1296 MsrcDccTccTimeoutMicroSeconds +
1297 MsrcOverheadMicroSeconds;
1298 }
1299 }
1300 }
1301
1302 if (Status == VL_ERROR_NONE) {
1303 if (SchedulerSequenceSteps.PreRangeOn) {
1304 Status = get_sequence_step_timeout(Dev,
1305 VL_SEQUENCESTEP_PRE_RANGE,
1306 &PreRangeTimeoutMicroSeconds);
1307 *pMeasurementTimingBudgetMicroSeconds +=
1308 PreRangeTimeoutMicroSeconds +
1309 PreRangeOverheadMicroSeconds;
1310 }
1311 }
1312
1313 if (Status == VL_ERROR_NONE) {
1314 if (SchedulerSequenceSteps.FinalRangeOn) {
1315 Status = get_sequence_step_timeout(Dev,
1316 VL_SEQUENCESTEP_FINAL_RANGE,
1317 &FinalRangeTimeoutMicroSeconds);
1318 *pMeasurementTimingBudgetMicroSeconds +=
1319 (FinalRangeTimeoutMicroSeconds +
1320 FinalRangeOverheadMicroSeconds);
1321 }
1322 }
1323
1324 if (Status == VL_ERROR_NONE) {
1325 VL_SETPARAMETERFIELD(Dev,
1326 MeasurementTimingBudgetMicroSeconds,
1327 *pMeasurementTimingBudgetMicroSeconds);
1328 }
1329
1330 LOG_FUNCTION_END(Status);
1331 return Status;
1332}
1333
1334
1335
1336int8_t VL_load_tuning_settings(struct vl_data *Dev,
1337 uint8_t *pTuningSettingBuffer)
1338{
1339 int8_t Status = VL_ERROR_NONE;
1340 int i;
1341 int Index;
1342 uint8_t msb;
1343 uint8_t lsb;
1344 uint8_t SelectParam;
1345 uint8_t NumberOfWrites;
1346 uint8_t Address;
1347 uint8_t localBuffer[4]; /* max */
1348 uint16_t Temp16;
1349
1350 LOG_FUNCTION_START("");
1351
1352 Index = 0;
1353
1354 while ((*(pTuningSettingBuffer + Index) != 0) &&
1355 (Status == VL_ERROR_NONE)) {
1356 NumberOfWrites = *(pTuningSettingBuffer + Index);
1357 Index++;
1358 if (NumberOfWrites == 0xFF) {
1359 /* internal parameters */
1360 SelectParam = *(pTuningSettingBuffer + Index);
1361 Index++;
1362 switch (SelectParam) {
1363 case 0: /* uint16_t SigmaEstRefArray -> 2 bytes */
1364 msb = *(pTuningSettingBuffer + Index);
1365 Index++;
1366 lsb = *(pTuningSettingBuffer + Index);
1367 Index++;
1368 Temp16 = VL_MAKEUINT16(lsb, msb);
1369 PALDevDataSet(Dev, SigmaEstRefArray, Temp16);
1370 break;
1371 case 1: /* uint16_t SigmaEstEffPulseWidth -> 2 bytes */
1372 msb = *(pTuningSettingBuffer + Index);
1373 Index++;
1374 lsb = *(pTuningSettingBuffer + Index);
1375 Index++;
1376 Temp16 = VL_MAKEUINT16(lsb, msb);
1377 PALDevDataSet(Dev, SigmaEstEffPulseWidth,
1378 Temp16);
1379 break;
1380 case 2: /* uint16_t SigmaEstEffAmbWidth -> 2 bytes */
1381 msb = *(pTuningSettingBuffer + Index);
1382 Index++;
1383 lsb = *(pTuningSettingBuffer + Index);
1384 Index++;
1385 Temp16 = VL_MAKEUINT16(lsb, msb);
1386 PALDevDataSet(Dev, SigmaEstEffAmbWidth, Temp16);
1387 break;
1388 case 3: /* uint16_t targetRefRate -> 2 bytes */
1389 msb = *(pTuningSettingBuffer + Index);
1390 Index++;
1391 lsb = *(pTuningSettingBuffer + Index);
1392 Index++;
1393 Temp16 = VL_MAKEUINT16(lsb, msb);
1394 PALDevDataSet(Dev, targetRefRate, Temp16);
1395 break;
1396 default: /* invalid parameter */
1397 Status = VL_ERROR_INVALID_PARAMS;
1398 }
1399
1400 } else if (NumberOfWrites <= 4) {
1401 Address = *(pTuningSettingBuffer + Index);
1402 Index++;
1403
1404 for (i = 0; i < NumberOfWrites; i++) {
1405 localBuffer[i] = *(pTuningSettingBuffer +
1406 Index);
1407 Index++;
1408 }
1409
1410 Status = VL_WriteMulti(Dev, Address, localBuffer,
1411 NumberOfWrites);
1412
1413 } else {
1414 Status = VL_ERROR_INVALID_PARAMS;
1415 }
1416 }
1417
1418 LOG_FUNCTION_END(Status);
1419 return Status;
1420}
1421
1422int8_t VL_get_total_xtalk_rate(struct vl_data *Dev,
1423 struct VL_RangingMeasurementData_t *pRangingMeasurementData,
1424 unsigned int *ptotal_xtalk_rate_mcps)
1425{
1426 int8_t Status = VL_ERROR_NONE;
1427
1428 uint8_t xtalkCompEnable;
1429 unsigned int totalXtalkMegaCps;
1430 unsigned int xtalkPerSpadMegaCps;
1431
1432 *ptotal_xtalk_rate_mcps = 0;
1433
1434 Status = VL_GetXTalkCompensationEnable(Dev, &xtalkCompEnable);
1435 if (Status == VL_ERROR_NONE) {
1436
1437 if (xtalkCompEnable) {
1438
1439 VL_GETPARAMETERFIELD(
1440 Dev,
1441 XTalkCompensationRateMegaCps,
1442 xtalkPerSpadMegaCps);
1443
1444 /* FixPoint1616 * FixPoint 8:8 = FixPoint0824 */
1445 totalXtalkMegaCps =
1446 pRangingMeasurementData->EffectiveSpadRtnCount *
1447 xtalkPerSpadMegaCps;
1448
1449 /* FixPoint0824 >> 8 = FixPoint1616 */
1450 *ptotal_xtalk_rate_mcps =
1451 (totalXtalkMegaCps + 0x80) >> 8;
1452 }
1453 }
1454
1455 return Status;
1456}
1457
1458int8_t VL_get_total_signal_rate(struct vl_data *Dev,
1459 struct VL_RangingMeasurementData_t *pRangingMeasurementData,
1460 unsigned int *ptotal_signal_rate_mcps)
1461{
1462 int8_t Status = VL_ERROR_NONE;
1463 unsigned int totalXtalkMegaCps;
1464
1465 LOG_FUNCTION_START("");
1466
1467 *ptotal_signal_rate_mcps =
1468 pRangingMeasurementData->SignalRateRtnMegaCps;
1469
1470 Status = VL_get_total_xtalk_rate(
1471 Dev, pRangingMeasurementData, &totalXtalkMegaCps);
1472
1473 if (Status == VL_ERROR_NONE)
1474 *ptotal_signal_rate_mcps += totalXtalkMegaCps;
1475
1476 return Status;
1477}
1478
1479int8_t VL_calc_dmax(
1480 struct vl_data *Dev,
1481 unsigned int totalSignalRate_mcps,
1482 unsigned int totalCorrSignalRate_mcps,
1483 unsigned int pwMult,
1484 uint32_t sigmaEstimateP1,
1485 unsigned int sigmaEstimateP2,
1486 uint32_t peakVcselDuration_us,
1487 uint32_t *pdmax_mm)
1488{
1489 const uint32_t cSigmaLimit = 18;
1490 const unsigned int cSignalLimit = 0x4000; /* 0.25 */
1491 const unsigned int cSigmaEstRef = 0x00000042; /* 0.001 */
1492 const uint32_t cAmbEffWidthSigmaEst_ns = 6;
1493 const uint32_t cAmbEffWidthDMax_ns = 7;
1494 uint32_t dmaxCalRange_mm;
1495 unsigned int dmaxCalSignalRateRtn_mcps;
1496 unsigned int minSignalNeeded;
1497 unsigned int minSignalNeeded_p1;
1498 unsigned int minSignalNeeded_p2;
1499 unsigned int minSignalNeeded_p3;
1500 unsigned int minSignalNeeded_p4;
1501 unsigned int sigmaLimitTmp;
1502 unsigned int sigmaEstSqTmp;
1503 unsigned int signalLimitTmp;
1504 unsigned int SignalAt0mm;
1505 unsigned int dmaxDark;
1506 unsigned int dmaxAmbient;
1507 unsigned int dmaxDarkTmp;
1508 unsigned int sigmaEstP2Tmp;
1509 uint32_t signalRateTemp_mcps;
1510
1511 int8_t Status = VL_ERROR_NONE;
1512
1513 LOG_FUNCTION_START("");
1514
1515 dmaxCalRange_mm =
1516 PALDevDataGet(Dev, DmaxCalRangeMilliMeter);
1517
1518 dmaxCalSignalRateRtn_mcps =
1519 PALDevDataGet(Dev, DmaxCalSignalRateRtnMegaCps);
1520
1521 /* uint32 * FixPoint1616 = FixPoint1616 */
1522 SignalAt0mm = dmaxCalRange_mm * dmaxCalSignalRateRtn_mcps;
1523
1524 /* FixPoint1616 >> 8 = FixPoint2408 */
1525 SignalAt0mm = (SignalAt0mm + 0x80) >> 8;
1526 SignalAt0mm *= dmaxCalRange_mm;
1527
1528 minSignalNeeded_p1 = 0;
1529 if (totalCorrSignalRate_mcps > 0) {
1530
1531 /* Shift by 10 bits to increase resolution prior to the */
1532 /* division */
1533 signalRateTemp_mcps = totalSignalRate_mcps << 10;
1534
1535 /* Add rounding value prior to division */
1536 minSignalNeeded_p1 = signalRateTemp_mcps +
1537 (totalCorrSignalRate_mcps/2);
1538
1539 /* FixPoint0626/FixPoint1616 = FixPoint2210 */
1540 minSignalNeeded_p1 /= totalCorrSignalRate_mcps;
1541
1542 /* Apply a factored version of the speed of light. */
1543 /* Correction to be applied at the end */
1544 minSignalNeeded_p1 *= 3;
1545
1546 /* FixPoint2210 * FixPoint2210 = FixPoint1220 */
1547 minSignalNeeded_p1 *= minSignalNeeded_p1;
1548
1549 /* FixPoint1220 >> 16 = FixPoint2804 */
1550 minSignalNeeded_p1 = (minSignalNeeded_p1 + 0x8000) >> 16;
1551 }
1552
1553 minSignalNeeded_p2 = pwMult * sigmaEstimateP1;
1554
1555 /* FixPoint1616 >> 16 = uint32 */
1556 minSignalNeeded_p2 = (minSignalNeeded_p2 + 0x8000) >> 16;
1557
1558 /* uint32 * uint32 = uint32 */
1559 minSignalNeeded_p2 *= minSignalNeeded_p2;
1560
1561 /* Check sigmaEstimateP2
1562 * If this value is too high there is not enough signal rate
1563 * to calculate dmax value so set a suitable value to ensure
1564 * a very small dmax.
1565 */
1566 sigmaEstP2Tmp = (sigmaEstimateP2 + 0x8000) >> 16;
1567 sigmaEstP2Tmp = (sigmaEstP2Tmp + cAmbEffWidthSigmaEst_ns/2)/
1568 cAmbEffWidthSigmaEst_ns;
1569 sigmaEstP2Tmp *= cAmbEffWidthDMax_ns;
1570
1571 if (sigmaEstP2Tmp > 0xffff) {
1572 minSignalNeeded_p3 = 0xfff00000;
1573 } else {
1574
1575 /* DMAX uses a different ambient width from sigma, so apply
1576 * correction.
1577 * Perform division before multiplication to prevent overflow.
1578 */
1579 sigmaEstimateP2 = (sigmaEstimateP2 + cAmbEffWidthSigmaEst_ns/2)/
1580 cAmbEffWidthSigmaEst_ns;
1581 sigmaEstimateP2 *= cAmbEffWidthDMax_ns;
1582
1583 /* FixPoint1616 >> 16 = uint32 */
1584 minSignalNeeded_p3 = (sigmaEstimateP2 + 0x8000) >> 16;
1585
1586 minSignalNeeded_p3 *= minSignalNeeded_p3;
1587
1588 }
1589
1590 /* FixPoint1814 / uint32 = FixPoint1814 */
1591 sigmaLimitTmp = ((cSigmaLimit << 14) + 500) / 1000;
1592
1593 /* FixPoint1814 * FixPoint1814 = FixPoint3628 := FixPoint0428 */
1594 sigmaLimitTmp *= sigmaLimitTmp;
1595
1596 /* FixPoint1616 * FixPoint1616 = FixPoint3232 */
1597 sigmaEstSqTmp = cSigmaEstRef * cSigmaEstRef;
1598
1599 /* FixPoint3232 >> 4 = FixPoint0428 */
1600 sigmaEstSqTmp = (sigmaEstSqTmp + 0x08) >> 4;
1601
1602 /* FixPoint0428 - FixPoint0428 = FixPoint0428 */
1603 sigmaLimitTmp -= sigmaEstSqTmp;
1604
1605 /* uint32_t * FixPoint0428 = FixPoint0428 */
1606 minSignalNeeded_p4 = 4 * 12 * sigmaLimitTmp;
1607
1608 /* FixPoint0428 >> 14 = FixPoint1814 */
1609 minSignalNeeded_p4 = (minSignalNeeded_p4 + 0x2000) >> 14;
1610
1611 /* uint32 + uint32 = uint32 */
1612 minSignalNeeded = (minSignalNeeded_p2 + minSignalNeeded_p3);
1613
1614 /* uint32 / uint32 = uint32 */
1615 minSignalNeeded += (peakVcselDuration_us/2);
1616 minSignalNeeded /= peakVcselDuration_us;
1617
1618 /* uint32 << 14 = FixPoint1814 */
1619 minSignalNeeded <<= 14;
1620
1621 /* FixPoint1814 / FixPoint1814 = uint32 */
1622 minSignalNeeded += (minSignalNeeded_p4/2);
1623 minSignalNeeded /= minSignalNeeded_p4;
1624
1625 /* FixPoint3200 * FixPoint2804 := FixPoint2804*/
1626 minSignalNeeded *= minSignalNeeded_p1;
1627
1628 /* Apply correction by dividing by 1000000.
1629 * This assumes 10E16 on the numerator of the equation
1630 * and 10E-22 on the denominator.
1631 * We do this because 32bit fix point calculation can't
1632 * handle the larger and smaller elements of this equation,
1633 * i.e. speed of light and pulse widths.
1634 */
1635 minSignalNeeded = (minSignalNeeded + 500) / 1000;
1636 minSignalNeeded <<= 4;
1637
1638 minSignalNeeded = (minSignalNeeded + 500) / 1000;
1639
1640 /* FixPoint1616 >> 8 = FixPoint2408 */
1641 signalLimitTmp = (cSignalLimit + 0x80) >> 8;
1642
1643 /* FixPoint2408/FixPoint2408 = uint32 */
1644 if (signalLimitTmp != 0)
1645 dmaxDarkTmp = (SignalAt0mm + (signalLimitTmp / 2))
1646 / signalLimitTmp;
1647 else
1648 dmaxDarkTmp = 0;
1649
1650 dmaxDark = VL_isqrt(dmaxDarkTmp);
1651
1652 /* FixPoint2408/FixPoint2408 = uint32 */
1653 if (minSignalNeeded != 0)
1654 dmaxAmbient = (SignalAt0mm + minSignalNeeded/2)
1655 / minSignalNeeded;
1656 else
1657 dmaxAmbient = 0;
1658
1659 dmaxAmbient = VL_isqrt(dmaxAmbient);
1660
1661 *pdmax_mm = dmaxDark;
1662 if (dmaxDark > dmaxAmbient)
1663 *pdmax_mm = dmaxAmbient;
1664
1665 LOG_FUNCTION_END(Status);
1666
1667 return Status;
1668}
1669
1670
1671int8_t VL_calc_sigma_estimate(struct vl_data *Dev,
1672 struct VL_RangingMeasurementData_t *pRangingMeasurementData,
1673 unsigned int *pSigmaEstimate,
1674 uint32_t *pDmax_mm)
1675{
1676 /* Expressed in 100ths of a ns, i.e. centi-ns */
1677 const uint32_t cPulseEffectiveWidth_centi_ns = 800;
1678 /* Expressed in 100ths of a ns, i.e. centi-ns */
1679 const uint32_t cAmbientEffectiveWidth_centi_ns = 600;
1680 /* 25ms */
1681 const unsigned int cDfltFinalRangeIntegrationTimeMilliSecs =
1682 0x00190000;
1683 const uint32_t cVcselPulseWidth_ps = 4700; /* pico secs */
1684 const unsigned int cSigmaEstMax = 0x028F87AE;
1685 const unsigned int cSigmaEstRtnMax = 0xF000;
1686 const unsigned int cAmbToSignalRatioMax = 0xF0000000/
1687 cAmbientEffectiveWidth_centi_ns;
1688 /* Time Of Flight per mm (6.6 pico secs) */
1689 const unsigned int cTOF_per_mm_ps = 0x0006999A;
1690 const uint32_t c16BitRoundingParam = 0x00008000;
1691 const unsigned int cMaxXTalk_kcps = 0x00320000;
1692 const uint32_t cPllPeriod_ps = 1655;
1693
1694 uint32_t vcselTotalEventsRtn;
1695 uint32_t finalRangeTimeoutMicroSecs;
1696 uint32_t preRangeTimeoutMicroSecs;
1697 uint32_t finalRangeIntegrationTimeMilliSecs;
1698 unsigned int sigmaEstimateP1;
1699 unsigned int sigmaEstimateP2;
1700 unsigned int sigmaEstimateP3;
1701 unsigned int deltaT_ps;
1702 unsigned int pwMult;
1703 unsigned int sigmaEstRtn;
1704 unsigned int sigmaEstimate;
1705 unsigned int xTalkCorrection;
1706 unsigned int ambientRate_kcps;
1707 unsigned int peakSignalRate_kcps;
1708 unsigned int xTalkCompRate_mcps;
1709 uint32_t xTalkCompRate_kcps;
1710 int8_t Status = VL_ERROR_NONE;
1711 unsigned int diff1_mcps;
1712 unsigned int diff2_mcps;
1713 unsigned int sqr1;
1714 unsigned int sqr2;
1715 unsigned int sqrSum;
1716 unsigned int sqrtResult_centi_ns;
1717 unsigned int sqrtResult;
1718 unsigned int totalSignalRate_mcps;
1719 unsigned int correctedSignalRate_mcps;
1720 unsigned int sigmaEstRef;
1721 uint32_t vcselWidth;
1722 uint32_t finalRangeMacroPCLKS;
1723 uint32_t preRangeMacroPCLKS;
1724 uint32_t peakVcselDuration_us;
1725 uint8_t finalRangeVcselPCLKS;
1726 uint8_t preRangeVcselPCLKS;
1727 /*! \addtogroup calc_sigma_estimate
1728 * @{
1729 *
1730 * Estimates the range sigma
1731 */
1732
1733 LOG_FUNCTION_START("");
1734
1735 VL_GETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps,
1736 xTalkCompRate_mcps);
1737
1738 /*
1739 * We work in kcps rather than mcps as this helps keep within the
1740 * confines of the 32 Fix1616 type.
1741 */
1742
1743 ambientRate_kcps =
1744 (pRangingMeasurementData->AmbientRateRtnMegaCps * 1000) >> 16;
1745
1746 correctedSignalRate_mcps =
1747 pRangingMeasurementData->SignalRateRtnMegaCps;
1748
1749
1750 Status = VL_get_total_signal_rate(
1751 Dev, pRangingMeasurementData, &totalSignalRate_mcps);
1752 Status = VL_get_total_xtalk_rate(
1753 Dev, pRangingMeasurementData, &xTalkCompRate_mcps);
1754
1755
1756 /* Signal rate measurement provided by device is the
1757 * peak signal rate, not average.
1758 */
1759 peakSignalRate_kcps = (totalSignalRate_mcps * 1000);
1760 peakSignalRate_kcps = (peakSignalRate_kcps + 0x8000) >> 16;
1761
1762 xTalkCompRate_kcps = xTalkCompRate_mcps * 1000;
1763
1764 if (xTalkCompRate_kcps > cMaxXTalk_kcps)
1765 xTalkCompRate_kcps = cMaxXTalk_kcps;
1766
1767 if (Status == VL_ERROR_NONE) {
1768
1769 /* Calculate final range macro periods */
1770 finalRangeTimeoutMicroSecs = VL_GETDEVICESPECIFICPARAMETER(
1771 Dev, FinalRangeTimeoutMicroSecs);
1772
1773 finalRangeVcselPCLKS = VL_GETDEVICESPECIFICPARAMETER(
1774 Dev, FinalRangeVcselPulsePeriod);
1775
1776 finalRangeMacroPCLKS = VL_calc_timeout_mclks(
1777 Dev, finalRangeTimeoutMicroSecs, finalRangeVcselPCLKS);
1778
1779 /* Calculate pre-range macro periods */
1780 preRangeTimeoutMicroSecs = VL_GETDEVICESPECIFICPARAMETER(
1781 Dev, PreRangeTimeoutMicroSecs);
1782
1783 preRangeVcselPCLKS = VL_GETDEVICESPECIFICPARAMETER(
1784 Dev, PreRangeVcselPulsePeriod);
1785
1786 preRangeMacroPCLKS = VL_calc_timeout_mclks(
1787 Dev, preRangeTimeoutMicroSecs, preRangeVcselPCLKS);
1788
1789 vcselWidth = 3;
1790 if (finalRangeVcselPCLKS == 8)
1791 vcselWidth = 2;
1792
1793
1794 peakVcselDuration_us = vcselWidth * 2048 *
1795 (preRangeMacroPCLKS + finalRangeMacroPCLKS);
1796 peakVcselDuration_us = (peakVcselDuration_us + 500)/1000;
1797 peakVcselDuration_us *= cPllPeriod_ps;
1798 peakVcselDuration_us = (peakVcselDuration_us + 500)/1000;
1799
1800 /* Fix1616 >> 8 = Fix2408 */
1801 totalSignalRate_mcps = (totalSignalRate_mcps + 0x80) >> 8;
1802
1803 /* Fix2408 * uint32 = Fix2408 */
1804 vcselTotalEventsRtn = totalSignalRate_mcps *
1805 peakVcselDuration_us;
1806
1807 /* Fix2408 >> 8 = uint32 */
1808 vcselTotalEventsRtn = (vcselTotalEventsRtn + 0x80) >> 8;
1809
1810 /* Fix2408 << 8 = Fix1616 = */
1811 totalSignalRate_mcps <<= 8;
1812 }
1813
1814 if (Status != VL_ERROR_NONE) {
1815 LOG_FUNCTION_END(Status);
1816 return Status;
1817 }
1818
1819 if (peakSignalRate_kcps == 0) {
1820 *pSigmaEstimate = cSigmaEstMax;
1821 PALDevDataSet(Dev, SigmaEstimate, cSigmaEstMax);
1822 *pDmax_mm = 0;
1823 } else {
1824 if (vcselTotalEventsRtn < 1)
1825 vcselTotalEventsRtn = 1;
1826
1827 sigmaEstimateP1 = cPulseEffectiveWidth_centi_ns;
1828
1829 /* ((FixPoint1616 << 16)* uint32)/uint32 = FixPoint1616 */
1830 sigmaEstimateP2 = (ambientRate_kcps << 16)/peakSignalRate_kcps;
1831 if (sigmaEstimateP2 > cAmbToSignalRatioMax) {
1832 /* Clip to prevent overflow. Will ensure safe */
1833 /* max result. */
1834 sigmaEstimateP2 = cAmbToSignalRatioMax;
1835 }
1836 sigmaEstimateP2 *= cAmbientEffectiveWidth_centi_ns;
1837
1838 sigmaEstimateP3 = 2 * VL_isqrt(vcselTotalEventsRtn * 12);
1839
1840 /* uint32 * FixPoint1616 = FixPoint1616 */
1841 deltaT_ps = pRangingMeasurementData->RangeMilliMeter *
1842 cTOF_per_mm_ps;
1843
1844 /* vcselRate - xtalkCompRate */
1845 /* (uint32 << 16) - FixPoint1616 = FixPoint1616. */
1846 /* Divide result by 1000 to convert to mcps. */
1847 /* 500 is added to ensure rounding when integer division */
1848 /* truncates. */
1849 diff1_mcps = (((peakSignalRate_kcps << 16) -
1850 2 * xTalkCompRate_kcps) + 500)/1000;
1851
1852 /* vcselRate + xtalkCompRate */
1853 diff2_mcps = ((peakSignalRate_kcps << 16) + 500)/1000;
1854
1855 /* Shift by 8 bits to increase resolution prior to the */
1856 /* division */
1857 diff1_mcps <<= 8;
1858
1859 /* FixPoint0824/FixPoint1616 = FixPoint2408 */
1860 xTalkCorrection = abs(diff1_mcps/diff2_mcps);
1861
1862 /* FixPoint2408 << 8 = FixPoint1616 */
1863 xTalkCorrection <<= 8;
1864
1865 if (pRangingMeasurementData->RangeStatus != 0) {
1866 pwMult = 1 << 16;
1867 } else {
1868 /* FixPoint1616/uint32 = FixPoint1616 *i */
1869 /* smaller than 1.0f */
1870 pwMult = deltaT_ps/cVcselPulseWidth_ps;
1871
1872 /* FixPoint1616 * FixPoint1616 = FixPoint3232, however both */
1873 /* values are small enough such that32 bits will not be */
1874 /* exceeded. */
1875 pwMult *= ((1 << 16) - xTalkCorrection);
1876
1877 /* (FixPoint3232 >> 16) = FixPoint1616 */
1878 pwMult = (pwMult + c16BitRoundingParam) >> 16;
1879
1880 /* FixPoint1616 + FixPoint1616 = FixPoint1616 */
1881 pwMult += (1 << 16);
1882
1883 /* At this point the value will be 1.xx, */
1884 /* therefore if we square */
1885 /* the value this will exceed 32 bits. */
1886 /* To address this perform */
1887 /* a single shift to the right before the multiplication. */
1888 pwMult >>= 1;
1889 /* FixPoint1715 * FixPoint1715 = FixPoint3430 */
1890 pwMult = pwMult * pwMult;
1891
1892 /* (FixPoint3430 >> 14) = Fix1616 */
1893 pwMult >>= 14;
1894 }
1895
1896 /* FixPoint1616 * uint32 = FixPoint1616 */
1897 sqr1 = pwMult * sigmaEstimateP1;
1898
1899 /* (FixPoint1616 >> 16) = FixPoint3200 */
1900 sqr1 = (sqr1 + 0x8000) >> 16;
1901
1902 /* FixPoint3200 * FixPoint3200 = FixPoint6400 */
1903 sqr1 *= sqr1;
1904
1905 sqr2 = sigmaEstimateP2;
1906
1907 /* (FixPoint1616 >> 16) = FixPoint3200 */
1908 sqr2 = (sqr2 + 0x8000) >> 16;
1909
1910 /* FixPoint3200 * FixPoint3200 = FixPoint6400 */
1911 sqr2 *= sqr2;
1912
1913 /* FixPoint64000 + FixPoint6400 = FixPoint6400 */
1914 sqrSum = sqr1 + sqr2;
1915
1916 /* SQRT(FixPoin6400) = FixPoint3200 */
1917 sqrtResult_centi_ns = VL_isqrt(sqrSum);
1918
1919 /* (FixPoint3200 << 16) = FixPoint1616 */
1920 sqrtResult_centi_ns <<= 16;
1921
1922 /*
1923 * Note that the Speed Of Light is expressed in um per 1E-10
1924 * seconds (2997) Therefore to get mm/ns we have to divide by
1925 * 10000
1926 */
1927 sigmaEstRtn = (((sqrtResult_centi_ns+50)/100) /
1928 sigmaEstimateP3);
1929 sigmaEstRtn *= VL_SPEED_OF_LIGHT_IN_AIR;
1930
1931 /* Add 5000 before dividing by 10000 to ensure rounding. */
1932 sigmaEstRtn += 5000;
1933 sigmaEstRtn /= 10000;
1934
1935 if (sigmaEstRtn > cSigmaEstRtnMax) {
1936 /* Clip to prevent overflow. Will ensure safe */
1937 /* max result. */
1938 sigmaEstRtn = cSigmaEstRtnMax;
1939 }
1940 finalRangeIntegrationTimeMilliSecs =
1941 (finalRangeTimeoutMicroSecs +
1942 preRangeTimeoutMicroSecs + 500)/1000;
1943
1944 /* sigmaEstRef = 1mm * 25ms/final range integration time */
1945 /* (inc pre-range) sqrt(FixPoint1616/int) = FixPoint2408) */
1946 sigmaEstRef =
1947 VL_isqrt((cDfltFinalRangeIntegrationTimeMilliSecs +
1948 finalRangeIntegrationTimeMilliSecs/2)/
1949 finalRangeIntegrationTimeMilliSecs);
1950
1951 /* FixPoint2408 << 8 = FixPoint1616 */
1952 sigmaEstRef <<= 8;
1953 sigmaEstRef = (sigmaEstRef + 500)/1000;
1954
1955 /* FixPoint1616 * FixPoint1616 = FixPoint3232 */
1956 sqr1 = sigmaEstRtn * sigmaEstRtn;
1957 /* FixPoint1616 * FixPoint1616 = FixPoint3232 */
1958 sqr2 = sigmaEstRef * sigmaEstRef;
1959
1960 /* sqrt(FixPoint3232) = FixPoint1616 */
1961 sqrtResult = VL_isqrt((sqr1 + sqr2));
1962 /* Note that the Shift by 4 bits increases */
1963 /*resolution prior to */
1964 /* the sqrt, therefore the result must be */
1965 /* shifted by 2 bits to */
1966 /* the right to revert back to the FixPoint1616 format. */
1967
1968 sigmaEstimate = 1000 * sqrtResult;
1969
1970 if ((peakSignalRate_kcps < 1) || (vcselTotalEventsRtn < 1) ||
1971 (sigmaEstimate > cSigmaEstMax)) {
1972 sigmaEstimate = cSigmaEstMax;
1973 }
1974
1975 *pSigmaEstimate = (uint32_t)(sigmaEstimate);
1976 PALDevDataSet(Dev, SigmaEstimate, *pSigmaEstimate);
1977 Status = VL_calc_dmax(
1978 Dev,
1979 totalSignalRate_mcps,
1980 correctedSignalRate_mcps,
1981 pwMult,
1982 sigmaEstimateP1,
1983 sigmaEstimateP2,
1984 peakVcselDuration_us,
1985 pDmax_mm);
1986 }
1987
1988 LOG_FUNCTION_END(Status);
1989 return Status;
1990}
1991
1992int8_t VL_get_pal_range_status(struct vl_data *Dev,
1993 uint8_t DeviceRangeStatus,
1994 unsigned int SignalRate,
1995 uint16_t EffectiveSpadRtnCount,
1996 struct VL_RangingMeasurementData_t *pRangingMeasurementData,
1997 uint8_t *pPalRangeStatus)
1998{
1999 int8_t Status = VL_ERROR_NONE;
2000 uint8_t NoneFlag;
2001 uint8_t SigmaLimitflag = 0;
2002 uint8_t SignalRefClipflag = 0;
2003 uint8_t RangeIgnoreThresholdflag = 0;
2004 uint8_t SigmaLimitCheckEnable = 0;
2005 uint8_t SignalRateFinalRangeLimitCheckEnable = 0;
2006 uint8_t SignalRefClipLimitCheckEnable = 0;
2007 uint8_t RangeIgnoreThresholdLimitCheckEnable = 0;
2008 unsigned int SigmaEstimate;
2009 unsigned int SigmaLimitValue;
2010 unsigned int SignalRefClipValue;
2011 unsigned int RangeIgnoreThresholdValue;
2012 unsigned int SignalRatePerSpad;
2013 uint8_t DeviceRangeStatusInternal = 0;
2014 uint16_t tmpWord = 0;
2015 uint8_t Temp8;
2016 uint32_t Dmax_mm = 0;
2017 unsigned int LastSignalRefMcps;
2018
2019 LOG_FUNCTION_START("");
2020
2021
2022 /*
2023 * VL53L0X has a good ranging when the value of the
2024 * DeviceRangeStatus = 11. This function will replace the value 0 with
2025 * the value 11 in the DeviceRangeStatus.
2026 * In addition, the SigmaEstimator is not included in the VL53L0X
2027 * DeviceRangeStatus, this will be added in the PalRangeStatus.
2028 */
2029
2030 DeviceRangeStatusInternal = ((DeviceRangeStatus & 0x78) >> 3);
2031
2032 if (DeviceRangeStatusInternal == 0 ||
2033 DeviceRangeStatusInternal == 5 ||
2034 DeviceRangeStatusInternal == 7 ||
2035 DeviceRangeStatusInternal == 12 ||
2036 DeviceRangeStatusInternal == 13 ||
2037 DeviceRangeStatusInternal == 14 ||
2038 DeviceRangeStatusInternal == 15
2039 ) {
2040 NoneFlag = 1;
2041 } else {
2042 NoneFlag = 0;
2043 }
2044
2045 /*
2046 * Check if Sigma limit is enabled, if yes then do comparison with limit
2047 * value and put the result back into pPalRangeStatus.
2048 */
2049 if (Status == VL_ERROR_NONE)
2050 Status = VL_GetLimitCheckEnable(Dev,
2051 VL_CHECKENABLE_SIGMA_FINAL_RANGE,
2052 &SigmaLimitCheckEnable);
2053
2054 if ((SigmaLimitCheckEnable != 0) && (Status == VL_ERROR_NONE)) {
2055 /* compute the Sigma and check with limit */
2056 Status = VL_calc_sigma_estimate(
2057 Dev,
2058 pRangingMeasurementData,
2059 &SigmaEstimate,
2060 &Dmax_mm);
2061 if (Status == VL_ERROR_NONE)
2062 pRangingMeasurementData->RangeDMaxMilliMeter = Dmax_mm;
2063
2064 if (Status == VL_ERROR_NONE) {
2065 Status = VL_GetLimitCheckValue(Dev,
2066 VL_CHECKENABLE_SIGMA_FINAL_RANGE,
2067 &SigmaLimitValue);
2068
2069 if ((SigmaLimitValue > 0) &&
2070 (SigmaEstimate > SigmaLimitValue))
2071 /* Limit Fail */
2072 SigmaLimitflag = 1;
2073 }
2074 }
2075
2076 /* Check if Signal ref clip limit is enabled, */
2077 /* if yes then do comparison */
2078 /* with limit value and put the result back into pPalRangeStatus. */
2079 if (Status == VL_ERROR_NONE)
2080 Status = VL_GetLimitCheckEnable(Dev,
2081 VL_CHECKENABLE_SIGNAL_REF_CLIP,
2082 &SignalRefClipLimitCheckEnable);
2083
2084 if ((SignalRefClipLimitCheckEnable != 0) &&
2085 (Status == VL_ERROR_NONE)) {
2086
2087 Status = VL_GetLimitCheckValue(Dev,
2088 VL_CHECKENABLE_SIGNAL_REF_CLIP,
2089 &SignalRefClipValue);
2090
2091 /* Read LastSignalRefMcps from device */
2092 if (Status == VL_ERROR_NONE)
2093 Status = VL_WrByte(Dev, 0xFF, 0x01);
2094
2095 if (Status == VL_ERROR_NONE)
2096 Status = VL_RdWord(Dev,
2097 VL_REG_RESULT_PEAK_SIGNAL_RATE_REF,
2098 &tmpWord);
2099
2100 if (Status == VL_ERROR_NONE)
2101 Status = VL_WrByte(Dev, 0xFF, 0x00);
2102
2103 LastSignalRefMcps = VL_FIXPOINT97TOFIXPOINT1616(tmpWord);
2104 PALDevDataSet(Dev, LastSignalRefMcps, LastSignalRefMcps);
2105
2106 if ((SignalRefClipValue > 0) &&
2107 (LastSignalRefMcps > SignalRefClipValue)) {
2108 /* Limit Fail */
2109 SignalRefClipflag = 1;
2110 }
2111 }
2112
2113 /*
2114 * Check if Signal ref clip limit is enabled, if yes then do comparison
2115 * with limit value and put the result back into pPalRangeStatus.
2116 * EffectiveSpadRtnCount has a format 8.8
2117 * If (Return signal rate < (1.5 x Xtalk x number of Spads)) : FAIL
2118 */
2119 if (Status == VL_ERROR_NONE)
2120 Status = VL_GetLimitCheckEnable(Dev,
2121 VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
2122 &RangeIgnoreThresholdLimitCheckEnable);
2123
2124 if ((RangeIgnoreThresholdLimitCheckEnable != 0) &&
2125 (Status == VL_ERROR_NONE)) {
2126
2127 /* Compute the signal rate per spad */
2128 if (EffectiveSpadRtnCount == 0) {
2129 SignalRatePerSpad = 0;
2130 } else {
2131 SignalRatePerSpad = (unsigned int)((256 * SignalRate)
2132 / EffectiveSpadRtnCount);
2133 }
2134
2135 Status = VL_GetLimitCheckValue(Dev,
2136 VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
2137 &RangeIgnoreThresholdValue);
2138
2139 if ((RangeIgnoreThresholdValue > 0) &&
2140 (SignalRatePerSpad < RangeIgnoreThresholdValue)) {
2141 /* Limit Fail add 2^6 to range status */
2142 RangeIgnoreThresholdflag = 1;
2143 }
2144 }
2145
2146 if (Status == VL_ERROR_NONE) {
2147 if (NoneFlag == 1) {
2148 *pPalRangeStatus = 255; /* NONE */
2149 } else if (DeviceRangeStatusInternal == 1 ||
2150 DeviceRangeStatusInternal == 2 ||
2151 DeviceRangeStatusInternal == 3) {
2152 *pPalRangeStatus = 5; /* HW fail */
2153 } else if (DeviceRangeStatusInternal == 6 ||
2154 DeviceRangeStatusInternal == 9) {
2155 *pPalRangeStatus = 4; /* Phase fail */
2156 } else if (DeviceRangeStatusInternal == 8 ||
2157 DeviceRangeStatusInternal == 10 ||
2158 SignalRefClipflag == 1) {
2159 *pPalRangeStatus = 3; /* Min range */
2160 } else if (DeviceRangeStatusInternal == 4 ||
2161 RangeIgnoreThresholdflag == 1) {
2162 *pPalRangeStatus = 2; /* Signal Fail */
2163 } else if (SigmaLimitflag == 1) {
2164 *pPalRangeStatus = 1; /* Sigma Fail */
2165 } else {
2166 *pPalRangeStatus = 0; /* Range Valid */
2167 }
2168 }
2169
2170 /* DMAX only relevant during range error */
2171 if (*pPalRangeStatus == 0)
2172 pRangingMeasurementData->RangeDMaxMilliMeter = 0;
2173
2174 /* fill the Limit Check Status */
2175
2176 Status = VL_GetLimitCheckEnable(Dev,
2177 VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
2178 &SignalRateFinalRangeLimitCheckEnable);
2179
2180 if (Status == VL_ERROR_NONE) {
2181 if ((SigmaLimitCheckEnable == 0) || (SigmaLimitflag == 1))
2182 Temp8 = 1;
2183 else
2184 Temp8 = 0;
2185 VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
2186 VL_CHECKENABLE_SIGMA_FINAL_RANGE, Temp8);
2187
2188 if ((DeviceRangeStatusInternal == 4) ||
2189 (SignalRateFinalRangeLimitCheckEnable == 0))
2190 Temp8 = 1;
2191 else
2192 Temp8 = 0;
2193 VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
2194 VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
2195 Temp8);
2196
2197 if ((SignalRefClipLimitCheckEnable == 0) ||
2198 (SignalRefClipflag == 1))
2199 Temp8 = 1;
2200 else
2201 Temp8 = 0;
2202
2203 VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
2204 VL_CHECKENABLE_SIGNAL_REF_CLIP, Temp8);
2205
2206 if ((RangeIgnoreThresholdLimitCheckEnable == 0) ||
2207 (RangeIgnoreThresholdflag == 1))
2208 Temp8 = 1;
2209 else
2210 Temp8 = 0;
2211
2212 VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
2213 VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
2214 Temp8);
2215 }
2216
2217 LOG_FUNCTION_END(Status);
2218 return Status;
2219
2220}