Last active
November 21, 2018 00:34
-
-
Save satakagi/0a41cf384d91ac9860a2f7f040d0c849 to your computer and use it in GitHub Desktop.
VL53L0X driver for CHIRIMEN Raspberry-Pi3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<meta charset="UTF-8" /> | |
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1"> | |
<title>i2c-VL53L0X</title> | |
<script src="../../../polyfill/polyfill.js"></script> | |
<script src="../../drivers/i2c-VL53L0X.js"></script> | |
<script src="./mainVL53L0X.js"></script> | |
<style> | |
table,p { | |
color: blue; | |
text-align: center; | |
font-size: 24px; | |
} | |
img { | |
position: absolute; | |
top: 50px; | |
right: 0px; | |
display: block; | |
margin-left: auto; | |
margin-right: auto; | |
} | |
</style> | |
</head> | |
<body> | |
<p id="head">VL53L0X</p> | |
<img src="schematic.png" width="400"/> | |
<table> | |
<tr><td>Distance [mm]</td><td id="dist"></td></tr> | |
</table> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// VL53L0X driver for CHIRIMEN WebI2C | |
// Ported from | |
// https://github.com/adafruit/Adafruit_CircuitPython_VL53L0X/blob/master/adafruit_vl53l0x.py | |
// by Satoru Takagi | |
var VL53L0X = function(i2cPort,slaveAddress,io_timeout_s){ | |
this.devConst={ | |
_SYSRANGE_START : (0x00), | |
_SYSTEM_THRESH_HIGH : (0x0C), | |
_SYSTEM_THRESH_LOW : (0x0E), | |
_SYSTEM_SEQUENCE_CONFIG : (0x01), | |
_SYSTEM_RANGE_CONFIG : (0x09), | |
_SYSTEM_INTERMEASUREMENT_PERIOD : (0x04), | |
_SYSTEM_INTERRUPT_CONFIG_GPIO : (0x0A), | |
_GPIO_HV_MUX_ACTIVE_HIGH : (0x84), | |
_SYSTEM_INTERRUPT_CLEAR : (0x0B), | |
_RESULT_INTERRUPT_STATUS : (0x13), | |
_RESULT_RANGE_STATUS : (0x14), | |
_RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN : (0xBC), | |
_RESULT_CORE_RANGING_TOTAL_EVENTS_RTN : (0xC0), | |
_RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF : (0xD0), | |
_RESULT_CORE_RANGING_TOTAL_EVENTS_REF : (0xD4), | |
_RESULT_PEAK_SIGNAL_RATE_REF : (0xB6), | |
_ALGO_PART_TO_PART_RANGE_OFFSET_MM : (0x28), | |
_I2C_SLAVE_DEVICE_ADDRESS : (0x8A), | |
_MSRC_CONFIG_CONTROL : (0x60), | |
_PRE_RANGE_CONFIG_MIN_SNR : (0x27), | |
_PRE_RANGE_CONFIG_VALID_PHASE_LOW : (0x56), | |
_PRE_RANGE_CONFIG_VALID_PHASE_HIGH : (0x57), | |
_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT : (0x64), | |
_FINAL_RANGE_CONFIG_MIN_SNR : (0x67), | |
_FINAL_RANGE_CONFIG_VALID_PHASE_LOW : (0x47), | |
_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH : (0x48), | |
_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT : (0x44), | |
_PRE_RANGE_CONFIG_SIGMA_THRESH_HI : (0x61), | |
_PRE_RANGE_CONFIG_SIGMA_THRESH_LO : (0x62), | |
_PRE_RANGE_CONFIG_VCSEL_PERIOD : (0x50), | |
_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI : (0x51), | |
_PRE_RANGE_CONFIG_TIMEOUT_MACROP_LO : (0x52), | |
_SYSTEM_HISTOGRAM_BIN : (0x81), | |
_HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT : (0x33), | |
_HISTOGRAM_CONFIG_READOUT_CTRL : (0x55), | |
_FINAL_RANGE_CONFIG_VCSEL_PERIOD : (0x70), | |
_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI : (0x71), | |
_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_LO : (0x72), | |
_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS : (0x20), | |
_MSRC_CONFIG_TIMEOUT_MACROP : (0x46), | |
_SOFT_RESET_GO2_SOFT_RESET_N : (0xBF), | |
_IDENTIFICATION_MODEL_ID : (0xC0), | |
_IDENTIFICATION_REVISION_ID : (0xC2), | |
_OSC_CALIBRATE_VAL : (0xF8), | |
_GLOBAL_CONFIG_VCSEL_WIDTH : (0x32), | |
_GLOBAL_CONFIG_SPAD_ENABLES_REF_0 : (0xB0), | |
_GLOBAL_CONFIG_SPAD_ENABLES_REF_1 : (0xB1), | |
_GLOBAL_CONFIG_SPAD_ENABLES_REF_2 : (0xB2), | |
_GLOBAL_CONFIG_SPAD_ENABLES_REF_3 : (0xB3), | |
_GLOBAL_CONFIG_SPAD_ENABLES_REF_4 : (0xB4), | |
_GLOBAL_CONFIG_SPAD_ENABLES_REF_5 : (0xB5), | |
_GLOBAL_CONFIG_REF_EN_START_SELECT : (0xB6), | |
_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD : (0x4E), | |
_DYNAMIC_SPAD_REF_EN_START_OFFSET : (0x4F), | |
_POWER_MANAGEMENT_GO1_POWER_FORCE : (0x80), | |
_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV : (0x89), | |
_ALGO_PHASECAL_LIM : (0x30), | |
_ALGO_PHASECAL_CONFIG_TIMEOUT : (0x30), | |
_VCSEL_PERIOD_PRE_RANGE : (0), | |
_VCSEL_PERIOD_FINAL_RANGE : (1) | |
} | |
this.i2cPort = i2cPort; | |
this.i2cSlave = null; | |
if (slaveAddress){ | |
this.slaveAddress = slaveAddress; | |
} else { | |
this.slaveAddress = 0x29; | |
} | |
if (io_timeout_s){ | |
this.io_timeout_s = io_timeout_s; | |
} else { | |
this.io_timeout_s = 0; | |
} | |
}; | |
VL53L0X.prototype = { | |
_decode_timeout: function(val){ | |
return ((val & 0xFF) * math.pow(2.0, ((val & 0xFF00) >> 8)) + 1); | |
}, | |
_encode_timeout: function(timeout_mclks){ | |
var timeout_mclks = (timeout_mclks) & 0xFFFF; | |
var ls_byte = 0; | |
var ms_byte = 0; | |
if (timeout_mclks > 0){ | |
ls_byte = timeout_mclks - 1; | |
while (ls_byte > 255){ | |
ls_byte = (ls_byte >> 1); | |
ms_byte += 1; | |
} | |
return (((ms_byte << 8) | (ls_byte & 0xFF)) & 0xFFFF); | |
} else { | |
return (0); | |
} | |
}, | |
init: async function(longRangeMode){ | |
this.i2cSlave = await this.i2cPort.open(this.slaveAddress); | |
var dc = this.devConst; | |
var init1 = [ | |
[0xFF, 0x01], [0x00, 0x00], [0xFF, 0x00], [0x09, 0x00], | |
[0x10, 0x00], [0x11, 0x00], [0x24, 0x01], [0x25, 0xFF], | |
[0x75, 0x00], [0xFF, 0x01], [0x4E, 0x2C], [0x48, 0x00], | |
[0x30, 0x20], [0xFF, 0x00], [0x30, 0x09], [0x54, 0x00], | |
[0x31, 0x04], [0x32, 0x03], [0x40, 0x83], [0x46, 0x25], | |
[0x60, 0x00], [0x27, 0x00], [0x50, 0x06], [0x51, 0x00], | |
[0x52, 0x96], [0x56, 0x08], [0x57, 0x30], [0x61, 0x00], | |
[0x62, 0x00], [0x64, 0x00], [0x65, 0x00], [0x66, 0xA0], | |
[0xFF, 0x01], [0x22, 0x32], [0x47, 0x14], [0x49, 0xFF], | |
[0x4A, 0x00], [0xFF, 0x00], [0x7A, 0x0A], [0x7B, 0x00], | |
[0x78, 0x21], [0xFF, 0x01], [0x23, 0x34], [0x42, 0x00], | |
[0x44, 0xFF], [0x45, 0x26], [0x46, 0x05], [0x40, 0x40], | |
[0x0E, 0x06], [0x20, 0x1A], [0x43, 0x40], [0xFF, 0x00], | |
[0x34, 0x03], [0x35, 0x44], [0xFF, 0x01], [0x31, 0x04], | |
[0x4B, 0x09], [0x4C, 0x05], [0x4D, 0x04], [0xFF, 0x00], | |
[0x44, 0x00], [0x45, 0x20], [0x47, 0x08], [0x48, 0x28], | |
[0x67, 0x00], [0x70, 0x04], [0x71, 0x01], [0x72, 0xFE], | |
[0x76, 0x00], [0x77, 0x00], [0xFF, 0x01], [0x0D, 0x01], | |
[0xFF, 0x00], [0x80, 0x01], [0x01, 0xF8], [0xFF, 0x01], | |
[0x8E, 0x01], [0x00, 0x01], [0xFF, 0x00], [0x80, 0x00] | |
]; | |
// await this.i2cSlave.read8(ra); | |
// await this.i2cSlave.write8(wa,wd); | |
// Check identification registers for expected values. | |
// From section 3.2 of the datasheet. | |
if (await this.i2cSlave.read8(0xC0) != 0xEE || await this.i2cSlave.read8(0xC1) != 0xAA || await this.i2cSlave.read8(0xC2) != 0x10){ | |
// raise RuntimeError('Failed to find expected ID register values. Check wiring!'); | |
} | |
// Initialize access to the sensor. This is based on the logic from: | |
// https://github.com/pololu/vl53l0x-arduino/blob/master/VL53L0X.cpp | |
// Set I2C standard mode. | |
await this.i2cSlave.write8(0x88, 0x00); | |
await this.i2cSlave.write8(0x80, 0x01); | |
await this.i2cSlave.write8(0xFF, 0x01); | |
await this.i2cSlave.write8(0x00, 0x00); | |
this._stop_variable = await this.i2cSlave.read8(0x91); | |
await this.i2cSlave.write8(0x00, 0x01); | |
await this.i2cSlave.write8(0xFF, 0x00); | |
await this.i2cSlave.write8(0x80, 0x00); | |
// disable SIGNAL_RATE_MSRC (bit 1) and SIGNAL_RATE_PRE_RANGE (bit 4) | |
// limit checks | |
var config_control = await this.i2cSlave.read8(dc._MSRC_CONFIG_CONTROL) | 0x12 ; | |
await this.i2cSlave.write8(dc._MSRC_CONFIG_CONTROL, config_control); | |
// set final range signal rate limit to 0.25 MCPS (million counts per second) | |
await this.set_signal_rate_limit (0.25); | |
await this.i2cSlave.write8(dc._SYSTEM_SEQUENCE_CONFIG, 0xFF); | |
var si = await this._get_spad_info(); // .spad_count, .spad_is_aperture | |
var spad_count = si.spad_count; | |
var spad_is_aperture = si.spad_is_aperture; | |
// console.log(si); | |
// The SPAD map (RefGoodSpadMap) is read by | |
// VL53L0X_get_info_from_device() in the API, but the same data seems to | |
// be more easily readable from GLOBAL_CONFIG_SPAD_ENABLES_REF_0 through | |
// _6, so read it from there. | |
var ref_spad_map = Array(7); | |
ref_spad_map[0] = dc._GLOBAL_CONFIG_SPAD_ENABLES_REF_0; | |
for ( var i = 0 ; i < 6 ; i++ ){ | |
ref_spad_map[i+1] = await this.i2cSlave.read8( dc._GLOBAL_CONFIG_SPAD_ENABLES_REF_0 + i ); | |
} | |
// console.log(ref_spad_map); | |
await this.i2cSlave.write8(0xFF, 0x01); | |
await this.i2cSlave.write8(dc._DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00); | |
await this.i2cSlave.write8(dc._DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C); | |
await this.i2cSlave.write8(0xFF, 0x00); | |
await this.i2cSlave.write8(dc._GLOBAL_CONFIG_REF_EN_START_SELECT, 0xB4); | |
var first_spad_to_enable = 12; | |
if (!spad_is_aperture){ | |
first_spad_to_enable = 0; | |
} | |
var spads_enabled = 0; | |
for ( var i = 0 ; i < 48 ; i++ ){ | |
if (i < first_spad_to_enable || spads_enabled == spad_count){ | |
// This bit is lower than the first one that should be enabled, | |
// or (reference_spad_count) bits have already been enabled, so | |
// zero this bit. | |
ref_spad_map[1 + Math.floor(i / 8)] &= ~(1 << (i % 8)); | |
} else if ((ref_spad_map[1 + Math.floor(i / 8)] >> (i % 8)) & 0x1 > 0){ | |
spads_enabled += 1; | |
} | |
} | |
// console.log("ref_spad_map:",ref_spad_map); | |
for ( var i = 1 ; i < 7 ; i++ ){ | |
await this.i2cSlave.write8(ref_spad_map[0] ,ref_spad_map[i] ); | |
} | |
for ( var i = 0 ; i < init1.length ; i++ ){ | |
await this.i2cSlave.write8(init1[i][0],init1[i][1]); | |
} | |
// console.log("long ini competed"); | |
await this.i2cSlave.write8(dc._SYSTEM_INTERRUPT_CONFIG_GPIO, 0x04); | |
var gpio_hv_mux_active_high = await this.i2cSlave.read8(dc._GPIO_HV_MUX_ACTIVE_HIGH); | |
// console.log("gpio_hv_mux_active_high:",gpio_hv_mux_active_high); | |
await this.i2cSlave.write8(dc._GPIO_HV_MUX_ACTIVE_HIGH,gpio_hv_mux_active_high & ~0x10); // active low | |
await this.i2cSlave.write8(dc._SYSTEM_INTERRUPT_CLEAR, 0x01); | |
this._measurement_timing_budget_us = await this.get_measurement_timing_budget(); | |
// console.log("this._measurement_timing_budget_us:",this._measurement_timing_budget_us); | |
await this.i2cSlave.write8(dc._SYSTEM_SEQUENCE_CONFIG, 0xE8); | |
await this.set_measurement_timing_budget ( this._measurement_timing_budget_us); | |
await this.i2cSlave.write8(dc._SYSTEM_SEQUENCE_CONFIG, 0x01); | |
await this._perform_single_ref_calibration(0x40); | |
await this.i2cSlave.write8(dc._SYSTEM_SEQUENCE_CONFIG, 0x02); | |
await this._perform_single_ref_calibration(0x00); | |
// "restore the previous Sequence Config" | |
await this.i2cSlave.write8(dc._SYSTEM_SEQUENCE_CONFIG, 0xE8); | |
if ( longRangeMode){ // based on https://github.com/bitbank2/VL53L0X/blob/master/tof.c | |
await this.set_signal_rate_limit (0.1); | |
await this.setVcselPulsePeriod("VcselPeriodPreRange", 18); | |
await this.setVcselPulsePeriod("VcselPeriodFinalRange", 14); | |
console.log("LongRangeModeSet end"); | |
} | |
console.log("init done!"); | |
}, | |
getRange: async function(){ | |
// Perform a single reading of the range for an object in front of | |
// the sensor and return the distance in millimeters. | |
// Adapted from readRangeSingleMillimeters & | |
// readRangeContinuousMillimeters in pololu code at: | |
// https://github.com/pololu/vl53l0x-arduino/blob/master/VL53L0X.cpp | |
var dc = this.devConst; | |
await this.i2cSlave.write8(0x80, 0x01); | |
await this.i2cSlave.write8(0xFF, 0x01); | |
await this.i2cSlave.write8(0x00, 0x00); | |
await this.i2cSlave.write8(0x91, this._stop_variable); | |
await this.i2cSlave.write8(0x00, 0x01); | |
await this.i2cSlave.write8(0xFF, 0x00); | |
await this.i2cSlave.write8(0x80, 0x00); | |
await this.i2cSlave.write8(dc._SYSRANGE_START, 0x01); | |
start = new Date().getTime(); | |
var ss =1; | |
while ( (ss & 0x01) > 0){ | |
ss = await this.i2cSlave.read8(dc._SYSRANGE_START); | |
/** | |
if self.io_timeout_s > 0 and \ | |
(time.monotonic() - start) >= self.io_timeout_s: | |
raise RuntimeError('Timeout waiting for VL53L0X!') | |
**/ | |
} | |
start = new Date().getTime(); | |
var ris = 0; | |
while ( (ris & 0x07) == 0){ | |
ris = await this.i2cSlave.read8(dc._RESULT_INTERRUPT_STATUS); | |
/** | |
if self.io_timeout_s > 0 and \ | |
(time.monotonic() - start) >= self.io_timeout_s: | |
raise RuntimeError('Timeout waiting for VL53L0X!') | |
**/ | |
} | |
// assumptions: Linearity Corrective Gain is 1000 (default) | |
// fractional ranging is not enabled | |
var range_mm = await this._read_u16(dc._RESULT_RANGE_STATUS + 10); | |
await this.i2cSlave.write8(dc._SYSTEM_INTERRUPT_CLEAR, 0x01); | |
console.log("Range:",range_mm,"[mm]"); | |
return (range_mm); | |
}, | |
_perform_single_ref_calibration: async function( vhv_init_byte){ | |
// based on VL53L0X_perform_single_ref_calibration() from ST API. | |
var dc = this.devConst; | |
await this.i2cSlave.write8(dc._SYSRANGE_START, 0x01 | vhv_init_byte & 0xFF); | |
start = new Date().getTime(); | |
var ris = 0x00; | |
while ( ris == 0x00){ | |
ris = await this.i2cSlave.read8(dc._RESULT_INTERRUPT_STATUS) & 0x07; | |
// console.log("ris:",ris); | |
/** | |
if self.io_timeout_s > 0 and \ | |
(time.monotonic() - start) >= self.io_timeout_s: | |
raise RuntimeError('Timeout waiting for VL53L0X!') | |
**/ | |
} | |
await this.i2cSlave.write8(dc._SYSTEM_INTERRUPT_CLEAR, 0x01); | |
await this.i2cSlave.write8(dc._SYSRANGE_START, 0x00); | |
}, | |
get_measurement_timing_budget: async function(){ | |
// The measurement timing budget in microseconds. | |
var budget_us = 1910 + 960; // Start overhead + end overhead. | |
var sse = await this._get_sequence_step_enables(); // tcc, dss, msrc, pre_range, final_range | |
// console.log("_get_sequence_step_enables:",sse); | |
var st = await this._get_sequence_step_timeouts(sse.pre_range); | |
// msrc_dss_tcc_us, pre_range_us, final_range_us, _, _ = step_timeouts | |
// console.log("_get_sequence_step_timeouts:",st); | |
if (sse.tcc){ | |
budget_us += (st.msrc_dss_tcc_us + 590); | |
} | |
if (sse.dss){ | |
budget_us += 2*(st.msrc_dss_tcc_us + 690); | |
} else if ( sse.msrc ){ | |
budget_us += (st.msrc_dss_tcc_us + 660); | |
} | |
if (sse.pre_range){ | |
budget_us += (st.pre_range_us + 660); | |
} | |
if (sse.final_range){ | |
budget_us += (st.final_range_us + 550); | |
} | |
this._measurement_timing_budget_us = budget_us; | |
// console.log("budget_us:",budget_us); | |
return (budget_us); | |
}, | |
set_measurement_timing_budget: async function( budget_us){ | |
console.log("set_measurement_timing_budget:",budget_us); | |
var dc = this.devConst; | |
if ( budget_us < 20000){ | |
console.log("ERROR :" , budget_us); | |
return; | |
} | |
var used_budget_us = 1320 + 960; // Start (diff from get) + end overhead | |
var sse = await this._get_sequence_step_enables(); // tcc, dss, msrc, pre_range, final_range | |
// tcc,dss,msrc,pre_range,final_range | |
var st = await this._get_sequence_step_timeouts(sse.pre_range); | |
// msrc_dss_tcc_us, pre_range_us, final_range_us, final_range_vcsel_period_pclks, pre_range_mclks | |
if (sse.tcc){ | |
used_budget_us += (st.msrc_dss_tcc_us + 590); | |
} | |
if (sse.dss){ | |
used_budget_us += 2*(st.msrc_dss_tcc_us + 690); | |
} else if (sse.msrc){ | |
used_budget_us += (st.msrc_dss_tcc_us + 660); | |
} | |
if (sse.pre_range){ | |
used_budget_us += (st.pre_range_us + 660); | |
} | |
if (sse.final_range){ | |
used_budget_us += 550; | |
// "Note that the final range timeout is determined by the timing | |
// budget and the sum of all other timeouts within the sequence. | |
// If there is no room for the final range timeout, then an error | |
// will be set. Otherwise the remaining time will be applied to | |
// the final range." | |
if (used_budget_us > budget_us){ | |
console.log('Requested timeout too big.'); | |
return; | |
} | |
var final_range_timeout_us = budget_us - used_budget_us; | |
var final_range_timeout_mclks = this._timeout_microseconds_to_mclks( final_range_timeout_us, st.final_range_vcsel_period_pclks); | |
if (sse.pre_range){ | |
final_range_timeout_mclks += st.pre_range_mclks | |
} | |
await this._write_u16(dc._FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, this._encode_timeout(final_range_timeout_mclks)); | |
this._measurement_timing_budget_us = budget_us; | |
} | |
}, | |
get_signal_rate_limit: async function(){ | |
//The signal rate limit in mega counts per second. | |
var dc = this.devConst; | |
var val = await this._read_u16(dc._FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT); | |
// Return value converted from 16-bit 9.7 fixed point to float. | |
return (val / (1 << 7)); | |
}, | |
set_signal_rate_limit: async function(val){ | |
var dc = this.devConst; | |
if (val => 0.0 && val <= 511.99){ | |
// OK | |
} else { | |
console.log("ERROR set_signal_rate_limit:" ,val); | |
return ; | |
} | |
// Convert to 16-bit 9.7 fixed point value from a float. | |
val = Math.floor(val * (1 << 7)); | |
await this._write_u16(dc._FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, val); | |
}, | |
_get_sequence_step_enables: async function(){ | |
// based on VL53L0X_GetSequenceStepEnables() from ST API | |
var dc = this.devConst; | |
var sequence_config = await this.i2cSlave.read8(dc._SYSTEM_SEQUENCE_CONFIG); | |
var tcc = (sequence_config >> 4) & 0x1 > 0; | |
var dss = (sequence_config >> 3) & 0x1 > 0; | |
var msrc = (sequence_config >> 2) & 0x1 > 0; | |
var pre_range = (sequence_config >> 6) & 0x1 > 0; | |
var final_range = (sequence_config >> 7) & 0x1 > 0; | |
return { | |
tcc:tcc, | |
dss:dss, | |
msrc:msrc, | |
pre_range:pre_range, | |
final_range:final_range | |
}; | |
}, | |
_get_sequence_step_timeouts: async function( pre_range){ | |
// based on get_sequence_step_timeout() from ST API but modified by | |
// pololu here: | |
// https://github.com/pololu/vl53l0x-arduino/blob/master/VL53L0X.cpp | |
var dc = this.devConst; | |
var pre_range_vcsel_period_pclks = await this._get_vcsel_pulse_period(dc._VCSEL_PERIOD_PRE_RANGE); | |
var msrc_dss_tcc_mclks = (await this.i2cSlave.read8(dc._MSRC_CONFIG_TIMEOUT_MACROP) + 1) & 0xFF; | |
var msrc_dss_tcc_us = this._timeout_mclks_to_microseconds(msrc_dss_tcc_mclks, pre_range_vcsel_period_pclks); | |
var pre_range_mclks = this._decode_timeout(await this._read_u16(dc._PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI)); | |
var pre_range_us = this._timeout_mclks_to_microseconds(pre_range_mclks, pre_range_vcsel_period_pclks); | |
var final_range_vcsel_period_pclks = await this._get_vcsel_pulse_period(dc._VCSEL_PERIOD_FINAL_RANGE) | |
var final_range_mclks = this._decode_timeout(await this._read_u16(dc._FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI)); | |
if (pre_range){ | |
final_range_mclks -= pre_range_mclks | |
} | |
var final_range_us = this._timeout_mclks_to_microseconds(final_range_mclks, final_range_vcsel_period_pclks); | |
return { | |
msrc_dss_tcc_us: msrc_dss_tcc_us, | |
pre_range_us: pre_range_us, | |
final_range_us: final_range_us, | |
final_range_vcsel_period_pclks: final_range_vcsel_period_pclks, | |
pre_range_mclks: pre_range_mclks | |
}; | |
}, | |
_get_vcsel_pulse_period: async function(vcsel_period_type){ | |
// Disable should be removed when refactor can be tested | |
var dc = this.devConst; | |
var val; | |
if (vcsel_period_type == dc._VCSEL_PERIOD_PRE_RANGE){ | |
val = await this.i2cSlave.read8(dc._PRE_RANGE_CONFIG_VCSEL_PERIOD); | |
return ((((val) + 1) & 0xFF) << 1); | |
} else if (vcsel_period_type == dc._VCSEL_PERIOD_FINAL_RANGE){ | |
val = await this.i2cSlave.read8(dc._FINAL_RANGE_CONFIG_VCSEL_PERIOD); | |
return ((((val) + 1) & 0xFF) << 1); | |
} | |
return (255); | |
}, | |
_timeout_mclks_to_microseconds: function(timeout_period_mclks, vcsel_period_pclks){ | |
macro_period_ns = Math.floor(((2304 * (vcsel_period_pclks) * 1655) + 500) / 1000); | |
return Math.floor(((timeout_period_mclks * macro_period_ns) + Math.floor(macro_period_ns / 2)) / 1000); | |
}, | |
_timeout_microseconds_to_mclks: function(timeout_period_us, vcsel_period_pclks){ | |
var macro_period_ns = Math.floor(((2304 * (vcsel_period_pclks) * 1655) + 500) / 1000); | |
return (Math.floor((timeout_period_us * 1000) + Math.floor(macro_period_ns / 2)) / macro_period_ns); | |
}, | |
_decode_timeout: function(val){ | |
// format: "(LSByte * 2^MSByte) + 1" | |
return ((val & 0xFF) * Math.pow(2.0, ((val & 0xFF00) >> 8)) + 1); | |
}, | |
_get_spad_info : async function(){ | |
// # Get reference SPAD count and type, returned as a 2-tuple of | |
// # count and boolean is_aperture. Based on code from: | |
// # https://github.com/pololu/vl53l0x-arduino/blob/master/VL53L0X.cpp | |
await this.i2cSlave.write8(0x80, 0x01); | |
await this.i2cSlave.write8 (0xFF, 0x01); | |
await this.i2cSlave.write8(0x00, 0x00); | |
await this.i2cSlave.write8(0xFF, 0x06); | |
await this.i2cSlave.write8(0x83, await this.i2cSlave.read8(0x83) | 0x04); | |
await this.i2cSlave.write8(0xFF, 0x07); | |
await this.i2cSlave.write8(0x81, 0x01); | |
await this.i2cSlave.write8(0x80, 0x01); | |
await this.i2cSlave.write8(0x94, 0x6b); | |
await this.i2cSlave.write8(0x83, 0x00); | |
start = new Date().getTime(); | |
var ox83=0x00; | |
while (ox83 == 0x00){ | |
ox83 = await this.i2cSlave.read8(0x83) ; | |
console.log("ox83:",ox83); | |
/** | |
if self.io_timeout_s > 0 and \ | |
(time.monotonic() - start) >= self.io_timeout_s: | |
raise RuntimeError('Timeout waiting for VL53L0X!') | |
**/ | |
} | |
await this.i2cSlave.write8(0x83, 0x01); | |
var tmp = await this.i2cSlave.read8(0x92); | |
var count = tmp & 0x7F; | |
var is_aperture = ((tmp >> 7) & 0x01) == 1; | |
await this.i2cSlave.write8(0x81, 0x00); | |
await this.i2cSlave.write8(0xFF, 0x06); | |
await this.i2cSlave.write8(0x83, await this.i2cSlave.read8((0x83) & ~0x04)); | |
await this.i2cSlave.write8(0xFF, 0x01); | |
await this.i2cSlave.write8(0x00, 0x01); | |
await this.i2cSlave.write8(0xFF, 0x00); | |
await this.i2cSlave.write8(0x80, 0x00); | |
return {spad_count:count, spad_is_aperture:is_aperture}; | |
}, | |
_read_u16: async function( address){ | |
// Read a 16-bit BE unsigned value from the specified 8-bit address. | |
return ((await this.i2cSlave.read8(address) << 8) | await this.i2cSlave.read8(address+1)); | |
}, | |
_write_u16: async function( address, val){ | |
// Write a 16-bit BE unsigned value to the specified 8-bit address. | |
await this.i2cSlave.write8( address, (val >> 8) & 0xFF); | |
await this.i2cSlave.write8( address + 1, val & 0xFF); | |
}, | |
read: async function(){ | |
if ( this.i2cSlave == null ){ | |
throw Error("i2cSlave Address does'nt yet open!"); | |
} | |
var MSB = await this.i2cSlave.read8(0x00); | |
var LSB = await this.i2cSlave.read8(0x01); | |
var data = ((MSB << 8) + LSB)/128.0; | |
return(data); | |
}, | |
getSVal: function(val){ | |
if ( val & 0x8000 ){ | |
return (( -val ^ 0xFFFF) + 1); | |
} else { | |
return ( val ); | |
} | |
}, | |
setVcselPulsePeriod: async function(vcselPeriodType , period_pclks){ | |
// for longRangeMode init() | |
// ported from https://github.com/bitbank2/VL53L0X/blob/master/tof.c | |
// | |
// Set the VCSEL (vertical cavity surface emitting laser) pulse period for the | |
// given period type (pre-range or final range) to the given value in PCLKs. | |
// Longer periods seem to increase the potential range of the sensor. | |
// Valid values are (even numbers only): | |
// pre: 12 to 18 (initialized default: 14) | |
// final: 8 to 14 (initialized default: 10) | |
// based on VL53L0X_set_vcsel_pulse_period() | |
var dc = this.devConst; | |
var vcsel_period_reg = (((period_pclks) >> 1) - 1); | |
var enables = await this.i2cSlave.read8(dc._SYSTEM_SEQUENCE_CONFIG); | |
var sse = await this._get_sequence_step_enables(); // tcc, dss, msrc, pre_range, final_range | |
var st = await this._get_sequence_step_timeouts(sse.pre_range); // msrc_dss_tcc_us, pre_range_us, final_range_us, final_range_vcsel_period_pclks, pre_range_mclks | |
// console.log("vcsel_period_reg:",vcsel_period_reg," period_pclks:",period_pclks); | |
// "Apply specific settings for the requested clock period" | |
// "Re-calculate and apply timeouts, in macro periods" | |
// "When the VCSEL period for the pre or final range is changed, | |
// the corresponding timeout must be read from the device using | |
// the current VCSEL period, then the new VCSEL period can be | |
// applied. The timeout then must be written back to the device | |
// using the new VCSEL period. | |
// | |
// For the MSRC timeout, the same applies - this timeout being | |
// dependant on the pre-range vcsel period." | |
if (vcselPeriodType == "VcselPeriodPreRange"){ | |
// "Set phase check limits" | |
switch (period_pclks){ | |
case 12: | |
await this.i2cSlave.write8(dc._PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x18); | |
break; | |
case 14: | |
await this.i2cSlave.write8(dc._PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x30); | |
break; | |
case 16: | |
await this.i2cSlave.write8(dc._PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x40); | |
break; | |
case 18: | |
await this.i2cSlave.write8(dc._PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x50); | |
break; | |
default: | |
// invalid period | |
return (false); | |
} | |
await this.i2cSlave.write8(dc._PRE_RANGE_CONFIG_VALID_PHASE_LOW, 0x08); | |
// apply new VCSEL period | |
await this.i2cSlave.write8(dc._PRE_RANGE_CONFIG_VCSEL_PERIOD, vcsel_period_reg); | |
// update timeouts | |
// set_sequence_step_timeout() begin | |
// (SequenceStepId == VL53L0X_SEQUENCESTEP_PRE_RANGE) | |
var new_pre_range_timeout_mclks = | |
this._timeout_microseconds_to_mclks(st.pre_range_us, period_pclks); | |
await this._write_u16(dc._PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI, | |
this._encode_timeout(new_pre_range_timeout_mclks)); | |
// set_sequence_step_timeout() end | |
// set_sequence_step_timeout() begin | |
// (SequenceStepId == VL53L0X_SEQUENCESTEP_MSRC) | |
var new_msrc_timeout_mclks = | |
this._timeout_microseconds_to_mclks(st.msrc_dss_tcc_us, period_pclks); | |
await this.i2cSlave.write8(dc._MSRC_CONFIG_TIMEOUT_MACROP, | |
(new_msrc_timeout_mclks > 256) ? 255 : (new_msrc_timeout_mclks - 1)); | |
// set_sequence_step_timeout() end | |
} else if (vcselPeriodType == "VcselPeriodFinalRange"){ | |
switch (period_pclks){ | |
case 8: | |
await this.i2cSlave.write8(dc._FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x10); | |
await this.i2cSlave.write8(dc._FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08); | |
await this.i2cSlave.write8(dc._GLOBAL_CONFIG_VCSEL_WIDTH, 0x02); | |
await this.i2cSlave.write8(dc._ALGO_PHASECAL_CONFIG_TIMEOUT, 0x0C); | |
await this.i2cSlave.write8(0xFF, 0x01); | |
await this.i2cSlave.write8(dc._ALGO_PHASECAL_LIM, 0x30); | |
await this.i2cSlave.write8(0xFF, 0x00); | |
break; | |
case 10: | |
await this.i2cSlave.write8(dc._FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x28); | |
await this.i2cSlave.write8(dc._FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08); | |
await this.i2cSlave.write8(dc._GLOBAL_CONFIG_VCSEL_WIDTH, 0x03); | |
await this.i2cSlave.write8(dc._ALGO_PHASECAL_CONFIG_TIMEOUT, 0x09); | |
await this.i2cSlave.write8(0xFF, 0x01); | |
await this.i2cSlave.write8(dc._ALGO_PHASECAL_LIM, 0x20); | |
await this.i2cSlave.write8(0xFF, 0x00); | |
break; | |
case 12: | |
await this.i2cSlave.write8(dc._FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x38); | |
await this.i2cSlave.write8(dc._FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08); | |
await this.i2cSlave.write8(dc._GLOBAL_CONFIG_VCSEL_WIDTH, 0x03); | |
await this.i2cSlave.write8(dc._ALGO_PHASECAL_CONFIG_TIMEOUT, 0x08); | |
await this.i2cSlave.write8(0xFF, 0x01); | |
await this.i2cSlave.write8(dc._ALGO_PHASECAL_LIM, 0x20); | |
await this.i2cSlave.write8(0xFF, 0x00); | |
break; | |
case 14: | |
await this.i2cSlave.write8(dc._FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x48); | |
await this.i2cSlave.write8(dc._FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08); | |
await this.i2cSlave.write8(dc._GLOBAL_CONFIG_VCSEL_WIDTH, 0x03); | |
await this.i2cSlave.write8(dc._ALGO_PHASECAL_CONFIG_TIMEOUT, 0x07); | |
await this.i2cSlave.write8(0xFF, 0x01); | |
await this.i2cSlave.write8(dc._ALGO_PHASECAL_LIM, 0x20); | |
await this.i2cSlave.write8(0xFF, 0x00); | |
break; | |
default: | |
// invalid period | |
return (false); | |
} | |
// apply new VCSEL period | |
await this.i2cSlave.write8(dc._FINAL_RANGE_CONFIG_VCSEL_PERIOD, vcsel_period_reg); | |
// update timeouts | |
// set_sequence_step_timeout() begin | |
// (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE) | |
// "For the final range timeout, the pre-range timeout | |
// must be added. To do this both final and pre-range | |
// timeouts must be expressed in macro periods MClks | |
// because they have different vcsel periods." | |
var new_final_range_timeout_mclks = | |
this._timeout_microseconds_to_mclks(st.final_range_us, period_pclks); | |
if (enables & dc._SEQUENCE_ENABLE_PRE_RANGE){ | |
new_final_range_timeout_mclks += timeouts.pre_range_mclks; | |
} | |
await this._write_u16(dc._FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, | |
this._encode_timeout(new_final_range_timeout_mclks)); | |
// set_sequence_step_timeout end | |
} else { | |
// invalid vcselPeriodType | |
return (false); | |
} | |
// "Finally, the timing budget must be re-applied" | |
// console.log(vcselPeriodType, " set_measurement_timing_budget:",this._measurement_timing_budget_us); | |
await this.set_measurement_timing_budget(this._measurement_timing_budget_us); | |
// "Perform the phase calibration. This is needed after changing on vcsel period." | |
// VL53L0X_perform_phase_calibration() begin | |
var sequence_config = await this.i2cSlave.read8(dc._SYSTEM_SEQUENCE_CONFIG); | |
await this.i2cSlave.write8(dc._SYSTEM_SEQUENCE_CONFIG, 0x02); | |
await this._perform_single_ref_calibration(0x00); | |
await this.i2cSlave.write8(dc._SYSTEM_SEQUENCE_CONFIG, sequence_config); | |
// VL53L0X_perform_phase_calibration() end | |
return (true); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
var head; | |
window.addEventListener( | |
"load", | |
function() { | |
head = document.querySelector("#head"); | |
mainFunction(); | |
}, | |
false | |
); | |
async function mainFunction() { | |
try { | |
var i2cAccess = await navigator.requestI2CAccess(); | |
var port = i2cAccess.ports.get(1); | |
var vl = new VL53L0X(port, 0x29); | |
await vl.init(); // long range mode : await vl.init(true); | |
while (1) { | |
var distance = await vl.getRange(); | |
dist.innerHTML=distance; | |
await sleep(200); | |
} | |
} catch (error) { | |
console.error("error", error); | |
} | |
} | |
function sleep(ms) { | |
return new Promise(function(resolve) { | |
setTimeout(resolve, ms); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
長距離モードも動作するようになりました。 init(true)で設定