Creating a project about VL6180XA1 for TT_Mxx

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers VL6180X.cpp Source File

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