mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Merge branch 'esp32_touch_isr' into integration
This commit is contained in:
		| @@ -23,7 +23,9 @@ namespace esp32_touch { | ||||
| // INTERRUPT BEHAVIOR: | ||||
| // - ESP32 v1: Interrupts fire when ANY pad is touched and continue while touched. | ||||
| //   Releases are detected by timeout since hardware doesn't generate release interrupts. | ||||
| // - ESP32-S2/S3 v2: Interrupts can be configured per-pad with both touch and release events. | ||||
| // - ESP32-S2/S3 v2: Hardware supports both touch and release interrupts, but release | ||||
| //   interrupts are unreliable and sometimes don't fire. We now only use touch interrupts | ||||
| //   and detect releases via timeout, similar to v1. | ||||
|  | ||||
| static const uint32_t SETUP_MODE_LOG_INTERVAL_MS = 250; | ||||
|  | ||||
| @@ -77,10 +79,21 @@ class ESP32TouchComponent : public Component { | ||||
|   void cleanup_touch_queue_(); | ||||
|   void configure_wakeup_pads_(); | ||||
|  | ||||
|   // Helper methods for loop() logic | ||||
|   void process_setup_mode_logging_(uint32_t now); | ||||
|   bool should_check_for_releases_(uint32_t now); | ||||
|   void publish_initial_state_if_needed_(ESP32TouchBinarySensor *child, uint32_t now); | ||||
|   void check_and_disable_loop_if_all_released_(size_t pads_off); | ||||
|   void calculate_release_timeout_(); | ||||
|  | ||||
|   // Common members | ||||
|   std::vector<ESP32TouchBinarySensor *> children_; | ||||
|   bool setup_mode_{false}; | ||||
|   uint32_t setup_mode_last_log_print_{0}; | ||||
|   uint32_t last_release_check_{0}; | ||||
|   uint32_t release_timeout_ms_{1500}; | ||||
|   uint32_t release_check_interval_ms_{50}; | ||||
|   bool initial_state_published_[TOUCH_PAD_MAX] = {false}; | ||||
|  | ||||
|   // Common configuration parameters | ||||
|   uint16_t sleep_cycle_{4095}; | ||||
| @@ -89,11 +102,13 @@ class ESP32TouchComponent : public Component { | ||||
|   touch_high_volt_t high_voltage_reference_{TOUCH_HVOLT_2V7}; | ||||
|   touch_volt_atten_t voltage_attenuation_{TOUCH_HVOLT_ATTEN_0V}; | ||||
|  | ||||
|   // Common constants | ||||
|   static constexpr uint32_t MINIMUM_RELEASE_TIME_MS = 100; | ||||
|  | ||||
|   // ==================== PLATFORM SPECIFIC ==================== | ||||
|  | ||||
| #ifdef USE_ESP32_VARIANT_ESP32 | ||||
|   // ESP32 v1 specific | ||||
|   static constexpr uint32_t MINIMUM_RELEASE_TIME_MS = 100; | ||||
|  | ||||
|   static void touch_isr_handler(void *arg); | ||||
|   QueueHandle_t touch_queue_{nullptr}; | ||||
| @@ -115,9 +130,6 @@ class ESP32TouchComponent : public Component { | ||||
|   // 4. Queue operations provide implicit memory barriers | ||||
|   // Using atomic/critical sections would add overhead without meaningful benefit | ||||
|   uint32_t last_touch_time_[TOUCH_PAD_MAX] = {0}; | ||||
|   bool initial_state_published_[TOUCH_PAD_MAX] = {false}; | ||||
|   uint32_t release_timeout_ms_{1500}; | ||||
|   uint32_t release_check_interval_ms_{50}; | ||||
|   uint32_t iir_filter_{0}; | ||||
|  | ||||
|   bool iir_filter_enabled_() const { return this->iir_filter_ > 0; } | ||||
| @@ -135,6 +147,9 @@ class ESP32TouchComponent : public Component { | ||||
|     uint32_t intr_mask; | ||||
|   }; | ||||
|  | ||||
|   // Track last touch time for timeout-based release detection | ||||
|   uint32_t last_touch_time_[TOUCH_PAD_MAX] = {0}; | ||||
|  | ||||
|  protected: | ||||
|   // Filter configuration | ||||
|   touch_filter_mode_t filter_mode_{TOUCH_PAD_FILTER_MAX}; | ||||
| @@ -171,7 +186,7 @@ class ESP32TouchComponent : public Component { | ||||
|   void update_touch_state_(ESP32TouchBinarySensor *child, bool is_touched); | ||||
|  | ||||
|   // Helper to read touch value and update state for a given child | ||||
|   void check_and_update_touch_state_(ESP32TouchBinarySensor *child); | ||||
|   bool check_and_update_touch_state_(ESP32TouchBinarySensor *child); | ||||
| #endif | ||||
|  | ||||
|   // Helper functions for dump_config - common to both implementations | ||||
|   | ||||
| @@ -4,6 +4,8 @@ | ||||
| #include "esphome/core/log.h" | ||||
| #include <cinttypes> | ||||
|  | ||||
| #include "soc/rtc.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace esp32_touch { | ||||
|  | ||||
| @@ -85,6 +87,72 @@ void ESP32TouchComponent::configure_wakeup_pads_() { | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ESP32TouchComponent::process_setup_mode_logging_(uint32_t now) { | ||||
|   if (this->setup_mode_ && now - this->setup_mode_last_log_print_ > SETUP_MODE_LOG_INTERVAL_MS) { | ||||
|     for (auto *child : this->children_) { | ||||
| #ifdef USE_ESP32_VARIANT_ESP32 | ||||
|       ESP_LOGD(TAG, "Touch Pad '%s' (T%" PRIu32 "): %" PRIu32, child->get_name().c_str(), | ||||
|                (uint32_t) child->get_touch_pad(), child->value_); | ||||
| #else | ||||
|       // Read the value being used for touch detection | ||||
|       uint32_t value = this->read_touch_value(child->get_touch_pad()); | ||||
|       ESP_LOGD(TAG, "Touch Pad '%s' (T%d): %d", child->get_name().c_str(), child->get_touch_pad(), value); | ||||
| #endif | ||||
|     } | ||||
|     this->setup_mode_last_log_print_ = now; | ||||
|   } | ||||
| } | ||||
|  | ||||
| bool ESP32TouchComponent::should_check_for_releases_(uint32_t now) { | ||||
|   if (now - this->last_release_check_ < this->release_check_interval_ms_) { | ||||
|     return false; | ||||
|   } | ||||
|   this->last_release_check_ = now; | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| void ESP32TouchComponent::publish_initial_state_if_needed_(ESP32TouchBinarySensor *child, uint32_t now) { | ||||
|   touch_pad_t pad = child->get_touch_pad(); | ||||
|   if (!this->initial_state_published_[pad]) { | ||||
|     // Check if enough time has passed since startup | ||||
|     if (now > this->release_timeout_ms_) { | ||||
|       child->publish_initial_state(false); | ||||
|       this->initial_state_published_[pad] = true; | ||||
|       ESP_LOGV(TAG, "Touch Pad '%s' state: OFF (initial)", child->get_name().c_str()); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ESP32TouchComponent::check_and_disable_loop_if_all_released_(size_t pads_off) { | ||||
|   // Disable the loop to save CPU cycles when all pads are off and not in setup mode. | ||||
|   if (pads_off == this->children_.size() && !this->setup_mode_) { | ||||
|     this->disable_loop(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ESP32TouchComponent::calculate_release_timeout_() { | ||||
|   // Calculate release timeout based on sleep cycle | ||||
|   // Design note: Hardware limitation - interrupts only fire reliably on touch (not release) | ||||
|   // We must use timeout-based detection for release events | ||||
|   // Formula: 3 sleep cycles converted to ms, with MINIMUM_RELEASE_TIME_MS minimum | ||||
|   // Per ESP-IDF docs: t_sleep = sleep_cycle / SOC_CLK_RC_SLOW_FREQ_APPROX | ||||
|  | ||||
|   uint32_t rtc_freq = rtc_clk_slow_freq_get_hz(); | ||||
|  | ||||
|   // Calculate timeout as 3 sleep cycles | ||||
|   this->release_timeout_ms_ = (this->sleep_cycle_ * 1000 * 3) / rtc_freq; | ||||
|  | ||||
|   if (this->release_timeout_ms_ < MINIMUM_RELEASE_TIME_MS) { | ||||
|     this->release_timeout_ms_ = MINIMUM_RELEASE_TIME_MS; | ||||
|   } | ||||
|  | ||||
|   // Check for releases at 1/4 the timeout interval | ||||
|   // Since hardware doesn't generate reliable release interrupts, we must poll | ||||
|   // for releases in the main loop. Checking at 1/4 the timeout interval provides | ||||
|   // a good balance between responsiveness and efficiency. | ||||
|   this->release_check_interval_ms_ = this->release_timeout_ms_ / 4; | ||||
| } | ||||
|  | ||||
| }  // namespace esp32_touch | ||||
| }  // namespace esphome | ||||
|  | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| // Include HAL for ISR-safe touch reading | ||||
| #include "hal/touch_sensor_ll.h" | ||||
| // Include for RTC clock frequency | ||||
| #include "soc/rtc.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace esp32_touch { | ||||
| @@ -59,20 +57,7 @@ void ESP32TouchComponent::setup() { | ||||
|   } | ||||
|  | ||||
|   // Calculate release timeout based on sleep cycle | ||||
|   // Design note: ESP32 v1 hardware limitation - interrupts only fire on touch (not release) | ||||
|   // We must use timeout-based detection for release events | ||||
|   // Formula: 3 sleep cycles converted to ms, with MINIMUM_RELEASE_TIME_MS minimum | ||||
|   // The division by 2 accounts for the fact that sleep_cycle is in half-cycles | ||||
|   uint32_t rtc_freq = rtc_clk_slow_freq_get_hz(); | ||||
|   this->release_timeout_ms_ = (this->sleep_cycle_ * 1000 * 3) / (rtc_freq * 2); | ||||
|   if (this->release_timeout_ms_ < MINIMUM_RELEASE_TIME_MS) { | ||||
|     this->release_timeout_ms_ = MINIMUM_RELEASE_TIME_MS; | ||||
|   } | ||||
|   // Check for releases at 1/4 the timeout interval | ||||
|   // Since the ESP32 v1 hardware doesn't generate release interrupts, we must poll | ||||
|   // for releases in the main loop. Checking at 1/4 the timeout interval provides | ||||
|   // a good balance between responsiveness and efficiency. | ||||
|   this->release_check_interval_ms_ = this->release_timeout_ms_ / 4; | ||||
|   this->calculate_release_timeout_(); | ||||
|  | ||||
|   // Enable touch pad interrupt | ||||
|   touch_pad_intr_enable(); | ||||
| @@ -98,13 +83,7 @@ void ESP32TouchComponent::loop() { | ||||
|   const uint32_t now = App.get_loop_component_start_time(); | ||||
|  | ||||
|   // Print debug info for all pads in setup mode | ||||
|   if (this->setup_mode_ && now - this->setup_mode_last_log_print_ > SETUP_MODE_LOG_INTERVAL_MS) { | ||||
|     for (auto *child : this->children_) { | ||||
|       ESP_LOGD(TAG, "Touch Pad '%s' (T%" PRIu32 "): %" PRIu32, child->get_name().c_str(), | ||||
|                (uint32_t) child->get_touch_pad(), child->value_); | ||||
|     } | ||||
|     this->setup_mode_last_log_print_ = now; | ||||
|   } | ||||
|   this->process_setup_mode_logging_(now); | ||||
|  | ||||
|   // Process any queued touch events from interrupts | ||||
|   // Note: Events are only sent by ISR for pads that were measured in that cycle (value != 0) | ||||
| @@ -142,26 +121,18 @@ void ESP32TouchComponent::loop() { | ||||
|   } | ||||
|  | ||||
|   // Check for released pads periodically | ||||
|   static uint32_t last_release_check = 0; | ||||
|   if (now - last_release_check < this->release_check_interval_ms_) { | ||||
|   if (!this->should_check_for_releases_(now)) { | ||||
|     return; | ||||
|   } | ||||
|   last_release_check = now; | ||||
|  | ||||
|   size_t pads_off = 0; | ||||
|   for (auto *child : this->children_) { | ||||
|     touch_pad_t pad = child->get_touch_pad(); | ||||
|  | ||||
|     // Handle initial state publication after startup | ||||
|     if (!this->initial_state_published_[pad]) { | ||||
|       // Check if enough time has passed since startup | ||||
|       if (now > this->release_timeout_ms_) { | ||||
|         child->publish_initial_state(false); | ||||
|         this->initial_state_published_[pad] = true; | ||||
|         ESP_LOGV(TAG, "Touch Pad '%s' state: OFF (initial)", child->get_name().c_str()); | ||||
|         pads_off++; | ||||
|       } | ||||
|     } else if (child->last_state_) { | ||||
|     this->publish_initial_state_if_needed_(child, now); | ||||
|  | ||||
|     if (child->last_state_) { | ||||
|       // Pad is currently in touched state - check for release timeout | ||||
|       // Using subtraction handles 32-bit rollover correctly | ||||
|       uint32_t time_diff = now - this->last_touch_time_[pad]; | ||||
| @@ -186,9 +157,7 @@ void ESP32TouchComponent::loop() { | ||||
|   // - v1 only generates interrupts on touch events (not releases) | ||||
|   // - We must poll for release timeouts in the main loop | ||||
|   // - We can only safely disable when no pads need timeout monitoring | ||||
|   if (pads_off == this->children_.size() && !this->setup_mode_) { | ||||
|     this->disable_loop(); | ||||
|   } | ||||
|   this->check_and_disable_loop_if_all_released_(pads_off); | ||||
| } | ||||
|  | ||||
| void ESP32TouchComponent::on_shutdown() { | ||||
|   | ||||
| @@ -12,19 +12,29 @@ static const char *const TAG = "esp32_touch"; | ||||
|  | ||||
| // Helper to update touch state with a known state | ||||
| void ESP32TouchComponent::update_touch_state_(ESP32TouchBinarySensor *child, bool is_touched) { | ||||
|   // Always update timer when touched | ||||
|   if (is_touched) { | ||||
|     this->last_touch_time_[child->get_touch_pad()] = App.get_loop_component_start_time(); | ||||
|   } | ||||
|  | ||||
|   if (child->last_state_ != is_touched) { | ||||
|     // Read value for logging | ||||
|     uint32_t value = this->read_touch_value(child->get_touch_pad()); | ||||
|  | ||||
|     child->last_state_ = is_touched; | ||||
|     child->publish_state(is_touched); | ||||
|     ESP_LOGD(TAG, "Touch Pad '%s' %s (value: %" PRIu32 " %s threshold: %" PRIu32 ")", child->get_name().c_str(), | ||||
|              is_touched ? "touched" : "released", value, is_touched ? ">" : "<=", child->get_threshold()); | ||||
|     if (is_touched) { | ||||
|       // ESP32-S2/S3 v2: touched when value > threshold | ||||
|       ESP_LOGV(TAG, "Touch Pad '%s' state: ON (value: %" PRIu32 " > threshold: %" PRIu32 ")", child->get_name().c_str(), | ||||
|                value, child->get_threshold()); | ||||
|     } else { | ||||
|       ESP_LOGV(TAG, "Touch Pad '%s' state: OFF", child->get_name().c_str()); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Helper to read touch value and update state for a given child (used for timeout events) | ||||
| void ESP32TouchComponent::check_and_update_touch_state_(ESP32TouchBinarySensor *child) { | ||||
| bool ESP32TouchComponent::check_and_update_touch_state_(ESP32TouchBinarySensor *child) { | ||||
|   // Read current touch value | ||||
|   uint32_t value = this->read_touch_value(child->get_touch_pad()); | ||||
|  | ||||
| @@ -32,6 +42,7 @@ void ESP32TouchComponent::check_and_update_touch_state_(ESP32TouchBinarySensor * | ||||
|   bool is_touched = value > child->get_threshold(); | ||||
|  | ||||
|   this->update_touch_state_(child, is_touched); | ||||
|   return is_touched; | ||||
| } | ||||
|  | ||||
| void ESP32TouchComponent::setup() { | ||||
| @@ -112,9 +123,11 @@ void ESP32TouchComponent::setup() { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Enable interrupts | ||||
|   touch_pad_intr_enable(static_cast<touch_pad_intr_mask_t>(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE | | ||||
|                                                            TOUCH_PAD_INTR_MASK_TIMEOUT)); | ||||
|   // Enable interrupts - only ACTIVE and TIMEOUT | ||||
|   // NOTE: We intentionally don't enable INACTIVE interrupts because they are unreliable | ||||
|   // on ESP32-S2/S3 hardware and sometimes don't fire. Instead, we use timeout-based | ||||
|   // release detection with the ability to verify the actual state. | ||||
|   touch_pad_intr_enable(static_cast<touch_pad_intr_mask_t>(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_TIMEOUT)); | ||||
|  | ||||
|   // Set FSM mode before starting | ||||
|   touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); | ||||
| @@ -122,19 +135,8 @@ void ESP32TouchComponent::setup() { | ||||
|   // Start FSM | ||||
|   touch_pad_fsm_start(); | ||||
|  | ||||
|   // Read initial states after all hardware is initialized | ||||
|   for (auto *child : this->children_) { | ||||
|     // Read current value | ||||
|     uint32_t value = this->read_touch_value(child->get_touch_pad()); | ||||
|  | ||||
|     // Set initial state and publish | ||||
|     bool is_touched = value > child->get_threshold(); | ||||
|     child->last_state_ = is_touched; | ||||
|     child->publish_initial_state(is_touched); | ||||
|  | ||||
|     ESP_LOGD(TAG, "Touch Pad '%s' initial state: %s (value: %d %s threshold: %d)", child->get_name().c_str(), | ||||
|              is_touched ? "touched" : "released", value, is_touched ? ">" : "<=", child->get_threshold()); | ||||
|   } | ||||
|   // Calculate release timeout based on sleep cycle | ||||
|   this->calculate_release_timeout_(); | ||||
| } | ||||
|  | ||||
| void ESP32TouchComponent::dump_config() { | ||||
| @@ -262,16 +264,15 @@ void ESP32TouchComponent::dump_config() { | ||||
| void ESP32TouchComponent::loop() { | ||||
|   const uint32_t now = App.get_loop_component_start_time(); | ||||
|  | ||||
|   // In setup mode, periodically log all pad values | ||||
|   if (this->setup_mode_ && now - this->setup_mode_last_log_print_ > SETUP_MODE_LOG_INTERVAL_MS) { | ||||
|     for (auto *child : this->children_) { | ||||
|       // Read the value being used for touch detection | ||||
|       uint32_t value = this->read_touch_value(child->get_touch_pad()); | ||||
|   // V2 TOUCH HANDLING: | ||||
|   // Due to unreliable INACTIVE interrupts on ESP32-S2/S3, we use a hybrid approach: | ||||
|   // 1. Process ACTIVE interrupts when pads are touched | ||||
|   // 2. Use timeout-based release detection (like v1) | ||||
|   // 3. But smarter than v1: verify actual state before releasing on timeout | ||||
|   //    This prevents false releases if we missed interrupts | ||||
|  | ||||
|       ESP_LOGD(TAG, "Touch Pad '%s' (T%d): %d", child->get_name().c_str(), child->get_touch_pad(), value); | ||||
|     } | ||||
|     this->setup_mode_last_log_print_ = now; | ||||
|   } | ||||
|   // In setup mode, periodically log all pad values | ||||
|   this->process_setup_mode_logging_(now); | ||||
|  | ||||
|   // Process any queued touch events from interrupts | ||||
|   TouchPadEventV2 event; | ||||
| @@ -281,8 +282,8 @@ void ESP32TouchComponent::loop() { | ||||
|       // Resume measurement after timeout | ||||
|       touch_pad_timeout_resume(); | ||||
|       // For timeout events, always check the current state | ||||
|     } else if (!(event.intr_mask & (TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE))) { | ||||
|       // Skip if not an active/inactive/timeout event | ||||
|     } else if (!(event.intr_mask & TOUCH_PAD_INTR_MASK_ACTIVE)) { | ||||
|       // Skip if not an active/timeout event | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
| @@ -295,29 +296,62 @@ void ESP32TouchComponent::loop() { | ||||
|       if (event.intr_mask & TOUCH_PAD_INTR_MASK_TIMEOUT) { | ||||
|         // For timeout events, we need to read the value to determine state | ||||
|         this->check_and_update_touch_state_(child); | ||||
|       } else { | ||||
|         // For ACTIVE/INACTIVE events, the interrupt tells us the state | ||||
|         bool is_touched = (event.intr_mask & TOUCH_PAD_INTR_MASK_ACTIVE) != 0; | ||||
|         this->update_touch_state_(child, is_touched); | ||||
|       } else if (event.intr_mask & TOUCH_PAD_INTR_MASK_ACTIVE) { | ||||
|         // We only get ACTIVE interrupts now, releases are detected by timeout | ||||
|         this->update_touch_state_(child, true);  // Always touched for ACTIVE interrupts | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|   if (!this->setup_mode_) { | ||||
|     // Disable the loop to save CPU cycles when not in setup mode. | ||||
|     // The loop will be re-enabled by the ISR when any touch event occurs. | ||||
|     // Unlike v1, we don't need to check if all pads are off because: | ||||
|     // - v2 hardware generates interrupts for both touch AND release events | ||||
|     // - We don't need to poll for timeouts or releases | ||||
|     // - All state changes are interrupt-driven | ||||
|     this->disable_loop(); | ||||
|  | ||||
|   // Check for released pads periodically (like v1) | ||||
|   if (!this->should_check_for_releases_(now)) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   size_t pads_off = 0; | ||||
|   for (auto *child : this->children_) { | ||||
|     touch_pad_t pad = child->get_touch_pad(); | ||||
|  | ||||
|     // Handle initial state publication after startup | ||||
|     this->publish_initial_state_if_needed_(child, now); | ||||
|  | ||||
|     if (child->last_state_) { | ||||
|       // Pad is currently in touched state - check for release timeout | ||||
|       // Using subtraction handles 32-bit rollover correctly | ||||
|       uint32_t time_diff = now - this->last_touch_time_[pad]; | ||||
|  | ||||
|       // Check if we haven't seen this pad recently | ||||
|       if (time_diff > this->release_timeout_ms_) { | ||||
|         // Haven't seen this pad recently - verify actual state | ||||
|         // Unlike v1, v2 hardware allows us to read the current state anytime | ||||
|         // This makes v2 smarter: we can verify if it's actually released before | ||||
|         // declaring a timeout, preventing false releases if interrupts were missed | ||||
|         bool still_touched = this->check_and_update_touch_state_(child); | ||||
|  | ||||
|         if (still_touched) { | ||||
|           // Still touched! Timer was reset in update_touch_state_ | ||||
|           ESP_LOGVV(TAG, "Touch Pad '%s' still touched after %" PRIu32 "ms timeout, resetting timer", | ||||
|                     child->get_name().c_str(), this->release_timeout_ms_); | ||||
|         } else { | ||||
|           // Actually released - already handled by check_and_update_touch_state_ | ||||
|           pads_off++; | ||||
|         } | ||||
|       } | ||||
|     } else { | ||||
|       // Pad is already off | ||||
|       pads_off++; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Disable the loop when all pads are off and not in setup mode (like v1) | ||||
|   // We need to keep checking for timeouts, so only disable when all pads are confirmed off | ||||
|   this->check_and_disable_loop_if_all_released_(pads_off); | ||||
| } | ||||
|  | ||||
| void ESP32TouchComponent::on_shutdown() { | ||||
|   // Disable interrupts | ||||
|   touch_pad_intr_disable(static_cast<touch_pad_intr_mask_t>(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE | | ||||
|                                                             TOUCH_PAD_INTR_MASK_TIMEOUT)); | ||||
|   touch_pad_intr_disable(static_cast<touch_pad_intr_mask_t>(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_TIMEOUT)); | ||||
|   touch_pad_isr_deregister(touch_isr_handler, this); | ||||
|   this->cleanup_touch_queue_(); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user