INSAT Mini Project
Dependencies: ST_INTERFACES X_NUCLEO_COMMON
Fork of X_NUCLEO_6180XA1 by
Components/VL6180X/vl6180x_class.cpp
- Committer:
- gallonm
- Date:
- 2015-09-17
- Revision:
- 4:a5abf7757947
- Parent:
- 3:454541a079f4
- Child:
- 7:2dc81120c917
File content as of revision 4:a5abf7757947:
/** ****************************************************************************** * @file vl6180x_class.cpp * @author AST / EST * @version V0.0.1 * @date 14-April-2015 * @brief Implementation file for the HTS221 driver class ****************************************************************************** * @attention * * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of STMicroelectronics nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "vl6180x_class.h" /* define for inizialization -------------------------------------------------*/ #if VL6180x_UPSCALE_SUPPORT == 1 #define _GetUpscale(dev, ... ) 1 #define _SetUpscale(...) -1 #define DEF_UPSCALE 1 #elif VL6180x_UPSCALE_SUPPORT == 2 #define _GetUpscale(dev, ... ) 2 #define _SetUpscale(...) #define DEF_UPSCALE 2 #elif VL6180x_UPSCALE_SUPPORT == 3 #define _GetUpscale(dev, ... ) 3 #define _SetUpscale(...) #define DEF_UPSCALE 3 #else #define DEF_UPSCALE (-(VL6180x_UPSCALE_SUPPORT)) #define _GetUpscale(dev, ... ) VL6180xDevDataGet(dev, UpscaleFactor) #define _SetUpscale(dev, Scaling ) VL6180xDevDataSet(dev, UpscaleFactor, Scaling) #endif #if VL6180x_SINGLE_DEVICE_DRIVER extern struct VL6180xDevData_t SingleVL6180xDevData; #define VL6180xDevDataGet(dev, field) (SingleVL6180xDevData.field) #define VL6180xDevDataSet(dev, field, data) SingleVL6180xDevData.field=(data) #endif #if VL6180x_UPSCALE_SUPPORT == 1 #define _GetUpscale(dev, ... ) 1 #define _SetUpscale(...) -1 #define DEF_UPSCALE 1 #elif VL6180x_UPSCALE_SUPPORT == 2 #define _GetUpscale(dev, ... ) 2 #define _SetUpscale(...) #define DEF_UPSCALE 2 #elif VL6180x_UPSCALE_SUPPORT == 3 #define _GetUpscale(dev, ... ) 3 #define _SetUpscale(...) #define DEF_UPSCALE 3 #else #define DEF_UPSCALE (-(VL6180x_UPSCALE_SUPPORT)) #define _GetUpscale(dev, ... ) VL6180xDevDataGet(dev, UpscaleFactor) #define _SetUpscale(dev, Scaling ) VL6180xDevDataSet(dev, UpscaleFactor, Scaling) #endif struct VL6180xDevData_t VL6180x_DEV_DATA_ATTR SingleVL6180xDevData={ .EceFactorM = DEF_ECE_FACTOR_M, .EceFactorD = DEF_ECE_FACTOR_D, #ifdef VL6180x_HAVE_UPSCALE_DATA .UpscaleFactor = DEF_UPSCALE, #endif #ifdef VL6180x_HAVE_ALS_DATA .IntegrationPeriod = DEF_INT_PEFRIOD, .AlsGainCode = DEF_ALS_GAIN, .AlsScaler = DEF_ALS_SCALER, #endif #ifdef VL6180x_HAVE_DMAX_RANGING .DMaxEnable = DEF_DMAX_ENABLE, #endif }; #define Fix7_2_KCPs(x) ((((uint32_t)(x))*1000)>>7) /* define for i2c configuration ----------------------------------------------*/ #define I2C_BUFFER_CONFIG 1 #define VL6180x_I2C_USER_VAR #define TEMP_BUF_SIZE 32 #ifndef I2C_BUFFER_CONFIG #error "I2C_BUFFER_CONFIG not defined" /* TODO you must define value for I2C_BUFFER_CONFIG in configuration or platform h */ #endif #if I2C_BUFFER_CONFIG == 0 /* GLOBAL config buffer */ uint8_t i2c_global_buffer[VL6180x_MAX_I2C_XFER_SIZE]; #define DECL_I2C_BUFFER #define VL6180x_GetI2cBuffer(dev, n_byte) i2c_global_buffer #elif I2C_BUFFER_CONFIG == 1 /* ON STACK */ #define DECL_I2C_BUFFER uint8_t LocBuffer[VL6180x_MAX_I2C_XFER_SIZE]; #define VL6180x_GetI2cBuffer(dev, n_byte) LocBuffer #elif I2C_BUFFER_CONFIG == 2 /* user define buffer type declare DECL_I2C_BUFFER as access via VL6180x_GetI2cBuffer */ #define DECL_I2C_BUFFER #else #error "invalid I2C_BUFFER_CONFIG " #endif /* Initialization functions --------------------------------------------------*/ int VL6180X::VL6180x_InitData(VL6180xDev_t dev) { int status, dmax_status ; int8_t offset; uint8_t FreshOutReset; uint32_t CalValue; uint16_t u16; uint32_t XTalkCompRate_KCps; LOG_FUNCTION_START(""); VL6180xDevDataSet(dev, EceFactorM , DEF_ECE_FACTOR_M); VL6180xDevDataSet(dev, EceFactorD , DEF_ECE_FACTOR_D); #ifdef VL6180x_HAVE_UPSCALE_DATA VL6180xDevDataSet(dev, UpscaleFactor , DEF_UPSCALE); #endif #ifdef VL6180x_HAVE_ALS_DATA VL6180xDevDataSet(dev, IntegrationPeriod, DEF_INT_PEFRIOD); VL6180xDevDataSet(dev, AlsGainCode, DEF_ALS_GAIN); VL6180xDevDataSet(dev, AlsScaler, DEF_ALS_SCALER); #endif #ifdef VL6180x_HAVE_WRAP_AROUND_DATA VL6180xDevDataSet(dev, WrapAroundFilterActive, (VL6180x_WRAP_AROUND_FILTER_SUPPORT >0)); VL6180xDevDataSet(dev, DMaxEnable, DEF_DMAX_ENABLE); #endif _DMax_OneTimeInit(dev); do{ /* backup offset initial value from nvm these must be done prior any over call that use offset */ status = VL6180x_RdByte(MyDevice,SYSRANGE_PART_TO_PART_RANGE_OFFSET, (uint8_t*)&offset); if( status ){ VL6180x_ErrLog("SYSRANGE_PART_TO_PART_RANGE_OFFSET rd fail"); break; } VL6180xDevDataSet(dev, Part2PartOffsetNVM, offset); status=VL6180x_RdDWord(MyDevice, SYSRANGE_RANGE_IGNORE_THRESHOLD, &CalValue); if( status ){ VL6180x_ErrLog("Part2PartAmbNVM rd fail"); break; } if( (CalValue&0xFFFF0000) == 0 ){ CalValue=0x00CE03F8; } VL6180xDevDataSet(dev, Part2PartAmbNVM, CalValue); status = VL6180x_RdWord(MyDevice, SYSRANGE_CROSSTALK_COMPENSATION_RATE ,&u16); if( status){ VL6180x_ErrLog("SYSRANGE_CROSSTALK_COMPENSATION_RATE rd fail "); break; } XTalkCompRate_KCps = Fix7_2_KCPs(u16); VL6180xDevDataSet(dev, XTalkCompRate_KCps , XTalkCompRate_KCps ); dmax_status = _DMax_InitData(dev); if( dmax_status < 0 ){ VL6180x_ErrLog("DMax init failure"); break; } /* Read or wait for fresh out of reset */ status = VL6180x_RdByte(MyDevice,SYSTEM_FRESH_OUT_OF_RESET, &FreshOutReset); if( status ) { VL6180x_ErrLog("SYSTEM_FRESH_OUT_OF_RESET rd fail"); break; } if( FreshOutReset!= 1 || dmax_status ) status = CALIBRATION_WARNING; } while(0); LOG_FUNCTION_END(status); return status; } #define _DMaxData(field) VL6180xDevDataGet(dev, DMaxData.field) #ifndef VL6180x_PLATFORM_PROVIDE_SQRT uint32_t VL6180X::VL6180x_SqrtUint32(uint32_t num) { uint32_t res = 0; uint32_t bit = 1 << 30; /* The second-to-top bit is set: 1 << 30 for 32 bits */ /* "bit" starts at the highest power of four <= the argument. */ while (bit > num) bit >>= 2; while (bit != 0) { if (num >= res + bit) { num -= res + bit; res = (res >> 1) + bit; } else res >>= 1; bit >>= 2; } return res; } #endif void VL6180X::_DMax_OneTimeInit(VL6180xDev_t dev){ _DMaxData(ambTuningWindowFactor_K)=DEF_AMBIENT_TUNING; } uint32_t VL6180X::_DMax_RawValueAtRateKCps(VL6180xDev_t dev, int32_t rate){ uint32_t snrLimit_K; int32_t DMaxSq; uint32_t RawDMax; DMaxFix_t retSignalAt400mm; uint32_t ambTuningWindowFactor_K; ambTuningWindowFactor_K = _DMaxData(ambTuningWindowFactor_K); snrLimit_K = _DMaxData(snrLimit_K); retSignalAt400mm = _DMaxData(retSignalAt400mm); /* 12 to 18 bits Kcps */ if( rate > 0 ){ DMaxSq = 400*400*1000 / rate -(400*400/330); /* K of (1/RtnAmb -1/330 )=> 30bit- (12-18)bit => 12-18 bits*/ if( DMaxSq<= 0){ RawDMax = 0; } else{ /* value can be more 32 bit so base on raneg apply *retSignalAt400mm before or after division to presevr accuracy */ if( DMaxSq< (2<<12) ){ DMaxSq = DMaxSq*retSignalAt400mm/(snrLimit_K+ambTuningWindowFactor_K); /* max 12 + 12 to 18 -10 => 12-26 bit */ }else{ DMaxSq = DMaxSq/(snrLimit_K+ambTuningWindowFactor_K)*retSignalAt400mm; /* 12 to 18 -10 + 12 to 18 *=> 12-26 bit */ } RawDMax=VL6180x_SqrtUint32(DMaxSq); } } else{ RawDMax = 0x7FFFFFFF; /* bigest possibmle 32bit signed value */ } return RawDMax; } int VL6180X::_DMax_InitData(VL6180xDev_t dev) { int status, warning; uint8_t u8; uint16_t u16; uint32_t u32; uint32_t Reg2A_KCps; uint32_t RegB8; uint8_t MaxConvTime; uint32_t XTalkCompRate_KCps; uint32_t RangeIgnoreThreshold; int32_t minSignalNeeded; uint8_t SysRangeCheckEn; uint8_t snrLimit; warning=0; static const int ROMABLE_DATA MaxConvTimeAdjust=-4; LOG_FUNCTION_START(""); do{ status = VL6180x_RdByte(MyDevice, 0x02A ,&u8); if( status ){ VL6180x_ErrLog("Reg 0x02A rd fail"); break; } if( u8 == 0 ) { warning = CALIBRATION_WARNING; u8 = 40; /* use a default average value */ } Reg2A_KCps = Fix7_2_KCPs(u8); /* convert to KCPs */ status = VL6180x_RdByte(MyDevice, SYSRANGE_RANGE_CHECK_ENABLES, &SysRangeCheckEn); if (status) { VL6180x_ErrLog("SYSRANGE_RANGE_CHECK_ENABLES rd fail "); break; } status = VL6180x_RdByte(MyDevice, SYSRANGE_MAX_CONVERGENCE_TIME, &MaxConvTime); if( status){ VL6180x_ErrLog("SYSRANGE_MAX_CONVERGENCE_TIME rd fail "); break; } status = VL6180x_RdDWord(MyDevice, 0x0B8, &RegB8); if( status ){ VL6180x_ErrLog("reg 0x0B8 rd fail "); break; } status = VL6180x_RdByte(MyDevice, SYSRANGE_MAX_AMBIENT_LEVEL_MULT, &snrLimit); if( status){ VL6180x_ErrLog("SYSRANGE_MAX_AMBIENT_LEVEL_MULT rd fail "); break; } _DMaxData(snrLimit_K) = (int32_t)16*1000/snrLimit; XTalkCompRate_KCps = VL6180xDevDataGet(dev, XTalkCompRate_KCps ); if( Reg2A_KCps >= XTalkCompRate_KCps){ _DMaxData(retSignalAt400mm)=( Reg2A_KCps - XTalkCompRate_KCps); } else{ _DMaxData(retSignalAt400mm)=0; /* Reg2A_K - XTalkCompRate_KCp <0 is invalid */ } /* if xtalk range check is off omit it in snr clipping */ if( SysRangeCheckEn&RANGE_CHECK_RANGE_ENABLE_MASK ){ status = VL6180x_RdWord(MyDevice, SYSRANGE_RANGE_IGNORE_THRESHOLD, &u16); if( status){ VL6180x_ErrLog("SYSRANGE_RANGE_IGNORE_THRESHOLD rd fail "); break; } RangeIgnoreThreshold = Fix7_2_KCPs(u16); } else{ RangeIgnoreThreshold = 0; } minSignalNeeded = (RegB8*256)/((int32_t)MaxConvTime+(int32_t)MaxConvTimeAdjust); /* KCps 8+8 bit -(1 to 6 bit) => 15-10 bit */ /* minSignalNeeded = max ( minSignalNeeded, RangeIgnoreThreshold - XTalkCompRate_KCps) */ if( minSignalNeeded <= RangeIgnoreThreshold - XTalkCompRate_KCps ) minSignalNeeded = RangeIgnoreThreshold - XTalkCompRate_KCps; u32 = (minSignalNeeded*(uint32_t)snrLimit)/16; _DMaxData(ClipSnrLimit ) = _DMax_RawValueAtRateKCps(dev, u32 ); /* clip to dmax to min signal snr limit rate*/ } while(0); if( !status ) status = warning; LOG_FUNCTION_END(status); return status; } #undef Fix7_2_KCPs /* Write and read functions from I2C -----------------------------------------*/ int VL6180X::VL6180x_WrByte(VL6180xDev_t dev, uint16_t index, uint8_t data) { int status; DECL_I2C_BUFFER VL6180x_I2C_USER_VAR status=VL6180x_I2CWrite(dev, index, &data,(uint8_t)3); return status; } int VL6180X::VL6180x_WrWord(VL6180xDev_t dev, uint16_t index, uint16_t data) { int status; DECL_I2C_BUFFER VL6180x_I2C_USER_VAR status=VL6180x_I2CWrite(dev, index, (uint8_t *)&data,(uint8_t)4); return status; } int VL6180X::VL6180x_WrDWord(VL6180xDev_t dev, uint16_t index, uint32_t data) { VL6180x_I2C_USER_VAR DECL_I2C_BUFFER int status; status=VL6180x_I2CWrite(dev, index, (uint8_t *)&data,(uint8_t)6); return status; } int VL6180X::VL6180x_RdByte(VL6180xDev_t dev, uint16_t index, uint8_t *data) { VL6180x_I2C_USER_VAR int status; uint8_t buffer; DECL_I2C_BUFFER status=VL6180x_I2CRead(dev, index, &buffer,1); if( !status ){ *data=buffer; } return status; } int VL6180X::VL6180x_RdWord(VL6180xDev_t dev, uint16_t index, uint16_t *data) { VL6180x_I2C_USER_VAR int status; uint8_t *buffer; DECL_I2C_BUFFER status=VL6180x_I2CRead(dev, index, buffer,2); if( !status ){ /* VL6180x register are Big endian if cpu is be direct read direct into *data is possible */ *data=((uint16_t)buffer[0]<<8)|(uint16_t)buffer[1]; } return status; } int VL6180X::VL6180x_RdDWord(VL6180xDev_t dev, uint16_t index, uint32_t *data) { VL6180x_I2C_USER_VAR int status; uint8_t *buffer; DECL_I2C_BUFFER status=VL6180x_I2CRead(dev, index, buffer,4); if( !status ){ /* VL6180x register are Big endian if cpu is be direct read direct into data is possible */ *data=((uint32_t)buffer[0]<<24)|((uint32_t)buffer[1]<<16)|((uint32_t)buffer[2]<<8)|((uint32_t)buffer[3]); } return status; } int VL6180X::VL6180x_I2CWrite(uint8_t DeviceAddr, uint16_t RegisterAddr, uint8_t* pBuffer, uint16_t NumByteToWrite) { int ret; int i; uint8_t tmp[TEMP_BUF_SIZE]; uint16_t myRegisterAddr = RegisterAddr; uint8_t *array; if(NumByteToWrite >= TEMP_BUF_SIZE) return -2; /* First, send 8 bits device address and 16 bits register address in BE format. Then, send data and STOP condition */ tmp[0] = *(((uint8_t*)&myRegisterAddr)+1); tmp[1] = (uint8_t)RegisterAddr; if(NumByteToWrite>1) { array=new uint8_t[NumByteToWrite]; for(i=0;i<NumByteToWrite;i++) { array[NumByteToWrite-1-i]=pBuffer[i]; } } memcpy(tmp+2, array, NumByteToWrite); ret = dev_i2c.write(DeviceAddr, (const char*)tmp, NumByteToWrite+sizeof(RegisterAddr), false); if(ret) return -1; return 0; } int VL6180X::VL6180x_I2CRead(uint8_t DeviceAddr, uint16_t RegisterAddr, uint8_t* pBuffer, uint16_t NumByteToRead) { int ret; uint16_t myRegisterAddr = RegisterAddr; uint16_t myRegisterAddrBE; myRegisterAddrBE = *(((uint8_t*)&myRegisterAddr)+1); *(((uint8_t*)&myRegisterAddrBE)+1) = (uint8_t)myRegisterAddr; /* Send 8 bits device address and 16 bits register address in BE format, with no STOP condition */ ret = dev_i2c.write(DeviceAddr, (const char*)&myRegisterAddrBE, sizeof(RegisterAddr), true); if(!ret) { /* Read data, with STOP condition */ ret = dev_i2c.read(DeviceAddr, (char*)pBuffer, NumByteToRead, false); } if(ret) return -1; return 0; } /* IO read funcitons ---------------------------------------------------------*/ int VL6180X::VL6180X_ReadID(uint8_t *rl_id) { if(!rl_id) { return API_ERROR; // DA DEFINIRE IL TIPO DI ERRORE!! } return VL6180X_IO_Read(rl_id, IDENTIFICATION_MODEL_ID, 1); } int VL6180X::VL6180X_IO_Read(uint8_t *pBuffer, uint8_t RegisterAddress, uint16_t NumByteToRead) { int lecture; lecture=dev_i2c.i2c_read(pBuffer, MyDeviceAddress, RegisterAddress, NumByteToRead); if(lecture!=0) { return INVALID_PARAMS; // DA DEFINIRE IL TIPO DI ERRORE!! } return API_NO_ERROR; // DA DEFINIRE IL TIPO DI ERRORE!! } /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/