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.
Dependents: Check_VL6180XA1_ToF
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****/
