ST Expansion SW Team / Mbed 2 deprecated VL6180_MB2_4sensors_interrupts

Dependencies:   X_NUCLEO_6180 mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /**
00002   ******************************************************************************
00003   * File Name          : main.c
00004   * Date               : 21/10/2020 09:21:14
00005   * Description        : Main program body
00006   ******************************************************************************
00007   *
00008   * COPYRIGHT(c) 2020 STMicroelectronics
00009   *
00010   * Redistribution and use in source and binary forms, with or without modification,
00011   * are permitted provided that the following conditions are met:
00012   *   1. Redistributions of source code must retain the above copyright notice,
00013   *      this list of conditions and the following disclaimer.
00014   *   2. Redistributions in binary form must reproduce the above copyright notice,
00015   *      this list of conditions and the following disclaimer in the documentation
00016   *      and/or other materials provided with the distribution.
00017   *   3. Neither the name of STMicroelectronics nor the names of its contributors
00018   *      may be used to endorse or promote products derived from this software
00019   *      without specific prior written permission.
00020   *
00021   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00022   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00024   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
00025   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00026   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00027   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00029   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00030   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031   *
00032   ******************************************************************************
00033   
00034   This program controls VL6180 ToF sensors running on an STM32F401 card with the
00035   VL6180 shield and up to 3 VL6180 satelite boards.  This program works in interrupt
00036   mode with all 4 VL6180s operating at the same time. 
00037   
00038   Because this program is designed to run on MBed V2 the normal RTOS features 
00039   such as threads and the signalling between them don't exist. Because of this 
00040   the interupt routine signals the main program by setting flags, there is one to
00041   signal that an interupt has been received from each VL6180. The mainloop then polls
00042   these flags to know that an interrupt has occured.
00043   
00044   The display is very crude with no storing of the last digits, each digit is written
00045   and then a wait occurs and then the next digit is written. Tjis means that a lot of time is 
00046   taken writing tyhe display and any loong period when the display is not serviced 
00047   will cause the display to flicker.
00048   
00049   In this program access to the VL6180 api is through wrapper functions in
00050   vl6180_class.cpp. It is also possible to access the api directly. E.G both the lines below
00051   do the same thing. 
00052   
00053 status = VL6180_ClearInterrupt(dev,INTERRUPT_CLEAR_ERROR|INTERRUPT_CLEAR_RANGING);
00054 status = sensor->vl6180_ClearInterrupt(dev,INTERRUPT_CLEAR_ERROR|INTERRUPT_CLEAR_RANGING);
00055   */
00056 
00057 /* Includes ------------------------------------------------------------------*/
00058 #include <stdio.h>
00059 #include <string.h>
00060 #include <stdlib.h>
00061 #include <stdio.h>
00062 
00063 #include "mbed.h"
00064 #include "XNucleo6810.h"
00065 #include <time.h>
00066 
00067 #include "spi_interface.h"
00068 #include "vl6180_api.h"
00069 #include "6180a1.h"
00070 
00071 
00072 //VL6180_SINGLE_DEVICE_DRIVER
00073 
00074 // i2c tx and rx pins
00075 #define I2C_SDA   D14 
00076 #define I2C_SCL   D15 
00077 
00078 #define DigitDisplay_ms     1 /* ms each digit is kept on */
00079 
00080 #define NUM_SENSORS 4
00081 
00082 // Define interrupt pins
00083 // The interrupt pins depend on solder blobs on the back of the shield.
00084 // Each interupt can have two possible pins, this allows all interrupts to be on the same gpio or different gpio
00085 // The first values are those an unmodified board has
00086 // see ST document UM2657 for more details
00087 PinName CentreIntPin = A3;
00088 PinName LeftIntPin = D13;
00089 PinName RightIntPin = D2;
00090 PinName BottomIntPin = A2;
00091 // alternate set
00092 //PinName CentreIntPin = A5;
00093 //PinName LeftIntPin = D8;
00094 //PinName RightIntPin = D4;
00095 //PinName BottomIntPin = A4;
00096 
00097 
00098 // flags that indicate an interrupt has occured
00099 static int int_centre_result = 0;
00100 static int int_left_result = 0;
00101 static int int_right_result = 0;
00102 static int int_bottom_result = 0;
00103 static int int_result = 0;
00104 
00105 void start_sensor(VL6180Dev_t  dev ,VL6180 *sensor);
00106 int get_sensor_data(VL6180Dev_t  dev ,VL6180 *sensor); 
00107 
00108 
00109 class WaitForMeasurement {
00110 public:
00111 
00112 
00113 // this class services the interrupts from the ToF sensors.
00114 // There is a limited amount you can do in an interrupt routine; printfs,mutexes break them among other things.
00115 // We keep things simple by only raising a flag so all the real work is done outside the interrupt.
00116 // This is designed around MBED V2 which doesn't have the RTOS features that would make this work nicely e.g. semaphores/queues.
00117 WaitForMeasurement(): _interrupt(A1)
00118 {
00119 }
00120 
00121 
00122     // constructor - Sensor is not used and can be removed
00123     WaitForMeasurement(PinName pin,int i2c_address) : _interrupt(pin)          // create the InterruptIn on the pin specified to Counter
00124     {
00125          int_result = 1;
00126          i2c_addr = i2c_address;
00127         _interrupt.rise(callback(this, &WaitForMeasurement::got_interrupt)); // attach increment function of this counter instance
00128         
00129     }
00130 
00131   // function is called every time an interupt is seen. A flag is raised which allows the main routine to service the interupt.
00132     void got_interrupt()
00133     {
00134         if (i2c_addr == NEW_SENSOR_CENTRE_ADDRESS)
00135             int_centre_result = 1;  //flag to main that interrupt happened
00136         if (i2c_addr == NEW_SENSOR_LEFT_ADDRESS)
00137             int_left_result = 1;   //flag to main that interrupt happened
00138         if (i2c_addr == NEW_SENSOR_RIGHT_ADDRESS)
00139             int_right_result = 1;  //flag to main that interrupt happened
00140         if (i2c_addr == NEW_SENSOR_BOTTOM_ADDRESS)
00141             int_bottom_result = 1;   //flag to main that interrupt happened
00142     }
00143     
00144     //destructor
00145     ~WaitForMeasurement()
00146     {
00147         printf("destruction \n");
00148     }
00149 
00150 private:
00151     InterruptIn _interrupt;
00152     int status;
00153     int i2c_addr;
00154     
00155 };
00156 
00157 
00158 
00159 
00160 MyVL6180Dev_t                   devCentre;  //data  for each of the vl6180
00161 MyVL6180Dev_t                   devLeft;
00162 MyVL6180Dev_t                   devRight;
00163 MyVL6180Dev_t                   devBottom;
00164 VL6180Dev_t                     Dev = &devCentre; // the currently used vl6180
00165 
00166 volatile int IntrFired=0;
00167 
00168 VL6180 *Sensor;  
00169 
00170 static XNucleo53L1A1 *board=NULL;
00171 
00172 // MBed V6.4 has renamed wait_ms and UnbufferedSerial replaces Serial
00173 #if (MBED_VERSION  > 60300) 
00174 UnbufferedSerial  pc(SERIAL_TX, SERIAL_RX); 
00175 extern "C" void wait_ms(int ms);
00176 #else
00177 Serial pc(SERIAL_TX, SERIAL_RX); 
00178 #endif
00179 
00180 vl6180_DevI2C *dev_I2C = new vl6180_DevI2C(I2C_SDA, I2C_SCL);
00181 
00182 
00183 #define theVL6180Dev   0x52    //the address of a sensor on power up
00184 
00185 #define i2c_bus      (&hi2c1)
00186 #define def_i2c_time_out 100
00187 
00188 static char DISP_CurString[10]; // used to store what is to be displayed on the display
00189 
00190 VL6180_RangeData_t Range;  /* Range measurmeent  */
00191 uint16_t range;             /* range average distance */
00192 
00193 
00194 int main(void)
00195 {
00196     
00197     WaitForMeasurement* int1; // the interrupt handler
00198     WaitForMeasurement* int2; // the interrupt handler
00199     WaitForMeasurement* int3; // the interrupt handler
00200     WaitForMeasurement* int4; // the interrupt handler
00201 
00202     pc.baud(115200);  // baud rate is important as printf statements take a lot of time
00203     
00204     printf("Interrupt 4 sensors mbed = %d \r\n",MBED_VERSION);
00205 
00206       //create I2C channel
00207     vl6180_DevI2C *dev_I2C = new vl6180_DevI2C(I2C_SDA, I2C_SCL);
00208 
00209     int status;
00210     
00211     // create instances for the sensors
00212     board = XNucleo53L1A1::instance(dev_I2C, CentreIntPin, LeftIntPin, RightIntPin ,BottomIntPin);      
00213         // find the sensors we have and initialise
00214     status = board->init_board();
00215     if (status) {
00216         printf("Failed to init board!\r\n");
00217         return 0;
00218     }
00219     
00220     
00221     //select centre sensor
00222     if (board->sensor_centre != NULL ) {
00223         devCentre.i2c_addr = NEW_SENSOR_CENTRE_ADDRESS;
00224         int1 =  new WaitForMeasurement(CentreIntPin,NEW_SENSOR_CENTRE_ADDRESS);  // create a interrupt class for this interrupt pin
00225         start_sensor(&devCentre ,board->sensor_centre);
00226     }
00227     
00228     if (board->sensor_left != NULL ) {
00229         devLeft.i2c_addr = NEW_SENSOR_LEFT_ADDRESS;
00230         int2 =  new WaitForMeasurement(LeftIntPin,NEW_SENSOR_LEFT_ADDRESS);  // create a interrupt class for this interrupt pin
00231         start_sensor(&devLeft ,board->sensor_left);
00232     }
00233     
00234     if (board->sensor_right != NULL ) {    
00235         devRight.i2c_addr = NEW_SENSOR_RIGHT_ADDRESS;
00236         int2 =  new WaitForMeasurement(RightIntPin,NEW_SENSOR_RIGHT_ADDRESS);  // create a interrupt class for this interrupt pin
00237         start_sensor(&devRight ,board->sensor_right);
00238     }
00239     
00240     if (board->sensor_bottom != NULL ) {   
00241         devBottom.i2c_addr = NEW_SENSOR_BOTTOM_ADDRESS;
00242         int2 =  new WaitForMeasurement(BottomIntPin,NEW_SENSOR_BOTTOM_ADDRESS);  // create a interrupt class for this interrupt pin
00243         start_sensor(&devBottom ,board->sensor_bottom);
00244     }
00245 
00246 
00247     
00248     /* Infinite loop */
00249     while (1) {
00250            
00251            // process interrupts    
00252         if ( int_centre_result == 1 )
00253         {
00254             int_centre_result = 0;  //clear interrupt flag
00255             Dev = &devCentre;
00256             Sensor=board->sensor_centre;
00257             
00258             int result = get_sensor_data(Dev , Sensor);
00259             if ( result != 0)
00260                 printf("C %d \n",result);
00261        }
00262        
00263         if ( int_left_result == 1 )
00264         {
00265             int_left_result = 0;  //clear interrupt flag
00266             Dev = &devLeft;
00267             Sensor=board->sensor_left;
00268             
00269             int result = get_sensor_data(Dev , Sensor);
00270             if ( result != 0)
00271                 printf("L %d \n",result);
00272        }
00273        
00274         if ( int_right_result == 1 )
00275         {
00276             int_right_result = 0;  //clear interrupt flag
00277             Dev = &devRight;
00278             Sensor=board->sensor_right;
00279             
00280             int result = get_sensor_data(Dev , Sensor);
00281             if ( result != 0)
00282                 printf("R %d \n",result);
00283         }
00284         
00285         if ( int_bottom_result == 1 )
00286         {
00287             int_bottom_result = 0;  //clear interrupt flag
00288             Dev = &devBottom;
00289             Sensor=board->sensor_bottom;
00290             
00291             int result = get_sensor_data(Dev , Sensor);
00292             if ( result != 0)
00293                 printf("B %d \n",result);
00294         }
00295 
00296 
00297        // the display is very simple and requires written to frequently so
00298        // we are writing to the display when we would normally sleep.
00299        // when we are not writing to the display it is blank
00300        {
00301            for (int i = 0 ;i < 10;i++)
00302            {  // write to display
00303                 XNUCLEO6180XA1_DisplayString(DISP_CurString, DigitDisplay_ms* 5);
00304            }
00305        }
00306 
00307     }
00308 }
00309 
00310 
00311 // start a sensor
00312 void start_sensor(VL6180Dev_t  dev ,VL6180 *sensor)
00313 {
00314     
00315         /* Note that if we waited  1msec we could bypass VL6180_WaitDeviceBooted(&Dev); */
00316     int status;
00317     status = sensor->vl6180_WaitDeviceBooted(dev);
00318     printf("vl6180_WaitDeviceBooted %d %d\n",status, dev->i2c_addr);
00319     status = sensor->vl6180_InitData(dev);
00320     printf("vl6180_InitData %d %d\n",status, dev->i2c_addr);
00321    
00322     status = sensor->vl6180_FilterSetState(dev,0); // disbale as not effective in continuous mose
00323     printf("vl6180_FilterSetState %d \n",status);
00324     status = sensor->vl6180_Prepare(dev);  // sensor init
00325     printf("vl6180_Prepare %d \n",status);
00326     
00327     status = sensor->vl6180_UpscaleSetScaling(dev, 2); // set scaling  by 2  to get ranging in range 0 to 400mm
00328     printf("vl6180_UpscaleSetScaling %d \n",status);
00329 
00330     // if slow reaction is enough then set a high time like 100 ms (up to 2550 msec)
00331     // if fastest reaction is required then set 0  that will set minimal possible
00332     status = sensor->vl6180_RangeSetInterMeasPeriod(dev, 100);
00333     printf("vl6180_RangeSetInterMeasPeriod %d \n",status);
00334      // set vl6180x gpio1 pin to range interrupt output with high polarity (rising edge)
00335     status = sensor->vl6180_SetupGPIO1(dev, GPIOx_SELECT_GPIO_INTERRUPT_OUTPUT, INTR_POL_HIGH);
00336     printf("vl6180_SetupGPIO1 %d \n",status);
00337     // set range interrupt reporting to low threshold   
00338     status = sensor->vl6180_RangeConfigInterrupt(dev, CONFIG_GPIO_INTERRUPT_LEVEL_LOW);
00339     printf("vl6180_RangeConfigInterrupt %d \n",status);
00340     // we don't care of high threshold as we don't use it , group hold is managed externaly    
00341     status = sensor->vl6180_RangeSetThresholds(dev, 100, 00, 0);
00342     printf("vl6180_RangeSetThresholds %d %d\n",status, dev->i2c_addr);
00343     
00344     status = sensor->vl6180_ClearInterrupt(dev,INTERRUPT_CLEAR_ERROR|INTERRUPT_CLEAR_RANGING);
00345     printf("vl6180_ClearInterrupt %d \n",status);
00346     
00347     status = sensor->vl6180_RangeStartContinuousMode(dev);
00348     printf("vl6180_RangeStartContinuousMode %d %d\n",status, dev->i2c_addr);
00349 }
00350 
00351 
00352 int get_sensor_data(VL6180Dev_t  dev ,VL6180 *sensor)
00353 {
00354     int status;
00355     int result = 0;
00356     status = sensor->vl6180_RangeGetMeasurement(dev, &Range);
00357     if( status == 0 ){         
00358         // Application must check Range.errorStatus before accessing the other data
00359         //    If Range.errorStatus is DataNotReady, application knows that it has to wait a bit before getting a new data
00360         //    If Range.errorStatus is 0, application knows it is a valid distance
00361         //    If Range.errorStatus is not 0, application knows that reported distance is invalid so may take some decisions depending on the errorStatus
00362         if (Range.errorStatus == DataNotReady){
00363             printf("notready \n");
00364         
00365             return result;
00366             }
00367         
00368         // only display the centre sensors values. All sensors values and printed out
00369        if((Range.errorStatus == 0) && (status == 0))
00370        {
00371             // only display the centre sensors values
00372              if ( dev->i2c_addr == NEW_SENSOR_CENTRE_ADDRESS )
00373              { 
00374                  sprintf(DISP_CurString, " %d", (int)Range.range_mm);
00375              }
00376              result = (int)Range.range_mm;
00377        } 
00378        else
00379        {
00380             // only display the centre sensors values
00381              if ( dev->i2c_addr == NEW_SENSOR_CENTRE_ADDRESS )
00382              { 
00383                  sprintf(DISP_CurString, " %4d", 0);
00384              }
00385              result = 0;
00386        }     
00387                  
00388             
00389         /* re-arm next measurement */ 
00390        sensor->vl6180_ClearInterrupt(dev,INTERRUPT_CLEAR_ERROR|INTERRUPT_CLEAR_RANGING);
00391 
00392     }  // status != 0
00393     else{
00394         // it is an critical error
00395 //           HandleError("critical error on VL6180x_RangeCheckAndGetMeasurement");
00396     }
00397 return result;
00398 
00399 }
00400 
00401 
00402  // wait_ms was removed in MBed V6.4          
00403 #if (MBED_VERSION  > 60300) 
00404 void wait_ms(int ms)
00405  {
00406     thread_sleep_for(ms);
00407  }
00408 #endif
00409 
00410 
00411 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/