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. * 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_run_count = 0;
ulp_debounce_counter = 3; ulp_debounce_counter = 3;
ulp_debounce_max_count = config.debounce_; 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_io_number = rtcio_num; /* map from GPIO# to RTC_IO# */
ulp_mean_exec_time = config.sleep_duration_ / microseconds{1}; 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() { UlpProgram::State UlpProgram::pop_state() {
// TODO count edges separately
State state = UlpProgram::peek_state(); State state = UlpProgram::peek_state();
ulp_edge_count = 0; ulp_rising_edge_count = 0;
ulp_falling_edge_count = 0;
ulp_run_count = 0; ulp_run_count = 0;
return state; 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 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 run_count = static_cast<uint16_t>(ulp_run_count);
auto mean_exec_time = microseconds{1} * static_cast<uint16_t>(ulp_mean_exec_time); 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) { 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"); ESP_LOGD(TAG, "Woke up from sleep, skipping set-up of ULP program");
this->storage_ = std::unique_ptr<UlpProgram>(new UlpProgram); this->storage_ = std::unique_ptr<UlpProgram>(new UlpProgram);
UlpProgram::State state = this->storage_->peek_state(); 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_) { if (!this->storage_) {
@ -126,8 +131,8 @@ void PulseCounterUlpSensor::dump_config() {
LOG_PIN(" Pin: ", this->config_.pin_); LOG_PIN(" Pin: ", this->config_.pin_);
ESP_LOGCONFIG(TAG, " Rising Edge: %s", to_string(this->config_.rising_edge_mode_)); 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, " 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, " Sleep Duration: %" PRIu32 " µs", this->config_.sleep_duration_ / microseconds{1});
ESP_LOGCONFIG(TAG, " Debounce: " PRIu16, this->config_.debounce_); ESP_LOGCONFIG(TAG, " Debounce: %" PRIu16, this->config_.debounce_);
LOG_UPDATE_INTERVAL(this); LOG_UPDATE_INTERVAL(this);
} }
@ -137,12 +142,23 @@ void PulseCounterUlpSensor::update() {
return; return;
} }
UlpProgram::State raw = this->storage_->pop_state(); 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::time_point now = clock::now();
clock::duration interval = now - this->last_time_; clock::duration interval = now - this->last_time_;
if (interval != clock::duration::zero()) { if (interval != clock::duration::zero()) {
this->storage_->set_mean_exec_time(std::chrono::duration_cast<microseconds>(interval / 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>(pulse_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: %" PRIu32 " pulses at %0.2f pulses/min", this->get_name().c_str(),
pulse_count, value);
this->publish_state(value); this->publish_state(value);
} }

View file

@ -28,9 +28,10 @@ class UlpProgram {
uint16_t debounce_; uint16_t debounce_;
}; };
struct State { struct State {
uint16_t edge_count; uint16_t rising_edge_count_;
uint16_t run_count; uint16_t falling_edge_count_;
microseconds mean_exec_time; uint16_t run_count_;
microseconds mean_exec_time_;
}; };
State pop_state(); State pop_state();
State peek_state() const; State peek_state() const;

View file

@ -50,9 +50,14 @@ debounce_counter:
debounce_max_count: debounce_max_count:
.long 0 .long 0
/* Number of signal edges acquired since last read */ /* Number of rising signal edges acquired since last read */
.global edge_count .global rising_edge_count
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 .long 0
/* Number of times program run since last read */ /* Number of times program run since last read */
@ -161,13 +166,24 @@ edge_detected:
add r2, r2, 1 add r2, r2, 1
and r2, r2, 1 and r2, r2, 1
st r2, r3, 0 st r2, r3, 0
/* Increment edge_count */ /* Jump to increment of current edge counter */
move r3, edge_count add r2, r2, 0 /* dummy ADD to use "jump if ALU result is zero" */
ld r2, r3, 0 jump rising, eq
add r2, r2, 1
st r2, r3, 0 .global falling
/* Increment edge_count_total */ falling:
move r3, edge_count_total /* 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 ld r2, r3, 0
add r2, r2, 1 add r2, r2, 1
st r2, r3, 0 st r2, r3, 0