In this example we connect a VL53L0X to a STM32 Nucleo
The VL53L0X is a new generation Time-of-Flight (ToF) laser-ranging module housed in the smallest package on the market today, providing accurate distance measurement whatever the target reflectances unlike conventional technologies. It can measure absolute distances up to 2m, setting a new benchmark in ranging performance levels, opening the door to various new applications.
The VL53L0X integrates a leading-edge SPAD array (Single Photon Avalanche Diodes) and embeds ST’s second generation FlightSenseTM patented technology.
Here is a typical module
The VL53L0X’s 940 nm VCSEL emitter (Vertical Cavity Surface-Emitting Laser), is totally invisible to the human eye, coupled with internal physical infrared filters, it enables longer ranging distances, higher immunity to ambient light, and better robustness to cover glass optical crosstalk.
Parts List
This is the parts that I used
Schematics/Layout
Code
You need to import this example into the MBed compiler. Build it and copy the bin file to the MBEd drive that is present on your PC
[codesyntax lang=”cpp”]
#include "mbed.h" #include "vl53l0x_api.h" #include "vl53l0x_platform.h" #include "vl53l0x_i2c_platform.h" Serial pc(SERIAL_TX, SERIAL_RX); void print_pal_error(VL53L0X_Error Status){ char buf[VL53L0X_MAX_STRING_LENGTH]; VL53L0X_GetPalErrorString(Status, buf); printf("API Status: %i : %s\n", Status, buf); } void print_range_status(VL53L0X_RangingMeasurementData_t* pRangingMeasurementData){ char buf[VL53L0X_MAX_STRING_LENGTH]; uint8_t RangeStatus; /* * New Range Status: data is valid when pRangingMeasurementData->RangeStatus = 0 */ RangeStatus = pRangingMeasurementData->RangeStatus; VL53L0X_GetRangeStatusString(RangeStatus, buf); printf("Range Status: %i : %s\n", RangeStatus, buf); } VL53L0X_Error WaitMeasurementDataReady(VL53L0X_DEV Dev) { VL53L0X_Error Status = VL53L0X_ERROR_NONE; uint8_t NewDatReady=0; uint32_t LoopNb; // Wait until it finished // use timeout to avoid deadlock if (Status == VL53L0X_ERROR_NONE) { LoopNb = 0; do { Status = VL53L0X_GetMeasurementDataReady(Dev, &NewDatReady); if ((NewDatReady == 0x01) || Status != VL53L0X_ERROR_NONE) { break; } LoopNb = LoopNb + 1; VL53L0X_PollingDelay(Dev); } while (LoopNb < VL53L0X_DEFAULT_MAX_LOOP); if (LoopNb >= VL53L0X_DEFAULT_MAX_LOOP) { Status = VL53L0X_ERROR_TIME_OUT; } } return Status; } VL53L0X_Error WaitStopCompleted(VL53L0X_DEV Dev) { VL53L0X_Error Status = VL53L0X_ERROR_NONE; uint32_t StopCompleted=0; uint32_t LoopNb; // Wait until it finished // use timeout to avoid deadlock if (Status == VL53L0X_ERROR_NONE) { LoopNb = 0; do { Status = VL53L0X_GetStopCompletedStatus(Dev, &StopCompleted); if ((StopCompleted == 0x00) || Status != VL53L0X_ERROR_NONE) { break; } LoopNb = LoopNb + 1; VL53L0X_PollingDelay(Dev); } while (LoopNb < VL53L0X_DEFAULT_MAX_LOOP); if (LoopNb >= VL53L0X_DEFAULT_MAX_LOOP) { Status = VL53L0X_ERROR_TIME_OUT; } } return Status; } int main() { VL53L0X_Error Status = VL53L0X_ERROR_NONE; VL53L0X_Dev_t MyDevice; VL53L0X_Dev_t *pMyDevice = &MyDevice; VL53L0X_Version_t Version; VL53L0X_Version_t *pVersion = &Version; VL53L0X_DeviceInfo_t DeviceInfo; int32_t status_int; pc.printf("VL53L0X API Simple Ranging Example\r\n"); // Initialize Comms pMyDevice->I2cDevAddr = 0x52; pMyDevice->comms_type = 1; pMyDevice->comms_speed_khz = 400; pc.printf("Init comms\r\n"); if(Status == VL53L0X_ERROR_NONE) { status_int = VL53L0X_GetVersion(pVersion); if (status_int != 0) Status = VL53L0X_ERROR_CONTROL_INTERFACE; } pc.printf("VL53L0X API Version: %d.%d.%d (revision %d)\r\n", pVersion->major, pVersion->minor ,pVersion->build, pVersion->revision); int addr; addr = VL53L0X_scan(); printf("Device found at: %i\r\n", addr); //uint8_t data; //data=0; if(Status == VL53L0X_ERROR_NONE) { printf ("Call of VL53L0X_DataInit\n"); uint16_t osc_calibrate_val=0; Status = VL53L0X_RdWord(&MyDevice, VL53L0X_REG_OSC_CALIBRATE_VAL,&osc_calibrate_val); printf("%i\n",osc_calibrate_val); Status = VL53L0X_DataInit(&MyDevice); // Data initialization print_pal_error(Status); } if(Status == VL53L0X_ERROR_NONE) { Status = VL53L0X_GetDeviceInfo(&MyDevice, &DeviceInfo); if(Status == VL53L0X_ERROR_NONE) { printf("VL53L0X_GetDeviceInfo:\n"); printf("Device Name : %s\n", DeviceInfo.Name); printf("Device Type : %s\n", DeviceInfo.Type); printf("Device ID : %s\n", DeviceInfo.ProductId); printf("ProductRevisionMajor : %d\n", DeviceInfo.ProductRevisionMajor); printf("ProductRevisionMinor : %d\n", DeviceInfo.ProductRevisionMinor); if ((DeviceInfo.ProductRevisionMinor != 1) && (DeviceInfo.ProductRevisionMinor != 1)) { printf("Error expected cut 1.1 but found cut %d.%d\n", DeviceInfo.ProductRevisionMajor, DeviceInfo.ProductRevisionMinor); Status = VL53L0X_ERROR_NOT_SUPPORTED; } } print_pal_error(Status); } VL53L0X_RangingMeasurementData_t RangingMeasurementData; VL53L0X_RangingMeasurementData_t *pRangingMeasurementData = &RangingMeasurementData; Status = VL53L0X_ERROR_NONE; uint32_t refSpadCount; uint8_t isApertureSpads; uint8_t VhvSettings; uint8_t PhaseCal; if(Status == VL53L0X_ERROR_NONE) { printf ("Call of VL53L0X_StaticInit\n"); Status = VL53L0X_StaticInit(pMyDevice); // Device Initialization // StaticInit will set interrupt by default print_pal_error(Status); } if(Status == VL53L0X_ERROR_NONE) { printf ("Call of VL53L0X_PerformRefCalibration\n"); Status = VL53L0X_PerformRefCalibration(pMyDevice, &VhvSettings, &PhaseCal); // Device Initialization print_pal_error(Status); } if(Status == VL53L0X_ERROR_NONE) { printf ("Call of VL53L0X_PerformRefSpadManagement\n"); Status = VL53L0X_PerformRefSpadManagement(pMyDevice, &refSpadCount, &isApertureSpads); // Device Initialization print_pal_error(Status); } if(Status == VL53L0X_ERROR_NONE) { printf ("Call of VL53L0X_SetDeviceMode\n"); Status = VL53L0X_SetDeviceMode(pMyDevice, VL53L0X_DEVICEMODE_CONTINUOUS_RANGING); // Setup in single ranging mode print_pal_error(Status); } if(Status == VL53L0X_ERROR_NONE) { printf ("Call of VL53L0X_StartMeasurement\n"); Status = VL53L0X_StartMeasurement(pMyDevice); print_pal_error(Status); } if(Status == VL53L0X_ERROR_NONE) { uint32_t measurement; uint32_t no_of_measurements = 32; uint16_t* pResults = (uint16_t*)malloc(sizeof(uint16_t) * no_of_measurements); for(measurement=0; measurement<no_of_measurements; measurement++) { Status = WaitMeasurementDataReady(pMyDevice); if(Status == VL53L0X_ERROR_NONE) { Status = VL53L0X_GetRangingMeasurementData(pMyDevice, pRangingMeasurementData); *(pResults + measurement) = pRangingMeasurementData->RangeMilliMeter; printf("In loop measurement %lu: %d\n", measurement, pRangingMeasurementData->RangeMilliMeter); // Clear the interrupt VL53L0X_ClearInterruptMask(pMyDevice, VL53L0X_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY); VL53L0X_PollingDelay(pMyDevice); } else { break; } } if(Status == VL53L0X_ERROR_NONE) { for(measurement=0; measurement<no_of_measurements; measurement++) { printf("measurement %lu: %d\n", measurement, *(pResults + measurement)); } } free(pResults); } if(Status == VL53L0X_ERROR_NONE) { printf ("Call of VL53L0X_StopMeasurement\n"); Status = VL53L0X_StopMeasurement(pMyDevice); } if(Status == VL53L0X_ERROR_NONE) { printf ("Wait Stop to be competed\n"); Status = WaitStopCompleted(pMyDevice); } if(Status == VL53L0X_ERROR_NONE) Status = VL53L0X_ClearInterruptMask(pMyDevice, VL53L0X_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY); while (true) if (pc.readable()) pc.putc(pc.getc()); }
[/codesyntax]
Output
Use a program like teraterm and open the serial port of your STM32 Nucleo
Links
https://www.st.com/resource/en/datasheet/vl53l0x.pdf