Доброго времени суток читающим. Сразу к сути. Есть ESP32 и VL53L0X. Преследую цель сделать счетчик посетителей с работой от АКБ с помощью этих компонентов. Так вот наткнулся на проблему: работа пина gpio1 (он же пин перырвания или int), при переходе в спящий режим ESP32. Логика работы проста: включаем все, настраиваем VL53L0X, отправляем основные ядра спать, а с помощью ULP ядра опрашиваем GPIO1 от датчика. Когда ловим высокий или низкий уровень, то инкрементируем некий счетчик внутри RTC памяти. Спустя n-ое кол-во времени просыпаемся и выводим эта значение на oled/serial/web платформу. Загвоздка в том, что при появлении какой-либо уровя на GPIO1 он не сбрасывается (прим.: Подставил руку → получил высокий уровень на GPIO1 → убрал руку, а высокий уровень остался (а должен был сброситься)). Пишу в среде arduino IDE, для лидара использую библиотеку от adafruit (тк она единственная поддерживает работу с GPIO1). Прошу помощи/совета как это исправить или натыкать носом что я не так сделал. API от лидара уже всю прочитал в доль и поперек, там ответа не нашел. Гугление так же не привело к желаемом результату. Код прилагаю:
#include <sys/time.h>
#include <Adafruit_VL53L0X.h>
#include <Adafruit_SSD1306.h>
#include <Wire.h>
#include "esp32/ulp.h"
#include "esp_sleep.h"
#include "driver/rtc_io.h"
#include "nvs.h"
#include "nvs_flash.h"
#define WAKE_UP_TIME 30 // Wake up time for main cpu (s)
#define WORKING_TIME 10 // Working time for main cpu (s)
#define ULP_UP_TIME 10 // Wake up time for ULP (ms)
#define VL53LOX_ShutdownPin 16
#define VL53LOX_InterruptPin 14
uint16_t distanceStr;
VL53L0X_RangingMeasurementData_t measure;
static RTC_DATA_ATTR struct timeval sleep_enter_time;
int32_t cpuCount = 0; // Суммарные данные со счетчика воды
int32_t ulp_count = 0; // Данные, посчитанные ULP сопроцессором
uint32_t timer1;
volatile byte VL53LOX_State = LOW;
Adafruit_VL53L0X lox = Adafruit_VL53L0X();
Adafruit_VL53L0X::VL53L0X_Sense_config_t long_range = Adafruit_VL53L0X::VL53L0X_SENSE_LONG_RANGE;
TwoWire *i2c = &Wire;
Adafruit_SSD1306 display(128, 32, &Wire, -1);
// Код для ULP процессора (бесконечный цикл)
const ulp_insn_t program[] = {
I_MOVI(R0, 0), // Сброс значения регистра R0
I_MOVI(R1, 0), // Сброс значения регистра R1
I_MOVI(R3, 0), // Сброс значения регистра R3
M_LABEL(1), // Метка №1
I_RD_REG(RTC_GPIO_IN_REG, 25, 25), // Чтение состояния ножки входа
I_SUBR(R2, R1, R0), // Находим разность между новым состоянием ножки и предыдущим
M_BXZ(2), // Если АЛУ - 0, то переходим в конец цикла, иначе инкрементируем счетчик импульсов
I_ADDI(R3, R3, 1), // Увеличиваем на 1 счетчик импульсов
M_LABEL(2), // Метка №2
I_MOVR(R1, R0), // Сохраняем значение состояния ножки
I_MOVI(R2, 16), // Устанавливаем адрес памяти, куда будем выводить значение счетчика
I_ST(R3, R2, 0), // Выводим в память RTC значения счетчика
M_BX(1), // Возвращаемся в начало цикла программы
I_HALT()
};
void sensInit(){
pinMode(VL53LOX_ShutdownPin, INPUT_PULLUP);
pinMode(VL53LOX_InterruptPin, INPUT_PULLUP);
digitalWrite(VL53LOX_InterruptPin, LOW);
//attachInterrupt(digitalPinToInterrupt(VL53LOX_InterruptPin), VL53LOXISR,
// CHANGE);
//pinMode(LED_BUILTIN, OUTPUT);
//digitalWrite(LED_BUILTIN, LOW);
// if lox.begin failes its becasue it was a warm boot and the VL53LOX is in
// continues mesurement mode we can use an IO pin to reset the device in case
// we get stuck in this mode
while (!lox.begin(0x29,false, i2c, long_range) ) {
Serial.println(F("Failed to boot VL53L0X"));
Serial.println("Adafruit VL53L0X XShut set Low to Force HW Reset");
digitalWrite(VL53LOX_ShutdownPin, LOW);
delay(100);
digitalWrite(VL53LOX_ShutdownPin, HIGH);
Serial.println("Adafruit VL53L0X XShut set high to Allow Boot");
delay(100);
}
lox.setGpioConfig(VL53L0X_DEVICEMODE_SINGLE_RANGING,
VL53L0X_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW,
VL53L0X_INTERRUPTPOLARITY_HIGH);
FixPoint1616_t LowThreashHold = (1000 * 65536.0);
lox.setInterruptThresholds(LowThreashHold, true);
// Enable Continous Measurement Mode
lox.setDeviceMode(VL53L0X_DEVICEMODE_CONTINUOUS_RANGING, false);
lox.clearInterruptMask(true);
Serial.println("StartMeasurement... ");
lox.startMeasurement();
}
void setup() {
// Инициализация UART
Serial.begin(115200);
delay(500);
Wire.begin(5,4);
gpio_num_t gpio_num = GPIO_NUM_14;
rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_INPUT_ONLY);
rtc_gpio_pulldown_dis(gpio_num);
rtc_gpio_pullup_dis(gpio_num);
rtc_gpio_pullup_en(gpio_num);
//rtc_gpio_hold_en(gpio_num);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.display();
// Измерение времени сна
struct timeval now;
gettimeofday(&now, NULL);
int sleep_time_ms = (now.tv_sec - sleep_enter_time.tv_sec) * 1000 + (now.tv_usec - sleep_enter_time.tv_usec) / 1000;
// Определение, по какому событию проснулись
switch (esp_sleep_get_wakeup_cause()) {
case ESP_SLEEP_WAKEUP_TIMER: {
Serial.println();
Serial.print("Wake up from timer. Time spent in deep sleep: ");
Serial.print(sleep_time_ms);
Serial.println(" ms");
Serial.println();
break;
}
case ESP_SLEEP_WAKEUP_UNDEFINED:
default: {
Serial.println();
Serial.println("Not a deep sleep reset");
Serial.println();
memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM);
}
}
// Считывание показаний из ULP сопроцессора
ulp_count = (RTC_SLOW_MEM[16] & 0xffff) / 2;
// Очистка памяти RTC для ULP сопроцессора
memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM);
// Новый запуск выполнения программы в ULP сопроцессоре
size_t load_addr = 0;
size_t size = sizeof(program) / sizeof(ulp_insn_t);
ulp_process_macros_and_load(load_addr, program, &size);
ulp_run(load_addr);
// Инициализация NVS памяти
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
// Считывание последних данных их NVS памяти, сложение с новыми данными и запись в NVS
cpuCount = 0;
nvs_handle my_nvs_handle;
Serial.print("Opening Non-Volatile Storage (NVS) handle... ");
// "Открытие" NVS памяти для чтения/записи
err = nvs_open("storage", NVS_READWRITE, &my_nvs_handle);
if (err != ESP_OK) {
Serial.print("Error opening NVS handle: ");
Serial.println(err);
} else {
Serial.println("Done");
Serial.print("Reading cpu counter from NVS ... ");
// Считывание поля из NVS памяти
err = nvs_get_i32(my_nvs_handle, "cpuCount", &cpuCount);
switch (err) {
case ESP_OK:
Serial.println("Done");
Serial.print("cpu counter = ");
Serial.println(cpuCount);
break;
case ESP_ERR_NVS_NOT_FOUND:
Serial.println("The value is not initialized yet!");
break;
default :
Serial.print("Error reading: ");
Serial.println(err);
}
// Сложение данных из памяти и из ULP
cpuCount = cpuCount + ulp_count;
// Запись поля данных в NVS память
Serial.print("Updating restart counter in NVS ... ");
err = nvs_set_i32(my_nvs_handle, "cpuCount", cpuCount);
if (err != ESP_OK) {
Serial.print("Error: ");
Serial.println(err);
} else {
Serial.println("Done");
}
err = nvs_commit(my_nvs_handle);
if (err != ESP_OK) {
Serial.print("Error: ");
Serial.println(err);
} else {
Serial.println("Done");
}
// Закрытие дескриптора NVS памяти
nvs_close(my_nvs_handle);
}
Serial.print("cpu counter: ");
Serial.println(cpuCount);
// Чтение значения счетчика из разделяемой памяти после пробуждения
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Count:");
display.println(cpuCount);
Serial.println(cpuCount);
display.display();
sensInit();
//if (VL53LOX_State == LOW) {
// Serial.print("Reading a measurement... ");
// lox.getRangingMeasurement(
// &measure, false); // pass in 'true' to get debug data printout!
// if (measure.RangeStatus != 4) {
// distanceStr = measure.RangeMilliMeter; // phase failures have incorrect data
// Serial.print("Distance (mm): ");
// Serial.println(distanceStr);
// } else {
// Serial.println(" out of range ");
// }
// // you have to clear the interrupt to get triggered again
// lox.clearInterruptMask(false);
//}
// Задержка перед уходом в спящий режим (только для тестов)
delay(WORKING_TIME * 1000);
// Установка таймера сна
Serial.print("Enabling timer wakeup: ");
Serial.println(WAKE_UP_TIME);
esp_sleep_enable_timer_wakeup(WAKE_UP_TIME * 1000000);
// Входим в режим сна
Serial.println("Entering deep sleep");
gettimeofday(&sleep_enter_time, NULL);
esp_deep_sleep_start();
}
void loop() {
//if (digitalRead(VL53LOX_InterruptPin) == HIGH){
// Serial.println("Handled sensor GPIO");
//}
// Этот код никогда не выполнится, так как после 10 секунд микроконтроллер переходит в режим сна
}```