pulse_counter_ulp: Count pulses not edges

- Count both separately in ULP program
- Manage pin inversion manually in update()
- Take into account configured mode
This commit is contained in:
brisk 2024-09-29 21:44:56 +09:30
parent 40b18666c9
commit c57ad9fff9
3 changed files with 58 additions and 25 deletions

View file

@ -51,11 +51,12 @@ std::unique_ptr<UlpProgram> 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<uint16_t>(!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> 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<uint16_t>(ulp_edge_count);
auto rising_edge_count = static_cast<uint16_t>(ulp_rising_edge_count);
auto falling_edge_count = static_cast<uint16_t>(ulp_falling_edge_count);
auto run_count = static_cast<uint16_t>(ulp_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};
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<UlpProgram>(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<int32_t>(config_.rising_edge_mode_) * raw.falling_edge_count_ +
static_cast<int32_t>(config_.falling_edge_mode_) * raw.rising_edge_count_;
} else {
pulse_count = static_cast<int32_t>(config_.rising_edge_mode_) * raw.rising_edge_count_ +
static_cast<int32_t>(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<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);
this->storage_->set_mean_exec_time(std::chrono::duration_cast<microseconds>(interval / raw.run_count_));
float value = std::chrono::minutes{1} * static_cast<float>(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);
}

View file

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

View file

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