Timer config for frequency measurement

Post here first, or if you can't find a relevant section!
Post Reply
timdf911
Posts: 5
Joined: Thu Dec 01, 2022 5:32 pm

Timer config for frequency measurement

Post by timdf911 »

Hi guys
1st post but long term lurker !

I've been trying to update a design I originally did 7 years ago which used a Teensy processor and was written entirely in C using the Atmel environmanr.

I've recently discovered the delights of an STM32F401re and have started to port the code using stm32duino environment - but I've run into a road block and despite lots of googling I've made little progress due to being overwhelmed with all the registers associated with the timers and what I suspect is limited timer functionality in the stm32duino environment.

Here's what I need to do - basically a one shot measurement of a frequency between 1 and 30MHz to a resolution of 10kHz.

Here's how I think it should be done

1. Use timer 2 with the signal using ETR input with possibly the prescaler if it can't handle 30MHz directly
2. Set the timer2 counter to zero
3. Open the gate for 1mS using a second timer (say timer3) then read the timer 2 to see how many times it's been incremented. The resulting count should be between 1000 and 30000

To do the above seems to need a bunch of registers setting, I've had some limited success using some snippets of code from Andrewbcn GPSDO project, but frankly my attempt is a mess and I'd be ashamed to post it !

I'm hoping someone can give me a few pointers on key registers and settings which will link the two timers together and operate as above.

I've tried reading the data and using CubeMx but managed to get myself wrapped round the axle there aswell.

Regards Tim

PS I've posed this question elsewhere, but figure this might be a better location to solicit help.
dannyf
Posts: 446
Joined: Sat Jul 04, 2020 7:46 pm

Re: Timer config for frequency measurement

Post by dannyf »

the simplest would be to count pulses over a period of time.

that gets tricky however for very low frequencies - the measurement period is extensively long. In those cases, you flip the coin: you measure the elapse of clock cycles between two (or more) input pulses.
ag123
Posts: 1653
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: Timer config for frequency measurement

Post by ag123 »

I think counting clock cycles is probably a 'simplest' way. That is provided the voltage swing is high enough between 0-3.3v, otherwise a comparator like LM(V)393 may be needed in front of a pin. ADC e.g. analogRead() can be used if the frequency isn't too high.

The *hard* part is to deal with very high frequencies, say beyond several MHz. We'd leave that topic for now.

Let's just say you are happy to make do with 'low' frequency measurements.
https://github.com/stm32duino/wiki/wiki ... er-library

A way to implement, Timer codes may look like such

Code: Select all


HardwareTimer *Timer1 = new HardwareTimer(TIM1);

enum State {
	Init = 0,
	Started = 1,
	Low = 2,
	High = 3,
	LowAgain = 4,
	Stopped = 5
}

State state = State::Init;

uint32_t max_count = 0;

/* unused
void Update_IT_callback(void)
{ // Toggle pin. 10hz toogle --> 5Hz PWM
  digitalWrite(pin, !digitalRead(pin));
}
*/

void setup() {

  Serial.begin(); 

  Timer1->setOverflow(10000000, HERTZ_FORMAT); // 10 MHz - note I'm not sure if 100 nsecs is after all feasible
  // Timer1->attachInterrupt(Update_IT_callback); // unused
  Timer1->pause();  //stop the timer
  Timer1->refresh(); //reset the counters
  
  maxcount = Timer1->getOverflow(); // get the max count value
  
  state = State::init;
  
  pinMode(PA0, INPUT); // monitor pin PA0 for input.
	
  while (! Serial); // wait for Serial monitor to connect
  /* optional
   delay(1);
   Serial.println("frequency counter, press s to start sampling"); 
   */
}

void loop() {

	if (state == State::Init || state == State::Stopped) {
		if(Serial.available()) {
			int16_t c = Serial.read();
			if( c == 's' ) { // start
				Timer1->pause(); // stop the timer
				Timer1->refresh(); // reset the counts
				state = State::Started;
			}
		}
	} else if ( state == State::Started ) {
		if ( digitalRead(PA0) == LOW ) {
			state = State::Low;
		}
	} else if ( state == State::Low ) {
		if ( digitalRead(PA0) == HIGH ) {
			// we detected a low to high transition here
			Timer1->resume(); //start the timer
			state = State::High;
		}
	} else if ( state == State::High ) {
		if ( digitalRead(PA0) == LOW ) {
			// we detected a high to low transition here
			state = State::LowAgain;
		}
	} else if ( state == State::LowAgain ) {
		if ( digitalRead(PA0) == HIGH ) {
			// we detected a low to high transition here
			Timer1->pause(); //stop the timer
			uint32_t count = Timer1->getCount();
			/* frequency =  timer_hz * maxcount / count   */
			float freqency = 10000000.0 * (float) maxcount / (float) count;
			Serial.print("frequency : ");
			Serial.println(frequency);			
			state = State::Stopped;
		}		
	}							
}
This is untested codes, i'm not sure if it'd even build or work or is even correct.
This is basically a software edge detector, there are probably some delays so that limits the accuracy and it'd likely be significantly worse while measuring high frequencies. For frequencies that are 'too low', you may need to reduce the timer frequency or use additional software counters, e.g. that timer interrupt call back to extend the counts.

You can find more examples in the examples repository
https://github.com/stm32duino/STM32Exam ... llback.ino
https://github.com/stm32duino/STM32Exam ... dwareTimer

For high frequencies, one way is instead to count the pulses / transitions over a fixed period. That's likely to be more accurate for high frequencies.
timdf911
Posts: 5
Joined: Thu Dec 01, 2022 5:32 pm

Re: Timer config for frequency measurement

Post by timdf911 »

Hi guys

thanks for your comments - all understood and I've been making some progress using Cubemx and cubeide to control two timers. One generates a 100mS trigger which is used to capture the current count of the other. Subtracting old from new counts gives me the number of pulses (cycles) in 100mS. Using the ETR clock input allows operation upto at least 10MHz, haven't tried any higher yet.

At some point I'll convert the Cube code across tostm32duino - hopefully !

Regards Tim
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Timer config for frequency measurement

Post by ozcar »

timdf911 wrote: Sun Dec 04, 2022 9:50 pm Using the ETR clock input allows operation upto at least 10MHz, haven't tried any higher yet.
As mentioned over on eevblog, you'd have to use the ETR prescaler to reach your maximum of 30MHz. If you look at AN4776 "General-purpose timer cookbook", there is a section there on using an external clock source, where it explains that without the prescaler, the maximum input signal frequency is one third of the timer clock (so 28MHz for 84MHz timer clock). I think it says the same thing at various points in the reference manual, but curiously, where it describes the ETPS prescaler bits in SMCR, it says max frequency without prescaler is one quarter of the timer clock. I think one third is the correct value, but maybe there is something subtle going on there that I do not understand. One third or one quarter, you'd still have to divide by two.
dannyf
Posts: 446
Joined: Sat Jul 04, 2020 7:46 pm

Re: Timer config for frequency measurement

Post by dannyf »

For synchronous timers, the max speed is half of the mcu's clock speed.

For asynchronous timers, it is up to how fast the timer can count.

So the idea architecture here is a mcu with an asynchronous timers. Unfortunately the stm32 isn't such a chip.

Some PICs have asynchronous timers.
dannyf
Posts: 446
Joined: Sat Jul 04, 2020 7:46 pm

Re: Timer config for frequency measurement

Post by dannyf »

The way to get around that is to use an external prescaler and devise a way to stop and read the prescaler. Usually by counting the input to it until it overflows.

Some prescalers go to GHz.
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Timer config for frequency measurement

Post by ozcar »

dannyf wrote: Sat Dec 17, 2022 8:35 pm For synchronous timers, the max speed is half of the mcu's clock speed.
For the STM32 timers it does seem to be that the max rate is 1/2 the timer clock. But the documentation gives different answers in different places. I just noticed that one section of the cookbook even disagrees with itself - where it talks about external clock mode 1, it says:

"Due to the resynchronization stage, it is required that the external clock-source frequency is less than twice the timer frequency, as shown at the formula below:

TIMxCLK freq >= 3 x ITxfreq"

i.e. words and formula are at odds with each other.
Post Reply

Return to “General discussion”