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