#include #include #include "common.h" #include "driver/gpio.h" #include "driver/i2c.h" #include "embedded_display.c" #include "esp_log.h" #include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "i2c.c" #define APDS_9960_INT_GPIO CONFIG_APDS_9960_INT_GPIO // =============================================== // Register addresses // =============================================== // 0x80 ENABLE R/W Enable states and interrupts 0x00 // 0x81 ATIME R/W ADC integration time 0xFF // 0x83 WTIME R/W Wait time (non-gesture) 0xFF // 0x84 AILTL R/W ALS interrupt low threshold low byte -- // 0x85 AILTH R/W ALS interrupt low threshold high byte -- // 0x86 AIHTL R/W ALS interrupt high threshold low byte 0x00 // 0x87 AIHTH R/W ALS interrupt high threshold high byte 0x00 // 0x89 PILT R/W Proximity interrupt low threshold 0x00 // 0x8B PIHT R/W Proximity interrupt high threshold 0x00 // 0x8C PERS R/W Interrupt persistence filters (non-gesture) 0x00 // 0x8D CONFIG1 R/W Configuration register one 0x60 // 0x8E PPULSE R/W Proximity pulse count and length 0x40 // 0x8F CONTROL R/W Gain control 0x00 // 0x90 CONFIG2 R/W Configuration register two 0x01 // 0x92 ID R Device ID ID // 0x93 STATUS R Device status 0x00 // 0x94 CDATAL R Low byte of clear channel data 0x00 // 0x95 CDATAH R High byte of clear channel data 0x00 // 0x96 RDATAL R Low byte of red channel data 0x00 // 0x97 RDATAH R High byte of red channel data 0x00 // 0x98 GDATAL R Low byte of green channel data 0x00 // 0x99 GDATAH R High byte of green channel data 0x00 // 0x9A BDATAL R Low byte of blue channel data 0x00 // 0x9B BDATAH R High byte of blue channel data 0x00 // 0x9C PDATA R Proximity data 0x00 // 0x9D POFFSET_UR R/W Proximity offset for UP and RIGHT photodiodes 0x00 // 0x9E POFFSET_DL R/W Proximity offset for DOWN and LEFT photodiodes 0x00 // 0x9F CONFIG3 R/W Configuration register three 0x00 // 0xA0 GPENTH R/W Gesture proximity enter threshold 0x00 // 0xA1 GEXTH R/W Gesture exit threshold 0x00 // 0xA2 GCONF1 R/W Gesture configuration one 0x00 // 0xA3 GCONF2 R/W Gesture configuration two 0x00 // 0xA4 GOFFSET_U R/W Gesture UP offset register 0x00 // 0xA5 GOFFSET_D R/W Gesture DOWN offset register 0x00 // 0xA7 GOFFSET_L R/W Gesture LEFT offset register 0x00 // 0xA9 GOFFSET_R R/W Gesture RIGHT offset register 0x00 // 0xA6 GPULSE R/W Gesture pulse count and length 0x40 // 0xAA GCONF3 R/W Gesture configuration three 0x00 // 0xAB GCONF4 R/W Gesture configuration four 0x00 // 0xAE GFLVL R Gesture FIFO level 0x00 // 0xAF GSTATUS R Gesture status 0x00 // 0xE4 (1) IFORCE W Force interrupt 0x00 // 0xE5 (1) PICLEAR W Proximity interrupt clear 0x00 // 0xE6 (1) CICLEAR W ALS clear channel interrupt clear 0x00 // 0xE7 (1) AICLEAR W All non-gesture interrupts clear 0x00 // 0xFC GFIFO_U R Gesture FIFO UP value 0x00 // 0xFD GFIFO_D R Gesture FIFO DOWN value 0x00 // 0xFE GFIFO_L R Gesture FIFO LEFT value 0x00 // 0xFF GFIFO_R R Gesture FIFO RIGHT value 0x00 // ----------------------------------- 描述 默认值 #define APDS_9960_REG_ENABLE 0x80 // 状态和中断的启用 0x00 #define APDS_9960_REG_ATIME 0x81 // ADC 积分时间 0xff #define APDS_9960_REG_WTIME 0x83 // 等待时间(非手势) 0xff #define APDS_9960_REG_AILTL 0x84 // ALS 中断低阈值低字节 -- #define APDS_9960_REG_AILTH 0x85 // ALS 中断低阈值高字节 -- #define APDS_9960_REG_AIHTL 0x86 // ALS 中断高阈值低字节 0x00 #define APDS_9960_REG_AIHTH 0x87 // ALS 中断高阈值高字节 0x00 #define APDS_9960_REG_PILT 0x89 // 接近中断低阈值 0x00 #define APDS_9960_REG_PIHT 0x8B // 接近中断高阈值 0x00 #define APDS_9960_REG_PERS 0x8C // 中断持续性过滤器(非手势) 0x00 #define APDS_9960_REG_CONFIG1 0x8D // 配置寄存器一 0x60 #define APDS_9960_REG_PPULSE 0x8E // 接近脉冲计数和长度 0x40 #define APDS_9960_REG_CONTROL 0x8F // 增益控制 0x00 #define APDS_9960_REG_CONFIG2 0x90 // 配置寄存器二 0x01 #define APDS_9960_REG_ID 0x92 // 设备 ID ID #define APDS_9960_REG_STATUS 0x93 // 设备状态 0x00 #define APDS_9960_REG_CDATAL 0x94 // 清除通道数据低字节 0x00 #define APDS_9960_REG_CDATAH 0x95 // 清除通道数据高字节 0x00 #define APDS_9960_REG_RDATAL 0x96 // 红色通道数据低字节 0x00 #define APDS_9960_REG_RDATAH 0x97 // 红色通道数据高字节 0x00 #define APDS_9960_REG_GDATAL 0x98 // 绿色通道数据低字节 0x00 #define APDS_9960_REG_GDATAH 0x99 // 绿色通道数据高字节 0x00 #define APDS_9960_REG_BDATAL 0x9A // 蓝色通道数据低字节 0x00 #define APDS_9960_REG_BDATAH 0x9B // 蓝色通道数据高字节 0x00 #define APDS_9960_REG_PDATA 0x9C // 接近数据 0x00 #define APDS_9960_REG_POFFSET_UR 0x9D // 接近偏移量上和右 0x00 #define APDS_9960_REG_POFFSET_DL 0x9E // 接近偏移量下和左 0x00 #define APDS_9960_REG_CONFIG3 0x9F // 配置寄存器三 0x00 #define APDS_9960_REG_GPENTH 0xA0 // 手势进入阈值 0x28 #define APDS_9960_REG_GEXTH 0xA1 // 手势退出阈值 0x1E #define APDS_9960_REG_GCONF1 0xA2 // 手势配置寄存器一 0x40 #define APDS_9960_REG_GCONF2 0xA3 // 手势配置寄存器二 0x66 #define APDS_9960_REG_GOFFSET_U 0xA4 // 手势偏移量上 0x00 #define APDS_9960_REG_GOFFSET_D 0xA5 // 手势偏移量下 0x00 #define APDS_9960_REG_GOFFSET_L 0xA7 // 手势偏移量左 0x00 #define APDS_9960_REG_GOFFSET_R 0xA9 // 手势偏移量右 0x00 #define APDS_9960_REG_GPULSE 0xA6 // 手势脉冲计数和长度 0xC5 #define APDS_9960_REG_GCONF3 0xAA // 手势配置寄存器三 0x00 #define APDS_9960_REG_GCONF4 0xAB // 手势配置寄存器四 0x00 #define APDS_9960_REG_GFLVL 0xAE // 手势 FIFO 级别 0x00 #define APDS_9960_REG_GSTATUS 0xAF // 手势状态 0x00 #define APDS_9960_REG_IFORCE 0xE4 // 强制中断 0x00 #define APDS_9960_REG_PICLEAR 0xE5 // 清除接近中断 0x00 #define APDS_9960_REG_CICLEAR 0xE6 // 清除 ALS 中断 0x00 #define APDS_9960_REG_AICLEAR 0xE7 // 清除手势中断 0x00 #define APDS_9960_REG_GFIFO_U 0xFC // 手势 FIFO 数据上 0x00 #define APDS_9960_REG_GFIFO_D 0xFD // 手势 FIFO 数据下 0x00 #define APDS_9960_REG_GFIFO_L 0xFE // 手势 FIFO 数据左 0x00 #define APDS_9960_REG_GFIFO_R 0xFF // 手势 FIFO 数据右 0x00 #define APDS_9960_GVALID 0b00000001 // GVALID #define APDS_9960_GFOV 0b00000010 // GFOV #define APDS_9960_PINT 0x20 // PINT #define APDS_9960_AINT 0x10 // AINT #define APDS_9960_GINT 0x04 // GINT // 50 mA LED, Reserved, 2x PGAIN, 4x ALS/Cain GAIN #define APDS_9960_CONTROL_VALUE 0b00001010 // Enable Gesture, Proximity, ALS, Power // X, GEN, PIEN, AIEN, WEN, PEN, AEN, PON #define APDS_9960_ENABLE_VALUE 0b01100111 #define APDS_9960_TAG "APDS-9960" static QueueHandle_t apds_9960_int_evt_queue = NULL; static int64_t last_apds_9960_int_time = 0; esp_err_t apds_9960_write_empty(uint8_t command) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_WRITE, ACK_CHECK_EN); i2c_master_write_byte(cmd, command, ACK_CHECK_DIS); i2c_master_stop(cmd); esp_err_t error = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 10 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); if (error != ESP_OK) { ESP_LOGW(APDS_9960_TAG, "write failed. %d", error); } return error; } esp_err_t apds_9960_write(uint8_t command, uint8_t data) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_WRITE, ACK_CHECK_EN); i2c_master_write_byte(cmd, command, ACK_CHECK_EN); i2c_master_write_byte(cmd, data, ACK_CHECK_EN); i2c_master_stop(cmd); esp_err_t error = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 10 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); if (error != ESP_OK) { ESP_LOGW(APDS_9960_TAG, "write failed. %d", error); } return error; } esp_err_t apds_9960_read_byte(uint8_t command, uint8_t* data) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_WRITE, ACK_CHECK_EN); i2c_master_write_byte(cmd, command, ACK_CHECK_EN); i2c_master_start(cmd); i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_READ, ACK_CHECK_EN); i2c_master_read_byte(cmd, data, NACK_VAL); i2c_master_stop(cmd); esp_err_t error = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 10 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); if (error != ESP_OK) { ESP_LOGW(APDS_9960_TAG, "read failed. %d", error); } return error; } // read word esp_err_t apds_9960_read_word(uint8_t command, uint16_t* data) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_WRITE, ACK_CHECK_EN); i2c_master_write_byte(cmd, command, ACK_CHECK_EN); i2c_master_start(cmd); i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_READ, ACK_CHECK_EN); i2c_master_read_byte(cmd, (uint8_t*)data, ACK_VAL); i2c_master_read_byte(cmd, (uint8_t*)data + 1, NACK_VAL); i2c_master_stop(cmd); esp_err_t error = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 10 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); if (error != ESP_OK) { ESP_LOGW(APDS_9960_TAG, "read failed. %d", error); } return error; } // read bytes by length esp_err_t apds_9960_read_bytes_len(uint8_t command, uint8_t* data, uint8_t len) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_WRITE, ACK_CHECK_EN); i2c_master_write_byte(cmd, command, ACK_CHECK_EN); i2c_master_start(cmd); i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_READ, ACK_CHECK_EN); for (int i = 0; i < len; i++) { if (i == len - 1) { i2c_master_read_byte(cmd, (uint8_t*)data + i, NACK_VAL); } else { i2c_master_read_byte(cmd, (uint8_t*)data + i, ACK_VAL); } } i2c_master_stop(cmd); esp_err_t error = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 100 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); if (error != ESP_OK) { ESP_LOGW(APDS_9960_TAG, "read failed. %d", error); } return error; } void apds_9960_clear_all_int(void) { ESP_LOGI(APDS_9960_TAG, "apds_9960_clear_all_int"); ESP_ERROR_CHECK_WITHOUT_ABORT(apds_9960_write_empty(APDS_9960_REG_AICLEAR)); ESP_ERROR_CHECK_WITHOUT_ABORT(apds_9960_write(APDS_9960_REG_GCONF4, 0x06)); } void apds_9960_fetch(void* arg) { ESP_LOGI(APDS_9960_TAG, "apds_9960_fetch"); esp_err_t error; uint16_t red_raw; uint16_t green_raw; uint16_t blue_raw; uint16_t clear_raw; uint8_t byte_buffer; uint8_t gesture_status_raw; uint8_t status_raw; char red_str[20]; char green_str[20]; char blue_str[20]; char clear_str[20]; char status_str[20]; uint8_t interrupt = 0; display_fill_rect(0, 2, 128, 8, 0x00); for (;;) { if (last_apds_9960_int_time + 1000000 < esp_timer_get_time()) { interrupt = gpio_get_level(APDS_9960_INT_GPIO); if (interrupt == 1 || last_apds_9960_int_time + 10000000 < esp_timer_get_time()) { apds_9960_clear_all_int(); } } // clear error = apds_9960_read_word(APDS_9960_REG_CDATAL, &clear_raw); if (error != ESP_OK) { ESP_LOGW(APDS_9960_TAG, "read failed. %d", error); } else { sprintf(clear_str, "C:% 5d", clear_raw); display_print8_str(64, 6, clear_str); ESP_LOGD(APDS_9960_TAG, "Clear: %d", clear_raw); } // red error = apds_9960_read_word(APDS_9960_REG_RDATAL, &red_raw); if (error != ESP_OK) { ESP_LOGW(APDS_9960_TAG, "read failed. %d", error); } else { sprintf(red_str, "R:% 5d", red_raw); display_print8_str(0, 4, red_str); ESP_LOGD(APDS_9960_TAG, "Red: %d", red_raw); } // green error = apds_9960_read_word(APDS_9960_REG_GDATAL, &green_raw); if (error != ESP_OK) { ESP_LOGW(APDS_9960_TAG, "read failed. %d", error); } else { sprintf(green_str, "G:% 5d", green_raw); display_print8_str(64, 4, green_str); ESP_LOGD(APDS_9960_TAG, "Green: %d", green_raw); } // blue error = apds_9960_read_word(APDS_9960_REG_BDATAL, &blue_raw); if (error != ESP_OK) { ESP_LOGW(APDS_9960_TAG, "read failed. %d", error); } else { sprintf(blue_str, "B:% 5d", blue_raw); display_print8_str(0, 6, blue_str); ESP_LOGD(APDS_9960_TAG, "Blue: %d", blue_raw); } vTaskDelay(pdMS_TO_TICKS(1000)); } display_fill_rect(0, 2, 128, 8, 0x00); } void apds_9960_auto_fetch() { if (is_apds_9960_online == 0) { return; } xTaskCreate(apds_9960_fetch, "APDS-9960-fetch", 2048, NULL, 10, NULL); } void apds_9960_read_gesture() { ESP_LOGI(APDS_9960_TAG, "apes_9960_gesture_fetch"); uint8_t byte_buffer; esp_err_t error; uint32_t gesture_values_raw_arr[32]; char gesture_values_str_arr[20]; error = apds_9960_read_byte(APDS_9960_REG_GSTATUS, &byte_buffer); if (error != ESP_OK) { ESP_LOGW(APDS_9960_TAG, "read APDS_9960_REG_GSTATUS failed. %d", error); return; } ESP_LOGD(APDS_9960_TAG, "APDS-9960 interrupt. status: %x", byte_buffer); if (!(byte_buffer & APDS_9960_GVALID)) { ESP_LOGI(APDS_9960_TAG, "Gesture no valid"); return; } ESP_LOGD(APDS_9960_TAG, "Gesture interrupt"); error = apds_9960_read_byte(APDS_9960_REG_GFLVL, &byte_buffer); if (error != ESP_OK) { ESP_LOGW(APDS_9960_TAG, "read APDS_9960_REG_GFLVL failed. %d", error); apds_9960_write(APDS_9960_REG_GCONF4, 0x06); return; } if (byte_buffer < 4) { ESP_LOGD(APDS_9960_TAG, "Gesture FIFO level too low: %d", byte_buffer); apds_9960_write(APDS_9960_REG_GCONF4, 0x06); return; } ESP_LOGD(APDS_9960_TAG, "Gesture FIFO Level: %d", byte_buffer); error = apds_9960_read_bytes_len( APDS_9960_REG_GFIFO_U, (uint8_t*)gesture_values_raw_arr, byte_buffer * 4); apds_9960_write(APDS_9960_REG_GCONF4, 0x06); if (error != ESP_OK) { ESP_LOGW(APDS_9960_TAG, "read APDS_9960_REG_GFIFO(len: %d) failed. % d", byte_buffer * 4, error); } else { int16_t before_ud = 0, before_lr = 0, after_ud = 0, after_lr = 0; int16_t u = 0, d = 0, l = 0, r = 0; uint8_t last_2_index = byte_buffer - 2; // head 2 for (int i = 0; i < 2; i++) { u = gesture_values_raw_arr[i] & 0xff; d = gesture_values_raw_arr[i] >> 8 & 0xff; l = gesture_values_raw_arr[i] >> 16 & 0xff; r = gesture_values_raw_arr[i] >> 24 & 0xff; before_ud += (u - d) * 100 / u + d; before_lr += (l - r) * 100 / l + r; } // last 2 for (int i = last_2_index; i < byte_buffer; i++) { u = gesture_values_raw_arr[i] & 0xff; d = gesture_values_raw_arr[i] >> 8 & 0xff; l = gesture_values_raw_arr[i] >> 16 & 0xff; r = gesture_values_raw_arr[i] >> 24 & 0xff; after_ud += (u - d) * 100 / u + d; after_lr += (l - r) * 100 / l + r; } for (int i = 0; i < byte_buffer; i++) { if (i < 2) { u = gesture_values_raw_arr[i] & 0xff; d = gesture_values_raw_arr[i] >> 8 & 0xff; l = gesture_values_raw_arr[i] >> 16 & 0xff; r = gesture_values_raw_arr[i] >> 24 & 0xff; before_ud += (u - d) * 100 / u + d; before_lr += (l - r) * 100 / l + r; } else if (i >= last_2_index) { u = gesture_values_raw_arr[i] & 0xff; d = gesture_values_raw_arr[i] >> 8 & 0xff; l = gesture_values_raw_arr[i] >> 16 & 0xff; r = gesture_values_raw_arr[i] >> 24 & 0xff; after_ud += (u - d) * 100 / u + d; after_lr += (l - r) * 100 / l + r; } } printf("Δud: %d, Δlr: %d \n", after_ud - before_ud, after_lr - before_lr); display_fill_rect(0, 0, 128, 2, 0x00); if (abs(after_ud - before_ud) * 2 > abs(after_lr - before_lr)) { if (after_ud - before_ud < -80) { display_print8_str(0, 0, "Gesture: up"); } else if (after_ud - before_ud > 80) { display_print8_str(0, 0, "Gesture: down"); } } else { if (after_lr - before_lr < -120) { display_print8_str(0, 0, "Gesture: left"); } else if (after_lr - before_lr > 120) { display_print8_str(0, 0, "Gesture: right"); } } // display_print8_str(0, 0, gesture_str); } } void apds_9960_read_proximity() { uint8_t proximity_raw; char proximity_str[20]; esp_err_t error; // Proximity error = apds_9960_read_byte(APDS_9960_REG_PDATA, &proximity_raw); if (error != ESP_OK) { ESP_LOGW(APDS_9960_TAG, "read proximity failed. %x", error); } else { ESP_LOGD(APDS_9960_TAG, "Prox: % 5d ", proximity_raw); sprintf(proximity_str, "Prox: % 5d ", proximity_raw); display_print8_str(8, 2, proximity_str); } } void apds_9960_int_handler(void* arg) { xQueueSendFromISR(apds_9960_int_evt_queue, &arg, NULL); } void apds_9960_int_evt_handler() { if (is_apds_9960_online == 0) { return; } apds_9960_clear_all_int(); esp_err_t error; uint8_t status_raw; while (xQueueReceive(apds_9960_int_evt_queue, NULL, portMAX_DELAY)) { last_apds_9960_int_time = esp_timer_get_time(); ESP_ERROR_RETRY(apds_9960_read_byte(APDS_9960_REG_STATUS, &status_raw), 10); ESP_ERROR_RETRY(apds_9960_write_empty(APDS_9960_REG_AICLEAR), 10); ESP_LOGD( APDS_9960_TAG, "[apds_9960_int_evt_handler] status %d%d%d%d %d%d%d%d", (status_raw >> 7) & 1, (status_raw >> 6) & 1, (status_raw >> 5) & 1, (status_raw >> 4) & 1, (status_raw >> 3) & 1, (status_raw >> 2) & 1, (status_raw >> 1) & 1, status_raw & 1); if (status_raw & APDS_9960_PINT) { apds_9960_read_proximity(); } if (status_raw & APDS_9960_GINT) { apds_9960_read_gesture(); } vTaskDelay(10 / portTICK_PERIOD_MS); } } void apds_9960_init() { if (is_apds_9960_online == 0) { ESP_LOGI(APDS_9960_TAG, "APDS-9960 is offline"); return; } ESP_LOGI(APDS_9960_TAG, "Initializing APDS-9960"); // esp_log_level_set(APDS_9960_TAG, ESP_LOG_DEBUG); gpio_config_t io_conf = {}; io_conf.mode = GPIO_MODE_INPUT; io_conf.pull_up_en = 0; io_conf.pull_down_en = 0; io_conf.intr_type = GPIO_INTR_NEGEDGE; io_conf.pin_bit_mask = 1ULL << APDS_9960_INT_GPIO; gpio_config(&io_conf); gpio_isr_handler_add(APDS_9960_INT_GPIO, apds_9960_int_handler, NULL); // 环境光 ADC 积分时间 ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_ATIME, 246)); // 27.8ms // 增益 ESP_ERROR_CHECK( apds_9960_write(APDS_9960_REG_CONTROL, APDS_9960_CONTROL_VALUE)); // enable gesture interrupt ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_GCONF4, 0x06)); // 累积的手势数据达到 4 组时触发中断 ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_GCONF1, 0x40)); // Gesture Enter Threshold ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_GPENTH, 3)); // Gesture Exit Threshold ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_GEXTH, 3)); // Gesture Drive Strength ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_GCONF2, 0b0110000)); // // set wait time // ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_WTIME, 171)); // set interrupt persistence ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_PERS, 0x44)); ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_PILT, 0x80)); ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_PIHT, 0x40)); ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_CONFIG2, 0x80)); // // enable sleep after interrupt // ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_CONFIG3, 0x10)); ESP_ERROR_CHECK( apds_9960_write(APDS_9960_REG_ENABLE, APDS_9960_ENABLE_VALUE)); apds_9960_int_evt_queue = xQueueCreate(10, NULL); xTaskCreate(apds_9960_int_evt_handler, "apds_9960_gesture_fetch", 2048, NULL, 10, NULL); }