Sample MBed program running ST XNucleo VL53L1CB ToF sensors directly connected to the the F401. Uses interrupts to cope with up to 3 sensors in multizone mode. Includes MBed V6.4

Dependencies:   X_NUCLEO_53L1A2

main.cpp

Committer:
charlesmn
Date:
2020-11-09
Revision:
0:2ee129a3b1e8
Child:
1:51e9344a1f33

File content as of revision 0:2ee129a3b1e8:

/*
 *  This VL53L1 test application performs range measurements
 *  using the onboard embedded centre sensor and two satelites, in ranging, interrupt mode.
 *  This program does not use the expansion board and the sensors a directly connected to the F401.
 *  Measured ranges are ouput on the Serial Port, running at 115200 baud.
 *
 * This is designed to work with MBed V2 , MBed V5 and MBed V6.
 *
 *
 *  The Reset button can be used to restart the program.
 */
 
#include <stdio.h>

#include "mbed.h"
#include "XNucleo53L1A1.h"
#include "ToF_I2C.h"
#include <time.h>

// i2c comms pins
#define I2C_SDA   D14 
#define I2C_SCL   D15 

// i2c addresses the sensors are configured to be
#define NEW_SENSOR_CENTRE_ADDRESS   0x56
#define NEW_SENSOR_LEFT_ADDRESS     0x58
#define NEW_SENSOR_RIGHT_ADDRESS    0x5a


#define NUM_SENSORS 3

// define the sensor interrupt pins. This much match the wiring!
PinName CentreIntPin = A2;
PinName LeftIntPin = D9;
PinName RightIntPin = D4;


// MBed V6.4 has renamed wait_ms and UnbufferedSerial replaces Serial
#if (MBED_VERSION  > 60300) 
UnbufferedSerial  pc(SERIAL_TX, SERIAL_RX); 
extern "C" void wait_ms(int ms);
#else
Serial pc(SERIAL_TX, SERIAL_RX); 
#endif

static int int_centre_result = 0;
static int int_left_result = 0;
static int int_right_result = 0;


class WaitForMeasurement {
public:


// this class services the interrupts from the ToF sensors.
// There is a limited amount you can do in an interrupt routine; printfs,mutexes break them among other things.
// We keep things simple by only raising a flag so all the real work is done outside the interrupt.
// This is designed around MBED V2 which doesn't have the RTOS features that would make this work nicely e.g. semaphores/queues.
WaitForMeasurement(): _interrupt(A1)
{
}


    // constructor 
    WaitForMeasurement(PinName pin, uint8_t slave_address) : _interrupt(pin)          // create the InterruptIn on the pin specified 
    {
        i2c_slave_address = slave_address;
        _interrupt.rise(callback(this, &WaitForMeasurement::got_interrupt)); // attach routine to deal with interrupt
        
    }
    

  // function is called every time an interupt is seen. A flag is raised which allows the main routine to service the interupt.
    void got_interrupt()
    {
    
        // identify which sensor this instance relates to and flag an interrupt has occured
        if (i2c_slave_address == NEW_SENSOR_CENTRE_ADDRESS)
            int_centre_result = 1;  //flag to main that interrupt happened
        if (i2c_slave_address == NEW_SENSOR_LEFT_ADDRESS)
            int_left_result = 1;   //flag to main that interrupt happened
        if (i2c_slave_address == NEW_SENSOR_RIGHT_ADDRESS)
            int_right_result = 1;  //flag to main that interrupt happened
    }

    
    //destructor
    ~WaitForMeasurement()
    {
        printf("destruction \n");
    }

private:
    InterruptIn _interrupt;
    int status;
    uint8_t   i2c_slave_address;
    
};

 
/*=================================== Main ==================================
=============================================================================*/
int main()
{   
    int status;
    VL53L1X * Sensor;
    VL53L1X * SensorCentre;
    VL53L1X * SensorLeft;
    VL53L1X * SensorRight;
    DigitalOut xshutdownCentre(D9);
    DigitalOut xshutdownLeft(D4);
    DigitalOut xshutdownRight(D3);

    uint8_t ToFSensor = 1; 
  
    
    WaitForMeasurement* int2;
    WaitForMeasurement* int1;
    WaitForMeasurement* int3;

    pc.baud(115200);  // baud rate is important as printf statements take a lot of time

    printf("VL53L1CB_NoShield_3sensors_interrupt_ranging mbed = %d \r\n",MBED_VERSION);

// create the i2c instance
    ToF_DevI2C *dev_I2C = new ToF_DevI2C(I2C_SDA, I2C_SCL);
// create the sensor instances    
    SensorCentre = new VL53L1X(dev_I2C, &xshutdownCentre, CentreIntPin); 
    SensorLeft = new VL53L1X(dev_I2C, &xshutdownLeft, LeftIntPin); 
    SensorRight = new VL53L1X(dev_I2C, &xshutdownRight, RightIntPin); 
    
    printf("board created!\r\n");
 // initialise sensors                                               
    for (ToFSensor=0;ToFSensor< NUM_SENSORS ;ToFSensor++){
    switch(ToFSensor){
        case 0:
            
            if (SensorCentre == NULL ) continue;
            // try to initialise the sensor. returns -1 if sensor is not there.
            if (SensorCentre->InitSensor(NEW_SENSOR_CENTRE_ADDRESS) ==-1) 
            {
                 printf("centre not found \n");
                 SensorCentre = NULL;
                 continue;
            }
            Sensor=SensorCentre;
            printf("configuring centre channel \n");
            break;
        case 1:
            if (SensorLeft== NULL ) continue;
            if (SensorLeft->InitSensor(NEW_SENSOR_LEFT_ADDRESS)==-1)
            {
                 printf("left not found \n");
                 SensorLeft = NULL;
                 continue;
            }
            Sensor=SensorLeft;
            printf("configuring left channel \n");
            break;
        case 2:
            if (SensorRight == NULL ) continue;
            if(SensorRight->InitSensor(NEW_SENSOR_RIGHT_ADDRESS)==-1)
            {
                 printf("right not found \n");
                 SensorRight = NULL;
                 continue;
            }
            Sensor=SensorRight;
            printf("configuring right channel \n");
            break;      
        default:
           printf(" error in switch, invalid ToF sensor \n");
    }
    wait_ms(250);  // wait for the sensor to come alive
        
// configure the sensors

/* Device Initialization and setting */  
    status = Sensor->vl53L1_DataInit();
    status = Sensor->vl53L1_StaticInit();
    status = Sensor->vl53L1_SetPresetMode( VL53L1_PRESETMODE_RANGING);
    status = Sensor->vl53L1_SetDistanceMode( VL53L1_DISTANCEMODE_LONG);
    status = Sensor->vl53L1_SetMeasurementTimingBudgetMicroSeconds( 50000);
    status = Sensor->vl53L1_SetInterMeasurementPeriodMilliSeconds( 100);
    }
    
    if (SensorCentre != NULL )
    {
        printf("starting interrupt centre\n");
        // create interrupt process for the centre sensor
        int1 =  new WaitForMeasurement(CentreIntPin,NEW_SENSOR_CENTRE_ADDRESS);
        // start the snesor measuring
        status = SensorCentre->vl53L1_StartMeasurement();
                    printf("end interrupt centre\n");
    }
    

    if (SensorLeft!= NULL )
    {
        printf("starting interrupt left\n");
        int2 = new WaitForMeasurement(LeftIntPin,NEW_SENSOR_LEFT_ADDRESS);
        status = SensorLeft->vl53L1_StartMeasurement();
    }

    if (SensorRight!= NULL )
    {
        printf("starting interrupt right\n");
        int3 = new WaitForMeasurement(RightIntPin,NEW_SENSOR_RIGHT_ADDRESS);
        status = SensorRight->vl53L1_StartMeasurement();
    }
            
    printf("loop forever \n");
   // loop waiting for interrupts to happen. This is signaled by   int_centre_result,int_left_result or int_right_result
   // being non zero. The are set back to zero when processing is completed
    while (1)
    {
        static VL53L1_RangingMeasurementData_t RangingData;  
        VL53L1_MultiRangingData_t MultiRangingData;
        VL53L1_MultiRangingData_t *pMultiRangingData = &MultiRangingData;   
        
        wait_ms( 1 * 50);
        if (int_centre_result != 0)
        {
            // as there has been an interrupt there is data waiting so get it
            status = SensorCentre->vl53L1_GetMultiRangingData( pMultiRangingData);
            if ( status == VL53L1_ERROR_NONE)
            {
                int no_of_object_found=pMultiRangingData->NumberOfObjectsFound;
                if ( no_of_object_found < 10 ) 
                {
                    for(int j=0;j<no_of_object_found;j++){
                        if ((pMultiRangingData->RangeData[j].RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) || 
                            (pMultiRangingData->RangeData[j].RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK_FAIL))
                        {
                            printf("centre\t status=%d, \t D=%5dmm, \t Signal=%2.2f Mcps, \t Ambient=%2.2f Mcps \n",
                            pMultiRangingData->RangeData[j].RangeStatus,
                            pMultiRangingData->RangeData[j].RangeMilliMeter,
                            pMultiRangingData->RangeData[j].SignalRateRtnMegaCps/65536.0,
                            pMultiRangingData->RangeData[j].AmbientRateRtnMegaCps/65536.0);
                        }
                    }
                }
            }
                int_centre_result = 0;
                status = SensorCentre->vl53L1_ClearInterruptAndStartMeasurement();
        }


        if (int_left_result != 0)
        {
            status = SensorLeft->vl53L1_GetMultiRangingData( pMultiRangingData);
            if ( status == VL53L1_ERROR_NONE)
            {
                int no_of_object_found=pMultiRangingData->NumberOfObjectsFound;
                if ( no_of_object_found < 10 ) 
                {
                    for(int j=0;j<no_of_object_found;j++){
                            if ((pMultiRangingData->RangeData[j].RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) || 
                                (pMultiRangingData->RangeData[j].RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK_FAIL))
                            {

                                printf("left  \t status=%d, \t D=%5dmm, \t Signal=%2.2f Mcps, \t Ambient=%2.2f Mcps \n",
                                pMultiRangingData->RangeData[j].RangeStatus,
                                pMultiRangingData->RangeData[j].RangeMilliMeter,
                                pMultiRangingData->RangeData[j].SignalRateRtnMegaCps/65536.0,
                                pMultiRangingData->RangeData[j].AmbientRateRtnMegaCps/65536.0);
                            }
                    }
                }
            }
 
                int_left_result = 0;
                status = SensorLeft->vl53L1_ClearInterruptAndStartMeasurement();

        }
            
            
        if (int_right_result != 0)
        {
            status = SensorRight->vl53L1_GetMultiRangingData( pMultiRangingData);
            if ( status == VL53L1_ERROR_NONE)
            {
                // if valid result print it
                int no_of_object_found=pMultiRangingData->NumberOfObjectsFound;
                if ( no_of_object_found < 10 ) 
                {
                    for(int j=0;j<no_of_object_found;j++){
                        if ((pMultiRangingData->RangeData[j].RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) || 
                            (pMultiRangingData->RangeData[j].RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK_FAIL))
                            {
                                printf("right \t status=%d, \t D=%5dmm, \t Signal=%2.2f Mcps, \t Ambient=%2.2f Mcps \n",
                                pMultiRangingData->RangeData[j].RangeStatus,
                                pMultiRangingData->RangeData[j].RangeMilliMeter,
                                pMultiRangingData->RangeData[j].SignalRateRtnMegaCps/65536.0,
                                pMultiRangingData->RangeData[j].AmbientRateRtnMegaCps/65536.0);
                            }
                    }
                }
            }
            // clear interrupt flag
            int_right_result = 0;
            // clear theinterrupt and wait for another result
            status = SensorRight->vl53L1_ClearInterruptAndStartMeasurement();

        }
    }
    printf("terminated");
}
    
  
  // this function doesn't exist in MBed6.4 onwards. It is required for the F401 drivers.
  // addded here as it allows the file to be compatible with all mbed versions          
#if (MBED_VERSION  > 60300) 
void wait_ms(int ms)
 {
    thread_sleep_for(ms);
 }
#endif