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_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> UlpProgram::start(gpio_num_t gpio_num, microseconds
return std::unique_ptr<UlpProgram>(new UlpProgram());
}
UlpProgram::state UlpProgram::pop_state() {
UlpProgram::State UlpProgram::pop_state() {
// TODO count edges separately
auto edge_count = static_cast<uint16_t>(ulp_edge_count);
auto run_count = static_cast<uint16_t>(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<uint16_t>(ulp_edge_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 ===*/
@ -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<UlpProgram>(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<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
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);
}

View file

@ -20,16 +20,17 @@ using microseconds = std::chrono::duration<uint32_t, std::micro>;
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<UlpProgram> start(gpio_num_t gpio_num, microseconds sleep_duration, CountMode rising_edge_mode,
CountMode falling_edge_mode);
// static std::unique_ptr<UlpProgram> 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<UlpProgram> storage_{};
clock::time_point last_time_{};
std::chrono::duration<float> ulp_mean_exec_time_{};
microseconds sleep_duration_{20000};
uint32_t current_total_{0};
sensor::Sensor *total_sensor_{nullptr};

View file

@ -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