Best Frequency Meter ever made with ESP32 - awesome!

User avatar
jgustavoam
Posts: 165
Joined: Thu Feb 01, 2018 2:43 pm
Location: Belo Horizonte , Brazil
Contact:

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby jgustavoam » Sat Feb 19, 2022 8:50 pm

Thanks Armin,
You are correct = sample_time = 1000000; ( one million microseconds)

"I am not very familiar with interrups, but is it possible to read and count 2-3 frequency signals from different GPIOs at the same time?"

Perhaps it is possible, yes.
Using other counters and other interrupts. If you need, using secondary processor.
Retired IBM Brasil
Electronic hobbyist since 1976.

MotoDan
Posts: 2
Joined: Fri Feb 18, 2022 3:41 am

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby MotoDan » Wed Feb 23, 2022 7:38 pm

Hi Gustava,

Thank you for posting this great Frequency Meter. It is very accurate and works well. I would like to modify your version to measure the frequency of a second input, but am having some difficulties with processing the second input. I am using the one second timer output for the control signal for two separate PCNT units. I have two ISR routines to accumulate pulses. I can get each channel to work independently, but not together. Are there any pitfalls to trying to process multiple inputs?

Thanks,
MotoDan

Ahmet58
Posts: 21
Joined: Sat Jan 22, 2022 8:38 pm

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby Ahmet58 » Thu Apr 28, 2022 8:01 pm

Thank you so much. I will use this code for firebeetle esp32 iot. I even uploaded it. However, I guess I'll have to make a change to the schema. I need to define a differential input. I don't know how to do this with this card. Also, is external adc used in your project?

Ahmet58
Posts: 21
Joined: Sat Jan 22, 2022 8:38 pm

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby Ahmet58 » Fri Apr 29, 2022 9:11 am

Also, I think the sample_time is a bit too much since the frequency range I want to measure is at most three digits for now. Can you tell me about the changes I can make to the code in this case?

k7ilo1
Posts: 5
Joined: Tue May 10, 2022 4:01 am

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby k7ilo1 » Wed May 11, 2022 8:30 pm

Hello all.
I am receiving "'PCNT' was not declared in this scope" when trying to compile this on my ESP32. It seems I have the library but if not, is this library provided by default or do i need to download it from somewhere?

Thanks all

Kilo

Update: I found the answer on the authors website.
Adding: #include "soc/pcnt_struct.h" fixed my issue.
Thanks
Last edited by k7ilo1 on Thu May 19, 2022 8:36 pm, edited 2 times in total.

zyghom
Posts: 6
Joined: Tue Oct 19, 2021 11:13 pm

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby zyghom » Sun May 15, 2022 6:32 am

exit status 1
'LEDC_HIGH_SPEED_MODE' was not declared in this scope

Mario Eric
Posts: 1
Joined: Mon May 23, 2022 2:06 am

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby Mario Eric » Mon May 23, 2022 2:09 am

Hi, sorry, I have a problem with the structure:
PCNT.int_clr.val = BIT(PCNT_COUNT_UNIT);
I get an alert: 'PCNT' was not declared in this scope
Could you help me to solve it?

SarahC
Posts: 1
Joined: Tue Jul 05, 2022 6:15 pm

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby SarahC » Tue Jul 05, 2022 6:18 pm

Fantastic!

Why are pins 32 and 35 tied together? Is there a hardware reason... I thought any interrupt lock could be done in software?

cp2011
Posts: 1
Joined: Wed Jul 06, 2022 6:17 pm

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby cp2011 » Wed Jul 06, 2022 6:39 pm

Dear jgustavoam,

Thank you very much for the code! It works like a champ!

I am using this module: https://www.az-delivery.de/en/products/ ... pmentboard.
I need to expand the capability to count the frequency from two independent signals. I tried defining a second pulse counter unit on Arduino framework but only the first one works. The two pulse counter units work fine when executed in different sketches. Could you please help me identify the error? Here is my code below:

Code: Select all

  Hardware connections PCNT 1:
    - ESP32 GPIO 34 - signal input
    - ESP32 GPIO 35 - ESP32 GPIO 32

 *   * Hardware connections PCNT 2:
    - ESP32 GPIO 12 - signal input
    - ESP32 GPIO 14 - ESP32 GPIO 27
*/
//==================================================================================================================

// Import libraries
//-----------------
#include "driver/pcnt.h"                                                  // Library ESP32 PCNT

// Definitions
//------------
#define PCNT_COUNT_UNIT       PCNT_UNIT_0                                 // Set Pulse Counter Unit - 0 
#define PCNT_COUNT_CHANNEL    PCNT_CHANNEL_0                              // Set Pulse Counter channel - 0 

#define PCNT_INPUT_SIG_IO     GPIO_NUM_34                                 // Set Pulse Counter input - Freq Meter Input GPIO 34
#define PCNT_INPUT_CTRL_IO    GPIO_NUM_35                                 // Set Pulse Counter Control GPIO pin - HIGH = count up, LOW = count down  
#define OUTPUT_CONTROL_GPIO   GPIO_NUM_32                                 // Timer output control port - GPIO_32
#define IN_BOARD_LED          GPIO_NUM_2                                  // ESP32 native LED - GPIO 2

// No2
#define PCNT_COUNT_UNIT1       PCNT_UNIT_1                                 // Set Pulse Counter Unit - 0 
#define PCNT_COUNT_CHANNEL1    PCNT_CHANNEL_1                              // Set Pulse Counter channel - 0 

#define PCNT_INPUT_SIG_IO1     GPIO_NUM_12                                 // Set Pulse Counter input - Freq Meter Input GPIO 34
#define PCNT_INPUT_CTRL_IO1    GPIO_NUM_14                                 // Set Pulse Counter Control GPIO pin - HIGH = count up, LOW = count down  
#define OUTPUT_CONTROL_GPIO1   GPIO_NUM_27                                 // Timer output control port - GPIO_32

// Variables
//----------

bool            flag          = true;                                     // Flag to enable print frequency reading
uint32_t        overflow      = 20000;                                    // Max Pulse Counter value
int16_t         pulses        = 0;                                        // Pulse Counter value
uint32_t        multPulses    = 0;                                        // Quantidade de overflows do contador PCNT
uint32_t        scale         = 10;                                       // scale factor to change sampling time
uint32_t        sample_time   = 1000000 / scale;                          // Sample time of t ms to count pulses
uint32_t        resolution    = 0;                                        // Resolution value
float           frequency     = 0;                                        // frequency value
char            buf[32];                                                  // Buffer

// No2
bool            flag1          = true;                                     // Flag to enable print frequency reading
uint32_t        overflow1      = 20000;                                    // Max Pulse Counter value
int16_t         pulses1        = 0;                                        // Pulse Counter value
uint32_t        multPulses1    = 0;                                        // Quantidade de overflows do contador PCNT
uint32_t        scale1         = 10;                                       // scale factor to change sampling time
uint32_t        sample_time1   = 1000000/scale1;                            // Sample time of t ms to count pulses
uint32_t        resolution1    = 0;                                        // Resolution value
float           frequency1     = 0;                                        // frequency value
char            buf1[32];                                                  // Buffer

esp_timer_create_args_t create_args;                                      // Create an esp_timer instance
esp_timer_handle_t timer_handle;                                          // Create an single timer

// No2
esp_timer_create_args_t create_args1;                                      // Create an esp_timer instance
esp_timer_handle_t timer_handle1;                                          // Create an single timer

portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;                     // portMUX_TYPE to do synchronism

// No2
portMUX_TYPE timerMux1 = portMUX_INITIALIZER_UNLOCKED;                     // portMUX_TYPE to do synchronism

//----------------------------------------------------------------------------------------
void setup()
{
  Serial.begin(115200);                                                   // Serial Console Arduino 115200 Bps

  init_frequencyMeter ();                                                 // Initialize Frequency Meter

  init_frequencyMeter1 ();                                                 // Initialize Frequency Meter
}
//----------------------------------------------------------------------------------
static void IRAM_ATTR pcnt_intr_handler(void *arg)                        // Counting overflow pulses
{
  portENTER_CRITICAL_ISR(&timerMux);                                      // disabling the interrupts
  multPulses++;                                                           // increment Overflow counter
  PCNT.int_clr.val = BIT(PCNT_COUNT_UNIT);                                // Clear Pulse Counter interrupt bit
  portEXIT_CRITICAL_ISR(&timerMux);                                       // enabling the interrupts
}

// No2
static void IRAM_ATTR pcnt_intr_handler1(void *arg)                        // Counting overflow pulses
{
  portENTER_CRITICAL_ISR(&timerMux1);                                      // disabling the interrupts
  multPulses1++;                                                           // increment Overflow counter
  PCNT.int_clr.val = BIT(PCNT_COUNT_UNIT1);                                // Clear Pulse Counter interrupt bit
  portEXIT_CRITICAL_ISR(&timerMux1);                                       // enabling the interrupts
}

//----------------------------------------------------------------------------------
void init_PCNT(void)                                                      // Set up and run PCNT unit
{
  pcnt_config_t pcnt_config = { };                                        // Create PCNT unit instance

  // Set up PCNT unit
  pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_IO;                         // Pulse input GPIO 34 - Freq Meter Input
  pcnt_config.ctrl_gpio_num = PCNT_INPUT_CTRL_IO;                         // Control signal input GPIO 35
  pcnt_config.unit = PCNT_COUNT_UNIT;                                     // Counting unit PCNT - 0
  pcnt_config.channel = PCNT_COUNT_CHANNEL;                               // PCNT unit number - 0
  pcnt_config.counter_h_lim = overflow;                             // Maximum counter value - 20000
  pcnt_config.pos_mode = PCNT_COUNT_INC;                                  // PCNT positive edge count mode - inc
  pcnt_config.neg_mode = PCNT_COUNT_INC;                                  // PCNT negative edge count mode - inc
  pcnt_config.lctrl_mode = PCNT_MODE_DISABLE;                             // PCNT low control mode - disable
  pcnt_config.hctrl_mode = PCNT_MODE_KEEP;                                // PCNT high control mode - won't change counter mode
  pcnt_unit_config(&pcnt_config);                                         // Initialize PCNT unit

  // Initialise PCNT unit
  pcnt_counter_pause(PCNT_COUNT_UNIT);                                    // Pause PCNT unit
  pcnt_counter_clear(PCNT_COUNT_UNIT);                                    // Clear PCNT unit

  // Interrupts
  pcnt_event_enable(PCNT_COUNT_UNIT, PCNT_EVT_H_LIM);                     // Enable event to watch - max count
  pcnt_isr_register(pcnt_intr_handler, NULL, 0, NULL);                    // Setup Register Interrupt Service Routine handler
  pcnt_intr_enable(PCNT_COUNT_UNIT);                                      // Enable INTERRUPTS for PCNT unit

  pcnt_counter_resume(PCNT_COUNT_UNIT);                                   // Resume PCNT unit - starts count
}

// No2
void init_PCNT1(void)                                                      // Set up and run PCNT unit
{
  pcnt_config_t pcnt_config1 = { };                                        // Create PCNT unit instance

  // Set up PCNT unit
  pcnt_config1.pulse_gpio_num = PCNT_INPUT_SIG_IO1;                         // Pulse input GPIO 34 - Freq Meter Input
  pcnt_config1.ctrl_gpio_num = PCNT_INPUT_CTRL_IO1;                         // Control signal input GPIO 35
  pcnt_config1.unit = PCNT_COUNT_UNIT1;                                     // Counting unit PCNT - 0
  pcnt_config1.channel = PCNT_COUNT_CHANNEL1;                               // PCNT unit number - 0
  pcnt_config1.counter_h_lim = overflow1;                             // Maximum counter value - 20000
  pcnt_config1.pos_mode = PCNT_COUNT_INC;                                  // PCNT positive edge count mode - inc
  pcnt_config1.neg_mode = PCNT_COUNT_INC;                                  // PCNT negative edge count mode - inc
  pcnt_config1.lctrl_mode = PCNT_MODE_DISABLE;                             // PCNT low control mode - disable
  pcnt_config1.hctrl_mode = PCNT_MODE_KEEP;                                // PCNT high control mode - won't change counter mode
  pcnt_unit_config(&pcnt_config1);                                         // Initialize PCNT unit

  // Initialise PCNT unit
  pcnt_counter_pause(PCNT_COUNT_UNIT1);                                    // Pause PCNT unit
  pcnt_counter_clear(PCNT_COUNT_UNIT1);                                    // Clear PCNT unit

  // Interrupts
  pcnt_event_enable(PCNT_COUNT_UNIT1, PCNT_EVT_H_LIM);                     // Enable event to watch - max count
  pcnt_isr_register(pcnt_intr_handler1, NULL, 0, NULL);                    // Setup Register Interrupt Service Routine handler
  pcnt_intr_enable(PCNT_COUNT_UNIT1);                                      // Enable INTERRUPTS for PCNT unit

  pcnt_counter_resume(PCNT_COUNT_UNIT1);                                   // Resume PCNT unit - starts count
}
//----------------------------------------------------------------------------------
void read_PCNT(void *p) {                                                 // Read Pulse Counter
  gpio_set_level(OUTPUT_CONTROL_GPIO, 0);                                 // Stop counter - output control LOW (same as digitalWrite() but faster)
  pcnt_get_counter_value(PCNT_COUNT_UNIT, &pulses);                       // Read Pulse Counter value
  flag = true;                                                            // Change flag to enable print
}

// No2
void read_PCNT1(void *p){                                                  // Read Pulse Counter
  gpio_set_level(OUTPUT_CONTROL_GPIO1, 0);                                 // Stop counter - output control LOW (same as digitalWrite() but faster)
  pcnt_get_counter_value(PCNT_COUNT_UNIT1, &pulses1);                       // Read Pulse Counter value
  flag1 = true;                                                            // Change flag to enable print
}
//---------------------------------------------------------------------------------
void init_frequencyMeter ()
{
  init_PCNT();                                                            // Initialize and run PCNT unit

  gpio_pad_select_gpio(OUTPUT_CONTROL_GPIO);                              // Set GPIO pad
  gpio_set_direction(OUTPUT_CONTROL_GPIO, GPIO_MODE_OUTPUT);              // Set GPIO 32 as output (same as pinMode)
  create_args.callback = read_PCNT;                                       // Set esp-timer argument
  esp_timer_create(&create_args, &timer_handle);                          // Create esp-timer instance

  gpio_set_direction(IN_BOARD_LED, GPIO_MODE_OUTPUT);                     // Set LED inboard as output

  gpio_matrix_in(PCNT_INPUT_SIG_IO, SIG_IN_FUNC226_IDX, false);           // Set GPIO matrin IN - Freq Meter input
  gpio_matrix_out(IN_BOARD_LED, SIG_IN_FUNC226_IDX, false, false);        // Set GPIO matrix OUT - to inboard LED
}

// No 2
void init_frequencyMeter1 ()
{
  init_PCNT1();                                                            // Initialize and run PCNT unit

  gpio_pad_select_gpio(OUTPUT_CONTROL_GPIO1);                              // Set GPIO pad
  gpio_set_direction(OUTPUT_CONTROL_GPIO1, GPIO_MODE_OUTPUT);              // Set GPIO 32 as output (same as pinMode)
  create_args1.callback = read_PCNT1;                                       // Set esp-timer argument
  esp_timer_create(&create_args1, &timer_handle1);                          // Create esp-timer instance

  gpio_set_direction(IN_BOARD_LED, GPIO_MODE_OUTPUT);                     // Set LED inboard as output

  gpio_matrix_in(PCNT_INPUT_SIG_IO1, SIG_IN_FUNC226_IDX, false);           // Set GPIO matrin IN - Freq Meter input
  gpio_matrix_out(IN_BOARD_LED, SIG_IN_FUNC226_IDX, false, false);        // Set GPIO matrix OUT - to inboard LED
}


//---------------------------------------------------------------------------------
void loop()
{
  if (flag == true)                                                     // If count has ended
  {
    flag = false;                                                       // change flag to disable print
    frequency  = (pulses + (multPulses * overflow)) / 2 * scale;       // Calculation of frequency

    Serial.print(frequency);
    Serial.println(" Hz");

    multPulses = 0;                                                     // Clear overflow counter
    pcnt_counter_clear(PCNT_COUNT_UNIT);                                // Clear Pulse Counter
    esp_timer_start_once(timer_handle, sample_time);                    // Initialize High resolution timer (1 sec)
    gpio_set_level(OUTPUT_CONTROL_GPIO, 1);                             // Set enable PCNT count (same as digitalWrite() but faster)
  }
  delay(1);

  if (flag1 == true)                                                     // If count has ended
  {
    flag1 = false;                                                       // change flag to disable print
    frequency1 = (pulses1 + (multPulses1 * overflow1)) / 2 * scale1  ;       // Calculation of frequency
    
    Serial.print(frequency1);
    Serial.println(" Hz");
    
    multPulses1 = 0;                                                     // Clear overflow counter
    pcnt_counter_clear(PCNT_COUNT_UNIT1);                                // Clear Pulse Counter
    esp_timer_start_once(timer_handle1, sample_time1);                    // Initialize High resolution timer (1 sec)
    gpio_set_level(OUTPUT_CONTROL_GPIO1, 1);                             // Set enable PCNT count (same as digitalWrite() but faster)
  }
  delay(1);
}
Many thanks!

Best,
Christoforos

k7ilo1
Posts: 5
Joined: Tue May 10, 2022 4:01 am

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby k7ilo1 » Wed Jul 20, 2022 1:52 pm

Mario Eric wrote:
Mon May 23, 2022 2:09 am
Hi, sorry, I have a problem with the structure:
PCNT.int_clr.val = BIT(PCNT_COUNT_UNIT);
I get an alert: 'PCNT' was not declared in this scope
Could you help me to solve it?
Adding: #include "soc/pcnt_struct.h" fixed my issue.

Kilo

Who is online

Users browsing this forum: Majestic-12 [Bot] and 26 guests