mirror of
https://github.com/esphome/esphome.git
synced 2024-11-23 23:48:11 +01:00
pulse_counter_ulp: Make sleep duration configurable, keep estimate of ulp runtime
This commit is contained in:
parent
bd9029c2b2
commit
5646dd5d0c
3 changed files with 25 additions and 8 deletions
|
@ -28,8 +28,7 @@ const char *to_string(CountMode count_mode) {
|
||||||
extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start");
|
extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start");
|
||||||
extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end");
|
extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end");
|
||||||
|
|
||||||
namespace {
|
bool UlpProgram::setup_ulp() {
|
||||||
bool setup_ulp(gpio_num_t gpio_num) {
|
|
||||||
esp_err_t error = ulp_load_binary(0, ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t));
|
esp_err_t error = ulp_load_binary(0, ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t));
|
||||||
if (error != ESP_OK) {
|
if (error != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Loading ULP binary failed: %s", esp_err_to_name(error));
|
ESP_LOGE(TAG, "Loading ULP binary failed: %s", esp_err_to_name(error));
|
||||||
|
@ -37,6 +36,7 @@ bool setup_ulp(gpio_num_t gpio_num) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* GPIO used for pulse counting. */
|
/* GPIO used for pulse counting. */
|
||||||
|
auto gpio_num = static_cast<gpio_num_t>(this->pin->get_pin());
|
||||||
int rtcio_num = rtc_io_number_get(gpio_num);
|
int rtcio_num = rtc_io_number_get(gpio_num);
|
||||||
if (!rtc_gpio_is_valid_gpio(gpio_num)) {
|
if (!rtc_gpio_is_valid_gpio(gpio_num)) {
|
||||||
ESP_LOGE(TAG, "GPIO used for pulse counting must be an RTC IO");
|
ESP_LOGE(TAG, "GPIO used for pulse counting must be an RTC IO");
|
||||||
|
@ -63,10 +63,10 @@ bool setup_ulp(gpio_num_t gpio_num) {
|
||||||
rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_INPUT_ONLY);
|
rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_INPUT_ONLY);
|
||||||
rtc_gpio_hold_en(gpio_num);
|
rtc_gpio_hold_en(gpio_num);
|
||||||
|
|
||||||
/* Set ULP wake up period to T = 20ms.
|
/* Set ULP wake up period T
|
||||||
* Minimum pulse width has to be T * (ulp_debounce_counter + 1) = 80ms.
|
* Minimum pulse width has to be T * (ulp_debounce_counter + 1).
|
||||||
*/
|
*/
|
||||||
ulp_set_wakeup_period(0, 20000);
|
ulp_set_wakeup_period(0, this->sleep_duration_ / std::chrono::microseconds{1});
|
||||||
|
|
||||||
/* Start the program */
|
/* Start the program */
|
||||||
error = ulp_run(&ulp_entry - RTC_SLOW_MEM);
|
error = ulp_run(&ulp_entry - RTC_SLOW_MEM);
|
||||||
|
@ -77,7 +77,6 @@ bool setup_ulp(gpio_num_t gpio_num) {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} // namespace
|
|
||||||
|
|
||||||
bool UlpProgram::setup(InternalGPIOPin *pin) {
|
bool UlpProgram::setup(InternalGPIOPin *pin) {
|
||||||
this->pin = pin;
|
this->pin = pin;
|
||||||
|
@ -88,7 +87,7 @@ bool UlpProgram::setup(InternalGPIOPin *pin) {
|
||||||
|
|
||||||
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_UNDEFINED) {
|
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_UNDEFINED) {
|
||||||
ESP_LOGD(TAG, "Did not wake up from sleep, assuming restart or first boot and setting up ULP program");
|
ESP_LOGD(TAG, "Did not wake up from sleep, assuming restart or first boot and setting up ULP program");
|
||||||
return setup_ulp(static_cast<gpio_num_t>(pin->get_pin()));
|
return setup_ulp();
|
||||||
} 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");
|
||||||
return true;
|
return true;
|
||||||
|
@ -138,6 +137,7 @@ void PulseCounterUlpSensor::update() {
|
||||||
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()) {
|
||||||
|
ulp_mean_exec_time_ = interval / static_cast<float>(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);
|
||||||
this->publish_state(value);
|
this->publish_state(value);
|
||||||
|
|
|
@ -15,7 +15,8 @@ enum class CountMode { disable = 0, increment = 1, decrement = -1 };
|
||||||
// millis() jumps when a time component synchronises, so we use steady_clock instead
|
// millis() jumps when a time component synchronises, so we use steady_clock instead
|
||||||
using clock = std::chrono::steady_clock;
|
using clock = std::chrono::steady_clock;
|
||||||
|
|
||||||
struct UlpProgram {
|
class UlpProgram {
|
||||||
|
public:
|
||||||
struct state {
|
struct state {
|
||||||
uint16_t edge_count;
|
uint16_t edge_count;
|
||||||
uint16_t run_count;
|
uint16_t run_count;
|
||||||
|
@ -27,6 +28,10 @@ struct UlpProgram {
|
||||||
InternalGPIOPin *pin;
|
InternalGPIOPin *pin;
|
||||||
CountMode rising_edge_mode{CountMode::increment};
|
CountMode rising_edge_mode{CountMode::increment};
|
||||||
CountMode falling_edge_mode{CountMode::disable};
|
CountMode falling_edge_mode{CountMode::disable};
|
||||||
|
std::chrono::duration<uint32_t, std::micro> sleep_duration_{20000};
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool setup_ulp();
|
||||||
};
|
};
|
||||||
|
|
||||||
class PulseCounterUlpSensor : public sensor::Sensor, public PollingComponent {
|
class PulseCounterUlpSensor : public sensor::Sensor, public PollingComponent {
|
||||||
|
@ -36,6 +41,10 @@ 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) { storage_.rising_edge_mode = mode; }
|
void set_rising_edge_mode(CountMode mode) { storage_.rising_edge_mode = mode; }
|
||||||
void set_falling_edge_mode(CountMode mode) { storage_.falling_edge_mode = mode; }
|
void set_falling_edge_mode(CountMode mode) { storage_.falling_edge_mode = mode; }
|
||||||
|
void set_sleep_duration(uint32_t duration_us) {
|
||||||
|
storage_.sleep_duration_ = std::chrono::microseconds{1} * duration_us;
|
||||||
|
this->ulp_mean_exec_time_ = duration_us * std::chrono::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);
|
||||||
|
@ -50,6 +59,7 @@ class PulseCounterUlpSensor : public sensor::Sensor, public PollingComponent {
|
||||||
InternalGPIOPin *pin_;
|
InternalGPIOPin *pin_;
|
||||||
UlpProgram storage_;
|
UlpProgram storage_;
|
||||||
clock::time_point last_time_{};
|
clock::time_point last_time_{};
|
||||||
|
std::chrono::duration<float> ulp_mean_exec_time_{};
|
||||||
uint32_t current_total_{0};
|
uint32_t current_total_{0};
|
||||||
sensor::Sensor *total_sensor_{nullptr};
|
sensor::Sensor *total_sensor_{nullptr};
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,8 @@ from esphome.const import (
|
||||||
CONF_PIN,
|
CONF_PIN,
|
||||||
CONF_RISING_EDGE,
|
CONF_RISING_EDGE,
|
||||||
CONF_NUMBER,
|
CONF_NUMBER,
|
||||||
|
CONF_SLEEP_DURATION,
|
||||||
|
CONF_DEBOUNCE,
|
||||||
CONF_TOTAL,
|
CONF_TOTAL,
|
||||||
CONF_VALUE,
|
CONF_VALUE,
|
||||||
ICON_PULSE,
|
ICON_PULSE,
|
||||||
|
@ -86,6 +88,10 @@ CONFIG_SCHEMA = cv.All(
|
||||||
),
|
),
|
||||||
validate_count_mode,
|
validate_count_mode,
|
||||||
),
|
),
|
||||||
|
cv.Optional(
|
||||||
|
CONF_SLEEP_DURATION, default="20000us"
|
||||||
|
): cv.positive_time_period_microseconds,
|
||||||
|
cv.Optional(CONF_DEBOUNCE, default=3): cv.positive_int,
|
||||||
cv.Optional(CONF_TOTAL): sensor.sensor_schema(
|
cv.Optional(CONF_TOTAL): sensor.sensor_schema(
|
||||||
unit_of_measurement=UNIT_PULSES,
|
unit_of_measurement=UNIT_PULSES,
|
||||||
icon=ICON_PULSE,
|
icon=ICON_PULSE,
|
||||||
|
@ -119,6 +125,7 @@ async def to_code(config):
|
||||||
count = config[CONF_COUNT_MODE]
|
count = config[CONF_COUNT_MODE]
|
||||||
cg.add(var.set_rising_edge_mode(count[CONF_RISING_EDGE]))
|
cg.add(var.set_rising_edge_mode(count[CONF_RISING_EDGE]))
|
||||||
cg.add(var.set_falling_edge_mode(count[CONF_FALLING_EDGE]))
|
cg.add(var.set_falling_edge_mode(count[CONF_FALLING_EDGE]))
|
||||||
|
cg.add(var.set_sleep_duration(config[CONF_SLEEP_DURATION]))
|
||||||
|
|
||||||
if CONF_TOTAL in config:
|
if CONF_TOTAL in config:
|
||||||
sens = await sensor.new_sensor(config[CONF_TOTAL])
|
sens = await sensor.new_sensor(config[CONF_TOTAL])
|
||||||
|
|
Loading…
Reference in a new issue