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.
This commit is contained in:
brisk 2024-09-08 21:37:36 +09:30
parent 2b453289a9
commit 4a8907d70d
3 changed files with 28 additions and 24 deletions

View file

@ -57,6 +57,7 @@ std::unique_ptr<UlpProgram> UlpProgram::start(gpio_num_t gpio_num, microseconds
ulp_debounce_max_count = 3; ulp_debounce_max_count = 3;
ulp_next_edge = 0; ulp_next_edge = 0;
ulp_io_number = rtcio_num; /* map from GPIO# to RTC_IO# */ 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 */ /* Initialize selected GPIO as RTC IO, enable input */
rtc_gpio_init(gpio_num); rtc_gpio_init(gpio_num);
@ -78,19 +79,23 @@ std::unique_ptr<UlpProgram> UlpProgram::start(gpio_num_t gpio_num, microseconds
return std::unique_ptr<UlpProgram>(new UlpProgram()); return std::unique_ptr<UlpProgram>(new UlpProgram());
} }
UlpProgram::state UlpProgram::pop_state() { UlpProgram::State UlpProgram::pop_state() {
// TODO count edges separately // TODO count edges separately
auto edge_count = static_cast<uint16_t>(ulp_edge_count); State state = UlpProgram::peek_state();
auto run_count = static_cast<uint16_t>(ulp_run_count);
ulp_edge_count = 0; ulp_edge_count = 0;
ulp_run_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<uint16_t>(ulp_edge_count); auto edge_count = static_cast<uint16_t>(ulp_edge_count);
auto run_count = static_cast<uint16_t>(ulp_run_count); auto run_count = static_cast<uint16_t>(ulp_run_count);
return {.edge_count = edge_count, .run_count = run_count}; auto mean_exec_time = microseconds{1} * static_cast<uint16_t>(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<uint16_t>(mean_exec_time / microseconds{1});
} }
/* === END ULP ===*/ /* === END ULP ===*/
@ -106,9 +111,9 @@ void PulseCounterUlpSensor::setup() {
this->rising_edge_mode, this->falling_edge_mode); this->rising_edge_mode, this->falling_edge_mode);
} else { } else {
ESP_LOGD(TAG, "Woke up from sleep, skipping set-up of ULP program"); 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_ = std::unique_ptr<UlpProgram>(new UlpProgram);
// this->storage_ = UlpProgram::load(); UlpProgram::State state = this->storage_->peek_state();
// this->last_time = clock::now() - this->storage_->peek_state().run_count * this->storage_->estimate ; this->last_time_ = clock::now() - state.run_count * state.mean_exec_time;
} }
if (!this->storage_) { if (!this->storage_) {
@ -135,16 +140,13 @@ void PulseCounterUlpSensor::update() {
if (!this->storage_) { if (!this->storage_) {
return; return;
} }
UlpProgram::state raw = this->storage_->pop_state(); UlpProgram::State raw = this->storage_->pop_state();
clock::time_point now = clock::now(); clock::time_point now = clock::now();
clock::duration interval = now - this->last_time_; clock::duration interval = now - this->last_time_;
auto estimated_interval = ulp_mean_exec_time_ * raw.run_count;
if (interval != clock::duration::zero()) { if (interval != clock::duration::zero()) {
ulp_mean_exec_time_ = interval / static_cast<float>(raw.run_count); this->storage_->set_mean_exec_time(std::chrono::duration_cast<microseconds>(interval / raw.run_count));
float value = std::chrono::minutes{1} * static_cast<float>(raw.edge_count) / interval; // pulses per minute float value = std::chrono::minutes{1} * static_cast<float>(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': 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); this->publish_state(value);
} }

View file

@ -20,16 +20,17 @@ using microseconds = std::chrono::duration<uint32_t, std::micro>;
class UlpProgram { class UlpProgram {
public: public:
struct state { struct State {
uint16_t edge_count; uint16_t edge_count;
uint16_t run_count; uint16_t run_count;
microseconds mean_exec_time;
}; };
state pop_state(); State pop_state();
state peek_state() const; State peek_state() const;
void set_mean_exec_time(microseconds mean_exec_time);
static std::unique_ptr<UlpProgram> start(gpio_num_t gpio_num, microseconds sleep_duration, CountMode rising_edge_mode, static std::unique_ptr<UlpProgram> start(gpio_num_t gpio_num, microseconds sleep_duration, CountMode rising_edge_mode,
CountMode falling_edge_mode); CountMode falling_edge_mode);
// static std::unique_ptr<UlpProgram> load();
}; };
class PulseCounterUlpSensor : public sensor::Sensor, public PollingComponent { 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_pin(InternalGPIOPin *pin) { pin_ = pin; }
void set_rising_edge_mode(CountMode mode) { this->rising_edge_mode = mode; } 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_falling_edge_mode(CountMode mode) { this->falling_edge_mode = mode; }
void set_sleep_duration(uint32_t duration_us) { void set_sleep_duration(uint32_t duration_us) { this->sleep_duration_ = duration_us * microseconds{1}; }
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_total_sensor(sensor::Sensor *total_sensor) { total_sensor_ = total_sensor; } void set_total_sensor(sensor::Sensor *total_sensor) { total_sensor_ = total_sensor; }
void set_total_pulses(uint32_t pulses); void set_total_pulses(uint32_t pulses);
@ -60,7 +57,6 @@ class PulseCounterUlpSensor : public sensor::Sensor, public PollingComponent {
CountMode falling_edge_mode{CountMode::disable}; CountMode falling_edge_mode{CountMode::disable};
std::unique_ptr<UlpProgram> storage_{}; std::unique_ptr<UlpProgram> storage_{};
clock::time_point last_time_{}; clock::time_point last_time_{};
std::chrono::duration<float> ulp_mean_exec_time_{};
microseconds sleep_duration_{20000}; microseconds sleep_duration_{20000};
uint32_t current_total_{0}; uint32_t current_total_{0};
sensor::Sensor *total_sensor_{nullptr}; sensor::Sensor *total_sensor_{nullptr};

View file

@ -71,6 +71,12 @@ edge_count_total:
io_number: io_number:
.long 0 .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 */ /* Code goes into .text section */
.text .text
.global entry .global entry