From 4a8907d70d5d78fbb817c64e5dcc36712a64a082 Mon Sep 17 00:00:00 2001 From: brisk Date: Sun, 8 Sep 2024 21:37:36 +0930 Subject: [PATCH] pulse_counter_ulp: Store mean_exec_time in Ulp Program This lets the estimated interval survive sleep, and finally provide reasonable interval estimates over deep sleep periods. --- .../pulse_counter_ulp_sensor.cpp | 30 ++++++++++--------- .../pulse_counter_ulp_sensor.h | 16 ++++------ .../pulse_counter_ulp/ulp/pulse_cnt.S | 6 ++++ 3 files changed, 28 insertions(+), 24 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 bfd9fa612f..2e390c96ec 100644 --- a/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.cpp +++ b/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.cpp @@ -57,6 +57,7 @@ std::unique_ptr UlpProgram::start(gpio_num_t gpio_num, microseconds ulp_debounce_max_count = 3; ulp_next_edge = 0; ulp_io_number = rtcio_num; /* map from GPIO# to RTC_IO# */ + ulp_mean_exec_time = sleep_duration / microseconds{1}; /* Initialize selected GPIO as RTC IO, enable input */ rtc_gpio_init(gpio_num); @@ -78,19 +79,23 @@ std::unique_ptr UlpProgram::start(gpio_num_t gpio_num, microseconds return std::unique_ptr(new UlpProgram()); } -UlpProgram::state UlpProgram::pop_state() { +UlpProgram::State UlpProgram::pop_state() { // TODO count edges separately - auto edge_count = static_cast(ulp_edge_count); - auto run_count = static_cast(ulp_run_count); + State state = UlpProgram::peek_state(); ulp_edge_count = 0; ulp_run_count = 0; - return {.edge_count = edge_count, .run_count = run_count}; + return state; } -UlpProgram::state UlpProgram::peek_state() const { +UlpProgram::State UlpProgram::peek_state() const { auto edge_count = static_cast(ulp_edge_count); auto run_count = static_cast(ulp_run_count); - return {.edge_count = edge_count, .run_count = 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}; +} + +void UlpProgram::set_mean_exec_time(microseconds mean_exec_time) { + ulp_mean_exec_time = static_cast(mean_exec_time / microseconds{1}); } /* === END ULP ===*/ @@ -106,9 +111,9 @@ void PulseCounterUlpSensor::setup() { this->rising_edge_mode, this->falling_edge_mode); } else { ESP_LOGD(TAG, "Woke up from sleep, skipping set-up of ULP program"); - // TODO need to store estimate in UlpProgram and load it in load. Maybe. - // this->storage_ = UlpProgram::load(); - // this->last_time = clock::now() - this->storage_->peek_state().run_count * this->storage_->estimate ; + 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; } if (!this->storage_) { @@ -135,16 +140,13 @@ void PulseCounterUlpSensor::update() { if (!this->storage_) { return; } - UlpProgram::state raw = this->storage_->pop_state(); + UlpProgram::State raw = this->storage_->pop_state(); clock::time_point now = clock::now(); clock::duration interval = now - this->last_time_; - auto estimated_interval = ulp_mean_exec_time_ * raw.run_count; if (interval != clock::duration::zero()) { - ulp_mean_exec_time_ = interval / static_cast(raw.run_count); + 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); - ESP_LOGD(TAG, "'%s': Interval: %0.2f\nEstimated: %0.2f", this->get_name().c_str(), - 1.0f * interval / std::chrono::seconds{1}, 1.0f * estimated_interval / std::chrono::seconds{1}); 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 b7ba90ee27..4dadb19cc1 100644 --- a/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.h +++ b/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.h @@ -20,16 +20,17 @@ using microseconds = std::chrono::duration; class UlpProgram { public: - struct state { + struct State { uint16_t edge_count; uint16_t run_count; + microseconds mean_exec_time; }; - state pop_state(); - state peek_state() const; + State pop_state(); + State peek_state() const; + void set_mean_exec_time(microseconds mean_exec_time); static std::unique_ptr start(gpio_num_t gpio_num, microseconds sleep_duration, CountMode rising_edge_mode, CountMode falling_edge_mode); - // static std::unique_ptr load(); }; class PulseCounterUlpSensor : public sensor::Sensor, public PollingComponent { @@ -39,11 +40,7 @@ class PulseCounterUlpSensor : public sensor::Sensor, public PollingComponent { void set_pin(InternalGPIOPin *pin) { pin_ = pin; } void set_rising_edge_mode(CountMode mode) { this->rising_edge_mode = mode; } void set_falling_edge_mode(CountMode mode) { this->falling_edge_mode = mode; } - void set_sleep_duration(uint32_t duration_us) { - this->sleep_duration_ = duration_us * microseconds{1}; - // Initial estimate assumes sleep duration >> execution time - this->ulp_mean_exec_time_ = duration_us * microseconds{1}; - } + void set_sleep_duration(uint32_t duration_us) { this->sleep_duration_ = duration_us * microseconds{1}; } void set_total_sensor(sensor::Sensor *total_sensor) { total_sensor_ = total_sensor; } void set_total_pulses(uint32_t pulses); @@ -60,7 +57,6 @@ class PulseCounterUlpSensor : public sensor::Sensor, public PollingComponent { CountMode falling_edge_mode{CountMode::disable}; std::unique_ptr storage_{}; clock::time_point last_time_{}; - std::chrono::duration ulp_mean_exec_time_{}; microseconds sleep_duration_{20000}; uint32_t current_total_{0}; sensor::Sensor *total_sensor_{nullptr}; diff --git a/esphome/components/pulse_counter_ulp/ulp/pulse_cnt.S b/esphome/components/pulse_counter_ulp/ulp/pulse_cnt.S index 578d77d314..e679a7182e 100644 --- a/esphome/components/pulse_counter_ulp/ulp/pulse_cnt.S +++ b/esphome/components/pulse_counter_ulp/ulp/pulse_cnt.S @@ -71,6 +71,12 @@ edge_count_total: io_number: .long 0 + /* Estimate of how long each execution of the ULP program takes. Managed + * entirely by main program, it is only defined here to survive deep sleep */ + .global mean_exec_time +mean_exec_time: + .long 0 + /* Code goes into .text section */ .text .global entry