VL53L0X not firing interrupts unless a read is performed

Hey there, and thanks for a great library for the sensors.

I’m working on a project where I’d really want my code to not poll the sensors, but instead, read in a distance measurement when one is ready. I want to use interrupts for this.

I’m using a teensy 3.2 via platformIO, and the following test code is what I’m running.

#include <Arduino.h>
#include <Wire.h>
#include "VL53L0X.h"

VL53L0X sensor;
const int timing_budget = 25000; // micro seconds
const unsigned int sensor_xshut = 16;
const unsigned int sensor_int = 17;
int distance;

void init_sensors();
void handle_sensors();
void isr_test();

uint32_t last_test = 0;



void setup() 
{
  Serial.begin(115200);
  while(!Serial)
  {}
  attachInterrupt(sensor_int, isr_test, FALLING);
  init_sensors();
}

void loop() 
{
  //handle_sensors();
}

void init_sensors()
{
  Wire.begin();

  sensor.setTimeout(100);
  sensor.init();

  sensor.setMeasurementTimingBudget(timing_budget);

  Serial.println("Starting continous ranging");
  sensor.startContinuous();
}

void handle_sensors()
{

    distance = sensor.readRangeContinuousMillimeters();
    if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
}

void isr_test()
{
  Serial.print("i: "); Serial.println(millis()-last_test);
  last_test = millis();
}

This code will only generate 3 interrupts on startup. Two before “starting continuous” and one after.
On the other hand, if I run handle_sensors(); in loop, the interrupts are fired with 25ms intervals.

I’m very confused why this is the behavior. I’d want to use the ISR to read the data from the sensor.
I’ve verified with a scope that the interrupts do indeed not fire, so it’s not a failure to fire the ISR.

Thanks for the help :slight_smile:

There are several problems with your use of interrupts.

  1. You should never print from within an interrupt, as printing is very slow and depends on interrupts, which are off within an interrupt routine. Instead, set a global flag, declared “volatile” and exit. Print from the main program.

  2. Variables that are shared between interrupt routines and the main program MUST be declared volatile, or the compiler may use a cached copy instead. This applies to your “last_test = millis()” line.

  3. You could use last_test as the interrupt flag, but since last_test is multibyte, it can be modified and corrupted by an interrupt while the main program is reading it. To avoid that, turn off the interrupts while making a copy of the variable, and then turn them back on again.

I’m aware of those limitations of ISRs but was lazy when writing my code, as my main concern was the sensor didn’t seem to generate any interrupt pulses unless it was being read.

I have cleaned up the code as you can see below, but the problem remains the same. No edges present on the GPIO pin of the sensor, unless I also read the sensor.

#include <Arduino.h>
#include <Wire.h>
#include "VL53L0X.h"

VL53L0X sensor;
const int timing_budget = 25000; // micro seconds
const unsigned int sensor_xshut = 16;
const unsigned int sensor_int = 17;
int distance;

void init_sensors();
void handle_sensors();
void isr_test();

volatile uint32_t last_test = 0;
volatile bool flag = false;

void setup() 
{
  Serial.begin(115200);
  while(!Serial)
  {}
  attachInterrupt(sensor_int, isr_test, FALLING);
  init_sensors();
}

void loop() 
{
  //handle_sensors();
  if(flag)
  {
    flag = false;
    Serial.println(millis() - last_test);
  }
}

void init_sensors()
{
  Wire.begin();

  sensor.setTimeout(100);
  sensor.init();

  sensor.setMeasurementTimingBudget(timing_budget);

  Serial.println("Starting continous ranging");
  sensor.startContinuous();
}

void handle_sensors()
{

    distance = sensor.readRangeContinuousMillimeters();
    if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
}

void isr_test()
{
  noInterrupts();
  last_test = millis();
  flag = true;
  interrupts();
}

You need to shut off interrupts and copy the variable contents in the main program, not in the ISR.

noInterrupts(); 
unsigned long copy_of_last_test = last_test; 
interrupts();
```
Serial.println(copy_of_last_test);
```

Normally, people call attachInterrupt() with digitalPinToInterrupt(). Are you sure “17” is the correct interrupt number?

[code]attachInterrupt(sensor_int, isr_test, FALLING);

Yeah, I’m sure pin 17 is the right pin. I’m usinga teensy 3.2, and all pins are interrupt capable, and use just their normal pin-name, however that isn’t super relevant.

As I said in the original post, I checked the GPIO pin with a scope, and the line is idle high with no falling edges, unless the data is read.

Now I’m wondering if the interrupt only happens on data_ready, if the previous data has been read. that might be the case.