Esp32 pulsecounter optional pcnt (#3691)

Co-authored-by: RoboMagus <->
This commit is contained in:
RoboMagus 2022-09-02 03:22:34 +02:00 committed by GitHub
parent 2650441013
commit 1b4156646e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 79 additions and 36 deletions

View file

@ -16,8 +16,17 @@ enum HLW8012SensorModels {
HLW8012_SENSOR_MODEL_BL0937
};
#ifdef HAS_PCNT
#define USE_PCNT true
#else
#define USE_PCNT false
#endif
class HLW8012Component : public PollingComponent {
public:
HLW8012Component()
: cf_store_(*pulse_counter::get_storage(USE_PCNT)), cf1_store_(*pulse_counter::get_storage(USE_PCNT)) {}
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
@ -49,9 +58,9 @@ class HLW8012Component : public PollingComponent {
uint64_t cf_total_pulses_{0};
GPIOPin *sel_pin_;
InternalGPIOPin *cf_pin_;
pulse_counter::PulseCounterStorage cf_store_;
pulse_counter::PulseCounterStorageBase &cf_store_;
InternalGPIOPin *cf1_pin_;
pulse_counter::PulseCounterStorage cf1_store_;
pulse_counter::PulseCounterStorageBase &cf1_store_;
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_{nullptr};
sensor::Sensor *power_sensor_{nullptr};

View file

@ -8,8 +8,16 @@ static const char *const TAG = "pulse_counter";
const char *const EDGE_MODE_TO_STRING[] = {"DISABLE", "INCREMENT", "DECREMENT"};
#ifndef HAS_PCNT
void IRAM_ATTR PulseCounterStorage::gpio_intr(PulseCounterStorage *arg) {
#ifdef HAS_PCNT
PulseCounterStorageBase *get_storage(bool hw_pcnt) {
return (hw_pcnt ? (PulseCounterStorageBase *) (new HwPulseCounterStorage)
: (PulseCounterStorageBase *) (new BasicPulseCounterStorage));
}
#else
PulseCounterStorageBase *get_storage(bool) { return new BasicPulseCounterStorage; }
#endif
void IRAM_ATTR BasicPulseCounterStorage::gpio_intr(BasicPulseCounterStorage *arg) {
const uint32_t now = micros();
const bool discard = now - arg->last_pulse < arg->filter_us;
arg->last_pulse = now;
@ -28,23 +36,22 @@ void IRAM_ATTR PulseCounterStorage::gpio_intr(PulseCounterStorage *arg) {
break;
}
}
bool PulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
bool BasicPulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
this->pin = pin;
this->pin->setup();
this->isr_pin = this->pin->to_isr();
this->pin->attach_interrupt(PulseCounterStorage::gpio_intr, this, gpio::INTERRUPT_ANY_EDGE);
this->pin->attach_interrupt(BasicPulseCounterStorage::gpio_intr, this, gpio::INTERRUPT_ANY_EDGE);
return true;
}
pulse_counter_t PulseCounterStorage::read_raw_value() {
pulse_counter_t BasicPulseCounterStorage::read_raw_value() {
pulse_counter_t counter = this->counter;
pulse_counter_t ret = counter - this->last_value;
this->last_value = counter;
return ret;
}
#endif
#ifdef HAS_PCNT
bool PulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
bool HwPulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
static pcnt_unit_t next_pcnt_unit = PCNT_UNIT_0;
this->pin = pin;
this->pin->setup();
@ -127,7 +134,7 @@ bool PulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
}
return true;
}
pulse_counter_t PulseCounterStorage::read_raw_value() {
pulse_counter_t HwPulseCounterStorage::read_raw_value() {
pulse_counter_t counter;
pcnt_get_counter_value(this->pcnt_unit, &counter);
pulse_counter_t ret = counter - this->last_value;

View file

@ -24,31 +24,44 @@ using pulse_counter_t = int16_t;
using pulse_counter_t = int32_t;
#endif
struct PulseCounterStorage {
bool pulse_counter_setup(InternalGPIOPin *pin);
pulse_counter_t read_raw_value();
static void gpio_intr(PulseCounterStorage *arg);
#ifndef HAS_PCNT
volatile pulse_counter_t counter{0};
volatile uint32_t last_pulse{0};
#endif
struct PulseCounterStorageBase {
virtual bool pulse_counter_setup(InternalGPIOPin *pin) = 0;
virtual pulse_counter_t read_raw_value() = 0;
InternalGPIOPin *pin;
#ifdef HAS_PCNT
pcnt_unit_t pcnt_unit;
#else
ISRInternalGPIOPin isr_pin;
#endif
PulseCounterCountMode rising_edge_mode{PULSE_COUNTER_INCREMENT};
PulseCounterCountMode falling_edge_mode{PULSE_COUNTER_DISABLE};
uint32_t filter_us{0};
pulse_counter_t last_value{0};
};
struct BasicPulseCounterStorage : public PulseCounterStorageBase {
static void gpio_intr(BasicPulseCounterStorage *arg);
bool pulse_counter_setup(InternalGPIOPin *pin) override;
pulse_counter_t read_raw_value() override;
volatile pulse_counter_t counter{0};
volatile uint32_t last_pulse{0};
ISRInternalGPIOPin isr_pin;
};
#ifdef HAS_PCNT
struct HwPulseCounterStorage : public PulseCounterStorageBase {
bool pulse_counter_setup(InternalGPIOPin *pin) override;
pulse_counter_t read_raw_value() override;
pcnt_unit_t pcnt_unit;
};
#endif
PulseCounterStorageBase *get_storage(bool hw_pcnt = false);
class PulseCounterSensor : public sensor::Sensor, public PollingComponent {
public:
explicit PulseCounterSensor(bool hw_pcnt = false) : storage_(*get_storage(hw_pcnt)) {}
void set_pin(InternalGPIOPin *pin) { pin_ = pin; }
void set_rising_edge_mode(PulseCounterCountMode mode) { storage_.rising_edge_mode = mode; }
void set_falling_edge_mode(PulseCounterCountMode mode) { storage_.falling_edge_mode = mode; }
@ -65,7 +78,7 @@ class PulseCounterSensor : public sensor::Sensor, public PollingComponent {
protected:
InternalGPIOPin *pin_;
PulseCounterStorage storage_;
PulseCounterStorageBase &storage_;
uint32_t last_time_{0};
uint32_t current_total_{0};
sensor::Sensor *total_sensor_;

View file

@ -20,6 +20,8 @@ from esphome.const import (
)
from esphome.core import CORE
CONF_USE_PCNT = "use_pcnt"
pulse_counter_ns = cg.esphome_ns.namespace("pulse_counter")
PulseCounterCountMode = pulse_counter_ns.enum("PulseCounterCountMode")
COUNT_MODES = {
@ -40,11 +42,19 @@ SetTotalPulsesAction = pulse_counter_ns.class_(
def validate_internal_filter(value):
value = cv.positive_time_period_microseconds(value)
if CORE.is_esp32:
if value.total_microseconds > 13:
raise cv.Invalid("Maximum internal filter value for ESP32 is 13us")
return value
use_pcnt = value.get(CONF_USE_PCNT)
if CORE.is_esp8266 and use_pcnt:
raise cv.Invalid(
"Using hardware PCNT is only available on ESP32",
[CONF_USE_PCNT],
)
if CORE.is_esp32 and use_pcnt:
if value.get(CONF_INTERNAL_FILTER).total_microseconds > 13:
raise cv.Invalid(
"Maximum internal filter value when using ESP32 hardware PCNT is 13us",
[CONF_INTERNAL_FILTER],
)
return value
@ -69,7 +79,7 @@ def validate_count_mode(value):
return value
CONFIG_SCHEMA = (
CONFIG_SCHEMA = cv.All(
sensor.sensor_schema(
PulseCounterSensor,
unit_of_measurement=UNIT_PULSES_PER_MINUTE,
@ -95,21 +105,25 @@ CONFIG_SCHEMA = (
),
validate_count_mode,
),
cv.Optional(CONF_INTERNAL_FILTER, default="13us"): validate_internal_filter,
cv.SplitDefault(CONF_USE_PCNT, esp32=True): cv.boolean,
cv.Optional(
CONF_INTERNAL_FILTER, default="13us"
): cv.positive_time_period_microseconds,
cv.Optional(CONF_TOTAL): sensor.sensor_schema(
unit_of_measurement=UNIT_PULSES,
icon=ICON_PULSE,
accuracy_decimals=0,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
}
},
)
.extend(cv.polling_component_schema("60s"))
.extend(cv.polling_component_schema("60s")),
validate_internal_filter,
)
async def to_code(config):
var = await sensor.new_sensor(config)
var = await sensor.new_sensor(config, config.get(CONF_USE_PCNT))
await cg.register_component(var, config)
pin = await cg.gpio_pin_expression(config[CONF_PIN])