PCNT second overflow Handler will not be called
Posted: Wed Jul 05, 2023 5:40 pm
Hello,
the esp32 has a few PCNT Units on Board. With a little bit of searching i managed to put a code together that works. I can count with multiple Units. But i want to Count more than 32.768 with at least two individual Signals.
The first overflow handler for Unit_0 works perfectly but the second one does not. If the overflow is reached the first handler will be always called. The first handler will be executed as long as the flag is not cleared. So if the second/third Unit reaches its limit the esp32 is in an endless loop. Why does the handler do this? Any suggestion how to get by this problem?
Booting
Unit_0 Overflow
Unit_1 Overflow see Comment
the esp32 has a few PCNT Units on Board. With a little bit of searching i managed to put a code together that works. I can count with multiple Units. But i want to Count more than 32.768 with at least two individual Signals.
The first overflow handler for Unit_0 works perfectly but the second one does not. If the overflow is reached the first handler will be always called. The first handler will be executed as long as the flag is not cleared. So if the second/third Unit reaches its limit the esp32 is in an endless loop. Why does the handler do this? Any suggestion how to get by this problem?
Code: Select all
#include "soc/pcnt_struct.h"
#include "driver/pcnt.h" // ESP32 library for pulse count
// Pin für den Pulszähler
const int pinPCNT_0 = 4;
const int pinPCNT_1 = 5;
const int pinPCNT_2 = 19;
//Counter
int16_t count_PCNT0;
int16_t count_PCNT1;
int16_t count_PCNT2;
//OverflowCounter
int overflowPCNT_0;
int overflowPCNT_1;
int overflowPCNT_2;
int overflowPCNT_3;
int overflowPCNT_4;
int overflowPCNT_5;
//OverflowInterrput
pcnt_isr_handle_t user_isr_handle = NULL;
//Overflow Handler
void IRAM_ATTR PCNTOverflow_Handler_0(void *arg) { // Interrupt for overflow of pulse counter
Serial.println("Overflow PCNT_0");
overflowPCNT_0 = overflowPCNT_0 + 1; // increase overflow counter
PCNT.int_clr.val = BIT(PCNT_UNIT_0); // clean overflow flag
pcnt_counter_clear(PCNT_UNIT_0); // zero and reset of pulse counter unit
}
void IRAM_ATTR PCNTOverflow_Handler_1(void *arg) { // Interrupt for overflow of pulse counter
Serial.println("Overflow PCNT_1");
overflowPCNT_1 = overflowPCNT_1 + 1; // increase overflow counter
PCNT.int_clr.val = BIT(PCNT_UNIT_1); // clean overflow flag
pcnt_counter_clear(PCNT_UNIT_1); // zero and reset of pulse counter unit
}
void IRAM_ATTR PCNTOverflow_Handler_2(void *arg) { // Interrupt for overflow of pulse counter
Serial.println("Overflow PCNT_2");
// overflowPCNT_0 = overflowPCNT_0 + 1; // increase overflow counter
PCNT.int_clr.val = BIT(PCNT_UNIT_2); // clean overflow flag
pcnt_counter_clear(PCNT_UNIT_2); // zero and reset of pulse counter unit
}
void FC_PCNT_Init_0(){
// Initialisierung des PCNT
pcnt_config_t pcntConfig;
pcntConfig.unit = PCNT_UNIT_0;
pcntConfig.pulse_gpio_num = pinPCNT_0;
pcntConfig.ctrl_gpio_num = PCNT_PIN_NOT_USED;
pcntConfig.channel = PCNT_CHANNEL_0;
pcntConfig.pos_mode = PCNT_COUNT_INC;
pcntConfig.neg_mode = PCNT_COUNT_DIS;
pcntConfig.lctrl_mode = PCNT_MODE_KEEP;
pcntConfig.hctrl_mode = PCNT_MODE_KEEP;
pcntConfig.counter_h_lim = 100;
pcntConfig.counter_l_lim = PCNT_COUNT_DIS;
// Konfiguration des PCNT
pcnt_unit_config(&pcntConfig);
pcnt_counter_pause(PCNT_UNIT_0); // pause puls counter unit
pcnt_counter_clear(PCNT_UNIT_0); // zero and reset of pulse counter unit
//Overflow Handler
pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_H_LIM); // enable event for interrupt on reaching upper limit of counting
pcnt_isr_register(PCNTOverflow_Handler_0, NULL, 0, &user_isr_handle); // configure register overflow interrupt handler
pcnt_intr_enable(PCNT_UNIT_0); // enable overflow interrupt
//Glitch Filter
pcnt_set_filter_value(PCNT_UNIT_0, 1000); // set damping, inertia
pcnt_filter_enable(PCNT_UNIT_0);
// Aktivierung des PCNT
pcnt_counter_resume(PCNT_UNIT_0);
}
void FC_PCNT_Init_1(){
// Initialisierung des PCNT
pcnt_config_t pcntConfig;
pcntConfig.unit = PCNT_UNIT_1;
pcntConfig.pulse_gpio_num = pinPCNT_1;
pcntConfig.ctrl_gpio_num = PCNT_PIN_NOT_USED;
pcntConfig.channel = PCNT_CHANNEL_0;
pcntConfig.pos_mode = PCNT_COUNT_INC;
pcntConfig.neg_mode = PCNT_COUNT_DIS;
pcntConfig.lctrl_mode = PCNT_MODE_KEEP;
pcntConfig.hctrl_mode = PCNT_MODE_KEEP;
pcntConfig.counter_h_lim = 100;
pcntConfig.counter_l_lim = PCNT_COUNT_DIS;
// Konfiguration des PCNT
pcnt_unit_config(&pcntConfig);
if ( pcnt_unit_config(&pcntConfig) == ESP_OK ) {
Serial.println("Init_PCNT_1 OK!");
pcnt_counter_pause(PCNT_UNIT_1); // pause puls counter unit
pcnt_counter_clear(PCNT_UNIT_1); // zero and reset of pulse counter unit
//Overflow Handler
pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_H_LIM); // enable event for interrupt on reaching upper limit of counting
pcnt_isr_register(PCNTOverflow_Handler_1, NULL, 0, &user_isr_handle); // configure register overflow interrupt handler
pcnt_intr_enable(PCNT_UNIT_1); // enable overflow interrupt
//Glitch Filter
pcnt_set_filter_value(PCNT_UNIT_1, 1000); // set damping, inertia
pcnt_filter_enable(PCNT_UNIT_1);
// Aktivierung des PCNT
pcnt_counter_resume(PCNT_UNIT_1);
}
else {
Serial.println("Init_PCNT_1 FAILED!!!!!!!!!!!!");
}
pcnt_counter_pause(PCNT_UNIT_1); // pause puls counter unit
pcnt_counter_clear(PCNT_UNIT_1); // zero and reset of pulse counter unit
//Overflow Handler
pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_H_LIM); // enable event for interrupt on reaching upper limit of counting
pcnt_isr_register(PCNTOverflow_Handler_1, NULL, 0, &user_isr_handle); // configure register overflow interrupt handler
pcnt_intr_enable(PCNT_UNIT_1); // enable overflow interrupt
//Glitch Filter
pcnt_set_filter_value(PCNT_UNIT_1, 1000); // set damping, inertia
pcnt_filter_enable(PCNT_UNIT_1);
// Aktivierung des PCNT
pcnt_counter_resume(PCNT_UNIT_1);
}
void FC_PCNT_Init_2(){
// Initialisierung des PCNT
pcnt_config_t pcntConfig;
pcntConfig.unit = PCNT_UNIT_2;
pcntConfig.pulse_gpio_num = pinPCNT_2;
pcntConfig.ctrl_gpio_num = PCNT_PIN_NOT_USED;
pcntConfig.channel = PCNT_CHANNEL_0;
pcntConfig.pos_mode = PCNT_COUNT_INC;
pcntConfig.neg_mode = PCNT_COUNT_DIS;
pcntConfig.lctrl_mode = PCNT_MODE_KEEP;
pcntConfig.hctrl_mode = PCNT_MODE_KEEP;
pcntConfig.counter_h_lim = 100;
pcntConfig.counter_l_lim = PCNT_COUNT_DIS;
// Konfiguration des PCNT
// pcnt_unit_config(&pcntConfig);
if ( pcnt_unit_config(&pcntConfig) == ESP_OK ) {
Serial.println("Init_PCNT_2 OK!");
pcnt_counter_pause(PCNT_UNIT_2); // pause puls counter unit
pcnt_counter_clear(PCNT_UNIT_2); // zero and reset of pulse counter unit
//Overflow Handler
pcnt_event_enable(PCNT_UNIT_2, PCNT_EVT_H_LIM); // enable event for interrupt on reaching upper limit of counting
pcnt_isr_register(PCNTOverflow_Handler_2, NULL, 0, &user_isr_handle); // configure register overflow interrupt handler
pcnt_intr_enable(PCNT_UNIT_2); // enable overflow interrupt
//Glitch Filter
pcnt_set_filter_value(PCNT_UNIT_2, 1000); // set damping, inertia
pcnt_filter_enable(PCNT_UNIT_2);
// Aktivierung des PCNT
pcnt_counter_resume(PCNT_UNIT_2);
}
else {
Serial.println("Init_PCNT_2 FAILED!!!!!!!!!!!!");
}
}
void setup() {
// Initialisierung der seriellen Kommunikation
Serial.begin(115200);
FC_PCNT_Init_0();
FC_PCNT_Init_1();
FC_PCNT_Init_2();
}
void loop() {
// Abrufen Zählerstand
pcnt_get_counter_value(PCNT_UNIT_0, &count_PCNT0);
pcnt_get_counter_value(PCNT_UNIT_1, &count_PCNT1);
pcnt_get_counter_value(PCNT_UNIT_2, &count_PCNT2);
// Anzeige des Zählerstandes
Serial.print("Unit_0 Count: ");
Serial.println(count_PCNT0);
Serial.print("Unit_0 Overflow: ");
Serial.println(overflowPCNT_0);
Serial.print("Unit_1 Count: ");
Serial.println(count_PCNT1);
Serial.print("Unit_1 Overflow: ");
Serial.println(overflowPCNT_1);
Serial.print("Unit_2 Count: ");
Serial.println(count_PCNT2);
Serial.print("Unit_2 Overflow: ");
Serial.println(overflowPCNT_2);
delay(100);
}
Code: Select all
Init_PCNT_1 OK!
Init_PCNT_2 OK!
Unit_0 Count: 0
Unit_0 Overflow: 0
Unit_1 Count: 0
Unit_1 Overflow: 0
Unit_2 Count: 0
Unit_2 Overflow: 0
Unit_0 Count: 0
Unit_0 Overflow: 0
Unit_1 Count: 0
Unit_1 Overflow: 0
Unit_2 Count: 0
Unit_2 Overflow: 0
Code: Select all
Unit_2 Overflow: 0
Overflow PCNT_0
Unit_0 Count: 1
Unit_0 Overflow: 1
Unit_1 Count: 0
Unit_1 Overflow: 0
Unit_2 Count: 0
Unit_2 Overflow: 0
Code: Select all
Unit_0 Count: 0
Unit_0 Overflow: 0
Unit_1 Count: 96
Unit_1 Overflow: 0
Unit_2 Count: 0
Unit_2 Overflow: 0
Overflow PCNT_0
Overflow PCNT_0
Overflow PCNT_0
Overflow PCNT_0
Overflow PCNT_0
Overflow PCNT_0
Overflow PCNT_0
Overflow PCNTGuru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1).
Core 1 register dump:
PC : 0x4008aae6 PS : 0x00060135 A0 : 0x80089a5a A1 : 0x3ffbf13c
A2 : 0x3ffb897c A3 : 0x3ffbce0c A4 : 0x00000004 A5 : 0x00060123
A6 : 0x00060123 A7 : 0x00000001 A8 : 0x3ffbce0c A9 : 0x00000019
A10 : 0x3ffbce0c A11 : 0x00000019 A12 : 0x3ffc298c A13 : 0x00060123
A14 : 0x007bf2f8 A15 : 0x003fffff SAR : 0x00000020 EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x40086355 LEND : 0x40086365 LCOUNT : 0xfffffffb
Core 1 was running in ISR context:
EPC1 : 0x400dabdb EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x00000000
Backtrace: 0x4008aae3:0x3ffbf13c |<-CORRUPTED
Core 0 register dump:
PC : 0x4008ac7f PS : 0x00060035 A0 : 0x80089683 A1 : 0x3ffbea1c
A2 : 0x3ffbf2f8 A3 : 0xb33fffff A4 : 0x0000abab A5 : 0x00060023
A6 : 0x00060021 A7 : 0x0000cdcd A8 : 0x0000abab A9 : 0xffffffff
A10 : 0x3ffc27a4 A11 : 0x00000000 A12 : 0x3ffc27a0 A13 : 0x00000007
A14 : 0x007bf2f8 A15 : 0x003fffff SAR : 0x0000001d EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x00000000 LEND : 0x00000000 LCOUNT : 0x00000000
Backtrace: 0x4008ac7c:0x3ffbea1c |<-CORRUPTED
ELF file SHA256: 50bb7d4c025eaee8
Rebooting...
ets Jun 8 2016 00:22:57
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13924
ho 0 tail 12 room 4
load:0x40080400,len:3600
entry 0x400805f0
Init_PCNT_1 OK!
Init_PCNT_2 OK!
Unit_0 Count: 0
Unit_0 Overflow: 0
Unit_1 Count: 0
Unit_1 Overflow: 0
Unit_2 Count: 0
Unit_2 Overflow: 0