1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-15 17:52:19 +01:00

Use interrupt based approach for esp32_touch

This commit is contained in:
J. Nick Koston
2025-06-11 22:32:25 -05:00
parent 261b561bb2
commit 9a37323eb8
2 changed files with 107 additions and 16 deletions

View File

@@ -15,6 +15,20 @@ static const char *const TAG = "esp32_touch";
void ESP32TouchComponent::setup() { void ESP32TouchComponent::setup() {
ESP_LOGCONFIG(TAG, "Running setup"); ESP_LOGCONFIG(TAG, "Running setup");
touch_pad_init(); touch_pad_init();
// Create queue for touch events - size based on number of touch pads
// Each pad can have at most a few events queued (press/release)
// Use 4x the number of pads to handle burst events
size_t queue_size = this->children_.size() * 4;
if (queue_size < 8)
queue_size = 8; // Minimum queue size
this->touch_queue_ = xQueueCreate(queue_size, sizeof(TouchPadEvent));
if (this->touch_queue_ == nullptr) {
ESP_LOGE(TAG, "Failed to create touch event queue of size %d", queue_size);
this->mark_failed();
return;
}
// set up and enable/start filtering based on ESP32 variant // set up and enable/start filtering based on ESP32 variant
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
if (this->filter_configured_()) { if (this->filter_configured_()) {
@@ -63,15 +77,32 @@ void ESP32TouchComponent::setup() {
for (auto *child : this->children_) { for (auto *child : this->children_) {
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
touch_pad_config(child->get_touch_pad()); touch_pad_config(child->get_touch_pad());
if (child->get_threshold() > 0) {
touch_pad_set_thresh(child->get_touch_pad(), child->get_threshold());
}
#else #else
// Disable interrupt threshold // Set interrupt threshold
touch_pad_config(child->get_touch_pad(), 0); touch_pad_config(child->get_touch_pad(), child->get_threshold());
#endif #endif
} }
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
touch_pad_fsm_start(); touch_pad_fsm_start();
#endif #endif
// Register ISR handler
esp_err_t err = touch_pad_isr_register(touch_isr_handler, this);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to register touch ISR: %s", esp_err_to_name(err));
vQueueDelete(this->touch_queue_);
this->touch_queue_ = nullptr;
this->mark_failed();
return;
}
// Enable touch pad interrupt
touch_pad_intr_enable();
ESP_LOGI(TAG, "Touch pad interrupts enabled");
} }
void ESP32TouchComponent::dump_config() { void ESP32TouchComponent::dump_config() {
@@ -294,29 +325,48 @@ uint32_t ESP32TouchComponent::component_touch_pad_read(touch_pad_t tp) {
void ESP32TouchComponent::loop() { void ESP32TouchComponent::loop() {
const uint32_t now = App.get_loop_component_start_time(); const uint32_t now = App.get_loop_component_start_time();
bool should_print = this->setup_mode_ && now - this->setup_mode_last_log_print_ > 250; bool should_print = this->setup_mode_ && now - this->setup_mode_last_log_print_ > 250;
for (auto *child : this->children_) {
child->value_ = this->component_touch_pad_read(child->get_touch_pad());
#if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3))
child->publish_state(child->value_ < child->get_threshold());
#else
child->publish_state(child->value_ > child->get_threshold());
#endif
if (should_print) { // In setup mode, also read values directly for calibration
if (this->setup_mode_ && should_print) {
for (auto *child : this->children_) {
uint32_t value = this->component_touch_pad_read(child->get_touch_pad());
ESP_LOGD(TAG, "Touch Pad '%s' (T%" PRIu32 "): %" PRIu32, child->get_name().c_str(), ESP_LOGD(TAG, "Touch Pad '%s' (T%" PRIu32 "): %" PRIu32, child->get_name().c_str(),
(uint32_t) child->get_touch_pad(), child->value_); (uint32_t) child->get_touch_pad(), value);
} }
this->setup_mode_last_log_print_ = now;
App.feed_wdt();
} }
if (should_print) { // Process any queued touch events
// Avoid spamming logs TouchPadEvent event;
this->setup_mode_last_log_print_ = now; while (xQueueReceive(this->touch_queue_, &event, 0) == pdTRUE) {
// Find the corresponding sensor
for (auto *child : this->children_) {
if (child->get_touch_pad() == event.pad) {
child->value_ = event.value;
bool new_state;
#if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3))
new_state = child->value_ < child->get_threshold();
#else
new_state = child->value_ > child->get_threshold();
#endif
// Only publish if state changed
if (new_state != child->last_state_) {
child->last_state_ = new_state;
child->publish_state(new_state);
}
break;
}
}
} }
} }
void ESP32TouchComponent::on_shutdown() { void ESP32TouchComponent::on_shutdown() {
touch_pad_intr_disable();
touch_pad_isr_deregister(touch_isr_handler, this);
if (this->touch_queue_) {
vQueueDelete(this->touch_queue_);
}
bool is_wakeup_source = false; bool is_wakeup_source = false;
#if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)) #if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3))
@@ -346,6 +396,36 @@ void ESP32TouchComponent::on_shutdown() {
} }
} }
void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) {
ESP32TouchComponent *component = static_cast<ESP32TouchComponent *>(arg);
uint32_t pad_intr = touch_pad_get_status();
touch_pad_clear_status();
// Check which pads triggered
for (int i = 0; i < TOUCH_PAD_MAX; i++) {
if ((pad_intr >> i) & 0x01) {
touch_pad_t pad = static_cast<touch_pad_t>(i);
TouchPadEvent event;
event.pad = pad;
// Read value in ISR
event.value = 0;
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
touch_pad_read_raw_data(pad, &event.value);
#else
uint16_t val = 0;
touch_pad_read(pad, &val);
event.value = val;
#endif
// Send to queue from ISR
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(component->touch_queue_, &event, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR();
}
}
}
}
ESP32TouchBinarySensor::ESP32TouchBinarySensor(touch_pad_t touch_pad, uint32_t threshold, uint32_t wakeup_threshold) ESP32TouchBinarySensor::ESP32TouchBinarySensor(touch_pad_t touch_pad, uint32_t threshold, uint32_t wakeup_threshold)
: touch_pad_(touch_pad), threshold_(threshold), wakeup_threshold_(wakeup_threshold) {} : touch_pad_(touch_pad), threshold_(threshold), wakeup_threshold_(wakeup_threshold) {}

View File

@@ -9,12 +9,19 @@
#include <vector> #include <vector>
#include <driver/touch_sensor.h> #include <driver/touch_sensor.h>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
namespace esphome { namespace esphome {
namespace esp32_touch { namespace esp32_touch {
class ESP32TouchBinarySensor; class ESP32TouchBinarySensor;
struct TouchPadEvent {
touch_pad_t pad;
uint32_t value;
};
class ESP32TouchComponent : public Component { class ESP32TouchComponent : public Component {
public: public:
void register_touch_pad(ESP32TouchBinarySensor *pad) { this->children_.push_back(pad); } void register_touch_pad(ESP32TouchBinarySensor *pad) { this->children_.push_back(pad); }
@@ -57,6 +64,9 @@ class ESP32TouchComponent : public Component {
void on_shutdown() override; void on_shutdown() override;
protected: protected:
static void touch_isr_handler(void *arg);
QueueHandle_t touch_queue_{nullptr};
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
bool filter_configured_() const { bool filter_configured_() const {
return (this->filter_mode_ != TOUCH_PAD_FILTER_MAX) && (this->smooth_level_ != TOUCH_PAD_SMOOTH_MAX); return (this->filter_mode_ != TOUCH_PAD_FILTER_MAX) && (this->smooth_level_ != TOUCH_PAD_SMOOTH_MAX);
@@ -113,6 +123,7 @@ class ESP32TouchBinarySensor : public binary_sensor::BinarySensor {
touch_pad_t touch_pad_{TOUCH_PAD_MAX}; touch_pad_t touch_pad_{TOUCH_PAD_MAX};
uint32_t threshold_{0}; uint32_t threshold_{0};
uint32_t value_{0}; uint32_t value_{0};
bool last_state_{false};
const uint32_t wakeup_threshold_{0}; const uint32_t wakeup_threshold_{0};
}; };