B29VS SysProj Group 5 Element / VL6180

Dependents:   final

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers VL6180.cpp Source File

VL6180.cpp

00001 /******************************************************************************
00002  * SFE_VL6180.cpp
00003  * Library for VL6180 time of flight range finder.
00004  * Casey Kuhns @ SparkFun Electronics
00005  * 10/29/2014
00006  * https://github.com/sparkfun/
00007  *
00008  * The VL6180 by ST micro is a time of flight range finder that
00009  * uses pulsed IR light to determine distances from object at close
00010  * range.  The average range of a sensor is between 0-200mm
00011  *
00012  * In this file are the functions in the VL6180 class
00013  *
00014  * Resources:
00015  * This library uses the Arduino Wire.h to complete I2C transactions.
00016  *
00017  * Development environment specifics:
00018  *  IDE: Arduino 1.0.5
00019  *  Hardware Platform: Arduino Pro 3.3V/8MHz
00020  *  VL6180 Breakout Version: 1.0
00021  *
00022  *
00023  * This code is beerware. If you see me (or any other SparkFun employee) at the
00024  * local pub, and you've found our code helpful, please buy us a round!
00025  *
00026  * Distributed as-is; no warranty is given.
00027  ******************************************************************************/
00028 
00029 #include "VL6180.h"
00030 
00031 //
00032 // Constructors
00033 //
00034 VL6180::VL6180(PinName sda, PinName scl)  : i2c(sda, scl)
00035 {
00036     VL6180_i2cAddress = VL6180_DEF_ADDR;
00037 }
00038 
00039 VL6180::VL6180(PinName sda, PinName scl, int i2cAddress)  : i2c(sda, scl)
00040 {
00041     VL6180_i2cAddress = i2cAddress;
00042     VL6180_error_no = 0;
00043 }
00044 //
00045 // destructor
00046 //
00047 VL6180::~VL6180()
00048 {
00049 }
00050 
00051 int8_t VL6180::VL6180_Init(void)
00052 {
00053     uint8_t data; //for temp data storage
00054 
00055     data = VL6180_getRegister(VL6180_SYSTEM_FRESH_OUT_OF_RESET);
00056 
00057     if(data != 1) return VL6180_FAILURE_RESET;
00058 
00059     //Required by datasheet
00060     //http://www.st.com/st-web-ui/static/active/en/resource/technical/document/application_note/DM00122600.pdf
00061     VL6180_setRegister(0x0207, 0x01);
00062     VL6180_setRegister(0x0208, 0x01);
00063     VL6180_setRegister(0x0096, 0x00);
00064     VL6180_setRegister(0x0097, 0xfd);
00065     VL6180_setRegister(0x00e3, 0x00);
00066     VL6180_setRegister(0x00e4, 0x04);
00067     VL6180_setRegister(0x00e5, 0x02);
00068     VL6180_setRegister(0x00e6, 0x01);
00069     VL6180_setRegister(0x00e7, 0x03);
00070     VL6180_setRegister(0x00f5, 0x02);
00071     VL6180_setRegister(0x00d9, 0x05);
00072     VL6180_setRegister(0x00db, 0xce);
00073     VL6180_setRegister(0x00dc, 0x03);
00074     VL6180_setRegister(0x00dd, 0xf8);
00075     VL6180_setRegister(0x009f, 0x00);
00076     VL6180_setRegister(0x00a3, 0x3c);
00077     VL6180_setRegister(0x00b7, 0x00);
00078     VL6180_setRegister(0x00bb, 0x3c);
00079     VL6180_setRegister(0x00b2, 0x09);
00080     VL6180_setRegister(0x00ca, 0x09);
00081     VL6180_setRegister(0x0198, 0x01);
00082     VL6180_setRegister(0x01b0, 0x17);
00083     VL6180_setRegister(0x01ad, 0x00);
00084     VL6180_setRegister(0x00ff, 0x05);
00085     VL6180_setRegister(0x0100, 0x05);
00086     VL6180_setRegister(0x0199, 0x05);
00087     VL6180_setRegister(0x01a6, 0x1b);
00088     VL6180_setRegister(0x01ac, 0x3e);
00089     VL6180_setRegister(0x01a7, 0x1f);
00090     VL6180_setRegister(0x0030, 0x00);
00091 
00092     return 0;
00093 }
00094 
00095 void VL6180::VL6180_DefautSettings(void)
00096 {
00097     //Recommended settings from datasheet
00098     //http://www.st.com/st-web-ui/static/active/en/resource/technical/document/application_note/DM00122600.pdf
00099 
00100     //Enable Interrupts on Conversion Complete (any source)
00101     VL6180_setRegister(VL6180_SYSTEM_INTERRUPT_CONFIG_GPIO, (4 << 3)|(4) ); // Set GPIO1 high when sample complete
00102 
00103 
00104     VL6180_setRegister(VL6180_SYSTEM_MODE_GPIO1, 0x10); // Set GPIO1 high when sample complete
00105     VL6180_setRegister(VL6180_READOUT_AVERAGING_SAMPLE_PERIOD, 0x30); //Set Avg sample period
00106     VL6180_setRegister(VL6180_SYSALS_ANALOGUE_GAIN, 0x46); // Set the ALS gain
00107     VL6180_setRegister(VL6180_SYSRANGE_VHV_REPEAT_RATE, 0xFF); // Set auto calibration period (Max = 255)/(OFF = 0)
00108     VL6180_setRegister(VL6180_SYSALS_INTEGRATION_PERIOD, 0x63); // Set ALS integration time to 100ms
00109     VL6180_setRegister(VL6180_SYSRANGE_VHV_RECALIBRATE, 0x01); // perform a single temperature calibration
00110     //Optional settings from datasheet
00111     //http://www.st.com/st-web-ui/static/active/en/resource/technical/document/application_note/DM00122600.pdf
00112     VL6180_setRegister(VL6180_SYSRANGE_INTERMEASUREMENT_PERIOD, 0x09); // Set default ranging inter-measurement period to 100ms
00113     VL6180_setRegister(VL6180_SYSALS_INTERMEASUREMENT_PERIOD, 0x0A); // Set default ALS inter-measurement period to 100ms
00114     VL6180_setRegister(VL6180_SYSTEM_INTERRUPT_CONFIG_GPIO, 0x24); // Configures interrupt on ‘New Sample Ready threshold event’
00115     //Additional settings defaults from community
00116     VL6180_setRegister(VL6180_SYSRANGE_MAX_CONVERGENCE_TIME, 0x32);
00117     VL6180_setRegister(VL6180_SYSRANGE_RANGE_CHECK_ENABLES, 0x10 | 0x01);
00118     VL6180_setRegister16bit(VL6180_SYSRANGE_EARLY_CONVERGENCE_ESTIMATE, 0x7B );
00119     VL6180_setRegister16bit(VL6180_SYSALS_INTEGRATION_PERIOD, 0x64);
00120 
00121     VL6180_setRegister(VL6180_READOUT_AVERAGING_SAMPLE_PERIOD,0x30);
00122     VL6180_setRegister(VL6180_SYSALS_ANALOGUE_GAIN,0x40);
00123     VL6180_setRegister(VL6180_FIRMWARE_RESULT_SCALER,0x01);
00124 }
00125 void VL6180::getIdentification(struct VL6180Identification *temp)
00126 {
00127 
00128     temp->idModel =  VL6180_getRegister(VL6180_IDENTIFICATION_MODEL_ID);
00129     temp->idModelRevMajor = VL6180_getRegister(VL6180_IDENTIFICATION_MODEL_REV_MAJOR);
00130     temp->idModelRevMinor = VL6180_getRegister(VL6180_IDENTIFICATION_MODEL_REV_MINOR);
00131     temp->idModuleRevMajor = VL6180_getRegister(VL6180_IDENTIFICATION_MODULE_REV_MAJOR);
00132     temp->idModuleRevMinor = VL6180_getRegister(VL6180_IDENTIFICATION_MODULE_REV_MINOR);
00133 
00134     temp->idDate = VL6180_getRegister16bit(VL6180_IDENTIFICATION_DATE);
00135     temp->idTime = VL6180_getRegister16bit(VL6180_IDENTIFICATION_TIME);
00136 }
00137 
00138 
00139 uint8_t VL6180::changeAddress(uint8_t old_address, uint8_t new_address)
00140 {
00141 
00142     //NOTICE:  IT APPEARS THAT CHANGING THE ADDRESS IS NOT STORED IN NON-VOLATILE MEMORY
00143     // POWER CYCLING THE DEVICE REVERTS ADDRESS BACK TO 0X29
00144 
00145     if( old_address == new_address) return old_address;
00146     if( new_address > 127) return old_address;
00147 
00148     VL6180_setRegister(VL6180_I2C_SLAVE_DEVICE_ADDRESS, new_address);
00149 
00150     return VL6180_getRegister(VL6180_I2C_SLAVE_DEVICE_ADDRESS);
00151 }
00152 
00153 
00154 
00155 uint8_t VL6180::getDistance()
00156 {
00157     VL6180_setRegister(VL6180_SYSRANGE_START, 0x01); //Start Single shot mode
00158     wait(0.01);    // 10mS
00159     return VL6180_getRegister(VL6180_RESULT_RANGE_VAL);
00160 //    VL6180_setRegister(VL6180_SYSTEM_INTERRUPT_CLEAR, 0x07);
00161 //    return distance;
00162 }
00163 
00164 float VL6180::getAmbientLight(VL6180_als_gain VL6180_ALS_GAIN)
00165 {
00166     //First load in Gain we are using, do it everytime incase someone changes it on us.
00167     //Note: Upper nibble shoudl be set to 0x4 i.e. for ALS gain of 1.0 write 0x46
00168     VL6180_setRegister(VL6180_SYSALS_ANALOGUE_GAIN, (0x40 | VL6180_ALS_GAIN)); // Set the ALS gain
00169 
00170     //Start ALS Measurement
00171     VL6180_setRegister(VL6180_SYSALS_START, 0x01);
00172 
00173     wait(0.1); //100Ms
00174 
00175     VL6180_setRegister(VL6180_SYSTEM_INTERRUPT_CLEAR, 0x07);
00176 
00177     //Retrieve the Raw ALS value from the sensoe
00178     unsigned int alsRaw = VL6180_getRegister16bit(VL6180_RESULT_ALS_VAL);
00179 
00180     //Get Integration Period for calculation, we do this everytime incase someone changes it on us.
00181     unsigned int alsIntegrationPeriodRaw = VL6180_getRegister16bit(VL6180_SYSALS_INTEGRATION_PERIOD);
00182 
00183     float alsIntegrationPeriod = 100.0 / alsIntegrationPeriodRaw ;
00184 
00185     //Calculate actual LUX from Appnotes
00186 
00187     float alsGain = 0.0;
00188 
00189     switch (VL6180_ALS_GAIN) {
00190         case GAIN_20:
00191             alsGain = 20.0;
00192             break;
00193         case GAIN_10:
00194             alsGain = 10.32;
00195             break;
00196         case GAIN_5:
00197             alsGain = 5.21;
00198             break;
00199         case GAIN_2_5:
00200             alsGain = 2.60;
00201             break;
00202         case GAIN_1_67:
00203             alsGain = 1.72;
00204             break;
00205         case GAIN_1_25:
00206             alsGain = 1.28;
00207             break;
00208         case GAIN_1:
00209             alsGain = 1.01;
00210             break;
00211         case GAIN_40:
00212             alsGain = 40.0;
00213             break;
00214     }
00215 
00216 //Calculate LUX from formula in AppNotes
00217 
00218     float alsCalculated = (float)0.32 * ((float)alsRaw / alsGain) * alsIntegrationPeriod;
00219 
00220     return alsCalculated;
00221 }
00222 
00223 // --- Private Functions --- //
00224 
00225 uint8_t VL6180::VL6180_getRegister(uint16_t reg_address)
00226 {
00227     char data[2];
00228 
00229     data[0] = (reg_address >> 8) & 0xFF; //MSB of register address
00230     data[1] = reg_address & 0xFF; //LSB of register address
00231     VL6180_error_no = i2c.write(VL6180_i2cAddress, data, 2);
00232     VL6180_error_no = i2c.read(VL6180_i2cAddress, data, 1, false);
00233     return data[0];
00234 }
00235 
00236 uint16_t VL6180::VL6180_getRegister16bit(uint16_t reg_address)
00237 {
00238     char data[2];
00239 
00240     data[0] = (reg_address >> 8) & 0xFF; //MSB of register address
00241     data[1] = reg_address & 0xFF; //LSB of register address
00242     VL6180_error_no = i2c.write(VL6180_i2cAddress, data, 2);
00243     VL6180_error_no = i2c.read(VL6180_i2cAddress, data, 2, false);
00244     return (data[0] + ((data[1] << 8) & 0xFF00));
00245 }
00246 
00247 void VL6180::VL6180_setRegister(uint16_t reg_address, uint8_t value)
00248 {
00249     char  data[3];
00250 
00251     data[0] = (reg_address >> 8) & 0xFF;    //MSB of register address
00252     data[1] = reg_address & 0xFF;           //LSB of register address
00253     data[2] = value;
00254     VL6180_error_no = VL6180_error_no = i2c.write(VL6180_i2cAddress, data, 3);
00255 }
00256 
00257 void VL6180::VL6180_setRegister16bit(uint16_t reg_address, uint16_t value)
00258 {
00259     char  data[4];
00260 
00261     data[0] = (reg_address >> 8) & 0xFF;    //MSB of register address
00262     data[1] = reg_address & 0xFF;           //LSB of register address
00263     data[2] = value & 0xFF;
00264     data[3] = ((value >> 8) & 0xFF);
00265     VL6180_error_no = VL6180_error_no = i2c.write(VL6180_i2cAddress, data, 4);
00266 }
00267 
00268 int VL6180::writeSingleRegister( uint16_t reg_address, uint8_t data )
00269 {
00270 
00271     char data_write[3];
00272     data_write[0] = (reg_address >> 8) & 0xFF; //MSB of register address
00273     data_write[1] = reg_address & 0xFF; //LSB of register address
00274     data_write[2] = data & 0xFF;
00275     return i2c.write(VL6180_DEF_ADDR, data_write, 3);
00276 
00277 //   char tx[2] = { address | 160, data }; //0d160 = 0b10100000
00278 //   int ack = i2c.write( SLAVE_ADDRESS << 1, tx, 2 );
00279 //   return ack;
00280 }