/**
* @file VL6180x_ATY.c
*
* @param Project DEVICE_DRIVER_ATY_LIB
*
* @author ATY
*
* @copyright
* - Copyright 2017 - 2026 MZ-ATY
* - This code follows:
* - MZ-ATY Various Contents Joint Statement -
*
* https://mengze.top/MZ-ATY_VCJS
* - CC 4.0 BY-NC-SA -
*
* https://creativecommons.org/licenses/by-nc-sa/4.0/
* - Your use will be deemed to have accepted the terms of this statement.
*
* @brief functions of VL6180 for C platform
*
* @version
* - 1_01_231228 > ATY
* -# Preliminary version, first Release
* - 1_01_240104 > ATY
* -# base tested VL6180
* - 1_01_240111 > ATY
* -# add lock
********************************************************************************
*/
#ifndef __VL6180x_ATY_C
#define __VL6180x_ATY_C
#include "VL6180x_ATY.h"
#define VL6180x_ATY_TAG "\r\n[VL6180x_ATY] "
/******************************* For user *************************************/
/******************************************************************************/
/**
* @brief
*
* @param reg
* @param data
* @param dev
* @return uint8_t
*/
uint8_t VL6180x_WriteByte(uint16_t reg, uint8_t data, struct VL6180x_ATY_Dev* dev){
uint8_t groupRegData[3], errCode = 0;
__ATY_LOCK(dev);
groupRegData[0] = (reg >> 8) & 0xFF; // MSB of register address
groupRegData[1] = reg & 0xFF; // LSB of register address
groupRegData[2] = data & 0xFF;
errCode = dev->i2cProcess(dev->addr, groupRegData, 3, __ATY_RW_W);
__ATY_UNLOCK(dev);
return errCode;
}
/**
* @brief
*
* @param reg
* @param data
* @param bytes num to write
* @param dev
* @return uint8_t
*/
uint8_t VL6180x_WriteBytes(uint16_t reg, uint8_t* data, uint8_t bytes, struct VL6180x_ATY_Dev* dev){
uint8_t groupRegData[3], i = 0, errCode = 0;
__ATY_LOCK(dev);
groupRegData[0] = (reg >> 8) & 0xFF; // MSB of register address
groupRegData[1] = reg & 0xFF; // LSB of register address
for(i = 0; i < bytes; i++)
groupRegData[2 + i] = data[i] & 0xFF;
errCode = dev->i2cProcess(dev->addr, groupRegData, 2 + bytes, __ATY_RW_W);
__ATY_UNLOCK(dev);
return errCode;
}
/**
* @brief
*
* @param reg
* @param data
* @param dev
* @return uint8_t
*/
uint8_t VL6180x_ReadByte(uint16_t reg, uint8_t* data, struct VL6180x_ATY_Dev* dev){
uint8_t groupReg[2], errCode = 0;
__ATY_LOCK(dev);
groupReg[0] = (reg >> 8) & 0xFF; // MSB of register address
groupReg[1] = reg & 0xFF; // LSB of register address
errCode = dev->i2cProcess(dev->addr, groupReg, 2, __ATY_RW_W);
if(errCode){ __ATY_UNLOCK(dev); return errCode; }
errCode = dev->i2cProcess(dev->addr, data, 1, __ATY_RW_R);
__ATY_UNLOCK(dev);
return errCode;
}
/**
* @brief
*
* @param reg
* @param data
* @param bytes num to read
* @param dev
* @return uint8_t
*/
uint8_t VL6180x_ReadBytes(uint16_t reg, uint8_t* data, uint8_t bytes, struct VL6180x_ATY_Dev* dev){
uint8_t groupReg[2], errCode = 0;
__ATY_LOCK(dev);
groupReg[0] = (reg >> 8) & 0xFF; // MSB of register address
groupReg[1] = reg & 0xFF; // LSB of register address
errCode = dev->i2cProcess(dev->addr, groupReg, 2, __ATY_RW_W);
if(errCode){ __ATY_UNLOCK(dev); return errCode; }
errCode = dev->i2cProcess(dev->addr, data, bytes, __ATY_RW_R);
__ATY_UNLOCK(dev);
return errCode;
}
/**
* @brief get ids
*
* @param id need 9 size array
* @param dev device
* @return uint8_t
* @note B4 01 03 ......
*/
uint8_t VL6180x_GetId(uint8_t* id, struct VL6180x_ATY_Dev* dev){
uint8_t errCode = 0;
errCode = 0x00 & VL6180x_ReadByte(VL6180x_REG_IDENTIFICATION_MODEL_ID, &id[0], dev);
errCode = 0x10 & VL6180x_ReadByte(VL6180x_REG_IDENTIFICATION_MODEL_REV_MAJOR, &id[1], dev);
errCode = 0x20 & VL6180x_ReadByte(VL6180x_REG_IDENTIFICATION_MODEL_REV_MINOR, &id[2], dev);
errCode = 0x30 & VL6180x_ReadByte(VL6180x_REG_IDENTIFICATION_MODULE_REV_MAJOR, &id[3], dev);
errCode = 0x40 & VL6180x_ReadByte(VL6180x_REG_IDENTIFICATION_MODULE_REV_MINOR, &id[4], dev);
errCode = 0x50 & VL6180x_ReadByte(VL6180x_REG_IDENTIFICATION_DATE_HI, &id[5], dev);
errCode = 0x60 & VL6180x_ReadByte(VL6180x_REG_IDENTIFICATION_DATE_LO, &id[6], dev);
errCode = 0x70 & VL6180x_ReadBytes(VL6180x_REG_IDENTIFICATION_TIME, &id[7], 2, dev);
printf_ATY_D("%sID: %02X %02X %02X %02X %02X %02X %02X %02X %02X\r\n",
VL6180x_ATY_TAG, id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8]);
if(id[0] != 0xB4){ return 0x81; }
return errCode;
}
/**
* @brief write new addr
*
* @param newAddr
* @param dev
* @note not real tested
* @return uint8_t
*/
uint8_t VL6180x_SetAddress(uint8_t newAddr, struct VL6180x_ATY_Dev* dev){
if(VL6180x_WriteByte(VL6180x_REG_SLAVE_DEVICE_ADDRESS, newAddr & 0x7F, dev) == 1)
return 1;
dev->addr = newAddr;
return 0;
}
/**
* @brief get offset
*
* @param offset
* @param dev
* @return uint8_t
*/
uint8_t VL6180x_GetOffset(uint8_t* offset, struct VL6180x_ATY_Dev* dev){
return VL6180x_ReadByte(VL6180x_REG_SYSRANGE_PART_TO_PART_RANGE_OFFSET, offset, dev);
}
/**
* @brief set offset
*
* @param offset
* @param dev
* @return uint8_t
*/
uint8_t VL6180x_SetOffset(uint8_t offset, struct VL6180x_ATY_Dev* dev){
return VL6180x_WriteByte(VL6180x_REG_SYSRANGE_PART_TO_PART_RANGE_OFFSET, offset, dev);
}
/**
* @brief
*
* @param dev
* @return uint8_t
*/
uint8_t VL6180x_Config(struct VL6180x_ATY_Dev* dev){
uint8_t errCode = 0;
// Mandatory : private registers
errCode = 0x10 & VL6180x_WriteByte(0x0207, 0x01, dev);
errCode = 0x10 & VL6180x_WriteByte(0x0208, 0x01, dev);
errCode = 0x10 & VL6180x_WriteByte(0x0096, 0x00, dev);
errCode = 0x10 & VL6180x_WriteByte(0x0097, 0xfd, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00e3, 0x01, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00e4, 0x03, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00e5, 0x02, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00e6, 0x01, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00e7, 0x03, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00f5, 0x02, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00d9, 0x05, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00db, 0xce, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00dc, 0x03, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00dd, 0xf8, dev);
errCode = 0x10 & VL6180x_WriteByte(0x009f, 0x00, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00a3, 0x3c, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00b7, 0x00, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00bb, 0x3c, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00b2, 0x09, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00ca, 0x09, dev);
errCode = 0x10 & VL6180x_WriteByte(0x0198, 0x01, dev);
errCode = 0x10 & VL6180x_WriteByte(0x01b0, 0x17, dev);
errCode = 0x10 & VL6180x_WriteByte(0x01ad, 0x00, dev);
errCode = 0x10 & VL6180x_WriteByte(0x00ff, 0x05, dev);
errCode = 0x10 & VL6180x_WriteByte(0x0100, 0x05, dev);
errCode = 0x10 & VL6180x_WriteByte(0x0199, 0x05, dev);
errCode = 0x10 & VL6180x_WriteByte(0x01a6, 0x1b, dev);
errCode = 0x10 & VL6180x_WriteByte(0x01ac, 0x3e, dev);
errCode = 0x10 & VL6180x_WriteByte(0x01a7, 0x1f, dev);
errCode = 0x10 & VL6180x_WriteByte(0x0030, 0x00, dev);
// Recommended : Public registers - See data sheet for more detail
errCode = 0x20 & VL6180x_WriteByte(0x0011, 0x10, dev); // Enables polling for "New Sample ready" when measurement completes
errCode = 0x20 & VL6180x_WriteByte(0x010a, 0x30, dev); // Set the averaging sample period (compromise between lower noise and increased execution time)
errCode = 0x20 & VL6180x_WriteByte(0x003f, 0x46, dev); // Sets the light and dark gain (upper nibble). Dark gain should not be changed.
errCode = 0x20 & VL6180x_WriteByte(0x0031, 0xFF, dev); // sets the # of range measurements after which auto calibration of system is performed
errCode = 0x20 & VL6180x_WriteByte(0x0041, 0x63, dev); // Set ALS integration time to 100ms
errCode = 0x20 & VL6180x_WriteByte(0x002e, 0x01, dev); // perform a single temperature calibration of the ranging sensor
// Optional: Public registers - See data sheet for more detail
errCode = 0x30 & VL6180x_WriteByte(0x001b, 0x09, dev); // Set default ranging inter-measurement period to 100ms
errCode = 0x30 & VL6180x_WriteByte(0x003e, 0x31, dev); // Set default ALS inter-measurement period to 500ms
errCode = 0x30 & VL6180x_WriteByte(0x0014, 0x24, dev); // Configures interrupt on "New Sample Ready threshold event"
return errCode;
}
/**
* @brief initializes I2C interface, checks that VL6180x is found and resets chip
*
* @param dev
* @return uint8_t
*/
uint8_t VL6180x_Init(struct VL6180x_ATY_Dev* dev){
uint8_t reset;
if(VL6180x_ReadByte(VL6180x_REG_SYSTEM_FRESH_OUT_OF_RESET, &reset, dev) == 1)
return 1;
// check to see has it be Initialised already
if(reset == 1){
if(VL6180x_Config(dev))
return 3;
//change fresh out of set status to 0
if(VL6180x_WriteByte(VL6180x_REG_SYSTEM_FRESH_OUT_OF_RESET, 0x00, dev) == 1)
return 2;
}
VL6180x_GetId(dev->id, dev);
return 0;
}
/**
* @brief
*
* @return uint8_t 1 for ready
*/
uint8_t VL6180x_IsDeviceReady(struct VL6180x_ATY_Dev* dev){
uint8_t byte = 0;
if(VL6180x_ReadByte(VL6180x_REG_RESULT_INTERRUPT_STATUS_GPIO, &byte, dev) == 1)
return 1;
if((byte & 0x01))
return 0;
return 2;
}
/**
* @brief
*
* @return uint8_t 1 for ready
*/
uint8_t VL6180x_WaitDeviceReady(struct VL6180x_ATY_Dev* dev){
uint16_t errCount = 0;
while(VL6180x_IsDeviceReady(dev) != 0){
errCount++;
if(errCount > 100) return 2;
}
return 1;
}
/**
* @brief
*
* @return uint8_t 1 for complete
*/
uint8_t VL6180x_IsRangeComplete(struct VL6180x_ATY_Dev* dev){
uint8_t status = 0;
if(VL6180x_ReadByte(VL6180x_REG_RESULT_INTERRUPT_STATUS_GPIO, &status, dev) == 1)
return 1;
status &= 0x07;
if((status & 0x04))
return 1;
return 2;
}
/**
* @brief
*
* @return uint8_t 1 for complete
*/
uint8_t VL6180x_WaitRangeComplete(struct VL6180x_ATY_Dev* dev){
uint16_t errCount = 0;
while(VL6180x_IsRangeComplete(dev) != 0){
errCount++;
if(errCount > 100) return 2;
}
return 1;
}
/**
* @brief
*
* @param dev
* @return uint8_t
*/
uint8_t VL6180x_StartRange(struct VL6180x_ATY_Dev* dev){
return VL6180x_WriteByte(VL6180x_REG_SYSRANGE_START, 0x01, dev);
}
/**
* @brief
*
* @param dev
* @return uint8_t
* @note Return results of read reqyest also clears out the interrupt
Be sure to check the return of {@link readRangeStatus} to before using
the return value!
*/
uint8_t VL6180x_ReadRangeResult(uint8_t* range, struct VL6180x_ATY_Dev* dev){
if(VL6180x_ReadByte(VL6180x_REG_RESULT_RANGE_VAL, range, dev) == 1)
return 1;
printf_ATY_D("%sRange: %d\r\n", VL6180x_ATY_TAG, *range);
return 0;
}
/**
* @brief
*
* @param dev
* @return uint8_t
*/
uint8_t VL6180x_ClearInterrupts(struct VL6180x_ATY_Dev* dev){
return VL6180x_WriteByte(VL6180x_REG_SYSTEM_INTERRUPT_CLEAR, 0x07, dev);
}
/**
* @brief
*
* @param range
* @param dev
* @return uint8_t distance in millimeters if valid
* @note tested in 100ms cycle with uart printf in stm32f103c8t6 72MHz(limited by uart)
*/
uint8_t VL6180x_MeasureRangeOnce(uint8_t* range, struct VL6180x_ATY_Dev* dev){
uint8_t errCode = 0;
errCode = 0x00 & VL6180x_WaitDeviceReady(dev); // slower
errCode = 0x10 & VL6180x_StartRange(dev);
errCode = 0x20 & VL6180x_WaitRangeComplete(dev);
errCode = 0x30 & VL6180x_ReadRangeResult(range, dev);
errCode = 0x40 & VL6180x_ClearInterrupts(dev);
return errCode;
}
/**
* @brief
*
* @param range
* @param dev
* @return uint8_t distance in millimeters if valid
* @note tested in 50ms cycle with uart printf in stm32f103c8t6 72MHz(limited by uart)
*/
uint8_t VL6180x_MeasureRangeOnceFast(uint8_t* range, struct VL6180x_ATY_Dev* dev){
uint8_t errCode = 0;
// errCode = 0x00 & VL6180x_WaitDeviceReady(dev);
errCode = 0x10 & VL6180x_StartRange(dev);
// errCode = 0x10 & VL6180x_StartRangeContinuous(10, dev);
errCode = 0x20 & VL6180x_WaitRangeComplete(dev);
errCode = 0x30 & VL6180x_ReadRangeResult(range, dev);
errCode = 0x40 & VL6180x_ClearInterrupts(dev);
return errCode;
}
/**
* @brief request ranging success/error message (retreive after ranging)
*
* @param value
* @param dev
* @return uint8_t one of possible VL6180x_ERROR_* values
*/
uint8_t VL6180x_ReadRangeStatus(uint8_t* status, struct VL6180x_ATY_Dev* dev){
if(VL6180x_ReadByte(VL6180x_REG_RESULT_RANGE_STATUS, status, dev) == 1)
return 1;
return 0;
}
/**
* @brief start continuous ranging
*
* @param period_msOptional Period between ranges in ms.
Values will be rounded down to 10ms units with minimum of 10ms.
Default is 50
* @param dev
* @return uint8_t
*/
uint8_t VL6180x_StartRangeContinuous(uint16_t period_ms, struct VL6180x_ATY_Dev* dev){
uint8_t period_reg = 0;
if(period_ms > 10){
if(period_ms < 2550)
period_reg = (period_ms / 10) - 1;
else
period_reg = 254;
}
// Set ranging inter-measurement
if(VL6180x_WriteByte(SYSRANGE__INTERMEASUREMENT_PERIOD, period_reg, dev) == 1)
return 1;
// Start a continuous range measurement
if(VL6180x_WriteByte(VL6180x_REG_SYSRANGE_START, 0x03, dev) == 1)
return 1;
return 0;
}
/**
* @brief stop continuous range operation
*
* @param dev
* @return uint8_t
* @note stop the continuous range operation, by setting the range register
back to 1, Page 7 of appication notes
*/
uint8_t VL6180x_StopRangeContinuous(struct VL6180x_ATY_Dev* dev){
return VL6180x_WriteByte(VL6180x_REG_SYSRANGE_START, 0x01, dev);
}
/**
* @brief single shot lux measurement
*
* @param gain gain setting, one of VL6180x_ALS_GAIN_*
* @param lux
* @param dev
* @return uint8_t
* @note only for VL6180X
*/
uint8_t VL6180x_ReadLux(uint8_t gain, float* lux, struct VL6180x_ATY_Dev* dev){
uint16_t errCount = 0;
uint8_t byte = 0;
if(VL6180x_ReadByte(VL6180x_REG_SYSTEM_INTERRUPT_CONFIG, &byte, dev) == 1)
return 1;
byte &= ~0x38;
byte |= (0x4 << 3); // IRQ on ALS ready
if(VL6180x_WriteByte(VL6180x_REG_SYSTEM_INTERRUPT_CONFIG, byte, dev) == 1)
return 2;
// 100 ms integration period
if(VL6180x_WriteByte(VL6180x_REG_SYSALS_INTEGRATION_PERIOD_HI, 0, dev) == 1)
return 3;
if(VL6180x_WriteByte(VL6180x_REG_SYSALS_INTEGRATION_PERIOD_LO, 100, dev) == 1)
return 4;
// analog gain
if(gain > VL6180x_ALS_GAIN_40){
gain = VL6180x_ALS_GAIN_40;
}
if(VL6180x_WriteByte(VL6180x_REG_SYSALS_ANALOGUE_GAIN, 0x40 | gain, dev) == 1)
return 5;
// start ALS
if(VL6180x_WriteByte(VL6180x_REG_SYSALS_START, 0x01, dev) == 1)
return 6;
if(VL6180x_ReadByte(VL6180x_REG_RESULT_INTERRUPT_STATUS_GPIO, &byte, dev) == 1)
return 7;
// Poll until "New Sample Ready threshold event" is set
while(4 != ((byte >> 3) & 0x7)){
if(VL6180x_ReadByte(VL6180x_REG_RESULT_INTERRUPT_STATUS_GPIO, &byte, dev) == 1)
return 8;
errCount++;
if(errCount > 1000) return 9;
}
// read lux!
uint8_t luxBytes[2] = {0};
if(VL6180x_ReadBytes(VL6180x_REG_RESULT_ALS_VAL, luxBytes, 2, dev) == 1)
return 10;
*lux = ((luxBytes[0] << 8) | luxBytes[1]);
// clear interrupt
if(VL6180x_WriteByte(VL6180x_REG_SYSTEM_INTERRUPT_CLEAR, 0x07, dev) == 1)
return 11;
*lux *= 0.32; // calibrated count/lux
switch(gain){
case VL6180x_ALS_GAIN_1:
break;
case VL6180x_ALS_GAIN_1_25:
*lux /= 1.25;
break;
case VL6180x_ALS_GAIN_1_67:
*lux /= 1.67;
break;
case VL6180x_ALS_GAIN_2_5:
*lux /= 2.5;
break;
case VL6180x_ALS_GAIN_5:
*lux /= 5;
break;
case VL6180x_ALS_GAIN_10:
*lux /= 10;
break;
case VL6180x_ALS_GAIN_20:
*lux /= 20;
break;
case VL6180x_ALS_GAIN_40:
*lux /= 40;
break;
}
*lux *= 100;
*lux /= 100; // integration time in ms
return 0;
}
#endif /* __VL6180x_ATY_C */
/************************************ etc *************************************/
/* init
// VL6180x ---------------------------------------------------------------------
#include "VL6180x_ATY.h"
uint8_t VL6180x_1_I2C_Soft(uint8_t addr, uint8_t* data_t, uint8_t len, uint8_t rw){
if(rw == __ATY_RW_W)
return I2C_Write(addr, data_t, len, &HW_I2C_ATY_Dev_1);
else if(rw == __ATY_RW_R)
return I2C_Read(addr, data_t, len, &HW_I2C_ATY_Dev_1);
}
uint8_t VL6180x_1_I2C(uint8_t addr, uint8_t* data_t, uint8_t len, uint8_t rw){
if(rw == __ATY_RW_W)
return (uint8_t)HAL_I2C_Master_Transmit(&hi2c1, (addr << 1 | 0), data_t, len, 1000);
else if(rw == __ATY_RW_R)
return (uint8_t)HAL_I2C_Master_Receive(&hi2c1, (addr << 1 | 1), data_t, len, 1000);
return 1;
}
uint8_t VL6180x_1_ATY_id[9] = {0};
struct VL6180x_ATY_Dev VL6180x_ATY_t_1 = {
.addr = VL6180x_ADDRESS,
.id = VL6180x_1_ATY_id,
.i2cProcess = VL6180x_1_I2C,
.lock = __ATY_UNLOCKED
};
*/
/* use
VL6180x_Init(&VL6180x_ATY_t_1);
VL6180x_GetId(idGroup, &VL6180x_ATY_t_1);
VL6180x_SetAddress(0x29, &VL6180x_ATY_t_1);
VL6180x_GetOffset(&offset, &VL6180x_ATY_t_1);
VL6180x_SetOffset(0x0D, &VL6180x_ATY_t_1);
VL6180x_MeasureRangeOnce(&range, &VL6180x_ATY_t_1);
VL6180x_MeasureRangeOnceFast(&range, &VL6180x_ATY_t_1);
// only for VL6180X
VL6180x_ReadLux(VL6180x_ALS_GAIN_40, &lux, &VL6180x_ATY_t_1);
*/
/******************************************************************************/
/******************************** End Of File *********************************/