Single Ranging example with High Accuracy for the VL53L0X Time-of-Flight sensor

Dependencies:   mbed vl53l0x_api

main.cpp

Committer:
adonisduo
Date:
2019-05-03
Revision:
2:98cd8c47c1ad
Parent:
0:b6867e1a23fa

File content as of revision 2:98cd8c47c1ad:

#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;
}

VL53L0X_Error rangingTest(VL53L0X_Dev_t *pMyDevice)
{
    VL53L0X_Error Status = VL53L0X_ERROR_NONE;
    VL53L0X_RangingMeasurementData_t    RangingMeasurementData;
    int i;
    FixPoint1616_t LimitCheckCurrent;
    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
        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) // needed if a coverglass is used and no calibration has been performed
    {
        printf ("Call of VL53L0X_PerformRefSpadManagement\n");
        Status = VL53L0X_PerformRefSpadManagement(pMyDevice,
                &refSpadCount, &isApertureSpads); // Device Initialization
        printf ("refSpadCount = %d, isApertureSpads = %d\n", refSpadCount, isApertureSpads);
        print_pal_error(Status);
    }

    if(Status == VL53L0X_ERROR_NONE)
    {

        // no need to do this when we use VL53L0X_PerformSingleRangingMeasurement
        printf ("Call of VL53L0X_SetDeviceMode\n");
        Status = VL53L0X_SetDeviceMode(pMyDevice, VL53L0X_DEVICEMODE_SINGLE_RANGING); // Setup in single ranging mode
        print_pal_error(Status);
    }

    // Enable/Disable Sigma and Signal check
    if (Status == VL53L0X_ERROR_NONE) {
        Status = VL53L0X_SetLimitCheckEnable(pMyDevice,
                VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE, 1);
    }
    if (Status == VL53L0X_ERROR_NONE) {
        Status = VL53L0X_SetLimitCheckEnable(pMyDevice,
                VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, 1);
    }
                
    if (Status == VL53L0X_ERROR_NONE) {
        Status = VL53L0X_SetLimitCheckValue(pMyDevice,
                VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
                (FixPoint1616_t)(0.25*65536));
    }           
    if (Status == VL53L0X_ERROR_NONE) {
        Status = VL53L0X_SetLimitCheckValue(pMyDevice,
                VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE,
                (FixPoint1616_t)(18*65536));            
    }
    if (Status == VL53L0X_ERROR_NONE) {
        Status = VL53L0X_SetMeasurementTimingBudgetMicroSeconds(pMyDevice,
                200000);
    }
    
    if(Status == VL53L0X_ERROR_NONE)
    {
        printf ("Call of VL53L0X_SetRangeFractionEnable\n");
        Status = VL53L0X_SetRangeFractionEnable(pMyDevice, 0x01);
    }
    /*
     *  Step  4 : Test ranging mode
     */

    if(Status == VL53L0X_ERROR_NONE)
    {
        for(i=0;i<100;i++){
            //printf ("Call of VL53L0X_PerformSingleRangingMeasurement\n");
            Status = VL53L0X_PerformSingleRangingMeasurement(pMyDevice,
                    &RangingMeasurementData);

            //print_pal_error(Status);
            //print_range_status(&RangingMeasurementData);

            VL53L0X_GetLimitCheckCurrent(pMyDevice,
                    VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD, &LimitCheckCurrent);

            printf("RANGE IGNORE THRESHOLD: %f\n", (float)LimitCheckCurrent/65536.0f);


            if (Status != VL53L0X_ERROR_NONE) break;

            //printf("Measured distance: %i\n\n", RangingMeasurementData.RangeMilliMeter);


        }
    }
    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.baud(460800);
    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) 
        {
            Status = VL53L0X_SetLimitCheckValue(pMyDevice, VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, (FixPoint1616_t)(0.25*65536));
            print_pal_error(Status);
        }
        if (Status == VL53L0X_ERROR_NONE) 
        {
            Status = VL53L0X_SetLimitCheckValue(pMyDevice, VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE, (FixPoint1616_t)(16*65536));
            print_pal_error(Status);
        }
        if (Status == VL53L0X_ERROR_NONE) 
        {
            Status = VL53L0X_SetMeasurementTimingBudgetMicroSeconds(pMyDevice, 200000);
            print_pal_error(Status);
        }
        
        if(Status == VL53L0X_ERROR_NONE)
        {
            printf ("Call of VL53L0X_SetRangeFractionEnable\n");
            Status = VL53L0X_SetRangeFractionEnable(pMyDevice, 0x01);
            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 accumulatingNbr = 24;
            uint32_t measureTimes = 1;
            
            uint32_t measurement;
            uint32_t no_of_measurements = accumulatingNbr * measureTimes;


            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);
//                    Status = VL53L0X_PerformSingleRangingMeasurement(pMyDevice, pRangingMeasurementData);
                    *(pResults + measurement) = pRangingMeasurementData->RangeMilliMeter * 100 + pRangingMeasurementData->RangeFractionalPart / 64 * 25;
                    //printf("In loop measurement %lu: %d.%d\n", measurement, pRangingMeasurementData->RangeMilliMeter, pRangingMeasurementData->RangeFractionalPart/64*25);

                    // 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(int times = 0; times < measureTimes; times++)
                {
                    float resMeasured = 0;
                    float resAccumulated = 0;
                    float resFiltered = 0;
                    float resMax = 0;
                    float resMin = 0;
                    
                    for(uint16_t aNbr = 0; aNbr < accumulatingNbr ; aNbr++)
                    {
                        resMeasured = *(pResults + aNbr + (uint16_t)(times * (float)accumulatingNbr));
                        resAccumulated += resMeasured;
                        if(resMeasured > resMax)
                        {
                            resMax = resMeasured;
                        }
                        if(resMeasured < resMin)
                        {
                            resMin = resMeasured;
                        }
                    }
                    
                    resFiltered = (resAccumulated - resMax - resMin) / (accumulatingNbr - 2) / 100;
                    printf("[%3d] %3.3f \n", times, resFiltered);    
//                    if (times % 10 == 9)
//                    {
//                        printf("\n");
//                    }              
                }
                    
                
//                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());
            if(Status == VL53L0X_ERROR_NONE)
            {
                Status = rangingTest(pMyDevice);
            }
       }
}