1 /*
2 * Copyright (c) 2017, STMicroelectronics - All Rights Reserved
3 *
4 * This file is part of VL53L1 Core and is dual licensed,
5 * either 'STMicroelectronics
6 * Proprietary license'
7 * or 'BSD 3-clause "New" or "Revised" License' , at your option.
8 *
9 ********************************************************************************
10 *
11 * 'STMicroelectronics Proprietary license'
12 *
13 ********************************************************************************
14 *
15 * License terms: STMicroelectronics Proprietary in accordance with licensing
16 * terms at www.st.com/sla0081
17 *
18 * STMicroelectronics confidential
19 * Reproduction and Communication of this document is strictly prohibited unless
20 * specifically authorized in writing by STMicroelectronics.
21 *
22 *
23 ********************************************************************************
24 *
25 * Alternatively, VL53L1 Core may be distributed under the terms of
26 * 'BSD 3-clause "New" or "Revised" License', in which case the following
27 * provisions apply instead of the ones mentioned above :
28 *
29 ********************************************************************************
30 *
31 * License terms: BSD 3-clause "New" or "Revised" License.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions are met:
35 *
36 * 1. Redistributions of source code must retain the above copyright notice, this
37 * list of conditions and the following disclaimer.
38 *
39 * 2. Redistributions in binary form must reproduce the above copyright notice,
40 * this list of conditions and the following disclaimer in the documentation
41 * and/or other materials provided with the distribution.
42 *
43 * 3. Neither the name of the copyright holder nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
50 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
53 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
54 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
55 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
56 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 *
58 *
59 ********************************************************************************
60 *
61 */
62
63 /**
64 * @file vl53l1_core_support.c
65 *
66 * @brief EwokPlus25 core function definition
67 */
68
69 #include "vl53l1_ll_def.h"
70 #include "vl53l1_ll_device.h"
71 #include "vl53l1_platform_log.h"
72 #include "vl53l1_core_support.h"
73 #include "vl53l1_platform_user_data.h"
74 #include "vl53l1_platform_user_defines.h"
75
76 #ifdef VL53L1_LOGGING
77 #include "vl53l1_debug.h"
78 #include "vl53l1_register_debug.h"
79 #endif
80
81 #define LOG_FUNCTION_START(fmt, ...) \
82 _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__)
83 #define LOG_FUNCTION_END(status, ...) \
84 _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__)
85 #define LOG_FUNCTION_END_FMT(status, fmt, ...) \
86 _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, \
87 status, fmt, ##__VA_ARGS__)
88
89 #define trace_print(level, ...) \
90 _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \
91 level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__)
92
93
VL53L1_calc_pll_period_us(uint16_t fast_osc_frequency)94 uint32_t VL53L1_calc_pll_period_us(
95 uint16_t fast_osc_frequency)
96 {
97 /* Calculates PLL frequency using NVM fast_osc_frequency
98 * Fast osc frequency fixed point format = unsigned 4.12
99 *
100 * PLL period fixed point format = unsigned 0.24
101 * Min input fast osc frequency = 1 MHz
102 * PLL Multiplier = 64 (fixed)
103 * Min PLL freq = 64.0MHz
104 * -> max PLL period = 1/ 64
105 * -> only the 18 LS bits are used
106 *
107 * 2^30 = (2^24) (1.0us) * 4096 (2^12) / 64 (PLL Multiplier)
108 */
109
110 uint32_t pll_period_us = 0;
111
112 LOG_FUNCTION_START("");
113
114 pll_period_us = (0x01 << 30) / fast_osc_frequency;
115
116 #ifdef VL53L1_LOGGING
117 trace_print(VL53L1_TRACE_LEVEL_DEBUG,
118 " %-48s : %10u\n", "pll_period_us",
119 pll_period_us);
120 #endif
121
122 LOG_FUNCTION_END(0);
123
124 return pll_period_us;
125 }
126
127
128 #ifdef PAL_EXTENDED
VL53L1_duration_maths(uint32_t pll_period_us,uint32_t vcsel_parm_pclks,uint32_t window_vclks,uint32_t elapsed_mclks)129 uint32_t VL53L1_duration_maths(
130 uint32_t pll_period_us,
131 uint32_t vcsel_parm_pclks,
132 uint32_t window_vclks,
133 uint32_t elapsed_mclks)
134 {
135 /*
136 * Generates the ranging duration in us
137 *
138 * duration_us = elapsed_mclks * vcsel_perm_pclks *
139 * window_vclks * pll_period_us
140 *
141 * returned value in [us] with no fraction bits
142 */
143
144 uint64_t tmp_long_int = 0;
145 uint32_t duration_us = 0;
146
147 /* PLL period us = 0.24 18 LS bits used
148 * window_vclks = 12.0 (2304 max)
149 * output 30b (6.24)
150 */
151 duration_us = window_vclks * pll_period_us;
152
153 /* down shift by 12
154 * output 18b (6.12)
155 */
156 duration_us = duration_us >> 12;
157
158 /* Save first part of the calc (#1) */
159 tmp_long_int = (uint64_t)duration_us;
160
161 /* Multiply elapsed macro periods (22-bit)
162 * by VCSEL parameter 6.4 (max 63.9999)
163 * output 32b (28.4)
164 */
165 duration_us = elapsed_mclks * vcsel_parm_pclks;
166
167 /* down shift by 4 to remove fractional bits (#2)
168 * output 28b (28.0)
169 */
170 duration_us = duration_us >> 4;
171
172 /* Multiply #1 18b (6.12) by #2 28b (28.0)
173 * output 46b (34.12)
174 */
175 tmp_long_int = tmp_long_int * (uint64_t)duration_us;
176
177 /* Remove fractional part
178 * output 34b (34.0)
179 */
180 tmp_long_int = tmp_long_int >> 12;
181
182 /* Clip to 32-bits */
183 if (tmp_long_int > 0xFFFFFFFF) {
184 tmp_long_int = 0xFFFFFFFF;
185 }
186
187 duration_us = (uint32_t)tmp_long_int;
188
189 return duration_us;
190 }
191
192
VL53L1_isqrt(uint32_t num)193 uint32_t VL53L1_isqrt(uint32_t num)
194 {
195
196 /*
197 * Implements an integer square root
198 *
199 * From: http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
200 */
201
202 uint32_t res = 0;
203 uint32_t bit = 1 << 30; /* The second-to-top bit is set: 1 << 14 for 16-bits, 1 << 30 for 32 bits */
204
205 /* "bit" starts at the highest power of four <= the argument. */
206 while (bit > num) {
207 bit >>= 2;
208 }
209
210 while (bit != 0) {
211 if (num >= res + bit) {
212 num -= res + bit;
213 res = (res >> 1) + bit;
214 } else {
215 res >>= 1;
216 }
217 bit >>= 2;
218 }
219
220 return res;
221 }
222
223
VL53L1_rate_maths(int32_t events,uint32_t time_us)224 uint16_t VL53L1_rate_maths(
225 int32_t events,
226 uint32_t time_us)
227 {
228 /*
229 * Converts events into count rate
230 *
231 * Max events = 512 Mcps * 1sec
232 * = 512,000,000 events
233 * = 29b
234 *
235 * If events > 2^24 use 3-bit fractional bits is used internally
236 * otherwise 7-bit fractional bits are used
237 */
238
239 uint32_t tmp_int = 0;
240 uint32_t frac_bits = 7;
241 uint16_t rate_mcps = 0; /* 9.7 format */
242
243 /*
244 * Clip input event range
245 */
246
247 if (events > VL53L1_SPAD_TOTAL_COUNT_MAX) {
248 tmp_int = VL53L1_SPAD_TOTAL_COUNT_MAX;
249 } else if (events > 0) {
250 tmp_int = (uint32_t)events;
251 }
252
253 /*
254 * if events > VL53L1_SPAD_TOTAL_COUNT_RES_THRES use 3 rather
255 * than 7 fractional bits internal to function
256 */
257
258 if (events > VL53L1_SPAD_TOTAL_COUNT_RES_THRES) {
259 frac_bits = 3;
260 } else {
261 frac_bits = 7;
262 }
263
264 /*
265 * Create 3 or 7 fractional bits
266 * output 32b (29.3 or 25.7)
267 * Divide by range duration in [us] - no fractional bits
268 */
269 if (time_us > 0) {
270 tmp_int = ((tmp_int << frac_bits) + (time_us / 2)) / time_us;
271 }
272
273 /*
274 * Re align if reduced resolution
275 */
276 if (events > VL53L1_SPAD_TOTAL_COUNT_RES_THRES) {
277 tmp_int = tmp_int << 4;
278 }
279
280 /*
281 * Firmware internal count is 17.7 (24b) but it this
282 * case clip to 16-bit value for reporting
283 */
284
285 if (tmp_int > 0xFFFF) {
286 tmp_int = 0xFFFF;
287 }
288
289 rate_mcps = (uint16_t)tmp_int;
290
291 return rate_mcps;
292 }
293
VL53L1_rate_per_spad_maths(uint32_t frac_bits,uint32_t peak_count_rate,uint16_t num_spads,uint32_t max_output_value)294 uint16_t VL53L1_rate_per_spad_maths(
295 uint32_t frac_bits,
296 uint32_t peak_count_rate,
297 uint16_t num_spads,
298 uint32_t max_output_value)
299 {
300
301 uint32_t tmp_int = 0;
302
303 /* rate_per_spad Format varies with prog frac_bits */
304 uint16_t rate_per_spad = 0;
305
306 /* Calculate rate per spad with variable fractional bits */
307
308 /* Frac_bits should be programmed as final frac_bits - 7 as
309 * the pk_rate contains an inherent 7 bit resolution
310 */
311
312 if (num_spads > 0) {
313 tmp_int = (peak_count_rate << 8) << frac_bits;
314 tmp_int = (tmp_int + ((uint32_t)num_spads / 2)) / (uint32_t)num_spads;
315 } else {
316 tmp_int = ((peak_count_rate) << frac_bits);
317 }
318
319 /* Clip in case of overwrap - special code */
320
321 if (tmp_int > max_output_value) {
322 tmp_int = max_output_value;
323 }
324
325 rate_per_spad = (uint16_t)tmp_int;
326
327 return rate_per_spad;
328 }
329
VL53L1_range_maths(uint16_t fast_osc_frequency,uint16_t phase,uint16_t zero_distance_phase,uint8_t fractional_bits,int32_t gain_factor,int32_t range_offset_mm)330 int32_t VL53L1_range_maths(
331 uint16_t fast_osc_frequency,
332 uint16_t phase,
333 uint16_t zero_distance_phase,
334 uint8_t fractional_bits,
335 int32_t gain_factor,
336 int32_t range_offset_mm)
337 {
338 /*
339 * Converts phase information into distance in [mm]
340 */
341
342 uint32_t pll_period_us = 0; /* 0.24 format */
343 int64_t tmp_long_int = 0;
344 int32_t range_mm = 0;
345
346 /* Calculate PLL period in [ps] */
347
348 pll_period_us = VL53L1_calc_pll_period_us(fast_osc_frequency);
349
350 /* Raw range in [mm]
351 *
352 * calculate the phase difference between return and reference phases
353 *
354 * phases 16b (5.11)
355 * output 17b including sign bit
356 */
357
358 tmp_long_int = (int64_t)phase - (int64_t)zero_distance_phase;
359
360 /*
361 * multiply by the PLL period
362 *
363 * PLL period 24bit (0.24) but only 18 LS bits used
364 *
365 * Output 35b (0.35) (17b + 18b)
366 */
367
368 tmp_long_int = tmp_long_int * (int64_t)pll_period_us;
369
370 /*
371 * Down shift by 9 - Output 26b (0.26)
372 */
373
374 tmp_long_int = tmp_long_int / (0x01 << 9);
375
376 /*
377 * multiply by speed of light in air divided by 8
378 * Factor of 8 includes 2 for the round trip and 4 scaling
379 *
380 * VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8 = 16b (16.2)
381 *
382 * Output 42b (18.24) (16b + 26b)
383 */
384
385 tmp_long_int = tmp_long_int * VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8;
386
387 /*
388 * Down shift by 22 - Output 20b (18.2)
389 */
390
391 tmp_long_int = tmp_long_int / (0x01 << 22);
392
393 /* Add range offset */
394 range_mm = (int32_t)tmp_long_int + range_offset_mm;
395
396 /* apply correction gain */
397 range_mm *= gain_factor;
398 range_mm += 0x0400;
399 range_mm /= 0x0800;
400
401 /* Remove fractional bits */
402 if (fractional_bits == 0)
403 range_mm = range_mm / (0x01 << 2);
404 else if (fractional_bits == 1)
405 range_mm = range_mm / (0x01 << 1);
406
407 return range_mm;
408 }
409 #endif
410
VL53L1_decode_vcsel_period(uint8_t vcsel_period_reg)411 uint8_t VL53L1_decode_vcsel_period(uint8_t vcsel_period_reg)
412 {
413 /*
414 * Converts the encoded VCSEL period register value into
415 * the real period in PLL clocks
416 */
417
418 uint8_t vcsel_period_pclks = 0;
419
420 vcsel_period_pclks = (vcsel_period_reg + 1) << 1;
421
422 return vcsel_period_pclks;
423 }
424
425
VL53L1_decode_row_col(uint8_t spad_number,uint8_t * prow,uint8_t * pcol)426 void VL53L1_decode_row_col(
427 uint8_t spad_number,
428 uint8_t *prow,
429 uint8_t *pcol)
430 {
431
432 /**
433 * Decodes the array (row,col) location from
434 * the input SPAD number
435 */
436
437 if (spad_number > 127) {
438 *prow = 8 + ((255-spad_number) & 0x07);
439 *pcol = (spad_number-128) >> 3;
440 } else {
441 *prow = spad_number & 0x07;
442 *pcol = (127-spad_number) >> 3;
443 }
444 }
445
446