From c57ad9fff9e4bc389498c33fce0b41ca586ab453 Mon Sep 17 00:00:00 2001 From: brisk Date: Sun, 29 Sep 2024 21:44:56 +0930 Subject: [PATCH] pulse_counter_ulp: Count pulses not edges - Count both separately in ULP program - Manage pin inversion manually in update() - Take into account configured mode --- .../pulse_counter_ulp_sensor.cpp | 40 +++++++++++++------ .../pulse_counter_ulp_sensor.h | 7 ++-- .../pulse_counter_ulp/ulp/pulse_cnt.S | 36 ++++++++++++----- 3 files changed, 58 insertions(+), 25 deletions(-) diff --git a/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.cpp b/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.cpp index 5f7b098c8a..533999a92f 100644 --- a/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.cpp +++ b/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.cpp @@ -51,11 +51,12 @@ std::unique_ptr UlpProgram::start(const Config &config) { * * Note that the ULP reads only the lower 16 bits of these variables. */ - ulp_edge_count = 0; + ulp_rising_edge_count = 0; + ulp_falling_edge_count = 0; ulp_run_count = 0; ulp_debounce_counter = 3; ulp_debounce_max_count = config.debounce_; - ulp_next_edge = 0; + ulp_next_edge = static_cast(!config.pin_->digital_read()); ulp_io_number = rtcio_num; /* map from GPIO# to RTC_IO# */ ulp_mean_exec_time = config.sleep_duration_ / microseconds{1}; @@ -80,18 +81,22 @@ std::unique_ptr UlpProgram::start(const Config &config) { } UlpProgram::State UlpProgram::pop_state() { - // TODO count edges separately State state = UlpProgram::peek_state(); - ulp_edge_count = 0; + ulp_rising_edge_count = 0; + ulp_falling_edge_count = 0; ulp_run_count = 0; return state; } UlpProgram::State UlpProgram::peek_state() const { - auto edge_count = static_cast(ulp_edge_count); + auto rising_edge_count = static_cast(ulp_rising_edge_count); + auto falling_edge_count = static_cast(ulp_falling_edge_count); auto run_count = static_cast(ulp_run_count); auto mean_exec_time = microseconds{1} * static_cast(ulp_mean_exec_time); - return {.edge_count = edge_count, .run_count = run_count, .mean_exec_time = mean_exec_time}; + return {.rising_edge_count_ = rising_edge_count, + .falling_edge_count_ = falling_edge_count, + .run_count_ = run_count, + .mean_exec_time_ = mean_exec_time}; } void UlpProgram::set_mean_exec_time(microseconds mean_exec_time) { @@ -112,7 +117,7 @@ void PulseCounterUlpSensor::setup() { ESP_LOGD(TAG, "Woke up from sleep, skipping set-up of ULP program"); this->storage_ = std::unique_ptr(new UlpProgram); UlpProgram::State state = this->storage_->peek_state(); - this->last_time_ = clock::now() - state.run_count * state.mean_exec_time; + this->last_time_ = clock::now() - state.run_count_ * state.mean_exec_time_; } if (!this->storage_) { @@ -126,8 +131,8 @@ void PulseCounterUlpSensor::dump_config() { LOG_PIN(" Pin: ", this->config_.pin_); ESP_LOGCONFIG(TAG, " Rising Edge: %s", to_string(this->config_.rising_edge_mode_)); ESP_LOGCONFIG(TAG, " Falling Edge: %s", to_string(this->config_.falling_edge_mode_)); - ESP_LOGCONFIG(TAG, " Sleep Duration: " PRIu32 " µs", this->config_.sleep_duration_ / microseconds{1}); - ESP_LOGCONFIG(TAG, " Debounce: " PRIu16, this->config_.debounce_); + ESP_LOGCONFIG(TAG, " Sleep Duration: %" PRIu32 " µs", this->config_.sleep_duration_ / microseconds{1}); + ESP_LOGCONFIG(TAG, " Debounce: %" PRIu16, this->config_.debounce_); LOG_UPDATE_INTERVAL(this); } @@ -137,12 +142,23 @@ void PulseCounterUlpSensor::update() { return; } UlpProgram::State raw = this->storage_->pop_state(); + // Since ULP can't use the GPIOPin abstraction, pin inversion needs to be + // manually implemented. + int32_t pulse_count; + if (this->config_.pin_->is_inverted()) { + pulse_count = static_cast(config_.rising_edge_mode_) * raw.falling_edge_count_ + + static_cast(config_.falling_edge_mode_) * raw.rising_edge_count_; + } else { + pulse_count = static_cast(config_.rising_edge_mode_) * raw.rising_edge_count_ + + static_cast(config_.falling_edge_mode_) * raw.falling_edge_count_; + } clock::time_point now = clock::now(); clock::duration interval = now - this->last_time_; if (interval != clock::duration::zero()) { - this->storage_->set_mean_exec_time(std::chrono::duration_cast(interval / raw.run_count)); - float value = std::chrono::minutes{1} * static_cast(raw.edge_count) / interval; // pulses per minute - ESP_LOGD(TAG, "'%s': Retrieved counter: %0.2f pulses/min", this->get_name().c_str(), value); + this->storage_->set_mean_exec_time(std::chrono::duration_cast(interval / raw.run_count_)); + float value = std::chrono::minutes{1} * static_cast(pulse_count) / interval; // pulses per minute + ESP_LOGD(TAG, "'%s': Retrieved counter: %" PRIu32 " pulses at %0.2f pulses/min", this->get_name().c_str(), + pulse_count, value); this->publish_state(value); } diff --git a/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.h b/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.h index 86b008e5f7..962fae8401 100644 --- a/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.h +++ b/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.h @@ -28,9 +28,10 @@ class UlpProgram { uint16_t debounce_; }; struct State { - uint16_t edge_count; - uint16_t run_count; - microseconds mean_exec_time; + uint16_t rising_edge_count_; + uint16_t falling_edge_count_; + uint16_t run_count_; + microseconds mean_exec_time_; }; State pop_state(); State peek_state() const; diff --git a/esphome/components/pulse_counter_ulp/ulp/pulse_cnt.S b/esphome/components/pulse_counter_ulp/ulp/pulse_cnt.S index e679a7182e..f5df1d39fe 100644 --- a/esphome/components/pulse_counter_ulp/ulp/pulse_cnt.S +++ b/esphome/components/pulse_counter_ulp/ulp/pulse_cnt.S @@ -50,9 +50,14 @@ debounce_counter: debounce_max_count: .long 0 - /* Number of signal edges acquired since last read */ - .global edge_count -edge_count: + /* Number of rising signal edges acquired since last read */ + .global rising_edge_count +rising_edge_count: + .long 0 + + /* Number of falling signal edges acquired since last read */ + .global falling_edge_count +falling_edge_count: .long 0 /* Number of times program run since last read */ @@ -161,13 +166,24 @@ edge_detected: add r2, r2, 1 and r2, r2, 1 st r2, r3, 0 - /* Increment edge_count */ - move r3, edge_count - ld r2, r3, 0 - add r2, r2, 1 - st r2, r3, 0 - /* Increment edge_count_total */ - move r3, edge_count_total + /* Jump to increment of current edge counter */ + add r2, r2, 0 /* dummy ADD to use "jump if ALU result is zero" */ + jump rising, eq + + .global falling +falling: + /* Increment falling_edge_count */ + move r3, falling_edge_count + ld r2, r3, 0 + add r2, r2, 1 + st r2, r3, 0 + /* End program */ + halt + + .global rising +rising: + /* Increment rising_edge_count */ + move r3, rising_edge_count ld r2, r3, 0 add r2, r2, 1 st r2, r3, 0