VL53L0X and STM32 Nucleo MBed example

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

Name Link
ST Nucleo STM32 Development Board NUCLEO-F446RE, STM32 STM32F446RET6 MCU, supports Arduino
VL53L0X VL53L0X Time-of-Flight (ToF) Laser Ranging Sensor Breakout 940nm
Connecting wire Free shipping Dupont line 120pcs 20cm male to male + male to female and female to female jumper wire

Schematics/Layout

stm32 nucleo and VL53L0X sensor
stm32 nucleo and VL53L0X sensor

 

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

This div height required for enabling the sticky sidebar
Ad Clicks : Ad Views : Ad Clicks : Ad Views : Ad Clicks : Ad Views :