Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
6 years, 5 months ago.
Frequency measure using interupts?
The frequency range I am interested in is 100kHz-200kHz. I am using mbed APIs to communicate with my PC. The code I have written is for an STM32L053C8 discovery board. I am able to measure the frequency only till 97kHz and at 97 kHz I am recieving a huge error in value of about 1 kHz. At 98 kHz the value mysteriously drops to zero. I am clueless as to why this happening. I need a more accurate and a frequency measure till 200 kHz of range. Please forgive me if I have made some silly errors as I am very new to this.
Freq measure
#include "mbed.h" #define GATE_TIME 1 // Gate time (period of time to count pulses within) in seconds Serial pc(PA_9,PA_10); InterruptIn input(PB_10); // input line Timeout timeout; volatile bool measuringEnabled = false; volatile uint64_t counter; volatile uint64_t freq=0; //ISR to count pulses void onPulse(void) { if (measuringEnabled) counter++; } // ISR to stop counting void stopMeasuring(void) { measuringEnabled = false; } // Initializes counting void startMeasuring(void) { counter = 0; timeout.attach(callback(&stopMeasuring), GATE_TIME); measuringEnabled = true; int main(void) { input.rise(callback(&onPulse)); // assign an ISR to count pulses while (1) { startMeasuring(); while (measuringEnabled); // wait until the measurement has completed if(GATE_TIME < 2) wait(2 - GATE_TIME); // wait at least one second before printing freq=counter; printf(" %u \n",freq); } }
1 Answer
6 years, 5 months ago.
First there are some formatting problems in what you posted. Brackets are missing. startMeasuring() is missing body end bracket (line 28). The If on line 34 does not have opening bracket making only that first line conditional.
This basic approach can work for low frequencies but there is an upper limit on the frequency you can measure this way. Looks like this board is 32MHz or 31.25ns per clock tick. The system will need some hundreds of clock ticks between every rising edge interrupt in order to do the ISR context switch. The rtos needs some CPU time every now and then and main itself needs some CPU time.
The control logic seems like it could be a lot simpler. If I were doing this I would have only the one interrupt for counting rising edges. Then in the main body I would use either the free us timer or a custom Timer to track time. Each loop something like:
// clear counter // reset timer or snapshot us timer at start of loop // wait(1 second) - counter ISR is doing it's thing here // capture copy of counter // capture timer value time_base = timer.read() // frequency = counter_copy / time_base
It wouldn't surprise me if at 100kHz the failure you're seeing is simply because the CPU can't keep up. I saw someone doing this same pulse counting on an Arduino at I think 8MHz and it failed above 50kHz - so same type of range.
You might be able to setup one of the hardware timers to do this more efficiently without involving the CPU and make it usable with higher frequencies. You would have to dig into the micro reference manual and then use the HAL driver layer to configure the timer.
Graham