Skip to main content
added comment where liter count is incremented
Source Link
Guntis
  • 111
  • 1
  • 4
#include "freertos/queue.h"
#include "driver/pcnt.h"
#include "driver/periph_ctrl.h"
#include "driver/gpio.h"
#include "esp_attr.h"


#define PCNT_H_LIM_VAL      1
#define PCNT_L_LIM_VAL     -1
#define PCNT_THRESH1_VAL    0
#define PCNT_THRESH0_VAL   -0
#define PCNT_INPUT_SIG_WC_HOT   32 // hot water counter  
#define PCNT_INPUT_SIG_WC_COLD  33 // cold water counter
/*
Cold meter uses PCNT_UNIT_1
hot meter uses PCNT_UNIT_0
*/
xQueueHandle pcnt_evt_queue;   // A queue to handle pulse counter events
pcnt_isr_handle_t user_isr_handle = NULL; //user's ISR service handle



/* A sample structure to pass events from the PCNT
 * interrupt handler to the main program.
 */
typedef struct {
    pcnt_unit_t unit;  // the PCNT unit that originated an interrupt
    uint32_t status; // information on the event type that caused the interrupt
} pcnt_evt_t;

/* Decode what PCNT's unit originated an interrupt
 * and pass this information together with the event type
 * the main program using a queue.
 */
static void IRAM_ATTR pcnt_example_intr_handler(void *arg)
{
    uint32_t intr_status = PCNT.int_st.val;
    int i;
    pcnt_evt_t evt;
    portBASE_TYPE HPTaskAwoken = pdFALSE;

    for (i = 0; i < PCNT_UNIT_MAX; i++) {
        if (intr_status & (BIT(i))) {
            evt.unit = (pcnt_unit_t)i;
            /* Save the PCNT event type that caused an interrupt
               to pass it to the main program */
            evt.status = PCNT.status_unit[i].val;
            PCNT.int_clr.val = BIT(i);
            xQueueSendFromISR(pcnt_evt_queue, &evt, &HPTaskAwoken);
            if (HPTaskAwoken == pdTRUE) {
                portYIELD_FROM_ISR();
            }
        }
    }
}


/* Initialize PCNT functions:
 *  - configure and initialize PCNT
 *  - set up the input filter
 *  - set up the counter events to watch
 */
static void pcnt_example_init()
{
    //Serial.printf("pcnt_example_init(%d, %d)\n", _unit, _pin);
    /* Prepare configuration for the PCNT unit */
    pcnt_config_t pcnt_config = {};
    pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_WC_HOT;
    pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
    pcnt_config.channel = PCNT_CHANNEL_0;
    pcnt_config.pos_mode = PCNT_COUNT_INC;
    pcnt_config.neg_mode = PCNT_COUNT_DIS;
    pcnt_config.lctrl_mode = PCNT_MODE_KEEP;//PCNT_MODE_REVERSE;
    pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
    pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
    pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
    pcnt_config.unit = PCNT_UNIT_0;
    
    /* Initialize PCNT unit */
    ESP_ERROR_CHECK(pcnt_unit_config(&pcnt_config));


    /* cold water meter */
    pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_WC_COLD;
    pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
    pcnt_config.channel = PCNT_CHANNEL_0;
    pcnt_config.pos_mode = PCNT_COUNT_INC;
    pcnt_config.neg_mode = PCNT_COUNT_DIS;
    pcnt_config.lctrl_mode = PCNT_MODE_KEEP;//PCNT_MODE_REVERSE;
    pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
    pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
    pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
    pcnt_config.unit = PCNT_UNIT_1;
    ESP_ERROR_CHECK(pcnt_unit_config(&pcnt_config));



    /* Configure and enable the input filter */
    ESP_ERROR_CHECK(pcnt_set_filter_value(PCNT_UNIT_0, 1000)); // filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
    ESP_ERROR_CHECK(pcnt_filter_enable(PCNT_UNIT_0));

    /* Set threshold 0 and 1 values and enable events to watch */
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1));
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
    /* Enable events on zero, maximum and minimum limit values */
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_ZERO));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_H_LIM));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_L_LIM));

    /* Initialize PCNT's counter */
    ESP_ERROR_CHECK(pcnt_counter_pause(PCNT_UNIT_0));
    ESP_ERROR_CHECK(pcnt_counter_clear(PCNT_UNIT_0));

    /* Register ISR handler and enable interrupts for PCNT unit */
    ESP_ERROR_CHECK(pcnt_isr_register(pcnt_example_intr_handler, NULL, 0, &user_isr_handle));
    ESP_ERROR_CHECK(pcnt_intr_enable(PCNT_UNIT_0));

    /* Everything is set up, now go to counting */
    ESP_ERROR_CHECK(pcnt_counter_resume(PCNT_UNIT_0));




    /* PCNT_UNIT_1 configuration  */
    /* Configure and enable the input filter */
    ESP_ERROR_CHECK(pcnt_set_filter_value(PCNT_UNIT_1, 1000)); // filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
    ESP_ERROR_CHECK(pcnt_filter_enable(PCNT_UNIT_1));

    /* Set threshold 0 and 1 values and enable events to watch */
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_1, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_THRES_1));
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_1, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_THRES_0));
    /* Enable events on zero, maximum and minimum limit values */
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_ZERO));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_H_LIM));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_L_LIM));

    /* Initialize PCNT's counter */
    ESP_ERROR_CHECK(pcnt_counter_pause(PCNT_UNIT_1));
    ESP_ERROR_CHECK(pcnt_counter_clear(PCNT_UNIT_1));

    ESP_ERROR_CHECK(pcnt_intr_enable(PCNT_UNIT_1));

    /* Everything is set up, now go to counting */
    ESP_ERROR_CHECK(pcnt_counter_resume(PCNT_UNIT_1));
}



void setup() {
  Serial.begin(115200);
  Serial.println("Boot...");
  // put your setup code here, to run once:
  pinMode(PCNT_INPUT_SIG_WC_HOT, INPUT_PULLUP);
  pinMode(PCNT_INPUT_SIG_WC_COLD, INPUT_PULLUP);
  /* Initialize PCNT event queue and PCNT functions */
  pcnt_evt_queue = xQueueCreate(10, sizeof(pcnt_evt_t));

  pcnt_example_init();
  //  pcnt_example_init(PCNT_UNIT_WC_HOT, PCNT_INPUT_SIG_WC_HOT);
    //pcnt_example_init(PCNT_UNIT_WC_COLD, PCNT_INPUT_SIG_WC_COLD);

    Serial.printf("Setup done\n");
}

int16_t count = 0;
pcnt_evt_t evt;
portBASE_TYPE res;

char * chToName(int ch)
{
  if (ch == 1) return "Cold";
  if (ch == 0) return "Hot";

  return "Unc";
}

void loop() {
  // put your main code here, to run repeatedly:
      /* Wait for the event information passed from PCNT's interrupt handler.
         * Once received, decode the event type and print it on the serial monitor.
         */
        res = xQueueReceive(pcnt_evt_queue, &evt, 1000 / portTICK_PERIOD_MS);
        if (res == pdTRUE) {
            pcnt_get_counter_value(evt.unit, &count);
            Serial.printf("Event PCNT unit[%d=%s]; cnt: %d, status: %d\n", evt.unit, chToName(evt.unit), count, evt.status);
            if (evt.status & PCNT_EVT_THRES_1) {
                Serial.printf("THRES1 EVT\n");
            }
            if (evt.status & PCNT_EVT_THRES_0) {
                Serial.printf("THRES0 EVT\n");
            }
            if (evt.status & PCNT_EVT_L_LIM) {
                Serial.printf("L_LIM EVT\n");
            }
            if (evt.status & PCNT_EVT_H_LIM) {
                Serial.printf("H_LIM EVT\n");
            }
            if (evt.status & PCNT_EVT_ZERO) {
                Serial.printf("ZERO EVT\n");
                // here we are increment liter count
            }
        } else {
            pcnt_get_counter_value(PCNT_UNIT_0, &count);
            Serial.printf("Current counter value: %s=%d,", chToName(PCNT_UNIT_0), count);
            pcnt_get_counter_value(PCNT_UNIT_1, &count);
            Serial.printf(" %s=%d\n", chToName(PCNT_UNIT_1), count);
            //pcnt_get_counter_value(PCNT_UNIT_WC_COLD, &count);
            //Serial.printf(", %d on unit: %d\n", count, PCNT_UNIT_WC_COLD);
        }    

        /*
        if(user_isr_handle) {
          Serial.printf("Clearing user_isr_handle\n");
          //Free the ISR service handle.
          esp_intr_free(user_isr_handle);
          user_isr_handle = NULL;
        }*/
} 
#include "freertos/queue.h"
#include "driver/pcnt.h"
#include "driver/periph_ctrl.h"
#include "driver/gpio.h"
#include "esp_attr.h"


#define PCNT_H_LIM_VAL      1
#define PCNT_L_LIM_VAL     -1
#define PCNT_THRESH1_VAL    0
#define PCNT_THRESH0_VAL   -0
#define PCNT_INPUT_SIG_WC_HOT   32 // hot water counter  
#define PCNT_INPUT_SIG_WC_COLD  33 // cold water counter
/*
Cold meter uses PCNT_UNIT_1
hot meter uses PCNT_UNIT_0
*/
xQueueHandle pcnt_evt_queue;   // A queue to handle pulse counter events
pcnt_isr_handle_t user_isr_handle = NULL; //user's ISR service handle



/* A sample structure to pass events from the PCNT
 * interrupt handler to the main program.
 */
typedef struct {
    pcnt_unit_t unit;  // the PCNT unit that originated an interrupt
    uint32_t status; // information on the event type that caused the interrupt
} pcnt_evt_t;

/* Decode what PCNT's unit originated an interrupt
 * and pass this information together with the event type
 * the main program using a queue.
 */
static void IRAM_ATTR pcnt_example_intr_handler(void *arg)
{
    uint32_t intr_status = PCNT.int_st.val;
    int i;
    pcnt_evt_t evt;
    portBASE_TYPE HPTaskAwoken = pdFALSE;

    for (i = 0; i < PCNT_UNIT_MAX; i++) {
        if (intr_status & (BIT(i))) {
            evt.unit = (pcnt_unit_t)i;
            /* Save the PCNT event type that caused an interrupt
               to pass it to the main program */
            evt.status = PCNT.status_unit[i].val;
            PCNT.int_clr.val = BIT(i);
            xQueueSendFromISR(pcnt_evt_queue, &evt, &HPTaskAwoken);
            if (HPTaskAwoken == pdTRUE) {
                portYIELD_FROM_ISR();
            }
        }
    }
}


/* Initialize PCNT functions:
 *  - configure and initialize PCNT
 *  - set up the input filter
 *  - set up the counter events to watch
 */
static void pcnt_example_init()
{
    //Serial.printf("pcnt_example_init(%d, %d)\n", _unit, _pin);
    /* Prepare configuration for the PCNT unit */
    pcnt_config_t pcnt_config = {};
    pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_WC_HOT;
    pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
    pcnt_config.channel = PCNT_CHANNEL_0;
    pcnt_config.pos_mode = PCNT_COUNT_INC;
    pcnt_config.neg_mode = PCNT_COUNT_DIS;
    pcnt_config.lctrl_mode = PCNT_MODE_KEEP;//PCNT_MODE_REVERSE;
    pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
    pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
    pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
    pcnt_config.unit = PCNT_UNIT_0;
    
    /* Initialize PCNT unit */
    ESP_ERROR_CHECK(pcnt_unit_config(&pcnt_config));


    /* cold water meter */
    pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_WC_COLD;
    pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
    pcnt_config.channel = PCNT_CHANNEL_0;
    pcnt_config.pos_mode = PCNT_COUNT_INC;
    pcnt_config.neg_mode = PCNT_COUNT_DIS;
    pcnt_config.lctrl_mode = PCNT_MODE_KEEP;//PCNT_MODE_REVERSE;
    pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
    pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
    pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
    pcnt_config.unit = PCNT_UNIT_1;
    ESP_ERROR_CHECK(pcnt_unit_config(&pcnt_config));



    /* Configure and enable the input filter */
    ESP_ERROR_CHECK(pcnt_set_filter_value(PCNT_UNIT_0, 1000)); // filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
    ESP_ERROR_CHECK(pcnt_filter_enable(PCNT_UNIT_0));

    /* Set threshold 0 and 1 values and enable events to watch */
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1));
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
    /* Enable events on zero, maximum and minimum limit values */
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_ZERO));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_H_LIM));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_L_LIM));

    /* Initialize PCNT's counter */
    ESP_ERROR_CHECK(pcnt_counter_pause(PCNT_UNIT_0));
    ESP_ERROR_CHECK(pcnt_counter_clear(PCNT_UNIT_0));

    /* Register ISR handler and enable interrupts for PCNT unit */
    ESP_ERROR_CHECK(pcnt_isr_register(pcnt_example_intr_handler, NULL, 0, &user_isr_handle));
    ESP_ERROR_CHECK(pcnt_intr_enable(PCNT_UNIT_0));

    /* Everything is set up, now go to counting */
    ESP_ERROR_CHECK(pcnt_counter_resume(PCNT_UNIT_0));




    /* PCNT_UNIT_1 configuration  */
    /* Configure and enable the input filter */
    ESP_ERROR_CHECK(pcnt_set_filter_value(PCNT_UNIT_1, 1000)); // filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
    ESP_ERROR_CHECK(pcnt_filter_enable(PCNT_UNIT_1));

    /* Set threshold 0 and 1 values and enable events to watch */
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_1, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_THRES_1));
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_1, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_THRES_0));
    /* Enable events on zero, maximum and minimum limit values */
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_ZERO));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_H_LIM));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_L_LIM));

    /* Initialize PCNT's counter */
    ESP_ERROR_CHECK(pcnt_counter_pause(PCNT_UNIT_1));
    ESP_ERROR_CHECK(pcnt_counter_clear(PCNT_UNIT_1));

    ESP_ERROR_CHECK(pcnt_intr_enable(PCNT_UNIT_1));

    /* Everything is set up, now go to counting */
    ESP_ERROR_CHECK(pcnt_counter_resume(PCNT_UNIT_1));
}



void setup() {
  Serial.begin(115200);
  Serial.println("Boot...");
  // put your setup code here, to run once:
  pinMode(PCNT_INPUT_SIG_WC_HOT, INPUT_PULLUP);
  pinMode(PCNT_INPUT_SIG_WC_COLD, INPUT_PULLUP);
  /* Initialize PCNT event queue and PCNT functions */
  pcnt_evt_queue = xQueueCreate(10, sizeof(pcnt_evt_t));

  pcnt_example_init();
  //  pcnt_example_init(PCNT_UNIT_WC_HOT, PCNT_INPUT_SIG_WC_HOT);
    //pcnt_example_init(PCNT_UNIT_WC_COLD, PCNT_INPUT_SIG_WC_COLD);

    Serial.printf("Setup done\n");
}

int16_t count = 0;
pcnt_evt_t evt;
portBASE_TYPE res;

char * chToName(int ch)
{
  if (ch == 1) return "Cold";
  if (ch == 0) return "Hot";

  return "Unc";
}

void loop() {
  // put your main code here, to run repeatedly:
      /* Wait for the event information passed from PCNT's interrupt handler.
         * Once received, decode the event type and print it on the serial monitor.
         */
        res = xQueueReceive(pcnt_evt_queue, &evt, 1000 / portTICK_PERIOD_MS);
        if (res == pdTRUE) {
            pcnt_get_counter_value(evt.unit, &count);
            Serial.printf("Event PCNT unit[%d=%s]; cnt: %d, status: %d\n", evt.unit, chToName(evt.unit), count, evt.status);
            if (evt.status & PCNT_EVT_THRES_1) {
                Serial.printf("THRES1 EVT\n");
            }
            if (evt.status & PCNT_EVT_THRES_0) {
                Serial.printf("THRES0 EVT\n");
            }
            if (evt.status & PCNT_EVT_L_LIM) {
                Serial.printf("L_LIM EVT\n");
            }
            if (evt.status & PCNT_EVT_H_LIM) {
                Serial.printf("H_LIM EVT\n");
            }
            if (evt.status & PCNT_EVT_ZERO) {
                Serial.printf("ZERO EVT\n");
            }
        } else {
            pcnt_get_counter_value(PCNT_UNIT_0, &count);
            Serial.printf("Current counter value: %s=%d,", chToName(PCNT_UNIT_0), count);
            pcnt_get_counter_value(PCNT_UNIT_1, &count);
            Serial.printf(" %s=%d\n", chToName(PCNT_UNIT_1), count);
            //pcnt_get_counter_value(PCNT_UNIT_WC_COLD, &count);
            //Serial.printf(", %d on unit: %d\n", count, PCNT_UNIT_WC_COLD);
        }    

        /*
        if(user_isr_handle) {
          Serial.printf("Clearing user_isr_handle\n");
          //Free the ISR service handle.
          esp_intr_free(user_isr_handle);
          user_isr_handle = NULL;
        }*/
} 
#include "freertos/queue.h"
#include "driver/pcnt.h"
#include "driver/periph_ctrl.h"
#include "driver/gpio.h"
#include "esp_attr.h"


#define PCNT_H_LIM_VAL      1
#define PCNT_L_LIM_VAL     -1
#define PCNT_THRESH1_VAL    0
#define PCNT_THRESH0_VAL   -0
#define PCNT_INPUT_SIG_WC_HOT   32 // hot water counter  
#define PCNT_INPUT_SIG_WC_COLD  33 // cold water counter
/*
Cold meter uses PCNT_UNIT_1
hot meter uses PCNT_UNIT_0
*/
xQueueHandle pcnt_evt_queue;   // A queue to handle pulse counter events
pcnt_isr_handle_t user_isr_handle = NULL; //user's ISR service handle



/* A sample structure to pass events from the PCNT
 * interrupt handler to the main program.
 */
typedef struct {
    pcnt_unit_t unit;  // the PCNT unit that originated an interrupt
    uint32_t status; // information on the event type that caused the interrupt
} pcnt_evt_t;

/* Decode what PCNT's unit originated an interrupt
 * and pass this information together with the event type
 * the main program using a queue.
 */
static void IRAM_ATTR pcnt_example_intr_handler(void *arg)
{
    uint32_t intr_status = PCNT.int_st.val;
    int i;
    pcnt_evt_t evt;
    portBASE_TYPE HPTaskAwoken = pdFALSE;

    for (i = 0; i < PCNT_UNIT_MAX; i++) {
        if (intr_status & (BIT(i))) {
            evt.unit = (pcnt_unit_t)i;
            /* Save the PCNT event type that caused an interrupt
               to pass it to the main program */
            evt.status = PCNT.status_unit[i].val;
            PCNT.int_clr.val = BIT(i);
            xQueueSendFromISR(pcnt_evt_queue, &evt, &HPTaskAwoken);
            if (HPTaskAwoken == pdTRUE) {
                portYIELD_FROM_ISR();
            }
        }
    }
}


/* Initialize PCNT functions:
 *  - configure and initialize PCNT
 *  - set up the input filter
 *  - set up the counter events to watch
 */
static void pcnt_example_init()
{
    //Serial.printf("pcnt_example_init(%d, %d)\n", _unit, _pin);
    /* Prepare configuration for the PCNT unit */
    pcnt_config_t pcnt_config = {};
    pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_WC_HOT;
    pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
    pcnt_config.channel = PCNT_CHANNEL_0;
    pcnt_config.pos_mode = PCNT_COUNT_INC;
    pcnt_config.neg_mode = PCNT_COUNT_DIS;
    pcnt_config.lctrl_mode = PCNT_MODE_KEEP;//PCNT_MODE_REVERSE;
    pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
    pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
    pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
    pcnt_config.unit = PCNT_UNIT_0;
    
    /* Initialize PCNT unit */
    ESP_ERROR_CHECK(pcnt_unit_config(&pcnt_config));


    /* cold water meter */
    pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_WC_COLD;
    pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
    pcnt_config.channel = PCNT_CHANNEL_0;
    pcnt_config.pos_mode = PCNT_COUNT_INC;
    pcnt_config.neg_mode = PCNT_COUNT_DIS;
    pcnt_config.lctrl_mode = PCNT_MODE_KEEP;//PCNT_MODE_REVERSE;
    pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
    pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
    pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
    pcnt_config.unit = PCNT_UNIT_1;
    ESP_ERROR_CHECK(pcnt_unit_config(&pcnt_config));



    /* Configure and enable the input filter */
    ESP_ERROR_CHECK(pcnt_set_filter_value(PCNT_UNIT_0, 1000)); // filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
    ESP_ERROR_CHECK(pcnt_filter_enable(PCNT_UNIT_0));

    /* Set threshold 0 and 1 values and enable events to watch */
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1));
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
    /* Enable events on zero, maximum and minimum limit values */
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_ZERO));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_H_LIM));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_L_LIM));

    /* Initialize PCNT's counter */
    ESP_ERROR_CHECK(pcnt_counter_pause(PCNT_UNIT_0));
    ESP_ERROR_CHECK(pcnt_counter_clear(PCNT_UNIT_0));

    /* Register ISR handler and enable interrupts for PCNT unit */
    ESP_ERROR_CHECK(pcnt_isr_register(pcnt_example_intr_handler, NULL, 0, &user_isr_handle));
    ESP_ERROR_CHECK(pcnt_intr_enable(PCNT_UNIT_0));

    /* Everything is set up, now go to counting */
    ESP_ERROR_CHECK(pcnt_counter_resume(PCNT_UNIT_0));




    /* PCNT_UNIT_1 configuration  */
    /* Configure and enable the input filter */
    ESP_ERROR_CHECK(pcnt_set_filter_value(PCNT_UNIT_1, 1000)); // filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
    ESP_ERROR_CHECK(pcnt_filter_enable(PCNT_UNIT_1));

    /* Set threshold 0 and 1 values and enable events to watch */
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_1, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_THRES_1));
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_1, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_THRES_0));
    /* Enable events on zero, maximum and minimum limit values */
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_ZERO));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_H_LIM));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_L_LIM));

    /* Initialize PCNT's counter */
    ESP_ERROR_CHECK(pcnt_counter_pause(PCNT_UNIT_1));
    ESP_ERROR_CHECK(pcnt_counter_clear(PCNT_UNIT_1));

    ESP_ERROR_CHECK(pcnt_intr_enable(PCNT_UNIT_1));

    /* Everything is set up, now go to counting */
    ESP_ERROR_CHECK(pcnt_counter_resume(PCNT_UNIT_1));
}



void setup() {
  Serial.begin(115200);
  Serial.println("Boot...");
  // put your setup code here, to run once:
  pinMode(PCNT_INPUT_SIG_WC_HOT, INPUT_PULLUP);
  pinMode(PCNT_INPUT_SIG_WC_COLD, INPUT_PULLUP);
  /* Initialize PCNT event queue and PCNT functions */
  pcnt_evt_queue = xQueueCreate(10, sizeof(pcnt_evt_t));

  pcnt_example_init();
  //  pcnt_example_init(PCNT_UNIT_WC_HOT, PCNT_INPUT_SIG_WC_HOT);
    //pcnt_example_init(PCNT_UNIT_WC_COLD, PCNT_INPUT_SIG_WC_COLD);

    Serial.printf("Setup done\n");
}

int16_t count = 0;
pcnt_evt_t evt;
portBASE_TYPE res;

char * chToName(int ch)
{
  if (ch == 1) return "Cold";
  if (ch == 0) return "Hot";

  return "Unc";
}

void loop() {
  // put your main code here, to run repeatedly:
      /* Wait for the event information passed from PCNT's interrupt handler.
         * Once received, decode the event type and print it on the serial monitor.
         */
        res = xQueueReceive(pcnt_evt_queue, &evt, 1000 / portTICK_PERIOD_MS);
        if (res == pdTRUE) {
            pcnt_get_counter_value(evt.unit, &count);
            Serial.printf("Event PCNT unit[%d=%s]; cnt: %d, status: %d\n", evt.unit, chToName(evt.unit), count, evt.status);
            if (evt.status & PCNT_EVT_THRES_1) {
                Serial.printf("THRES1 EVT\n");
            }
            if (evt.status & PCNT_EVT_THRES_0) {
                Serial.printf("THRES0 EVT\n");
            }
            if (evt.status & PCNT_EVT_L_LIM) {
                Serial.printf("L_LIM EVT\n");
            }
            if (evt.status & PCNT_EVT_H_LIM) {
                Serial.printf("H_LIM EVT\n");
            }
            if (evt.status & PCNT_EVT_ZERO) {
                Serial.printf("ZERO EVT\n");
                // here we are increment liter count
            }
        } else {
            pcnt_get_counter_value(PCNT_UNIT_0, &count);
            Serial.printf("Current counter value: %s=%d,", chToName(PCNT_UNIT_0), count);
            pcnt_get_counter_value(PCNT_UNIT_1, &count);
            Serial.printf(" %s=%d\n", chToName(PCNT_UNIT_1), count);
            //pcnt_get_counter_value(PCNT_UNIT_WC_COLD, &count);
            //Serial.printf(", %d on unit: %d\n", count, PCNT_UNIT_WC_COLD);
        }    

        /*
        if(user_isr_handle) {
          Serial.printf("Clearing user_isr_handle\n");
          //Free the ISR service handle.
          esp_intr_free(user_isr_handle);
          user_isr_handle = NULL;
        }*/
} 
Source Link
Guntis
  • 111
  • 1
  • 4

As @Majenko suggested, i created solution with pulse counter.

Here is working code, based on espressif PCNT Example. Arduino studio, Olimex ESP32-POE board.

Each water meter uses separate pulse counter unit. Now I am testing this code and after several days i will accept answer if all works like i want :)

#include "freertos/queue.h"
#include "driver/pcnt.h"
#include "driver/periph_ctrl.h"
#include "driver/gpio.h"
#include "esp_attr.h"


#define PCNT_H_LIM_VAL      1
#define PCNT_L_LIM_VAL     -1
#define PCNT_THRESH1_VAL    0
#define PCNT_THRESH0_VAL   -0
#define PCNT_INPUT_SIG_WC_HOT   32 // hot water counter  
#define PCNT_INPUT_SIG_WC_COLD  33 // cold water counter
/*
Cold meter uses PCNT_UNIT_1
hot meter uses PCNT_UNIT_0
*/
xQueueHandle pcnt_evt_queue;   // A queue to handle pulse counter events
pcnt_isr_handle_t user_isr_handle = NULL; //user's ISR service handle



/* A sample structure to pass events from the PCNT
 * interrupt handler to the main program.
 */
typedef struct {
    pcnt_unit_t unit;  // the PCNT unit that originated an interrupt
    uint32_t status; // information on the event type that caused the interrupt
} pcnt_evt_t;

/* Decode what PCNT's unit originated an interrupt
 * and pass this information together with the event type
 * the main program using a queue.
 */
static void IRAM_ATTR pcnt_example_intr_handler(void *arg)
{
    uint32_t intr_status = PCNT.int_st.val;
    int i;
    pcnt_evt_t evt;
    portBASE_TYPE HPTaskAwoken = pdFALSE;

    for (i = 0; i < PCNT_UNIT_MAX; i++) {
        if (intr_status & (BIT(i))) {
            evt.unit = (pcnt_unit_t)i;
            /* Save the PCNT event type that caused an interrupt
               to pass it to the main program */
            evt.status = PCNT.status_unit[i].val;
            PCNT.int_clr.val = BIT(i);
            xQueueSendFromISR(pcnt_evt_queue, &evt, &HPTaskAwoken);
            if (HPTaskAwoken == pdTRUE) {
                portYIELD_FROM_ISR();
            }
        }
    }
}


/* Initialize PCNT functions:
 *  - configure and initialize PCNT
 *  - set up the input filter
 *  - set up the counter events to watch
 */
static void pcnt_example_init()
{
    //Serial.printf("pcnt_example_init(%d, %d)\n", _unit, _pin);
    /* Prepare configuration for the PCNT unit */
    pcnt_config_t pcnt_config = {};
    pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_WC_HOT;
    pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
    pcnt_config.channel = PCNT_CHANNEL_0;
    pcnt_config.pos_mode = PCNT_COUNT_INC;
    pcnt_config.neg_mode = PCNT_COUNT_DIS;
    pcnt_config.lctrl_mode = PCNT_MODE_KEEP;//PCNT_MODE_REVERSE;
    pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
    pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
    pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
    pcnt_config.unit = PCNT_UNIT_0;
    
    /* Initialize PCNT unit */
    ESP_ERROR_CHECK(pcnt_unit_config(&pcnt_config));


    /* cold water meter */
    pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_WC_COLD;
    pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
    pcnt_config.channel = PCNT_CHANNEL_0;
    pcnt_config.pos_mode = PCNT_COUNT_INC;
    pcnt_config.neg_mode = PCNT_COUNT_DIS;
    pcnt_config.lctrl_mode = PCNT_MODE_KEEP;//PCNT_MODE_REVERSE;
    pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
    pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
    pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
    pcnt_config.unit = PCNT_UNIT_1;
    ESP_ERROR_CHECK(pcnt_unit_config(&pcnt_config));



    /* Configure and enable the input filter */
    ESP_ERROR_CHECK(pcnt_set_filter_value(PCNT_UNIT_0, 1000)); // filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
    ESP_ERROR_CHECK(pcnt_filter_enable(PCNT_UNIT_0));

    /* Set threshold 0 and 1 values and enable events to watch */
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1));
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
    /* Enable events on zero, maximum and minimum limit values */
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_ZERO));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_H_LIM));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_L_LIM));

    /* Initialize PCNT's counter */
    ESP_ERROR_CHECK(pcnt_counter_pause(PCNT_UNIT_0));
    ESP_ERROR_CHECK(pcnt_counter_clear(PCNT_UNIT_0));

    /* Register ISR handler and enable interrupts for PCNT unit */
    ESP_ERROR_CHECK(pcnt_isr_register(pcnt_example_intr_handler, NULL, 0, &user_isr_handle));
    ESP_ERROR_CHECK(pcnt_intr_enable(PCNT_UNIT_0));

    /* Everything is set up, now go to counting */
    ESP_ERROR_CHECK(pcnt_counter_resume(PCNT_UNIT_0));




    /* PCNT_UNIT_1 configuration  */
    /* Configure and enable the input filter */
    ESP_ERROR_CHECK(pcnt_set_filter_value(PCNT_UNIT_1, 1000)); // filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
    ESP_ERROR_CHECK(pcnt_filter_enable(PCNT_UNIT_1));

    /* Set threshold 0 and 1 values and enable events to watch */
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_1, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_THRES_1));
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_1, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_THRES_0));
    /* Enable events on zero, maximum and minimum limit values */
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_ZERO));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_H_LIM));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_L_LIM));

    /* Initialize PCNT's counter */
    ESP_ERROR_CHECK(pcnt_counter_pause(PCNT_UNIT_1));
    ESP_ERROR_CHECK(pcnt_counter_clear(PCNT_UNIT_1));

    ESP_ERROR_CHECK(pcnt_intr_enable(PCNT_UNIT_1));

    /* Everything is set up, now go to counting */
    ESP_ERROR_CHECK(pcnt_counter_resume(PCNT_UNIT_1));
}



void setup() {
  Serial.begin(115200);
  Serial.println("Boot...");
  // put your setup code here, to run once:
  pinMode(PCNT_INPUT_SIG_WC_HOT, INPUT_PULLUP);
  pinMode(PCNT_INPUT_SIG_WC_COLD, INPUT_PULLUP);
  /* Initialize PCNT event queue and PCNT functions */
  pcnt_evt_queue = xQueueCreate(10, sizeof(pcnt_evt_t));

  pcnt_example_init();
  //  pcnt_example_init(PCNT_UNIT_WC_HOT, PCNT_INPUT_SIG_WC_HOT);
    //pcnt_example_init(PCNT_UNIT_WC_COLD, PCNT_INPUT_SIG_WC_COLD);

    Serial.printf("Setup done\n");
}

int16_t count = 0;
pcnt_evt_t evt;
portBASE_TYPE res;

char * chToName(int ch)
{
  if (ch == 1) return "Cold";
  if (ch == 0) return "Hot";

  return "Unc";
}

void loop() {
  // put your main code here, to run repeatedly:
      /* Wait for the event information passed from PCNT's interrupt handler.
         * Once received, decode the event type and print it on the serial monitor.
         */
        res = xQueueReceive(pcnt_evt_queue, &evt, 1000 / portTICK_PERIOD_MS);
        if (res == pdTRUE) {
            pcnt_get_counter_value(evt.unit, &count);
            Serial.printf("Event PCNT unit[%d=%s]; cnt: %d, status: %d\n", evt.unit, chToName(evt.unit), count, evt.status);
            if (evt.status & PCNT_EVT_THRES_1) {
                Serial.printf("THRES1 EVT\n");
            }
            if (evt.status & PCNT_EVT_THRES_0) {
                Serial.printf("THRES0 EVT\n");
            }
            if (evt.status & PCNT_EVT_L_LIM) {
                Serial.printf("L_LIM EVT\n");
            }
            if (evt.status & PCNT_EVT_H_LIM) {
                Serial.printf("H_LIM EVT\n");
            }
            if (evt.status & PCNT_EVT_ZERO) {
                Serial.printf("ZERO EVT\n");
            }
        } else {
            pcnt_get_counter_value(PCNT_UNIT_0, &count);
            Serial.printf("Current counter value: %s=%d,", chToName(PCNT_UNIT_0), count);
            pcnt_get_counter_value(PCNT_UNIT_1, &count);
            Serial.printf(" %s=%d\n", chToName(PCNT_UNIT_1), count);
            //pcnt_get_counter_value(PCNT_UNIT_WC_COLD, &count);
            //Serial.printf(", %d on unit: %d\n", count, PCNT_UNIT_WC_COLD);
        }    

        /*
        if(user_isr_handle) {
          Serial.printf("Clearing user_isr_handle\n");
          //Free the ISR service handle.
          esp_intr_free(user_isr_handle);
          user_isr_handle = NULL;
        }*/
}