Vl6180x gpio1 interrupt / asynchronous use

Hello. I am using the Pololu vl6180x TOF sensor and the associated Arduino library. I am looking for a way to use these sensors asynchronously (so my code can do other stuff while the sensor is reading) in continuous/interleaving mode. I read in the datasheet that GPIO1 can be used as an interrupt when a sensor has completed a reading but I hooked that pin up to a scope and it always seems to be high. So I’m asumming I need to do some writing to the register to utilize this function? Is there any easy way to do this through the Pololu library?

Thank you.

Hello.

By default, our Arduino library for the VL6180X does not configure GPIO1 as an interrupt output. You can do so by calling:

writeReg(VL6180X::SYSTEM__MODE_GPIO1, 0x10);

-Jon

Thanks for the reply. I tried using this command but the interrupt pin is now just constantly low so I’m assuming it is not indicating when a measurement is ready? Or do I need to modify other parts of the interleaving continuous example to see this pin changing on the scope?

I read that there is a specific mode for asynchronous use of the Vl6180x so does this mean that I cannot take advantage of this feature in continuous mode?

Note that the interrupt output is active low when configured this way, so if you are not reading the sensor very quickly, it might be low to indicate that data is ready most of the time. Can you confirm that you are using scope to detect the output at GPIO1?

-Jon

Hello,

Yes I am using a scope. It is constantly low in interleaving continuous mode. If I use the single shot example, it works as expected: about 37 times a second the interrupt pin dips from high to low. Even with that, though, it’s unclear how I could use the sensor asynchronously as the “sensor.readRangeSingleMillimeters()” command seems to stop and wait until it receives a reply. Also, I’m hoping to be able to use the interleaving continuous mode asynchronously so I can get a higher update rate.

Hi, mureytasroc.

It looks like the way our library sets up the data ready signal, the GPIO1 interrupt output works if you are using interleaved mode (startContinuousInterleaved()) and retrieving both ambient and range results (readAmbientContinuous() and readRangeContinuous()), but it doesn’t work well if you are only retrieving one type of result. Which are you trying to read: ambient, range, or both?

The library in its current state also doesn’t provide functions for asynchronous reading, but it’s pretty straightforward to check the RESULT__INTERRUPT_STATUS_GPIO to see whether the results are ready.

I can give you some more specific code examples for both setting up the GPIO1 interrupt and doing asynchronous readings once I know what type(s) of measurements you are trying to get.

Kevin

Hello,

Thanks for the reply. I only need range data.

This sketch should set up the interrupt correctly (it seems like the best solution is to just clear any existing interrupts just before starting continuous mode) and has a few functions that let you read the sensor asynchronously:

#include <Wire.h>
#include <VL6180X.h>

VL6180X sensor;

bool rangeDataReady()
{
  return ((sensor.readReg(VL6180X::RESULT__INTERRUPT_STATUS_GPIO) & 0x04) != 0);
}

uint8_t readRangeNonBlocking()
{
  uint8_t range = sensor.readReg(VL6180X::RESULT__RANGE_VAL);
  sensor.writeReg(VL6180X::SYSTEM__INTERRUPT_CLEAR, 0x01);

  return range;
}

uint8_t readRangeNonBlockingMillimeters()
{
  return readRangeNonBlocking() * sensor.getScaling();
}

void setup()
{
  Serial.begin(9600);
  Wire.begin();

  sensor.init();
  sensor.configureDefault();

  // Reduce range max convergence time and ALS integration
  // time to 30 ms and 50 ms, respectively, to allow 10 Hz
  // operation (as suggested by Table 6 ("Interleaved mode
  // limits (10 Hz operation)") in the datasheet).
  sensor.writeReg(VL6180X::SYSRANGE__MAX_CONVERGENCE_TIME, 30);
  sensor.writeReg16Bit(VL6180X::SYSALS__INTEGRATION_PERIOD, 50);

  sensor.setTimeout(500);

   // stop continuous mode if already active
  sensor.stopContinuous();
  // in case stopContinuous() triggered a single-shot
  // measurement, wait for it to complete
  delay(300);

  // enable interrupt output on GPIO1
  sensor.writeReg(VL6180X::SYSTEM__MODE_GPIO1, 0x10);
  // clear any existing interrupts
  sensor.writeReg(VL6180X::SYSTEM__INTERRUPT_CLEAR, 0x03);
  
  // start interleaved continuous mode with period of 100 ms
  sensor.startRangeContinuous(100);
}

void loop()
{
  // only get a range reading if it is ready
  if (rangeDataReady())
  {
    Serial.print("Range: ");
    Serial.println(readRangeNonBlockingMillimeters());
  }
}

I would like to eventually get this into the library (our similar VL53L1X library already has support for asynchronous reading).

Kevin

Thanks, this totally works. Interestingly enough, the output of gpio1 on the scope still seems to be constantly low (or about +200mV) but the code works asynchronously so I’m not complaining. Does this mean I don’t actually have to hook up another Arduino pin to the sensor’s gpio1 output?

That’s strange; with the exact sketch I posted above, I see GPIO1 high (2.8 V) most of the time and going low briefly every 100 ms. If you still want to get the interrupt signal working, I can try to help you troubleshoot more. However, if you are fine with using the rangeDataReady() function to check when a reading is available, then you shouldn’t need the interrupt output.

Kevin

Actually, I checked again and that is the behavior I am getting as well. I must have made a mistake when I was probing it the last time. So I guess I can use either that pin or the
rangeDataReady() function. Thanks for all your help.

Any chance you can provide guidance on implementing (or an implementation of) the VL6180x_RangeSetThresholds() function. I don’t see this ported in the .h or .cpp files. Looks like this will also required porting the VL6180x_SetGroupParamHold() function. That is used in the vl6180x_range_interrupt.c example in the STMicro API.

Hello Kevin,
Can you please help with me in GPIO Interrupt settings.
I am using your Github library for the vl6180x sensor and i have configured it as Range Continuous mode. I have define MAX/MIN thresholds and also configured SYSTEM_INTERRUPT_CONFIG_GPIO1 as 0x02 but it seem not working

Hi, YJVYAS.

Could you simplify your code to the minimum that you think should work and then post it here?

Kevin

Hello,

I am using a PNUCLEO VL6180X and I would like to drive my LED from the GPIO1 interrupt output only this output as shown in the diagrams above is always at 1 and it goes to 0 only for a few nanoseconds; I would like to have an interrupt signal only when I bring my hand closer to the sensor, I would like it to send a 1 to the LED when there is a target and a 0 when there is nothing.
Here are some images on the oscilloscope with the target and without the target

Hi, Veck.

It looks like you asked this same question on the ST forums and got a response there. If you are using their API, they should be better able to help you with your questions.

-Claire

Hi kevin,

I want to use the sensors in a non-blocking code but even your code is somehwat blocking because rangeDataReady() leads to a loop frequency of aprox. 600Hz. The function just checks via I2C if GPIO is set after a reading, when I get it right. So why does it take so lang to read a register?

Thanks

schlank

Hi, schlank.

When I run the program I posted earlier on a standard Arduino Uno, I get a loop frequency of about 1.7 kHz, which is about what I expect (reading the register once involves transferring 5 bytes over I2C). If you’re having trouble reproducing that result, could you post some info about your setup, including what type of Arduino you’re using and whether you modified the program?

You can speed up the loop by calling Wire.setClock(400000); to increase the I2C frequency from the Arduino’s default of 100 kHz to 400 kHz. This got me a loop frequency of about 4.8 kHz, which isn’t 4x but is still a substantial increase. Or, if you really want to avoid the overhead of polling the data ready register, you could look into using the interrupt output from the sensor.

Kevin