/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file app_tof_vl53l0x_range.c * @author Yunhorn (r) Technology Limited Application Team * @brief Application of the LRWAN Middleware ****************************************************************************** * @attention * * Copyright (c) 2023 Yunhorn Technology Limited. * Copyright (c) 2023 Shenzhen Yunhorn Technology Co., Ltd. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm32xxx_hal.h" /* USER CODE BEGIN Includes */ #include #include "X-WL55_WLE5_53L0X.h" #include "main.h" #include "vl53l0x_api.h" #include #include "sys_app.h" /** * @defgroup Configuration Static configuration * @{ */ /** @} */ /* config group */ #ifndef MIN # define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif /** * @defgroup ErrCode Errors code shown on display * @{ */ #define STS_MAX_L0_RANGE ((uint32_t) 2500) #define ERR_DETECT -1 #define ERR_DEMO_RANGE_ONE 1 #define ERR_DEMO_RANGE_MULTI 2 extern I2C_HandleTypeDef hi2c2; #define X_WL55_WLE5_53L0X_hi2c hi2c2 /** }@} */ /* defgroup ErrCode */ /* USER CODE END Includes */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ typedef enum { LONG_RANGE = 0, /*!< Long range mode */ HIGH_SPEED = 1, /*!< High speed mode */ HIGH_ACCURACY = 2, /*!< High accuracy mode */ } RangingConfig_e; /** * Global ranging struct */ VL53L0X_RangingMeasurementData_t RangingMeasurementData; /** leaky factor for filtered range * * r(n) = averaged_r(n-1)*leaky +r(n)(1-leaky) * * */ int LeakyFactorFix8 = (int)( 0.6 *256); // 0.6 for ranging, 0.0 for gesture detect /** How many device detect set by @a DetectSensors()*/ int nDevPresent=0; /** bit is index in VL53L0XDevs that is not necessary the dev id of the BSP */ int nDevMask=0; int nSensorPresent; volatile int sts_tof_distance_data[MAX_TOF_COUNT]={0,0,0}; extern volatile uint8_t sensor_data_ready; VL53L0X_Dev_t VL53L0XDevs[]={ {.Id=XNUCLEO53L0X_LEFT, .DevLetter='l',.I2cHandle=&X_WL55_WLE5_53L0X_hi2c, .I2cDevAddr=0x52}, {.Id=XNUCLEO53L0X_CENTER,.DevLetter='c', .I2cHandle=&X_WL55_WLE5_53L0X_hi2c, .I2cDevAddr=0x52}, {.Id=XNUCLEO53L0X_RIGHT, .DevLetter='r',.I2cHandle=&X_WL55_WLE5_53L0X_hi2c, .I2cDevAddr=0x52}, }; /* USER CODE BEGIN PFP */ /* Private function prototypes -----------------------------------------------*/ //void ResetAndDetectSensor(int SetDisplay); void sts_tof_vl53l0x_Sensor_SetNewRange(VL53L0X_Dev_t *pDev, VL53L0X_RangingMeasurementData_t *pRange); void sts_tof_vl53l0x_SetupSingleShot(RangingConfig_e rangingConfig); /* USER CODE END PFP */ /* USER CODE BEGIN 0 */ /** * Handle Error * * Set err on display and loop forever * @param err Error case code */ void HandleError(int err){ //char msg[16]; //sprintf(msg,"Er%d", err); APP_LOG(TS_OFF, VLEVEL_L,"Er %04u\r\n",err); //while(1){}; } /** * Reset all sensor then goes true presence detection * * All present devices are data initiated and assigned with their final address * @return */ int sts_tof_vl53l0x_DetectSensors(void) { int i; uint16_t Id; int status; int FinalAddress; nDevPresent = 0; for (i=0; i < MAX_TOF_COUNT; i++) { XWL55_WLE5_53L0X_ResetId(i,0); //XWL55_WLE5_53L0X_SetIntrStateId(0,i); } /* detect all sensors (even on-board)*/ for (i=0; i < MAX_TOF_COUNT; i++) { VL53L0X_Dev_t *pDev; pDev = &VL53L0XDevs[i]; pDev->I2cDevAddr = 0x52; pDev->Present = 0; XWL55_WLE5_53L0X_ResetId(pDev->Id, 1); HAL_Delay(3); FinalAddress = 0x52+(i+1)*2; //APP_LOG(TS_OFF, VLEVEL_H, "\r\n Detect TOF sensors #%u with I2CDevAddr=0x%02x \r\n", i, pDev->I2cDevAddr); do { /* Set I2C standard mode (400 KHz) before doing the first register access */ //if (status == VL53L0X_ERROR_NONE) status = VL53L0X_WrByte(pDev, 0x88, 0x00); /* Try to read one register using default 0x52 address */ status = VL53L0X_RdWord(pDev, VL53L0X_REG_IDENTIFICATION_MODEL_ID, &Id); //APP_LOG(TS_OFF, VLEVEL_H, "#%u read id = %04x I2C ADDR=0x%2X\r\n",i, Id, pDev->I2cDevAddr); if (status) { APP_LOG(TS_OFF, VLEVEL_H, "# Read id fail \r\n"); break; } if (Id == 0xEEAA) { /* Sensor is found => Change its I2C address to final one */ status = VL53L0X_SetDeviceAddress(pDev,FinalAddress); if (status != 0) { APP_LOG(TS_OFF, VLEVEL_H, "#i VL53L0X_SetDeviceAddress fail\r\n"); break; } pDev->I2cDevAddr = FinalAddress; /* Check all is OK with the new I2C address and initialize the sensor */ status = VL53L0X_RdWord(pDev, VL53L0X_REG_IDENTIFICATION_MODEL_ID, &Id); if (status !=0) { APP_LOG(TS_OFF, VLEVEL_H, "#i VL53L0X_RdWord fail\r\n"); break; } status = VL53L0X_DataInit(pDev); if( status == 0 ){ pDev->Present = 1; } else{ APP_LOG(TS_OFF, VLEVEL_H, "VL53L0X_DataInit %d fail\r\n", Id); break; } nDevPresent++; nDevMask |= 1 << i; pDev->Present = 1; APP_LOG(TS_OFF, VLEVEL_H, "VL53L0X %d Present and initiated to final 0x%2x, Position Mask=0x%02x\r\n", pDev->Id, pDev->I2cDevAddr, nDevMask); } else { APP_LOG(TS_OFF, VLEVEL_H, "# unknown ID %x\r\n", Id); status = 1; } } while(0); /* Display detected sensor(s) */ if (status) { XWL55_WLE5_53L0X_ResetId(i,0); } } return nDevPresent; } /** * Setup all detected sensors for single shot mode and setup ranging configuration */ void sts_tof_vl53l0x_SetupSingleShot(RangingConfig_e rangingConfig) { int i; int status=VL53L0X_ERROR_NONE; uint8_t VhvSettings; uint8_t PhaseCal; uint32_t refSpadCount; uint8_t isApertureSpads; FixPoint1616_t signalLimit = (FixPoint1616_t)(0.25*65536); FixPoint1616_t sigmaLimit = (FixPoint1616_t)(18*65536); uint32_t timingBudget = 33000; uint8_t preRangeVcselPeriod = 14; uint8_t finalRangeVcselPeriod = 10; // uart_printf("\r\n######### start setup for single shot \r\n"); for( i=0; i< MAX_TOF_COUNT; i++){ if( VL53L0XDevs[i].Present){ APP_LOG(TS_OFF, VLEVEL_H, "\r\n ###### Starting Range #%u sensor \r\n",i); status=VL53L0X_StaticInit(&VL53L0XDevs[i]); if( status ){ APP_LOG(TS_OFF, VLEVEL_H, "VL53L0X_StaticInit failed\n"); } status = VL53L0X_PerformRefCalibration(&VL53L0XDevs[i], &VhvSettings, &PhaseCal); if( status ){ APP_LOG(TS_OFF, VLEVEL_H, "VL53L0X_PerformRefCalibration failed\n"); } status = VL53L0X_PerformRefSpadManagement(&VL53L0XDevs[i], &refSpadCount, &isApertureSpads); if( status ){ APP_LOG(TS_OFF, VLEVEL_H, "VL53L0X_PerformRefSpadManagement failed\n"); } status = VL53L0X_SetDeviceMode(&VL53L0XDevs[i], VL53L0X_DEVICEMODE_SINGLE_RANGING); // Setup in single ranging mode if( status ){ APP_LOG(TS_OFF, VLEVEL_H, "VL53L0X_SetDeviceMode failed\n"); } status = VL53L0X_SetLimitCheckEnable(&VL53L0XDevs[i], VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE, 1); // Enable Sigma limit if( status ){ APP_LOG(TS_OFF, VLEVEL_H, "VL53L0X_SetLimitCheckEnable failed\n"); } status = VL53L0X_SetLimitCheckEnable(&VL53L0XDevs[i], VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, 1); // Enable Signa limit if( status ){ APP_LOG(TS_OFF, VLEVEL_H, "VL53L0X_SetLimitCheckEnable failed\n"); } /* Ranging configuration */ switch(rangingConfig) { case LONG_RANGE: signalLimit = (FixPoint1616_t)(0.1*65536); sigmaLimit = (FixPoint1616_t)(60*65536); timingBudget = 33000; preRangeVcselPeriod = 18; finalRangeVcselPeriod = 14; break; case HIGH_ACCURACY: signalLimit = (FixPoint1616_t)(0.25*65536); sigmaLimit = (FixPoint1616_t)(18*65536); timingBudget = 200000; preRangeVcselPeriod = 14; finalRangeVcselPeriod = 10; break; case HIGH_SPEED: signalLimit = (FixPoint1616_t)(0.25*65536); sigmaLimit = (FixPoint1616_t)(32*65536); timingBudget = 20000; preRangeVcselPeriod = 14; finalRangeVcselPeriod = 10; break; default: APP_LOG(TS_OFF, VLEVEL_H, "Not Supported"); break; } status = VL53L0X_SetLimitCheckValue(&VL53L0XDevs[i], VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, signalLimit); if( status ){ APP_LOG(TS_OFF, VLEVEL_H, "VL53L0X_SetLimitCheckValue failed\n"); } status = VL53L0X_SetLimitCheckValue(&VL53L0XDevs[i], VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE, sigmaLimit); if( status ){ APP_LOG(TS_OFF, VLEVEL_H, "VL53L0X_SetLimitCheckValue failed\n"); } status = VL53L0X_SetMeasurementTimingBudgetMicroSeconds(&VL53L0XDevs[i], timingBudget); if( status ){ APP_LOG(TS_OFF, VLEVEL_H, "VL53L0X_SetMeasurementTimingBudgetMicroSeconds failed\n"); } status = VL53L0X_SetVcselPulsePeriod(&VL53L0XDevs[i], VL53L0X_VCSEL_PERIOD_PRE_RANGE, preRangeVcselPeriod); if( status ){ APP_LOG(TS_OFF, VLEVEL_H, "VL53L0X_SetVcselPulsePeriod failed\n"); } status = VL53L0X_SetVcselPulsePeriod(&VL53L0XDevs[i], VL53L0X_VCSEL_PERIOD_FINAL_RANGE, finalRangeVcselPeriod); if( status ){ APP_LOG(TS_OFF, VLEVEL_H, "VL53L0X_SetVcselPulsePeriod failed\n"); } status = VL53L0X_PerformRefCalibration(&VL53L0XDevs[i], &VhvSettings, &PhaseCal); if( status ){ APP_LOG(TS_OFF, VLEVEL_H, "VL53L0X_PerformRefCalibration failed\n"); } VL53L0XDevs[i].LeakyFirst =1; } } } /* Store new ranging data into the device structure, apply leaky integrator if needed */ void sts_tof_vl53l0x_Sensor_SetNewRange(VL53L0X_Dev_t *pDev, VL53L0X_RangingMeasurementData_t *pRange) { if( pRange->RangeStatus == 0 ){ if( pDev->LeakyFirst ){ pDev->LeakyFirst = 0; pDev->LeakyRange = pRange->RangeMilliMeter; } else{ pDev->LeakyRange = (pDev->LeakyRange*LeakyFactorFix8 + (256-LeakyFactorFix8)*pRange->RangeMilliMeter)>>8; } } else{ pDev->LeakyFirst = 1; } } /* USER CODE END 0 */ void STS_TOF250_Range_Process(void) { #define I2C_TIME_OUT_BASE 10 #define I2C_TIME_OUT_BYTE 1 int status; uint8_t pdata[2]={0x0,0x0}; uint32_t count=2; int i2c_time_out = I2C_TIME_OUT_BASE + count*I2C_TIME_OUT_BYTE; sensor_data_ready = 0 ; sts_tof_distance_data[0] = STS_MAX_L0_RANGE; sts_tof_distance_data[1] = STS_MAX_L0_RANGE; sts_tof_distance_data[2] = STS_MAX_L0_RANGE; status = HAL_I2C_Master_Receive(&hi2c2, TOF250_I2C_ADDR, pdata, count, i2c_time_out); if (status == HAL_OK) { APP_LOG(TS_OFF, VLEVEL_H, "\r\n## TOF250 ranging value %02x %02x %4d ",pdata[0],pdata[1], *pdata); sts_tof_distance_data[2] = pdata[0]*255+pdata[1]; sensor_data_ready = 1; APP_LOG(TS_OFF, VLEVEL_H, "\r\n## Measured Range: \r\nTOF #0 = %4u mm, \r\nTOF #1 = %4u mm, \r\nTOF #2 = %4u mm\r\n", (int)sts_tof_distance_data[0],(int)sts_tof_distance_data[1],(int)sts_tof_distance_data[2]); } } void STS_TOF_VL53L0X_Range_Process(void) { int status=0, i; RangingConfig_e RangingConfig = LONG_RANGE; //HIGH_ACCURACY; //LONG_RANGE; XWL55_WLE5_53L0X_Init(); if ((nDevMask ==0) || (nSensorPresent ==0)) { nSensorPresent = sts_tof_vl53l0x_DetectSensors(); // confirm sensor online APP_LOG(TS_OFF, VLEVEL_H, "\r\n %u pcs sensor(s) online \r\n", nSensorPresent); } sts_tof_distance_data[0] = 0; sts_tof_distance_data[1] = 0; sts_tof_distance_data[2] = 0; if (nSensorPresent > 0) { // RangingConfig == HIGH ACCURACY, LONG RANGE, HIGH SPEED sts_tof_vl53l0x_SetupSingleShot(RangingConfig); sensor_data_ready = 0 ; for (i=0; i< MAX_TOF_COUNT; i++) { if (VL53L0XDevs[i].Present ==1) { uint8_t rep=0; do { rep++; status = VL53L0X_PerformSingleRangingMeasurement(&VL53L0XDevs[i], &RangingMeasurementData); if (status ==0) { sts_tof_vl53l0x_Sensor_SetNewRange(&VL53L0XDevs[i],&RangingMeasurementData); if( RangingMeasurementData.RangeStatus == 0 ) { sts_tof_distance_data[i] = (int)VL53L0XDevs[i].LeakyRange; nDevMask |= (1 << i); sensor_data_ready |= 1; } else { //HandleError(ERR_DEMO_RANGE_ONE); APP_LOG(TS_OFF, VLEVEL_H,"\r\n#%u sensor ERR code = %04u\r\n",i, ERR_DEMO_RANGE_ONE); } // ########## two conditions // ########## 1) return status ==0, // ########## 2) and ranging status for valid ranging value !!!!!!!!!!!!!!!!! } HAL_Delay(1); } while ((RangingMeasurementData.RangeStatus != 0)&&(rep <10)); sts_tof_distance_data[i] = (int)VL53L0XDevs[i].LeakyRange ==0?STS_MAX_L0_RANGE:(int)VL53L0XDevs[i].LeakyRange; } HAL_Delay(5); } // for i < MAX_TOF_COUNT if (sensor_data_ready != 0) { APP_LOG(TS_OFF, VLEVEL_L, "\r\n## Measured Range: \r\nTOF #0 = %4u mm, \r\nTOF #1 = %4u mm, \r\nTOF #2 = %4u mm\r\n", (int)sts_tof_distance_data[0],(int)sts_tof_distance_data[1],(int)sts_tof_distance_data[2]); } } // nSensorPresent >0 // reset for next ranging //nDevMask = 0; //nSensorPresent = 0; } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/