/** * @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 *********************************/