Hello,
I am using the Arduino framework in PlatformIO and wanted to use the Pulse Counter module.
How do I configure and use this module using the Arduino framework?
I have seen the reference https://docs.espressif.com/projects/esp ... t_config_t but as far as I'm concerned it is used some kind of structure.
How to use "Pulse Counter" module usage under Arduino framework
-
- Posts: 3
- Joined: Thu May 28, 2020 4:11 pm
Re: How to use "Pulse Counter" module usage under Arduino framework
Yes, that is a structure for initializing the PCNT hardware. I have made more steps than you in Arduino, however I have not yet been able to make it work. I am normally very good at taking code snippets and getting a solution. For example, to initialize the struct with the declaration, you must provide all members in the proper order for it to compile in Arduino IDE.
Below is some code I believe required. On my computer, I was able to open the pcnt.h file for reading in the following folder:
C: \ Users \ yourusername \ Documents \ ArduinoData \ packages \ esp32 \ hardware \ esp32 \ 1.0.2 \ tools \ sdk \ include \ driver \ driver
At this point, I am beginning to believe esp-idf is required to make PCNT module operational. When I started on ESP32 last year, I was not able to successfully install the tool chain to operate in windows 10, so I use Arduino IDE. At this point, I am disappointed in my project because of failure to make PCNT work, so I will watch the milli()s pass for my test and also the m5stack UI code is not sufficiently ready for me to employ it for my program. It is elaborate, however seemingly impossible to have it continuously display a status on the screen. So now I have to build x,y and program the entire UI also.
Below is some code I believe required. On my computer, I was able to open the pcnt.h file for reading in the following folder:
C: \ Users \ yourusername \ Documents \ ArduinoData \ packages \ esp32 \ hardware \ esp32 \ 1.0.2 \ tools \ sdk \ include \ driver \ driver
At this point, I am beginning to believe esp-idf is required to make PCNT module operational. When I started on ESP32 last year, I was not able to successfully install the tool chain to operate in windows 10, so I use Arduino IDE. At this point, I am disappointed in my project because of failure to make PCNT work, so I will watch the milli()s pass for my test and also the m5stack UI code is not sufficiently ready for me to employ it for my program. It is elaborate, however seemingly impossible to have it continuously display a status on the screen. So now I have to build x,y and program the entire UI also.
- #include "driver/pcnt.h"
- #define COUNT_PIN 17 // the gpio I output pulses on which I want to count
- pcnt_config_t pcnt_config = {
- .pulse_gpio_num = COUNT_PIN, // set gpio for pulse input gpio
- .ctrl_gpio_num = -1, // no gpio for control
- .lctrl_mode = PCNT_MODE_KEEP, // when control signal is low, keep the primary counter mode
- .hctrl_mode = PCNT_MODE_KEEP, // when control signal is high, keep the primary counter mode
- .pos_mode = PCNT_COUNT_INC, // increment the counter on positive edge
- .neg_mode = PCNT_COUNT_DIS, // do nothing on falling edge
- .counter_h_lim = 2500,
- .counter_l_lim = 0,
- .unit = PCNT_UNIT_0, /*!< PCNT unit number */
- .channel = PCNT_CHANNEL_0
- };
- // https://esp32.com/viewtopic.php?t=6737
- pcnt_isr_handle_t user_isr_handle = NULL; //user's ISR service handle
- unsigned int test_count = 2500;
- void setup() {
- // possible problem, esp_idf mentions pin mode IN_OUT but that is not in arduino. So I tried shorting
- // my pulse output pin to adjacent gpio and look at this input. Still didn't work for me.
- pinMode(COUNT_PIN,INPUT);
- pcnt_unit_config(&pcnt_config); //init unit
- pcnt_set_filter_value(PCNT_UNIT_0, test_count);
- pcnt_filter_enable(PCNT_UNIT_0);
- /* Register ISR handler and enable interrupts for PCNT unit */
- pcnt_isr_register(pcnt_intr_handler, NULL, 0, &user_isr_handle);
- pcnt_intr_enable(PCNT_UNIT_0);
- /* Everything is set up, now go to counting */
- pcnt_counter_resume(PCNT_UNIT_0);
- }
- static void pcnt_intr_handler(void *arg) {
- test = false;
- if(user_isr_handle) {
- //Free the ISR service handle.
- esp_intr_free(user_isr_handle);
- user_isr_handle = NULL;
- }
- }
- jgustavoam
- Posts: 164
- Joined: Thu Feb 01, 2018 2:43 pm
- Location: Belo Horizonte , Brazil
- Contact:
Re: How to use "Pulse Counter" module usage under Arduino framework
Hi,
This code (part of sketch) was tested and running OK. Comments in portuguese.
This code (part of sketch) was tested and running OK. Comments in portuguese.
Code: Select all
#include "driver/pcnt.h" // Biblioteca de pulse count
#define PCNT_FREQ_UNIT PCNT_UNIT_0 // Unidade de Pulse Count 0
#define PCNT_H_LIM_VAL 10000 // Limite superior de contagem 32767
#define PCNT_INPUT_SIG_IO 4 // Pulse Input GPIO 4
int16_t contador = 0; // Contador de pulsos - valor max 65536
int contadorOverflow; // Contador de overflow do Contador de Pulsos
float frequencia = 0; // Frequencia medida
String unidade; // Unidade de medida da escala
unsigned long tempo; // base de tempo da medida dos pulsos
int prescaler; // Divisor de frequencia do Timer
bool contadorOK = false;
pcnt_isr_handle_t user_isr_handle = NULL; // handler da interrupção - não usado
hw_timer_t * timer = NULL; // Instancia do timer
//------------------------------------------------------------------------------------
void IRAM_ATTR overflowContador(void *arg) // Rotina de interrupção de overflow do Contador
{
contadorOverflow = contadorOverflow + 1; // soma contador de overflow
PCNT.int_clr.val = BIT(PCNT_FREQ_UNIT); // Limpa flag de overflow
pcnt_counter_clear(PCNT_FREQ_UNIT); // Zera e reseta o Contador de Pulsos
}
//------------------------------------------------------------
void iniciaContadorPulsos ()
{
pcnt_config_t pcntFreqConfig = { }; // Instancia do Contador de Pulsos
pcntFreqConfig.pulse_gpio_num = PCNT_INPUT_SIG_IO; // Port de entrada dos pulsos = GPIO 4
pcntFreqConfig.pos_mode = PCNT_COUNT_INC; // Conta na subida do pulso
pcntFreqConfig.counter_h_lim = PCNT_H_LIM_VAL; // Limite maximo de contagem
pcntFreqConfig.unit = PCNT_FREQ_UNIT; // Unidade 0 do Contador de Pulsos
pcntFreqConfig.channel = PCNT_CHANNEL_0; // Canal 0 da Unidade 0 Contador de Pulsos
pcnt_unit_config(&pcntFreqConfig); // configura os registradores do Contador de Pulsos
pcnt_counter_pause(PCNT_FREQ_UNIT); // pausa o Contador de Pulsos
pcnt_counter_clear(PCNT_FREQ_UNIT); // Zera e reseta o Contador de Pulsos
pcnt_event_enable(PCNT_FREQ_UNIT, PCNT_EVT_H_LIM); // Ativa evento - interrupção no limite maximo de contagem
pcnt_isr_register(overflowContador, NULL, 0, &user_isr_handle); // configura registrador da interrupção
pcnt_intr_enable(PCNT_FREQ_UNIT); // habilita as interrupções do Contador de Pulsos
pcnt_counter_resume(PCNT_FREQ_UNIT); // reinicia o Contador de Pulsos
}
//------------------------------------------------------------
void baseTempo() // Rotina de leitura do contador de pulsos (Base de tempo)
{
pcnt_get_counter_value(PCNT_FREQ_UNIT, &contador); // obtem o valor do contador de pulsos - valor max 16 bits
contadorOverflow = 0; // zera o contador de overflow
pcnt_counter_clear(PCNT_FREQ_UNIT); // Zera e reseta o Contador de Pulsos
contadorOK = true;
}
Retired IBM Brasil
Electronic hobbyist since 1976.
Electronic hobbyist since 1976.
Re: How to use "Pulse Counter" module usage under Arduino framework
I successfully used the code of jgustavoam! Thanks a lot. This was the only clear source on Arduino IDE and ESP32 pulse counter, which I found on the net. I was happy to understand your Portuguese with my Spanish, so that your comments plus the explanations from
https://docs.espressif.com/projects/esp ... ing-pulses added up to a lot of sense.
#include "driver/pcnt.h" worked without any additional step in Arduino IDE after having installed the
when in the Arduino IDE properties the sketchbook storage location had been set to C:\Users\User\Documents\Arduino
My remaining problem for the correct pulse count are glitches. Significant overcounting improved somewhat, but not completely, after defining the pulse counter filter: https://docs.espressif.com/projects/esp ... ing-pulses
Increasing the filter value to 1000, i.e. close to maximum, did not yet solve the problem. Any further idea would be helpful.
For the Forum find here my conversion of the code of jgustavoam to English:
https://docs.espressif.com/projects/esp ... ing-pulses added up to a lot of sense.
#include "driver/pcnt.h" worked without any additional step in Arduino IDE after having installed the
i.e. in my case the file was already there at the following path C:\Users\User\Documents\Arduino\hardware\arduino-esp32-master\tools\sdk\include\driver\driver\pcnt.harduino-esp32-master
when in the Arduino IDE properties the sketchbook storage location had been set to C:\Users\User\Documents\Arduino
My remaining problem for the correct pulse count are glitches. Significant overcounting improved somewhat, but not completely, after defining the pulse counter filter: https://docs.espressif.com/projects/esp ... ing-pulses
Increasing the filter value to 1000, i.e. close to maximum, did not yet solve the problem. Any further idea would be helpful.
For the Forum find here my conversion of the code of jgustavoam to English:
Code: Select all
#include "driver/pcnt.h" // ESP32 library for pulse count
// e.g. stored in following path C:\Users\User\Documents\Arduino\hardware\arduino-esp32-master\tools\sdk\include\driver\driver\pcnt.h
// when in the Arduino IDE properties the sketchbook storage location is set to C:\Users\User\Documents\Arduino
#define PCNT_FREQ_UNIT PCNT_UNIT_0 // select ESP32 pulse counter unit 0 (out of 0 to 7 indipendent counting units)
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/pcnt.html
int SPEED_IR_INPUT_PIN = 15; // Input D15 = signal from IR-diode for pulse counter
bool _flag = 0; // only for testing ####################################
int16_t PulseCounter = 0; // pulse counter, max. value is 65536
int OverflowCounter = 0; // pulse counter overflow counter
int PCNT_H_LIM_VAL = 10000; // upper limit of counting max. 32767, write +1 to overflow counter, when reached
uint16_t PCNT_FILTER_VAL= 1000; // filter (damping, inertia) value for avoiding glitches in the count, max. 1023
// not in use, copy from example code ########################################
//float frequencia = 0; // Frequencia medida
//String unidade; // Unidade de medida da escala
//unsigned long tempo; // base de tempo da medida dos pulsos
//int prescaler; // frequency devider of timer
//bool conterOK = false;
pcnt_isr_handle_t user_isr_handle = NULL; // interrupt handler - not used
hw_timer_t * timer = NULL; // Instancia do timer
void IRAM_ATTR CounterOverflow(void *arg) { // Interrupt for overflow of pulse counter
OverflowCounter = OverflowCounter + 1; // increase overflow counter
PCNT.int_clr.val = BIT(PCNT_FREQ_UNIT); // clean overflow flag
pcnt_counter_clear(PCNT_FREQ_UNIT); // zero and reset of pulse counter unit
}
void initPulseCounter (){ // initialise pulse counter
pcnt_config_t pcntFreqConfig = { }; // Instance of pulse counter
pcntFreqConfig.pulse_gpio_num = SPEED_IR_INPUT_PIN; // pin assignment for pulse counter = GPIO 15
pcntFreqConfig.pos_mode = PCNT_COUNT_INC; // count rising edges (=change from low to high logical level) as pulses
pcntFreqConfig.counter_h_lim = PCNT_H_LIM_VAL; // set upper limit of counting
pcntFreqConfig.unit = PCNT_FREQ_UNIT; // select ESP32 pulse counter unit 0
pcntFreqConfig.channel = PCNT_CHANNEL_0; // select channel 0 of pulse counter unit 0
pcnt_unit_config(&pcntFreqConfig); // configur rigisters of the pulse counter
pcnt_counter_pause(PCNT_FREQ_UNIT); // pause puls counter unit
pcnt_counter_clear(PCNT_FREQ_UNIT); // zero and reset of pulse counter unit
pcnt_event_enable(PCNT_FREQ_UNIT, PCNT_EVT_H_LIM); // enable event for interrupt on reaching upper limit of counting
pcnt_isr_register(CounterOverflow, NULL, 0, &user_isr_handle); // configure register overflow interrupt handler
pcnt_intr_enable(PCNT_FREQ_UNIT); // enable overflow interrupt
pcnt_set_filter_value(PCNT_FREQ_UNIT, PCNT_FILTER_VAL); // set damping, inertia
pcnt_filter_enable(PCNT_FREQ_UNIT); // enable counter glitch filter (damping)
pcnt_counter_resume(PCNT_FREQ_UNIT); // resume counting on pulse counter unit
}
void Read_Reset_PCNT() { // function for reading pulse counter (for timer)
pcnt_get_counter_value(PCNT_FREQ_UNIT, &PulseCounter); // get pulse counter value - maximum value is 16 bits
// resetting counter as if example, delet for application in PiedPiperS
OverflowCounter = 0; // set overflow counter to zero
pcnt_counter_clear(PCNT_FREQ_UNIT); // zero and reset of pulse counter unit
//conterOK = true; // not in use, copy from example code ########################################
}
void Read_PCNT() { // function for reading pulse counter (for timer)
pcnt_get_counter_value(PCNT_FREQ_UNIT, &PulseCounter); // get pulse counter value - maximum value is 16 bits
}
Re: How to use "Pulse Counter" module usage under Arduino framework
Hello all.
I am trying to use either of the codes mentioned here but continue to get a "PCNT was not declared in this scope" for the line
PCNT.int_clr.val = BIT(PCNT_FREQ_UNIT); // clean overflow flag.
Anything specific I need to look for to rectify this issue?
Thanks
Kilo
I am trying to use either of the codes mentioned here but continue to get a "PCNT was not declared in this scope" for the line
PCNT.int_clr.val = BIT(PCNT_FREQ_UNIT); // clean overflow flag.
Anything specific I need to look for to rectify this issue?
Thanks
Kilo
Re: How to use "Pulse Counter" module usage under Arduino framework
Never-mind everyone, if there is anyone even monitoring this.
I found the answer after days on someone else's website about this counter.
For those that might run across this in days or years to come with the same issue, adding #include "soc/pcnt_struct.h" did the trick for me so now it will at least compile without errors.
Now to see if this serves the purpose for my project.
Thanks for the help anyway.
Kilo
I found the answer after days on someone else's website about this counter.
For those that might run across this in days or years to come with the same issue, adding #include "soc/pcnt_struct.h" did the trick for me so now it will at least compile without errors.
Now to see if this serves the purpose for my project.
Thanks for the help anyway.
Kilo
Re: How to use "Pulse Counter" module usage under Arduino framework
Now that I have found the answer to my original issue and determined that this is the closes to what I need for my project, I need to ask a question based on specifically my projects needs.
My project was originally developed using the Arduino Nano which has a 16bit timer used as a counter. The timer, as a counter is trigger every 1 second with an external interrupt with my gps pps pulse and the counter counts how many pulses happen within that 1 second period for 40 seconds, equally 100Mhz or 1 million or so pulses, then some other math is done with those results of the to pulses and the overruns since the counter has a limit of 65536 events. Its actually used to gps calibrate my VFO built using W3PM's VFO project. I really want to transition this code over to the esp32 because of its power, memory and speed due to my modifications of the LCD being used which i have everything else working. I just need this function to work in order to restore the gps calibration.
PCNT seems to be the closest of what I need because it seems the esp32 does not like the direct 2.5Mhz input as an external interrupt because it continues to reboot the esp32.
My main question is, is there a way to have PCNT to continuously count the pulses and I have my external interrupt from the PPS input take a sample every 1 second for 40 seconds and reset for the next calibration period?
The original interrupt that is triggered every 1 second by the gps is below. I think you can figure out most of it and for those who have used the timers/counters on a Nano can see that the variables are the timers variables for the pulse counts and the overruns
An explanation of how the timer is also copied/pasted from the original author of how the math is done in the interrupt.
Thanks all for any help....
void PPSinterrupt()
{
s_GpsOneSecTick = true; // New second by GPS.
tcount++;
if (tcount == 4) // Start counting the 2.5 MHz signal from Si5351A CLK0
{
TCCR1B = 7; //Clock on rising edge of pin 5
}
else if (tcount == 44) //The 40 second gate time elapsed - stop counting
{
TCCR1B = 0; //Turn off counter
XtalFreq = mult * 0x10000 + TCNT1; //Calculate correction factor
TCNT1 = 0; //Reset count to zero
mult = 0;
tcount = 0; //Reset the seconds counter
}
}
Explanation of Counter...
Timer1 is configured as a counter with an input of 2.5MHz in the setup() function. It can only count a maximum of 65536 events. Every time it hits the maximum count it triggers an overflow interrupt 'ISR(TIMER1_OVF_vect)' which counts the number of overflows.
The counter is turned on and off every 40 seconds by 'tcount' in the PPSinterrupt(). Therefore 40 x 2.5MHz = 100 MHz. Remember timer1 can only count to 65536 therefore 100 MHz / 65536 = 1525.87891. Timer1 overflowed 1525 times as stored in the 'mult' variable. The remainder (0.87891 x 65536 = 57600) is stored as TCNT1.
Thus:
XtalFreq = mult * 0x10000 + TCNT1;
XtalFreq = 1525 x 65536 + 57600
XtalFreq = 100,000,000
The 100,000,000is divided by 4 elsewhere in the sketch to give the crystal frequency of 25,000,000.
My project was originally developed using the Arduino Nano which has a 16bit timer used as a counter. The timer, as a counter is trigger every 1 second with an external interrupt with my gps pps pulse and the counter counts how many pulses happen within that 1 second period for 40 seconds, equally 100Mhz or 1 million or so pulses, then some other math is done with those results of the to pulses and the overruns since the counter has a limit of 65536 events. Its actually used to gps calibrate my VFO built using W3PM's VFO project. I really want to transition this code over to the esp32 because of its power, memory and speed due to my modifications of the LCD being used which i have everything else working. I just need this function to work in order to restore the gps calibration.
PCNT seems to be the closest of what I need because it seems the esp32 does not like the direct 2.5Mhz input as an external interrupt because it continues to reboot the esp32.
My main question is, is there a way to have PCNT to continuously count the pulses and I have my external interrupt from the PPS input take a sample every 1 second for 40 seconds and reset for the next calibration period?
The original interrupt that is triggered every 1 second by the gps is below. I think you can figure out most of it and for those who have used the timers/counters on a Nano can see that the variables are the timers variables for the pulse counts and the overruns
An explanation of how the timer is also copied/pasted from the original author of how the math is done in the interrupt.
Thanks all for any help....
void PPSinterrupt()
{
s_GpsOneSecTick = true; // New second by GPS.
tcount++;
if (tcount == 4) // Start counting the 2.5 MHz signal from Si5351A CLK0
{
TCCR1B = 7; //Clock on rising edge of pin 5
}
else if (tcount == 44) //The 40 second gate time elapsed - stop counting
{
TCCR1B = 0; //Turn off counter
XtalFreq = mult * 0x10000 + TCNT1; //Calculate correction factor
TCNT1 = 0; //Reset count to zero
mult = 0;
tcount = 0; //Reset the seconds counter
}
}
Explanation of Counter...
Timer1 is configured as a counter with an input of 2.5MHz in the setup() function. It can only count a maximum of 65536 events. Every time it hits the maximum count it triggers an overflow interrupt 'ISR(TIMER1_OVF_vect)' which counts the number of overflows.
The counter is turned on and off every 40 seconds by 'tcount' in the PPSinterrupt(). Therefore 40 x 2.5MHz = 100 MHz. Remember timer1 can only count to 65536 therefore 100 MHz / 65536 = 1525.87891. Timer1 overflowed 1525 times as stored in the 'mult' variable. The remainder (0.87891 x 65536 = 57600) is stored as TCNT1.
Thus:
XtalFreq = mult * 0x10000 + TCNT1;
XtalFreq = 1525 x 65536 + 57600
XtalFreq = 100,000,000
The 100,000,000is divided by 4 elsewhere in the sketch to give the crystal frequency of 25,000,000.
Re: How to use "Pulse Counter" module usage under Arduino framework
i've tried input the program like yours but mine is keep gettin error. it says: too few arguments to function 'void overflowContador(void*)' . how to fix it? i'm a newbie on esp32 controller
Who is online
Users browsing this forum: Google [Bot] and 36 guests