pulse_counter: Integrate platformio ulp example into pulse_counter

This commit is contained in:
brisk 2024-04-03 22:03:08 +10:30
parent 49b4169f51
commit 30d4a7fb34
2 changed files with 110 additions and 2 deletions

View file

@ -1,5 +1,10 @@
#include "pulse_counter_sensor.h"
#include "esphome/core/log.h"
// TODO This cannot be a general dependency for this file
#include "esp32/ulp.h"
#include "ulp_main.h"
#include "soc/rtc_periph.h"
#include "driver/rtc_io.h"
namespace esphome {
namespace pulse_counter {
@ -15,7 +20,10 @@ PulseCounterStorageBase *get_storage(Storage storage) {
return new BasicPulseCounterStorage;
case Storage::pcnt:
return new HwPulseCounterStorage;
case Storage::ulp:
return new UlpPulseCounterStorage;
}
return new BasicPulseCounterStorage;
}
#else
PulseCounterStorageBase *get_storage(Storage) { return new BasicPulseCounterStorage; }
@ -145,6 +153,101 @@ pulse_counter_t HwPulseCounterStorage::read_raw_value() {
this->last_value = counter;
return ret;
}
/* === ULP === */
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");
bool UlpPulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
this->pin = pin;
this->pin->setup();
uint32_t rising = 0;
uint32_t falling = 0;
switch (this->rising_edge_mode) {
case PULSE_COUNTER_DISABLE:
rising = 0;
break;
case PULSE_COUNTER_INCREMENT:
rising = +1;
break;
case PULSE_COUNTER_DECREMENT:
rising = -1;
break;
}
switch (this->falling_edge_mode) {
case PULSE_COUNTER_DISABLE:
falling = 0;
break;
case PULSE_COUNTER_INCREMENT:
falling = +1;
break;
case PULSE_COUNTER_DECREMENT:
falling = -1;
break;
}
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) {
ESP_LOGE(TAG, "Loading ULP binary failed: %s", esp_err_to_name(error));
return false;
}
/* GPIO used for pulse counting. */
gpio_num_t gpio_num = GPIO_NUM_0;
int rtcio_num = rtc_io_number_get(gpio_num);
assert(rtc_gpio_is_valid_gpio(gpio_num) && "GPIO used for pulse counting must be an RTC IO");
/* Initialize some variables used by ULP program.
* Each 'ulp_xyz' variable corresponds to 'xyz' variable in the ULP program.
* These variables are declared in an auto generated header file,
* 'ulp_main.h', name of this file is defined in component.mk as ULP_APP_NAME.
* These variables are located in RTC_SLOW_MEM and can be accessed both by the
* ULP and the main CPUs.
*
* Note that the ULP reads only the lower 16 bits of these variables.
*/
ulp_debounce_counter = 3;
ulp_debounce_max_count = 3;
ulp_next_edge = 0;
ulp_io_number = rtcio_num; /* map from GPIO# to RTC_IO# */
ulp_edge_count_to_wake_up = 10;
/* Initialize selected GPIO as RTC IO, enable input, disable pullup and pulldown */
rtc_gpio_init(gpio_num);
rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_INPUT_ONLY);
rtc_gpio_pulldown_dis(gpio_num);
rtc_gpio_pullup_dis(gpio_num);
rtc_gpio_hold_en(gpio_num);
/* Set ULP wake up period to T = 20ms.
* Minimum pulse width has to be T * (ulp_debounce_counter + 1) = 80ms.
*/
ulp_set_wakeup_period(0, 20000);
/* Start the program */
error = ulp_run(&ulp_entry - RTC_SLOW_MEM);
if (error != ESP_OK) {
ESP_LOGE(TAG, "Starting ULP program failed: %s", esp_err_to_name(error));
return false;
}
// TODO Support Filter
return true;
}
pulse_counter_t UlpPulseCounterStorage::read_raw_value() {
// TODO count edges separately
uint32_t count = (ulp_edge_count & UINT16_MAX) / 2;
ulp_edge_count = 0;
return count;
}
/* === END ULP ===*/
#endif
void PulseCounterSensor::setup() {

View file

@ -20,7 +20,7 @@ enum PulseCounterCountMode {
PULSE_COUNTER_DECREMENT,
};
enum class Storage { basic, pcnt };
enum class Storage { basic, pcnt, ulp };
#ifdef HAS_PCNT
using pulse_counter_t = int16_t;
@ -58,6 +58,11 @@ struct HwPulseCounterStorage : public PulseCounterStorageBase {
pcnt_unit_t pcnt_unit;
};
struct UlpPulseCounterStorage : public PulseCounterStorageBase {
bool pulse_counter_setup(InternalGPIOPin *pin) override;
pulse_counter_t read_raw_value() override;
};
#endif
PulseCounterStorageBase *get_storage(Storage storage = Storage::basic);
@ -65,7 +70,7 @@ PulseCounterStorageBase *get_storage(Storage storage = Storage::basic);
class PulseCounterSensor : public sensor::Sensor, public PollingComponent {
public:
explicit PulseCounterSensor(Storage storage = Storage::basic) : storage_(*get_storage(storage)) {}
explicit PulseCounterSensor(int storage = 0) : PulseCounterSensor(Storage(storage)) {}
PulseCounterSensor(int storage = 0) : PulseCounterSensor(Storage(storage)) {}
void set_pin(InternalGPIOPin *pin) { pin_ = pin; }
void set_rising_edge_mode(PulseCounterCountMode mode) { storage_.rising_edge_mode = mode; }