Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: X_NUCLEO_6180 mbed
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****/
Generated on Sat Sep 16 2023 06:53:28 by
 1.7.2
 1.7.2