Generating interrupts from VL53L0X pin GPIO1
Hi there,
My first post on here, and I appreciate your time reading it.
I have some VL53L0X time-of-flight boards, and want to interface one with the Espressif ESP32 development board.
My primary objective is to run this set up at low power, so I want to be able put the ESP32 to sleep and wake it up when the VL53L0X detects a "below the low distance threshold" event. To do this I will need the GPIO1 pin to fire an interrupt when the threshold is breached. I have copied the Pololu VL53L0X library source and am currently using that as my library. It works well for basic measuring functions in both continuous and single shot modes. But no matter what I do I have been unable to get it to generate an interrupt. I've tried lots of approaches... the code posted here is working for basic measurement at least.
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <Wire.h>
#include <VL53L0X.h> // Copy of the Pololu VL53L0X library is included. Acknowledgements to the author!
// TFT pins
#define TFT_CS 15
#define TFT_DC 2
#define TFT_RST 4
// VL53L0X I2C pins
#define I2C_SDA 21
#define I2C_SCL 22
#define XSHUT_PIN 26
#define VL53L0X_INTERRUPT_PIN 25 // Pin on ESP32 connected to GPIO1 on VL53L0X
// Initialize TFT and VL53L0X objects
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
VL53L0X sensor;
const uint16_t lowThreshold = 200; // Set low threshold in mm
const uint16_t highThreshold = 400; // Set high threshold in mm
const uint8_t interruptConfig = 0x02; // Range below threshold mode
volatile int counter = 0;
// Minimal interrupt handler
void IRAM_ATTR vl53l0xInterruptHandler() {
// Increment a counter to check that it triggers
counter++;
}
void powerOffVL53L0X() {
digitalWrite(XSHUT_PIN, LOW); // Set XSHUT low to power down
}
void powerOnVL53L0X() {
digitalWrite(XSHUT_PIN, HIGH); // Set XSHUT high to power up
delay(100); // Allow time for initialization
}
void cycleTheVL53L0X()
{
powerOffVL53L0X();
delay(3000);
powerOnVL53L0X();
// Initialize VL53L0X
if (!sensor.init()) {
Serial.println("Failed to detect VL53L0X sensor!");
while (1);
}
sensor.setTimeout(2000);
}
void setup() {
// Initialize Serial for debugging
Serial.begin(115200);
pinMode(XSHUT_PIN, OUTPUT);
pinMode(VL53L0X_INTERRUPT_PIN, INPUT_PULLUP); // Configure interrupt pin as input
attachInterrupt(digitalPinToInterrupt(VL53L0X_INTERRUPT_PIN), vl53l0xInterruptHandler, FALLING);
// Initialize TFT
tft.begin();
tft.setRotation(1);
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(10, 10);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.println("TFT & VL53L0X");
// Initialize I2C with custom pins for VL53L0X
Wire.begin(I2C_SDA, I2C_SCL);
digitalWrite(XSHUT_PIN, HIGH); // Set XSHUT high to enable the sensor
cycleTheVL53L0X();
// Initialize VL53L0X
if (!sensor.init()) {
Serial.println("Failed to detect VL53L0X sensor!");
while (1);
}
sensor.setTimeout(500);
Serial.println("VL53L0X initialized.");
// Configure VL53L0X for "range below threshold" with low polarity interrupt
Serial.println("Configuring interrupt and thresholds...");
sensor.writeReg16Bit(VL53L0X::SYSTEM_THRESH_LOW, lowThreshold); // Set low threshold
sensor.writeReg16Bit(VL53L0X::SYSTEM_THRESH_HIGH, highThreshold); // Set high threshold
//sensor.writeReg(VL53L0X::SYSTEM_INTERRUPT_CONFIG_GPIO, interruptConfig); // Interrupt on range below threshold. This causes problems when included!
// Set GPIO polarity to active low
uint8_t gpioConfig = sensor.readReg(VL53L0X::GPIO_HV_MUX_ACTIVE_HIGH) & ~0x10;
sensor.writeReg(VL53L0X::GPIO_HV_MUX_ACTIVE_HIGH, gpioConfig);
// Clear any existing interrupts
sensor.writeReg(VL53L0X::SYSTEM_INTERRUPT_CLEAR, 0x01);
}
void loop() {
// Read distance from VL53L0X
uint16_t distance = sensor.readRangeSingleMillimeters();
// Print to Serial and display on TFT
Serial.print("Distance: "); Serial.print(distance); Serial.println(" mm");
// Write to the Adafruit TFT
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(10, 30);
tft.print("Distance: ");
tft.print(distance);
tft.println(" mm");
// *** This check works but I need to replace it in the setup() function with a proper SYSTEM_INTERRUPT_CONFIG_GPIO registration ***
if (distance < 130)
{
Serial.print("Distance less than 130mm. Cycling power: "); Serial.print(distance); Serial.println(" mm");
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(10, 30);
tft.print("Distance less than 130mm. Cycling power: ");
tft.print(distance);
tft.println(" mm");
cycleTheVL53L0X();
}
// counter > 0 means that the interrupt must have fired, except that the LED I have attached to GPIO1 does not flicker
if (counter > 0)
{
counter--;
Serial.println("Interrupt fired!");
tft.println("Interrupt fired...");
// Clear any existing interrupts
sensor.writeReg(VL53L0X::SYSTEM_INTERRUPT_CLEAR, 0x01);
}
delay(1000);
}
In terms of hardware, I knocked up a temporary Veroboard set up. It has physical pull-up 4.7k resistors on the SDA and SCK lines, and a 10k pull-up resistor on GPIO1. I've also got an LED on GPIO1 to monitor the logic voltage on that. I have a separate 5v and 3.3v DC supply to the VL53L0X.
I attach a video of my setup. It keeps telling me the interrupt has fired, but I don't believe that. I think my VL53L0X configuration is wrong, but don't know where to start changing it!
Can anyone shed any light on how to get interrupts working, please?
It would be very much appreciated :)
