Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
VL6180X.cpp
00001 #include <VL6180X.h> 00002 //#include "dm_platform.h" 00003 #include "common_define.h" 00004 // Defines ///////////////////////////////////////////////////////////////////// 00005 00006 // The Arduino two-wire interface uses a 7-bit number for the address, 00007 // and sets the last bit correctly based on reads and writes 00008 #define ADDRESS_DEFAULT (0x29 << 1) 00009 00010 // RANGE_SCALER values for 1x, 2x, 3x scaling - see STSW-IMG003 core/src/vl6180x_api.c (ScalerLookUP[]) 00011 static uint16_t const ScalerValues[] = {0, 253, 127, 84}; 00012 00013 #define constrain(amt,low,high) ((amt)<=(low)?(low):((amt)>(high)?(high):(amt))) 00014 // Constructors //////////////////////////////////////////////////////////////// 00015 00016 VL6180X::VL6180X(I2C *_i2c) 00017 : address(ADDRESS_DEFAULT) 00018 , scaling(0) 00019 , ptp_offset(0) 00020 , io_timeout(0) // no timeout 00021 , did_timeout(false) 00022 { 00023 i2c = _i2c; 00024 //configureDefault(); 00025 } 00026 00027 // Public Methods ////////////////////////////////////////////////////////////// 00028 00029 void VL6180X::setAddress(uint8_t new_addr) 00030 { 00031 writeReg(I2C_SLAVE__DEVICE_ADDRESS, new_addr & 0x7F); 00032 address = new_addr; 00033 } 00034 00035 // Initialize sensor with settings from ST application note AN4545, section 9 - 00036 // "Mandatory : private registers" 00037 void VL6180X::init() 00038 { 00039 // Store part-to-part range offset so it can be adjusted if scaling is changed 00040 ptp_offset = readReg(SYSRANGE__PART_TO_PART_RANGE_OFFSET); 00041 00042 if (readReg(SYSTEM__FRESH_OUT_OF_RESET) == 1) 00043 { 00044 scaling = 1; 00045 00046 writeReg(0x207, 0x01); 00047 writeReg(0x208, 0x01); 00048 writeReg(0x096, 0x00); 00049 writeReg(0x097, 0xFD); // RANGE_SCALER = 253 00050 writeReg(0x0E3, 0x00); 00051 writeReg(0x0E4, 0x04); 00052 writeReg(0x0E5, 0x02); 00053 writeReg(0x0E6, 0x01); 00054 writeReg(0x0E7, 0x03); 00055 writeReg(0x0F5, 0x02); 00056 writeReg(0x0D9, 0x05); 00057 writeReg(0x0DB, 0xCE); 00058 writeReg(0x0DC, 0x03); 00059 writeReg(0x0DD, 0xF8); 00060 writeReg(0x09F, 0x00); 00061 writeReg(0x0A3, 0x3C); 00062 writeReg(0x0B7, 0x00); 00063 writeReg(0x0BB, 0x3C); 00064 writeReg(0x0B2, 0x09); 00065 writeReg(0x0CA, 0x09); 00066 writeReg(0x198, 0x01); 00067 writeReg(0x1B0, 0x17); 00068 writeReg(0x1AD, 0x00); 00069 writeReg(0x0FF, 0x05); 00070 writeReg(0x100, 0x05); 00071 writeReg(0x199, 0x05); 00072 writeReg(0x1A6, 0x1B); 00073 writeReg(0x1AC, 0x3E); 00074 writeReg(0x1A7, 0x1F); 00075 writeReg(0x030, 0x00); 00076 00077 writeReg(SYSTEM__FRESH_OUT_OF_RESET, 0); 00078 } 00079 else 00080 { 00081 // Sensor has already been initialized, so try to get scaling settings by 00082 // reading registers. 00083 00084 uint16_t s = readReg16Bit(RANGE_SCALER); 00085 00086 if (s == ScalerValues[3]) { scaling = 3; } 00087 else if (s == ScalerValues[2]) { scaling = 2; } 00088 else { scaling = 1; } 00089 00090 // Adjust the part-to-part range offset value read earlier to account for 00091 // existing scaling. If the sensor was already in 2x or 3x scaling mode, 00092 // precision will be lost calculating the original (1x) offset, but this can 00093 // be resolved by resetting the sensor and Arduino again. 00094 ptp_offset *= scaling; 00095 } 00096 } 00097 00098 // Configure some settings for the sensor's default behavior from AN4545 - 00099 // "Recommended : Public registers" and "Optional: Public registers" 00100 // 00101 // Note that this function does not set up GPIO1 as an interrupt output as 00102 // suggested, though you can do so by calling: 00103 // writeReg(SYSTEM__MODE_GPIO1, 0x10); 00104 void VL6180X::configureDefault(void) 00105 { 00106 // "Recommended : Public registers" 00107 00108 // readout__averaging_sample_period = 48 00109 writeReg(READOUT__AVERAGING_SAMPLE_PERIOD, 0x30); 00110 00111 // sysals__analogue_gain_light = 6 (ALS gain = 1 nominal, actually 1.01 according to Table 14 in datasheet) 00112 writeReg(SYSALS__ANALOGUE_GAIN, 0x46); 00113 00114 // sysrange__vhv_repeat_rate = 255 (auto Very High Voltage temperature recalibration after every 255 range measurements) 00115 writeReg(SYSRANGE__VHV_REPEAT_RATE, 0xFF); 00116 00117 // sysals__integration_period = 99 (100 ms) 00118 // AN4545 incorrectly recommends writing to register 0x040; 0x63 should go in the lower byte, which is register 0x041. 00119 writeReg16Bit(SYSALS__INTEGRATION_PERIOD, 0x0063); 00120 00121 // sysrange__vhv_recalibrate = 1 (manually trigger a VHV recalibration) 00122 writeReg(SYSRANGE__VHV_RECALIBRATE, 0x01); 00123 00124 00125 // "Optional: Public registers" 00126 00127 // sysrange__intermeasurement_period = 9 (100 ms) 00128 writeReg(SYSRANGE__INTERMEASUREMENT_PERIOD, 0x09); 00129 00130 // sysals__intermeasurement_period = 49 (500 ms) 00131 writeReg(SYSALS__INTERMEASUREMENT_PERIOD, 0x31); 00132 00133 // als_int_mode = 4 (ALS new sample ready interrupt); range_int_mode = 4 (range new sample ready interrupt) 00134 writeReg(SYSTEM__INTERRUPT_CONFIG_GPIO, 0x24); 00135 00136 00137 // Reset other settings to power-on defaults 00138 00139 // sysrange__max_convergence_time = 49 (49 ms) 00140 writeReg(VL6180X::SYSRANGE__MAX_CONVERGENCE_TIME, 0x31); 00141 00142 // disable interleaved mode 00143 writeReg(INTERLEAVED_MODE__ENABLE, 0); 00144 00145 // reset range scaling factor to 1x 00146 setScaling(1); 00147 } 00148 00149 // Writes an 8-bit register 00150 void VL6180X::writeReg(uint16_t reg, uint8_t value) 00151 { 00152 i2cWriteForVL6180X(i2c,ADDRESS_DEFAULT,&value,reg,sizeof(value)); 00153 // Wire.beginTransmission(address); 00154 // Wire.write((reg >> 8) & 0xff); // reg high byte 00155 // Wire.write(reg & 0xff); // reg low byte 00156 // Wire.write(value); 00157 // last_status = Wire.endTransmission(); 00158 } 00159 00160 // Writes a 16-bit register 00161 void VL6180X::writeReg16Bit(uint16_t reg, uint16_t value) 00162 { 00163 uint8_t buffer[2]; 00164 buffer[0] = (value >> 8) & 0xff; 00165 buffer[1] = value & 0xff; 00166 i2cWriteForVL6180X(i2c,ADDRESS_DEFAULT,buffer,reg,sizeof(value)); 00167 // Wire.beginTransmission(address); 00168 // Wire.write((reg >> 8) & 0xff); // reg high byte 00169 // Wire.write(reg & 0xff); // reg low byte 00170 // Wire.write((value >> 8) & 0xff); // value high byte 00171 // Wire.write(value & 0xff); // value low byte 00172 // last_status = Wire.endTransmission(); 00173 } 00174 00175 // Writes a 32-bit register 00176 void VL6180X::writeReg32Bit(uint16_t reg, uint32_t value) 00177 { 00178 uint8_t buffer[4]; 00179 buffer[0] = (value >> 24) & 0xff; 00180 buffer[1] = (value >> 16)& 0xff; 00181 buffer[2] = (value >> 8)& 0xff; 00182 buffer[3] = value & 0xff; 00183 i2cWriteForVL6180X(i2c,ADDRESS_DEFAULT,buffer,reg,sizeof(value)); 00184 // Wire.beginTransmission(address); 00185 // Wire.write((reg >> 8) & 0xff); // reg high byte 00186 // Wire.write(reg & 0xff); // reg low byte 00187 // Wire.write((value >> 24) & 0xff); // value highest byte 00188 // Wire.write((value >> 16) & 0xff); 00189 // Wire.write((value >> 8) & 0xff); 00190 // Wire.write(value & 0xff); // value lowest byte 00191 // last_status = Wire.endTransmission(); 00192 } 00193 00194 // Reads an 8-bit register 00195 uint8_t VL6180X::readReg(uint16_t reg) 00196 { 00197 uint8_t value = 0xff; 00198 i2cReadForVL6180X(i2c,ADDRESS_DEFAULT,&value,reg,1); 00199 return value; 00200 00201 // Wire.beginTransmission(address); 00202 // Wire.write((reg >> 8) & 0xff); // reg high byte 00203 // Wire.write(reg & 0xff); // reg low byte 00204 // last_status = Wire.endTransmission(); 00205 00206 // Wire.requestFrom(address, (uint8_t)1); 00207 // value = Wire.read(); 00208 // Wire.endTransmission(); 00209 00210 // return value; 00211 } 00212 00213 // Reads a 16-bit register 00214 uint16_t VL6180X::readReg16Bit(uint16_t reg) 00215 { 00216 uint16_t value; 00217 i2cReadForVL6180X(i2c,ADDRESS_DEFAULT,(uint8_t *)&value,reg,sizeof(value)); 00218 return value; 00219 // uint16_t value; 00220 00221 // Wire.beginTransmission(address); 00222 // Wire.write((reg >> 8) & 0xff); // reg high byte 00223 // Wire.write(reg & 0xff); // reg low byte 00224 // last_status = Wire.endTransmission(); 00225 00226 // Wire.requestFrom(address, (uint8_t)2); 00227 // value = (uint16_t)Wire.read() << 8; // value high byte 00228 // value |= Wire.read(); // value low byte 00229 // Wire.endTransmission(); 00230 00231 // return value; 00232 } 00233 00234 // Reads a 32-bit register 00235 uint32_t VL6180X::readReg32Bit(uint16_t reg) 00236 { 00237 uint32_t value; 00238 i2cReadForVL6180X(i2c,ADDRESS_DEFAULT,(uint8_t *)&value,reg,sizeof(value)); 00239 return value; 00240 // uint32_t value; 00241 00242 // Wire.beginTransmission(address); 00243 // Wire.write((reg >> 8) & 0xff); // reg high byte 00244 // Wire.write(reg & 0xff); // reg low byte 00245 // last_status = Wire.endTransmission(); 00246 00247 // Wire.requestFrom(address, (uint8_t)4); 00248 // value = (uint32_t)Wire.read() << 24; // value highest byte 00249 // value |= (uint32_t)Wire.read() << 16; 00250 // value |= (uint16_t)Wire.read() << 8; 00251 // value |= Wire.read(); // value lowest byte 00252 // Wire.endTransmission(); 00253 00254 // return value; 00255 } 00256 00257 // Set range scaling factor. The sensor uses 1x scaling by default, giving range 00258 // measurements in units of mm. Increasing the scaling to 2x or 3x makes it give 00259 // raw values in units of 2 mm or 3 mm instead. In other words, a bigger scaling 00260 // factor increases the sensor's potential maximum range but reduces its 00261 // resolution. 00262 00263 // Implemented using ST's VL6180X API as a reference (STSW-IMG003); see 00264 // VL6180x_UpscaleSetScaling() in vl6180x_api.c. 00265 void VL6180X::setScaling(uint8_t new_scaling) 00266 { 00267 uint8_t const DefaultCrosstalkValidHeight = 20; // default value of SYSRANGE__CROSSTALK_VALID_HEIGHT 00268 00269 // do nothing if scaling value is invalid 00270 if (new_scaling < 1 || new_scaling > 3) { return; } 00271 00272 scaling = new_scaling; 00273 writeReg16Bit(RANGE_SCALER, ScalerValues[scaling]); 00274 00275 // apply scaling on part-to-part offset 00276 writeReg(VL6180X::SYSRANGE__PART_TO_PART_RANGE_OFFSET, ptp_offset / scaling); 00277 00278 // apply scaling on CrossTalkValidHeight 00279 writeReg(VL6180X::SYSRANGE__CROSSTALK_VALID_HEIGHT, DefaultCrosstalkValidHeight / scaling); 00280 00281 // This function does not apply scaling to RANGE_IGNORE_VALID_HEIGHT. 00282 00283 // enable early convergence estimate only at 1x scaling 00284 uint8_t rce = readReg(VL6180X::SYSRANGE__RANGE_CHECK_ENABLES); 00285 writeReg(VL6180X::SYSRANGE__RANGE_CHECK_ENABLES, (rce & 0xFE) | (scaling == 1)); 00286 } 00287 00288 // Performs a single-shot ranging measurement 00289 uint8_t VL6180X::readRangeSingle() 00290 { 00291 writeReg(SYSRANGE__START, 0x01); 00292 return readRangeContinuous(); 00293 } 00294 00295 // Performs a single-shot ambient light measurement 00296 uint16_t VL6180X::readAmbientSingle() 00297 { 00298 writeReg(SYSALS__START, 0x01); 00299 return readAmbientContinuous(); 00300 } 00301 00302 // Starts continuous ranging measurements with the given period in ms 00303 // (10 ms resolution; defaults to 100 ms if not specified). 00304 // 00305 // The period must be greater than the time it takes to perform a 00306 // measurement. See section 2.4.4 ("Continuous mode limits") in the datasheet 00307 // for details. 00308 void VL6180X::startRangeContinuous(uint16_t period) 00309 { 00310 int16_t period_reg = (int16_t)(period / 10) - 1; 00311 period_reg = constrain(period_reg, 0, 254); 00312 00313 writeReg(SYSRANGE__INTERMEASUREMENT_PERIOD, period_reg); 00314 writeReg(SYSRANGE__START, 0x03); 00315 } 00316 00317 // Starts continuous ambient light measurements with the given period in ms 00318 // (10 ms resolution; defaults to 500 ms if not specified). 00319 // 00320 // The period must be greater than the time it takes to perform a 00321 // measurement. See section 2.4.4 ("Continuous mode limits") in the datasheet 00322 // for details. 00323 void VL6180X::startAmbientContinuous(uint16_t period) 00324 { 00325 int16_t period_reg = (int16_t)(period / 10) - 1; 00326 period_reg = constrain(period_reg, 0, 254); 00327 00328 writeReg(SYSALS__INTERMEASUREMENT_PERIOD, period_reg); 00329 writeReg(SYSALS__START, 0x03); 00330 } 00331 00332 // Starts continuous interleaved measurements with the given period in ms 00333 // (10 ms resolution; defaults to 500 ms if not specified). In this mode, each 00334 // ambient light measurement is immediately followed by a range measurement. 00335 // 00336 // The datasheet recommends using this mode instead of running "range and ALS 00337 // continuous modes simultaneously (i.e. asynchronously)". 00338 // 00339 // The period must be greater than the time it takes to perform both 00340 // measurements. See section 2.4.4 ("Continuous mode limits") in the datasheet 00341 // for details. 00342 void VL6180X::startInterleavedContinuous(uint16_t period) 00343 { 00344 int16_t period_reg = (int16_t)(period / 10) - 1; 00345 period_reg = constrain(period_reg, 0, 254); 00346 00347 writeReg(INTERLEAVED_MODE__ENABLE, 1); 00348 writeReg(SYSALS__INTERMEASUREMENT_PERIOD, period_reg); 00349 writeReg(SYSALS__START, 0x03); 00350 } 00351 00352 // Stops continuous mode. This will actually start a single measurement of range 00353 // and/or ambient light if continuous mode is not active, so it's a good idea to 00354 // wait a few hundred ms after calling this function to let that complete 00355 // before starting continuous mode again or taking a reading. 00356 void VL6180X::stopContinuous() 00357 { 00358 00359 writeReg(SYSRANGE__START, 0x01); 00360 writeReg(SYSALS__START, 0x01); 00361 00362 writeReg(INTERLEAVED_MODE__ENABLE, 0); 00363 } 00364 00365 // Returns a range reading when continuous mode is activated 00366 // (readRangeSingle() also calls this function after starting a single-shot 00367 // range measurement) 00368 uint8_t VL6180X::readRangeContinuous() 00369 { 00370 uint16_t millis_start = millis(); 00371 while ((readReg(RESULT__INTERRUPT_STATUS_GPIO) & 0x04) == 0) 00372 { 00373 if (io_timeout > 0 && ((uint16_t)millis() - millis_start) > io_timeout) 00374 { 00375 did_timeout = true; 00376 return 255; 00377 } 00378 } 00379 00380 uint8_t range = readReg(RESULT__RANGE_VAL); 00381 writeReg(SYSTEM__INTERRUPT_CLEAR, 0x01); 00382 00383 return range; 00384 } 00385 00386 // Returns an ambient light reading when continuous mode is activated 00387 // (readAmbientSingle() also calls this function after starting a single-shot 00388 // ambient light measurement) 00389 uint16_t VL6180X::readAmbientContinuous() 00390 { 00391 uint16_t millis_start = millis(); 00392 while ((readReg(RESULT__INTERRUPT_STATUS_GPIO) & 0x20) == 0) 00393 { 00394 if (io_timeout > 0 && ((uint16_t)millis() - millis_start) > io_timeout) 00395 { 00396 did_timeout = true; 00397 return 0; 00398 } 00399 } 00400 writeReg(SYSTEM__FRESH_OUT_OF_RESET, 0); 00401 uint16_t ambient = readReg16Bit(RESULT__ALS_VAL); 00402 writeReg(SYSTEM__INTERRUPT_CLEAR, 0x02); 00403 return ambient; 00404 } 00405 00406 // Did a timeout occur in one of the read functions since the last call to 00407 // timeoutOccurred()? 00408 bool VL6180X::timeoutOccurred() 00409 { 00410 bool tmp = did_timeout; 00411 did_timeout = false; 00412 return tmp; 00413 } 00414
Generated on Tue Jul 12 2022 21:49:23 by
