Frequency Measurement on digital input

rodmcm
Posts: 32
Joined: Sat Sep 02, 2017 3:31 am

Frequency Measurement on digital input

Postby rodmcm » Tue Jul 24, 2018 9:56 pm

Enclosed is a program to measure the frequency of a square wave on a digital input. The program uses a free running timer/counter and digital interrupts. Hope this assists someone out there....


Code: Select all

/* 
Measures the frequency of a square wave appliet to a digital input
Uses a free running timer/counter for the period measurement
by: rodmcm
date: 25/7/2018
*/

const byte        interruptPin = 23;              // Assign the interrupt pin
volatile uint64_t StartValue;                     // First interrupt value
volatile uint64_t PeriodCount;                    // period in counts of 0.000001 of a second
float             Freg;                           // frequency     
char              str[21];                        // for printing uint64_t values
 
hw_timer_t * timer = NULL;                        // pointer to a variable of type hw_timer_t 
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;  // synchs between maon cose and interrupt?


// Digital Event Interrupt
// Enters on falling edge in this example
//=======================================
void IRAM_ATTR handleInterrupt() 
{
  portENTER_CRITICAL_ISR(&mux);
      uint64_t TempVal= timerRead(timer);         // value of timer at interrupt
      PeriodCount= TempVal - StartValue;          // period count between rising edges in 0.000001 of a second
      StartValue = TempVal;                       // puts latest reading as start for next calculation
  portEXIT_CRITICAL_ISR(&mux);
}


// Converts unit64_t to char for printing
// Serial.println(uintToStr( num, str ));
//================================================
char * uintToStr( const uint64_t num, char *str )
{
  uint8_t i = 0;
  uint64_t n = num;
  do
    i++;
  while ( n /= 10 );
  
  str[i] = '\0';
  n = num;
 
  do
    str[--i] = ( n % 10 ) + '0';
  while ( n /= 10 );

  return str;
}

// SetUp
//======================================
void setup() 
{
  Serial.begin(115200);
  pinMode(interruptPin, INPUT_PULLUP);                                            // sets pin high
  attachInterrupt(digitalPinToInterrupt(interruptPin), handleInterrupt, FALLING); // attaches pin to interrupt on Falling Edge
  timer = timerBegin(0, 80, true);                                                // this returns a pointer to the hw_timer_t global variable
                                                                                  // 0 = first timer
                                                                                  // 80 is prescaler so 80MHZ divided by 80 = 1MHZ signal ie 0.000001 of a second
                                                                                  // true - counts up
  timerStart(timer);                                                              // starts the timer
}

void loop() 
  {
  portENTER_CRITICAL(&mux);
  Freg =1000000.00/PeriodCount;                       // PeriodCount in 0.000001 of a second
  portEXIT_CRITICAL(&mux);
  Serial.print("Frequency   ");Serial.println(Freg,2);
  delay(200);
  }
 

Anderson_Oli
Posts: 1
Joined: Thu Jul 26, 2018 3:27 pm

Re: Frequency Measurement on digital input

Postby Anderson_Oli » Thu Jul 26, 2018 3:41 pm

Good Morning.
I'm starting on ESP32, I see it's good with TIMER.
You could give an example of how I can use a timer, so that from a button I can turn on an LED and wait 500ms for the led to turn off.
but without the use of delay ().
If this help is possible, I thank you. :D

ESP_Sprite
Posts: 2761
Joined: Thu Nov 26, 2015 4:08 am

Re: Frequency Measurement on digital input

Postby ESP_Sprite » Fri Jul 27, 2018 1:18 am

@Anderson_Oli: For something like this, I suggest you use the esp_timer API. There's an example for this in esp-idf: esp-idf/examples/system/esp_timer

Don Warr
Posts: 6
Joined: Fri Oct 19, 2018 10:01 am

Re: Frequency Measurement on digital input

Postby Don Warr » Fri Oct 19, 2018 10:18 am

"Hope this assists someone out there...." Yes I'm sure, future google searchers like me will be happy you shared..
You never added what the top frequency you were able to achieve, or the amount of jitter (digit bobble) you got.. Can you share that, as slew and rise times are a big secret, and never talked about anywhere...

ESP_Sprite
Posts: 2761
Joined: Thu Nov 26, 2015 4:08 am

Re: Frequency Measurement on digital input

Postby ESP_Sprite » Fri Oct 19, 2018 11:31 am

Note that this possibly is not the best approach to do frequency measurement... there are other posts as well that use peripherals (MPWM or pulse counter, I don't remember) that get up to 40MHz, which in theory is the limit of anything going through the GPIO matrix. Those measurements should have a jitter of 1/40MHz. Not sure about slew rates.

Don Warr
Posts: 6
Joined: Fri Oct 19, 2018 10:01 am

Re: Frequency Measurement on digital input

Postby Don Warr » Sat Oct 20, 2018 4:37 am

Thank's For your input " ESP_Sprite" .. After decades with microchip, I am just now evaluating the ESP32,, What a wonderful little chip this is.. I threw together the code of "rodmcm"'s and saw it does work well.. Are you just guessing at 40Mhz, or did you hear this somewhere..?? Nowhere, do I see a ESP32 datasheet that specifies, the characteristic specs, like input rise times clock ppm etc.. But rodmcm code, does give me a proof of concept, so now I will checkout the "peripherals (MPWM or pulse counter" you suggested..
Thank's ...

ESP_Sprite
Posts: 2761
Joined: Thu Nov 26, 2015 4:08 am

Re: Frequency Measurement on digital input

Postby ESP_Sprite » Sat Oct 20, 2018 7:34 am

40MHz is because all peripherals as well as the GPIO matrix work at the APB frequency of 80MHz. They will sample the GPIO once per 80MHz clock tick, and as such 40MHz is the maximum they will be able to measure (without aliasing).

User avatar
TinkerBearNZ
Posts: 4
Joined: Mon Jun 17, 2019 11:20 pm

Re: Frequency Measurement on digital input

Postby TinkerBearNZ » Mon Jul 15, 2019 5:57 am

Wouldn't you get more accuracy by using a hardware signal to gate the counter?

Like... using a 5Hz signal from the LEDC, fed to a GPIO that's also used as the counter gate. Then it's just a matter of adding an interrupt routine on the negative edge of the gate signal to grab the count.

I've had to poke around in the GPIO matrix to avoid using a second GPIO pin, but this does actually work.

My one remaining problem is that sometimes the low-speed LEDC pwm channel I'm using as a gate signal doesn't start, depending on what other LEDC channels are running. I don't have a reliable workaround yet.

Who is online

Users browsing this forum: No registered users and 3 guests