PCNT for 2 input signals
Posted: Mon Jun 19, 2023 5:27 pm
Hello,
I want to use an ESP32 Dev Kit C V2 to read 2 separate analog signals. In my project, this is the vehicle engine RPM and vehicle speed.
I first used this project I found on Reddit as a guide: https://www.reddit.com/r/arduino/commen ... e_racecar/
But I realized I couldn't use pulseIn to read from multiple pins.
I couldn't find an example of how to read from two pins at once using the PCNT function.
I tried by "doubling" the code and use a different PCNT_UNIT, but when I try to read a signal from the second PCNT pin the ESP crashes.
Why is the ESP crashing when I try to read from 2 pins?
Also I am open if there is a better/easier way to do this.
I want to use an ESP32 Dev Kit C V2 to read 2 separate analog signals. In my project, this is the vehicle engine RPM and vehicle speed.
I first used this project I found on Reddit as a guide: https://www.reddit.com/r/arduino/commen ... e_racecar/
But I realized I couldn't use pulseIn to read from multiple pins.
I couldn't find an example of how to read from two pins at once using the PCNT function.
I tried by "doubling" the code and use a different PCNT_UNIT, but when I try to read a signal from the second PCNT pin the ESP crashes.
Why is the ESP crashing when I try to read from 2 pins?
Also I am open if there is a better/easier way to do this.
Code: Select all
#include "driver/pcnt.h" /* Include the required header file, Its working Arduion IDE 2.0*/
/* For detailed reference please follow the documentations in following Link:-
Link:- https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/pcnt.html
*/
#define PCNT_UNIT_UsedA PCNT_UNIT_1 /* Select the Pulse Count 0 as the unit..*/
#define PCNT_UNIT_UsedB PCNT_UNIT_0 /* Select the Pulse Count 1 as the unit..*/
#define PCNT_H_LIM_VAL 1 /* Set the max limit to trigger the interrupt*/
#define PCNT_INPUT_SIG_IOA 18 /* Pulse Input selected as GPIO 4 */
#define PCNT_INPUT_SIG_IOB 4 /* Pulse Input selected as GPIO 34 */
int contadorOverflowA, diffA; /* Variable to store the over flow count */
int contadorOverflowB, diffB; /* Variable to store the over flow count */
pcnt_isr_handle_t user_isr_handleA = NULL; /* User ISR handler for Interrupt */
pcnt_isr_handle_t user_isr_handleB = NULL; /* User ISR handler for Interrupt */
/* *********************************************************************************
ISR Function to trigen when ever over flow is detected.......
*************************************************************************************/
void IRAM_ATTR CounterOverflow_ISRA(void *arg)
{
/* Increment Over flow counter */
contadorOverflowA = contadorOverflowA + 1;
/* Clear counter*/
PCNT.int_clr.val = BIT(PCNT_UNIT_UsedA);
pcnt_counter_clear(PCNT_UNIT_UsedA);
}
void IRAM_ATTR CounterOverflow_ISRB(void *arg)
{
/* Increment Over flow counter */
contadorOverflowB = contadorOverflowB + 1;
/* Clear counter*/
PCNT.int_clr.val = BIT(PCNT_UNIT_UsedB);
pcnt_counter_clear(PCNT_UNIT_UsedB);
}
//------------------------------------------------------------
void Init_PulseCounterA (void)
{
pcnt_config_t pcntFreqConfigA = { }; // Declear variable for cinfig
pcntFreqConfigA.pulse_gpio_num = PCNT_INPUT_SIG_IOA; // Set the port ping using for counting
pcntFreqConfigA.pos_mode = PCNT_COUNT_INC; // set Counter mode: Increase counter value
pcntFreqConfigA.counter_h_lim = PCNT_H_LIM_VAL; // Set Over flow Interupt / event value
pcntFreqConfigA.unit = PCNT_UNIT_UsedA; // Set Pulsos unit to ne used
pcntFreqConfigA.channel = PCNT_CHANNEL_0; // select PCNT channel 0
pcnt_unit_config(&pcntFreqConfigA); // Configure PCNT.
pcnt_counter_pause(PCNT_UNIT_UsedA); // Pause PCNT counter such that we can set event.
pcnt_counter_clear(PCNT_UNIT_UsedA); // Clear PCNT counter to avoid ant mis counting.
pcnt_event_enable(PCNT_UNIT_UsedA, PCNT_EVT_H_LIM); // Enable event for when PCNT watch point event: Maximum counter value
pcnt_isr_register(CounterOverflow_ISRA, NULL, 0, &user_isr_handleA); // Set call back function for the Event.
pcnt_intr_enable(PCNT_UNIT_UsedA); // Enable PCNT
pcnt_counter_resume(PCNT_UNIT_UsedA); // Re-started PCNT.
Serial.println("PCNT Init Completed A....");
}
void Init_PulseCounterB (void)
{
pcnt_config_t pcntFreqConfigB = { }; // Declear variable for cinfig
pcntFreqConfigB.pulse_gpio_num = PCNT_INPUT_SIG_IOB; // Set the port ping using for counting
pcntFreqConfigB.pos_mode = PCNT_COUNT_INC; // set Counter mode: Increase counter value
pcntFreqConfigB.counter_h_lim = PCNT_H_LIM_VAL; // Set Over flow Interupt / event value
pcntFreqConfigB.unit = PCNT_UNIT_UsedB; // Set Pulsos unit to ne used
pcntFreqConfigB.channel = PCNT_CHANNEL_0; // select PCNT channel 0
pcnt_unit_config(&pcntFreqConfigB); // Configure PCNT.
pcnt_counter_pause(PCNT_UNIT_UsedB); // Pause PCNT counter such that we can set event.
pcnt_counter_clear(PCNT_UNIT_UsedB); // Clear PCNT counter to avoid ant mis counting.
pcnt_event_enable(PCNT_UNIT_UsedB, PCNT_EVT_H_LIM); // Enable event for when PCNT watch point event: Maximum counter value
pcnt_isr_register(CounterOverflow_ISRB, NULL, 0, &user_isr_handleB); // Set call back function for the Event.
pcnt_intr_enable(PCNT_UNIT_UsedB); // Enable PCNT
pcnt_counter_resume(PCNT_UNIT_UsedB); // Re-started PCNT.
Serial.println("PCNT Init Completed B....");
}
/* *********************************************************************************
Function to clean the Counter and its variables......
*************************************************************************************/
void Clean_Counters()
{
pcnt_counter_pause(PCNT_UNIT_UsedA); // Pause PCNT counter such that we can set event.
contadorOverflowA = 0; // Clear global Over flow counter.
pcnt_counter_clear(PCNT_UNIT_UsedA); // Clean Pulse Counter...
pcnt_counter_resume(PCNT_UNIT_UsedA); // Re-started PCNT.
pcnt_counter_pause(PCNT_UNIT_UsedB); // Pause PCNT counter such that we can set event.
contadorOverflowB = 0; // Clear global Over flow counter.
pcnt_counter_clear(PCNT_UNIT_UsedB); // Clean Pulse Counter...
pcnt_counter_resume(PCNT_UNIT_UsedB); // Re-started PCNT.
}
void setup() {
Serial.begin(115200);
delay(500);
// put your setup code here, to run once:
Init_PulseCounterA();
Init_PulseCounterB();
}
void loop()
{
/* Add static variable to store previous value*/
static int16_t Previous_countA = 0;
static int Previous_contadorOverflowA = 0;
// put your main code here, to run repeatedly:
int16_t countA = 0;
pcnt_get_counter_value(PCNT_UNIT_UsedA, &countA);
/* Add static variable to store previous value*/
static int16_t Previous_countB = 0;
static int Previous_contadorOverflowB = 0;
// put your main code here, to run repeatedly:
int16_t countB = 0;
pcnt_get_counter_value(PCNT_UNIT_UsedB, &countB);
// /* Print only if there is any difference or change in tha value.*/
// if( (Previous_count != count) || (Previous_contadorOverflow != contadorOverflow) )
// {
diffA = contadorOverflowA - Previous_contadorOverflowA;
Serial.print(" Each Count A= ");
Serial.print((int)countA);
Serial.print(", Overflow Count A= ");
Serial.println((int)diffA);
// /* Print only if there is any difference or change in tha value.*/
// if( (Previous_count != count) || (Previous_contadorOverflow != contadorOverflow) )
// {
diffB = contadorOverflowB - Previous_contadorOverflowB;
Serial.print(" Each Count B= ");
Serial.print((int)countB);
Serial.print(", Overflow Count B= ");
Serial.println((int)diffB);
Previous_countA = countA;
Previous_contadorOverflowA = contadorOverflowA;
Previous_countB = countB;
Previous_contadorOverflowB = contadorOverflowB;
// }
delay(500); /* Delay is given to give result properly..*/
}