/**
* @file VL6180X_ATY.c
*
* @param Project DEVICE_GENERAL_ATY_LIB
*
* @author ATY
*
* @copyright
* - Copyright 2017 - 2023 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 Familiar functions of VL6180 for all embedded device
*
* @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"
/******************************* 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
*/
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);
if(dev->debugEnable == 1){
uint8_t i = 0;
for(i = 0; i < 9; i++)
dev->LOG("%02X ", id[i]);
dev->LOG("\r\n");
}
if(id[0] != 0x84){ return 0x81; }
return errCode;
}
/**
* @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 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
*
* @param dev
* @return uint8_t
*/
uint8_t VL6180X_ClearInterrupts(struct VL6180X_ATY_Dev* dev)
{
if(VL6180X_WriteByte(VL6180X_REG_SYSTEM_INTERRUPT_CLEAR, 0x07, dev) == 1)
return 1;
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 2;
if((byte & 0x01))
return 1;
return 0;
}
/**
* @brief
*
* @return uint8_t 1 for ready
*/
uint8_t VL6180X_WaitDeviceReady(struct VL6180X_ATY_Dev* dev)
{
uint16_t errCount = 0;
while(VL6180X_IsDeviceReady(dev) != 1){
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 2;
status &= 0x07;
if((status & 0x04))
return 1;
return 0;
}
/**
* @brief
*
* @return uint8_t 1 for complete
*/
uint8_t VL6180X_WaitRangeComplete(struct VL6180X_ATY_Dev* dev)
{
uint16_t errCount = 0;
while(VL6180X_IsRangeComplete(dev) != 1){
errCount++;
if(errCount > 100) return 2;
}
return 1;
}
/**
* @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
*
* @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;
if(dev->debugEnable == 1)
dev->LOG("%d\r\n", *range);
return 0;
}
/**
* @brief
*
* @param dev
* @return uint8_t
*/
uint8_t VL6180X_StartRange(struct VL6180X_ATY_Dev* dev)
{
if(VL6180X_WriteByte(VL6180X_REG_SYSRANGE_START, 0x01, 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)
{
if(VL6180X_WriteByte(VL6180X_REG_SYSRANGE_START, 0x01, dev) == 1)
return 1;
return 0;
}
/**
* @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;
}
return 0;
}
/**
* @brief
*
* @param range
* @param dev
* @return uint8_t distance in millimeters if valid
*/
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(100ms cycle tested)
*/
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 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;
}
/**
* @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;
}
#endif /* __VL6180X_ATY_C */
/************************************ etc *************************************/
/* init */
// uint8_t VL6180X_1_I2C(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);
// }
// struct VL6180X_ATY_Dev VL6180X_ATY_t_1 = {
// .addr = VL6180X_ADDRESS,
// .i2cProcess = VL6180X_1_I2C,
// .lock = _ATY_UNLOCKED,
// .debugEnable = 0,
// .LOG = printf
// };
// VL6180X_Init(&VL6180X_ATY_t_1);
/* use */
// VL6180X_ATY_t_1.debugEnable = 1;
// uint8_t idGroup[9] = {0};
// VL6180X_GetId(idGroup, &VL6180X_ATY_t_1);
// VL6180X_SetOffset(10, &VL6180X_ATY_t_1);
// VL6180X_SetAddress(0x10, &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);
// rcPara_t rcParam_VL6180 = {0.028, 0};
// rcLpFilter(&rcParam_VL6180, value);
/******************************************************************************/
/******************************** End Of File *********************************/