Closed ruudvdb closed 1 year ago
I just tried it: I took my example sketch VL6180X_WE_Interrupt_demo, and the only thing I changed was line 50 to:
sensor.VL6180xSetDistInt(254,255);
Interrupts are triggered then only if something is in the measuring range of the VL6180X. And values are only displayed when interrupts are fired. So it does exactly what it should do.
If you define a window using:
sensor.VL6180xSetDistInt(lowerThreshold, upperThreshold);
then the rules are:
Does it behave like that?
If this does not work on your side like this then you could try to add the following line at the end of setup():
sensor.VL6180xClearInterrupt();
I hope I understood the issue correctly.
I've mounted the sensor in a box (35 cm x 35 cm). There is no light inside the box. When I hold my hand in front of the sensor (~10cm) while the ESP32 is booting (setup method is called), then the sensor goes into continuous mode and the interrupts work. But when the sensor is 'free' (nothing in front of it) while the ESP32 is booting, the sensor goes on and immediately stops. I've checked this with the camera of my phone so I can see the IR light on the sensor.
This behavior is consistent.
Maybe it has something to do with the mounting place (= very dark).
This is the program I'm using to test:
/******************************************************************************
* Modified by Wolfgang (Wolle) Ewald
* https://wolles-elektronikkiste.de/en/vl6180x-tof-proximity-and-ambient-light-sensor
*
* ****************************************************************************
* Based on the Sparkfun library example for the VL6180X:
* https://github.com/sparkfun/SparkFun_ToF_Range_Finder-VL6180_Arduino_Library
*
******************************************************************************/
#include <Wire.h>
#include <VL6180X_WE.h>
#define VL6180X_ADDRESS 0x29
VL6180xIdentification identification;
VL6180x sensor(VL6180X_ADDRESS);
byte shutPin=32;
volatile bool event = false;
void setup() {
pinMode(shutPin, OUTPUT);
digitalWrite(shutPin, LOW); //disable sensor2
pinMode(34, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(34), blink, FALLING);
Serial.begin(115200);
Wire.begin(); //Start I2C library
delay(100); // delay .1s
if(sensor.VL6180xInit() != 0){
Serial.println("FAILED TO INITALIZE"); //Initialize device and check for errors
}
sensor.VL6180xDefautSettings(); //Load default settings to get started.
delay(1000); // delay 1s
// Range Threshold Interrupt:
sensor.VL6180xSetDistInt(254,255);
sensor.getDistanceContinously();
}
void loop() {
if(event){
Serial.println("Interrupt!");
Serial.print("Last Distance Value: ");
Serial.println(sensor.getLastDistanceFromHistory());
event = false;
sensor.VL6180xClearInterrupt();
}
while(!event)delay(1);
}
void blink(){
Serial.println("event");
event = true;
}
I've just found out that this happens when the power is switched off and on. So I've plugged the USB in and the ESP32 powers on without my hand in front of the sensor => continuous mode does not work. I've pressed the reset button on the ESP32 multiple times and still no continuous mode.
When I hold my hand in front of the sensor while hitting the reset button, continuous mode works. And from now on it keeps working even if I hit the reset button.
As soon as I unplug the USB power and plug it back in, the same thing: no hand = no continuous mode.
PS: I'm using 2 VL6180 sensors and with the SHUT-pin I disable one.
I have just taken your program and did try it with an ESP32. I works without issues, independent of having something in front of the sensor or not, with USB newly plugged in or not or reset. Difficult to work on an issue which I can't reproduce. Maybe a difference in the board? Which ESP32 board do you use? Mine is such a development board based on an ESP32-WROOM-32:
I can only guess that there is a timing issue with the interrupts. For which reason ever event might be false although the interrupt on VL6180 has fired. Then nothing will happen. Can you try to add:
sensor.VL6180xClearInterrupt();
at the end of setup?
I'm also using the same board. But I'm using two sensors. The more I try, the more it confuses me.
When the ESP runs the setup, I can see the IR light from the sensor flickering once or twice and then it stops. So I don't think it has something to do with the interrupt itself because continuous mode doesn't stop when there is an interrupt...?
I am going to keep testing and try different things in order to find the issue.
I have added a second sensor to my test. Same I2C line, but shut it down with pin 32. Just to see if it has any impact. The only thing I noticed is that using the same interrupt pin for both modules is an issue. I agree with your statements about the interrupt. However adding the clear interrupt will at least not cause issues. Not sure what else I can recommend. Good luck!
This issue is ongoing in my head as a kind of sub-task. Since you are using two VL6180X modules, I assume the program you shared is only a part of the program you have developed for your project. If this is the case, would you share the complete program? Maybe the issue is related with the second module? I still have the modules and the ESP32 wired on a breadboard, so testing would be easy for me.
I had wired everything on my table when I was writing the program and everything worked until I mounted everything inside my mailbox. That's why I was thinking it maybe had something to do with my mailbox (dark inside and made entirely from metal).
I didn't have any time yet to experiment some more.
Here is large part of my program:
#include <ArduinoJson.h>
#include <Wire.h>
#include <VL6180X_WE.h>
#include <SPI.h>
#include <MFRC522.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include "driver/ledc.h"
#define VL6180X_ADDRESS_1 0x29 //ToF sensor1 uses default I2C address
#define VL6180X_ADDRESS_2 0x30 //ToF sensor2 has to be changed to this I2C address at boot
#define SHUT_1_PIN GPIO_NUM_32 //SHUT pin to shutdown ToF sensor1, so we can update I2C address of ToF sensor2
#define IRQ_1_PIN GPIO_NUM_34 //IRQ pin ToF sensor1
#define IRQ_2_PIN GPIO_NUM_35 //IRQ pin ToF sensor2
#define LOCK_PIN GPIO_NUM_13 //MOSFET pin door lock
#define RFID_RST_PIN GPIO_NUM_17 //RST pin RFID
#define RFID_SS_PIN GPIO_NUM_5 //SDA pin RFID
#define RFID_IRQ_PIN GPIO_NUM_16 //IRQ pin RFID
#define SW_OUT_DOOR_PIN GPIO_NUM_14 //REED SW pin output door (back)
#define SW_INP_DOOR_PIN GPIO_NUM_12 //REED SW pin input door (front)
#define LED_R_PIN GPIO_NUM_27 //LED red pin
#define LED_G_PIN GPIO_NUM_33 //LED green pin
#define LED_B_PIN GPIO_NUM_25 //LED blue pin
#define LED_W_PIN GPIO_NUM_26 //LED white pin
// Replace the next variables with your SSID/Password combination
const char* ssid = "****";
const char* password = "****";
// Add your MQTT Broker IP address
const char* mqtt_server = "****";
const char* mqtt_user = "****";
const char* mqtt_pass = "****";
WiFiClient wifiClient;
PubSubClient MQTTclient(mqtt_server, 1883, wifiClient);
// ToF sensors
VL6180x sensor1(VL6180X_ADDRESS_1);
VL6180x sensor2(VL6180X_ADDRESS_2);
// RFID
MFRC522 rfid(RFID_SS_PIN, RFID_RST_PIN);
MFRC522::MIFARE_Key key;
// IRQ
volatile bool eventToF = false;
volatile bool eventSWOut = false;
volatile bool eventSWIn = false;
// LED
#define REDC LEDC_CHANNEL_1
#define GREENC LEDC_CHANNEL_2
#define BLUEC LEDC_CHANNEL_3
#define WHITEC LEDC_CHANNEL_4
#define LEDC_FADE_TIME (3000)
uint8_t RGBW[4] = {0,0,0,0};
ledc_channel_t channels[4] = {REDC, GREENC, BLUEC, WHITEC};
// Tasks
SemaphoreHandle_t sema_MQTT_KeepAlive;
/*********************************************************************************
* WIFI
*********************************************************************************/
void IRAM_ATTR WiFiEvent(WiFiEvent_t event) {
switch (event) {
case SYSTEM_EVENT_STA_CONNECTED:
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
Serial.println("Disconnected from WiFi access point");
break;
case SYSTEM_EVENT_AP_STADISCONNECTED:
Serial.println("WiFi client disconnected");
break;
default: break;
}
}
void connectToWiFi() {
int TryCount = 0;
Serial.println("connect to wifi");
while (WiFi.status() != WL_CONNECTED) {
TryCount++;
WiFi.disconnect();
WiFi.begin(ssid, password);
vTaskDelay(4000);
if (TryCount == 10) {
ESP.restart();
}
}
WiFi.onEvent(WiFiEvent);
}
/*********************************************************************************
* MQTT
*********************************************************************************/
void MQTTkeepalive( void *pvParameters ) {
sema_MQTT_KeepAlive = xSemaphoreCreateBinary();
xSemaphoreGive(sema_MQTT_KeepAlive); // found keep alive can mess with a publish, stop keep alive during publish
MQTTclient.setKeepAlive(90); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xFrequency = 250; //delay for ms
for (;;) {
//check for a is-connected and if the WiFi 'thinks' its connected, found checking on both is more realible than just a single check
if ((wifiClient.connected()) && (WiFi.status() == WL_CONNECTED)) {
xSemaphoreTake(sema_MQTT_KeepAlive, portMAX_DELAY); // whiles client.loop() is running no other mqtt operations should be in process
MQTTclient.loop();
xSemaphoreGive(sema_MQTT_KeepAlive);
} else {
Serial.printf("MQTT keep alive found MQTT status % s WiFi status % s", String(wifiClient.connected()), String(WiFi.status()));
if (!wifiClient.connected() || !(WiFi.status() == WL_CONNECTED)) {
connectToWiFi();
}
connectToMQTT();
}
xLastWakeTime = xTaskGetTickCount();
vTaskDelayUntil(&xLastWakeTime, xFrequency);
}
vTaskDelete(NULL);
}
void connectToMQTT() {
MQTTclient.setKeepAlive(90); // needs be made before connecting
byte mac[5];
WiFi.macAddress(mac); // get mac address
String clientID = String(mac[0]) + String(mac[4]) ; // use mac address to create clientID
while (!MQTTclient.connected()) {
MQTTclient.connect(clientID.c_str(), mqtt_user, mqtt_pass, NULL , 1, true, NULL);
vTaskDelay(250);
}
MQTTclient.setCallback(callbackMQTT);
MQTTclient.subscribe("****");
Serial.println("MQTT Connected");
}
void callbackMQTT(char* topic, byte* message, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(". Message: ");
String messageTemp;
for (int i = 0; i < length; i++) {
Serial.print((char)message[i]);
messageTemp += (char)message[i];
}
Serial.println();
}
void sendMessageMQTT(const char* topic, const char* msg) {
while (!MQTTclient.connected()) {
vTaskDelay(250);
}
xSemaphoreTake(sema_MQTT_KeepAlive, portMAX_DELAY);
MQTTclient.publish(topic, msg);
xSemaphoreGive(sema_MQTT_KeepAlive);
Serial.print("MQTT message send on topic ");
Serial.print(topic);
Serial.print(" => ");
Serial.println(msg);
}
/*********************************************************************************
* SENSORS
*********************************************************************************/
void IRAM_ATTR interruptToF() {
Serial.println("tof");
eventToF = true;
}
void setupSensorsToF() {
//Init IRQ pins
pinMode(IRQ_1_PIN, INPUT_PULLUP);
pinMode(IRQ_2_PIN, INPUT_PULLUP);
//Start I2C library
Wire.begin();
vTaskDelay(250);
//Check addresses
byte error,address;
Wire.beginTransmission(VL6180X_ADDRESS_1);
error = Wire.endTransmission();
if (error == 0) {
Wire.beginTransmission(VL6180X_ADDRESS_2);
error = Wire.endTransmission();
} else {
Serial.println("Error during setup ToF");
}
if (error != 0) {
Serial.println("Sensor2 has same addres of sensor1, changing it now...");
//Shutdown sensor1
pinMode(SHUT_1_PIN, OUTPUT);
digitalWrite(SHUT_1_PIN, LOW);
vTaskDelay(250);
//Init sensor2 and change address
sensor2 = VL6180x(VL6180X_ADDRESS_1);
sensor2.changeAddress(VL6180X_ADDRESS_1, VL6180X_ADDRESS_2);
//Start sensor 1
digitalWrite(SHUT_1_PIN, HIGH);
vTaskDelay(250);
}
//Init sensor 2
sensor2 = VL6180x(VL6180X_ADDRESS_2);
if(sensor2.VL6180xInit() != 0){
Serial.println("FAILED TO INITALIZE 2"); //Initialize device and check for errors
};
sensor2.VL6180xDefautSettings();
//sensor2.getDistance(); //stops previous getDistanceContinously calls
//Init sensor 1
sensor1 = VL6180x(VL6180X_ADDRESS_1);
if(sensor1.VL6180xInit() != 0){
Serial.println("FAILED TO INITALIZE 1"); //Initialize device and check for errors
};
sensor1.VL6180xDefautSettings();
//sensor1.getDistance(); //stops previous getDistanceContinously calls
//Init interrupts
attachInterrupt(IRQ_1_PIN, interruptToF, FALLING);
attachInterrupt(IRQ_2_PIN, interruptToF, FALLING);
sensor1.VL6180xClearInterrupt();
sensor2.VL6180xClearInterrupt();
//Read constant and interrupt if reading is detected under 250
vTaskDelay(250);
sensor1.VL6180xSetDistInt(254,255);
Serial.println(sensor1.getDistanceContinously());
vTaskDelay(250);
sensor2.VL6180xSetDistInt(254,255);
Serial.println(sensor2.getDistanceContinously());
eventToF = false;
Serial.println("ToF sensors initialized");
}
void IRAM_ATTR interruptReedOutput() {
Serial.println("out");
eventSWOut = true;
}
void IRAM_ATTR interruptReedInput() {
Serial.println("in");
eventSWIn = true;
}
void setupLock() {
pinMode(LOCK_PIN, OUTPUT);
pinMode(SW_OUT_DOOR_PIN, INPUT_PULLUP);
pinMode(SW_INP_DOOR_PIN, INPUT_PULLUP);
attachInterrupt(SW_OUT_DOOR_PIN, interruptReedOutput, CHANGE);
attachInterrupt(SW_INP_DOOR_PIN, interruptReedInput, FALLING);
Serial.println("Lock and reeds initialized");
}
void setupLED() {
ledcSetup(REDC, 5000, 8); // 5kHz 8 bit
ledcSetup(GREENC, 5000, 8);
ledcSetup(BLUEC, 5000, 8);
ledcSetup(WHITEC, 5000, 8);
ledcAttachPin(LED_R_PIN, REDC);
ledcAttachPin(LED_G_PIN, GREENC);
ledcAttachPin(LED_B_PIN, BLUEC);
ledcAttachPin(LED_W_PIN, WHITEC);
ledc_fade_func_install(0);
Serial.println("RGBW LED initialized");
}
void unlock() {
digitalWrite(LOCK_PIN, HIGH);
vTaskDelay(2500);
digitalWrite(LOCK_PIN, LOW);
}
void setLED(uint r, uint g, uint b, uint w) {
//Serial.printf("Set RGBW LED to: R%d G%d B%d W%d\n", r, g, b, w);
RGBW[0] = r;
RGBW[1] = g;
RGBW[2] = b;
RGBW[3] = w;
}
// Setup runs on core 1
void setup() {
Serial.begin(115200);
while (!Serial);
xTaskCreatePinnedToCore(MQTTkeepalive, "MQTTkeepalive", 7000, NULL, 5, NULL, 1);
xTaskCreatePinnedToCore(irqWatchdog, "irqWatchdog", 10000, NULL, 4, NULL, 0);
xTaskCreatePinnedToCore(updateLEDs, "updateLEDs", 2000, NULL, 7, NULL, 1);
Serial.println("end setup");
}
void irqWatchdog(void * pvParameters) {
setupLock();
unlock();
setupSensorsToF();
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xFrequency = 100; //delay for mS
bool send = false;
StaticJsonDocument<48> doc;
for(;;) {
// When letter or package passes the ToF sensor
if (eventToF) {
Serial.println("eventToF");
setLED(0,0,125,0); //blue 50%
doc["letter"] = true;
send = true;
eventToF = false;
sensor1.VL6180xClearInterrupt();
sensor2.VL6180xClearInterrupt();
}
// When back door (output) opens or closes
if (eventSWOut) {
Serial.println("eventSWOut");
vTaskDelay(5);
if (digitalRead(SW_OUT_DOOR_PIN) == 1) {
setLED(0,0,0,255); //white 100%
doc["dooropen"] = true;
} else {
setLED(0,0,0,0); //red 50%
doc["letter"] = false;
doc["packet"] = false;
doc["dooropen"] = false;
}
send = true;
eventSWOut = false;
}
// When front packet door (input) closes
if (eventSWIn) {
Serial.println("eventSWIn");
doc["packet"] = true;
send = true;
eventSWIn = false;
}
doc.clear();
xLastWakeTime = xTaskGetTickCount();
vTaskDelayUntil(&xLastWakeTime, xFrequency);
}
vTaskDelete(NULL);
}
void updateLEDs(void * pvParameters) {
setupLED();
bool change = 0;
for(;;) {
while(change) {
for (int ch = 0; ch < 4; ch++) {
ledc_set_fade_with_time(LEDC_HIGH_SPEED_MODE, channels[ch], RGBW[ch], 500);
ledc_fade_start(LEDC_HIGH_SPEED_MODE, channels[ch], LEDC_FADE_NO_WAIT);
change |= (ledc_get_duty(LEDC_HIGH_SPEED_MODE, channels[ch]) != RGBW[ch]);
}
}
}
vTaskDelete(NULL);
}
// This runs on core 1
void loop() {
}
Hi, I have extracted the relevant part for the two VL6180 modules and played a bit. Both modules work fine, independ of having something in the range or not during reset, re-power, fresh upload, etc. Maybe you try it also. If it works, then the issue should be somehow related with the oher code. If not, then I would think it's an hardware issue.
Two observations:
sensor2 = VL6180x(VL6180X_ADDRESS_1);
are redundant. The code below works with and without. Good luck!
#include <Wire.h>
#include <VL6180X_WE.h>
#define VL6180X_ADDRESS_1 0x29
#define VL6180X_ADDRESS_2 0x30
#define SHUT_1_PIN GPIO_NUM_32
#define IRQ_1_PIN GPIO_NUM_34
#define IRQ_2_PIN GPIO_NUM_35
//VL6180xIdentification identification;
VL6180x sensor1(VL6180X_ADDRESS_1);
VL6180x sensor2(VL6180X_ADDRESS_2);
volatile bool eventToF = false;
void IRAM_ATTR interruptToF() {
Serial.println("tof");
eventToF = true;
}
void setup() {
Serial.begin(115200);
while (!Serial);
pinMode(IRQ_1_PIN, INPUT_PULLUP);
pinMode(IRQ_2_PIN, INPUT_PULLUP);
Wire.begin(); //Start I2C library
delay(250);
Wire.beginTransmission(VL6180X_ADDRESS_1);
uint8_t error = Wire.endTransmission();
if (error == 0) {
Wire.beginTransmission(VL6180X_ADDRESS_2);
error = Wire.endTransmission();
} else {
Serial.println("Error during setup ToF");
}
if (error != 0) {
Serial.println("Sensor2 has same addres of sensor1, changing it now...");
//Shutdown sensor1
pinMode(SHUT_1_PIN, OUTPUT);
digitalWrite(SHUT_1_PIN, LOW);
delay(250);
//change address sensor 2
//sensor2 = VL6180x(VL6180X_ADDRESS_1);
sensor2.changeAddress(VL6180X_ADDRESS_1, VL6180X_ADDRESS_2);
//Start sensor 1
digitalWrite(SHUT_1_PIN, HIGH);
delay(250);
}
// Init Sensor 2
//sensor2 = VL6180x(VL6180X_ADDRESS_2);
if(sensor2.VL6180xInit() != 0){
Serial.println("FAILED TO INITALIZE 2"); //Initialize device and check for errors
};
sensor2.VL6180xDefautSettings();
//Init sensor 1
//sensor1 = VL6180x(VL6180X_ADDRESS_1);
if(sensor1.VL6180xInit() != 0){
Serial.println("FAILED TO INITALIZE 1"); //Initialize device and check for errors
};
sensor1.VL6180xDefautSettings();
//sensor1.getDistance(); //stops previous getDistanceContinously calls
//Init interrupts
attachInterrupt(IRQ_1_PIN, interruptToF, FALLING);
attachInterrupt(IRQ_2_PIN, interruptToF, FALLING);
sensor1.VL6180xClearInterrupt();
sensor2.VL6180xClearInterrupt();
//Read constant and interrupt if reading is detected under 250
delay(250);
sensor1.VL6180xSetDistInt(254,255);
Serial.println(sensor1.getDistanceContinously());
delay(250);
sensor2.VL6180xSetDistInt(254,255);
Serial.println(sensor2.getDistanceContinously());
eventToF = false;
Serial.println("ToF sensors initialized");
}
void loop() {
if (eventToF) {
Serial.println("eventToF");
eventToF = false;
sensor1.VL6180xClearInterrupt();
sensor2.VL6180xClearInterrupt();
}
while(!eventToF)delay(1);
}
I have used another library (https://github.com/DFRobot/DFRobot_VL6180X) and now everything is working. I don't have time to compare them in order to identify the issue. So I will close this ticket.
I'm using:
to get interrupts when a distance between 0 and 254 are measured. But the sensor doesn't go into continuous-mode when there is nothing in front of the sensor. It only works when there is something in front of the sensor (within range) when setting the continuous mode.