#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;
}*/
}
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;
}*/
}