Black Pill Arduino low frequency (<350 kHz) high accuracy frequency measurement - Page 1
Forum section: electronics / general

author: bb1
author_rank: Regular Contributor
timestamp: November 19, 2021, 12:05:14 am
content: It is interesting to find what accuracy of frequency measurement can be achieved using only Black Pill STM32F411 internal counters.For low frequencies stm32duino HardwareTimer library provides nice examples of frequency measurement based on Capture Interrupt.I modified these examples to obtain as high accuracy as possible.The resulting Arduino .ino program can be found in the attached zip file.At low frequencies my program provides at least 7 correct frequency digits.At the highest frequency of about 350 kHz 5 correct digits are observed using 2 sec measurement time,and 6 correct frequency digits are obtained using 20 sec measurement time.Input frequency signal is connected to pin PA1. No other signal connections are required.The frequency measurement results are shown by Arduino Serial Monitor.Measurement time can be set via Arduino Serial Monitor by sending numbers 0, 1 or 2,which set the measurement time to 0.22 sec, 2.2 sec and 22 sec accordingly.Capture interrupt used to measure frequency takes about 2.9 uS.If such interrupts come faster than approximately 350 kHz, then they cannot be counted correctly.Because of that if the input frequency exceeds 350 kHz, then the measured frequency is wrong.For the same reason if the input frequency is close to the upper limit of 350 kHz,setting of the measurement time via Arduino Serial Monitor becomes unresponsive,as all processor power is spent inside Capture Interrupt.Black Pill clock is not very accurate. In my case it is about 93 ppm lower than it should be.To achieve high absolute accuracy frequency correction coefficient should be used.It can be found using some high accuracy calibration clock, such as GPS 1PPS signal.For my Black Pill freqCorrection = 1.000093675.Of course, there is Black Pill clock drift, but it is not very high.My Arduino program does not pretend to be perfect, but it was tested at many frequencies between 0.1 Hz and 350 kHz,and had no problem.Feel free to improve it.

author: PCB.Wiz
author_rank: Super Contributor
timestamp: November 19, 2021, 03:28:26 am
content: Quote from: bb1 on November 19, 2021, 12:05:14 amOn MCUs with external clock ability, you can also connect the FreqIn to the CLK of the counter and capture the counter on a fixed timebase.That allows MHz region measurements without worrying about interrupt times.If the HW allows, you can runtwotiming channels, one capturing time and one capturing cycles. Those are allowed to run, and after some nominal aperture time (say ~100ms or ~1s) you enableone-shot capture on the next Fi edge.The HW then rounds-up to thenextwhole period of FreqIN, and the time-capture is thetime for N whole cycles.Now, you can use Reciprocal Counter maths to calculate WholeCycles/Time to get very high precisions over a wide range if FreqIn.100MHz timebases allow 8 digits per second of precision.(Config Logic units can help here, not sure if STM32F411 has those)

author: mino-fm
author_rank: Regular Contributor
timestamp: November 19, 2021, 08:27:42 am
content: I guess F411 is running at 100 MHz. For any input frequency you should get 8 digits/s.Counting pulses at PA0 should be possible up to 1 - 2 MHz. Setting IC1PSC to 3 (in TIM2_CCMR1) enables factor 8 of input-capture prescaler. Maximum frequency will reach >= 10 MHz; resolution and accuracy will not be affected.For lower frequencies and faster reading prescaler can be reset to 1 again.Maybe you try to change your code for better performance.

author: AndrewBCN
author_rank: Frequent Contributor
timestamp: November 20, 2021, 05:32:41 am
content: There are two ways to measure the frequency of a repetitive input signal: one can measure the period (e.g. time elapsed between two rising edges) and then calculate the frequency, or one can directly count the cycles per second (or another "gate time", e.g. 0.1s, 10s, 100s, 1000s, etc).On the STM32F411 you can configure some pins as an external clock, but the timer/counters are still clocked by an internal clock, so the external clock maximum frequency that can be measured on the Black Pill is 24MHz, according to the STM32F411 datasheet.I have posted the code for this frequency measuring method on the stm32duino forum, a few months ago, and it is the method I use for the STM32 GPSDO.The Hardware Timer library example code and the OP code both measure the period.

author: wilhe_jo
author_rank: Regular Contributor
timestamp: November 20, 2021, 08:07:33 am
content: Don't ever dare to use interrupts to measure frequencies!That's way too inaccurate since you cannot predict the times needed to enter it (the memory bus is highly unpredictable).Feed the signal to one counter and let it count to1 (or whatever pressing factor you need). A second timer is clocked at max clk in free running mode.Use the first counter to generate a DMA event to copy the counter value from the freerunning one to memory.Now configure the DMA to get you eg to 17 samples (the first one will be wrong for obvious reasons) and look on the values.After enabling the first on the DMA, I got down to a few clk cycles of deviation (max difference between any 2 results) for a 1pps signal over 5minutes.73

author: mino-fm
author_rank: Regular Contributor
timestamp: November 20, 2021, 09:25:43 am
content: Quote from: AndrewBCN on November 20, 2021, 05:32:41 amF411 clocked at 100 MHz is capable to count nearly 50 MHz but 40 MHz is more realistically. Without additional hardware another timer of F411 could be used as a variable prescaler to measure frequencies from sub Hz range up to 40 MHz.Quote from: wilhe_jo on November 20, 2021, 08:07:33 amWhy?Interrupts are independet of memory bus cycles. As long as timer-capture ISR is handled faster than counting events arrive no interrupt is missing - counting is accurate as required.Years ago I had a reciprocal counter project with F407 @ 168 MHz. Upper frequency has been 2.5 MHz counting directly and 20 MHz using internal /8 prescaler.

author: PCB.Wiz
author_rank: Super Contributor
timestamp: November 20, 2021, 09:51:52 am
content: Quote from: AndrewBCN on November 20, 2021, 05:32:41 amNot quite, there is a 3rd variant, that usestwocounters, running concurrently, called a Reciprocal frequency counter.This has a nominal minimum gate time, but always captures time over awhole number of FreqIn cycles, so the actual capture time varies,The two counters give you Cycles and Time in SysCLK units and Cycles/Time is HzA Reciprocal frequency counter has very wide dynamic range, and does not lose precision at low frequency (like a gated counter does) or lose precision at high frequency (like Period capture does)#4 above uses two timers, so is very close to this but it need manual set of N samples.A system that arms capture after some nominal minimum time, autoscales automatically so can read 1Hz ~ 25+MHz to 8 digits per second at 100Mhz sysclk.

author: wilhe_jo
author_rank: Regular Contributor
timestamp: November 20, 2021, 11:41:26 am
content: Quote from: mino-fm on November 20, 2021, 09:25:43 amÄhm, data has to be pushed onto the stack and instructions need to be fetched.If you need to fetch timer values with a minimum of jitter/uncertainty, there's really no way around DMA on a STM32.But even there, you have some slight uncertainty due to the way bus abitration is done... just study the appnotes!73

author: mino-fm
author_rank: Regular Contributor
timestamp: November 20, 2021, 12:04:23 pm
content: Quote from: wilhe_jo on November 20, 2021, 11:41:26 amI don't know what you are talking about. Everyone ist using capture registers to get timer values exactly.In between I tried to test shown .ino-file on a Nucleo-G431 board and to do some optimizations. I had to change user led pin to PB8. TIM2 will not run, TIM1 does.Looking at sourcecode there are serveral things you shouldn't do like stopping timers. Looking arround www you can find other sources looking exactly like this and AndrewBCN has used.Don't mind, that's Arduino

author: wilhe_jo
author_rank: Regular Contributor
timestamp: November 20, 2021, 01:17:36 pm
content: never mind... I understood that first posting maybe the wrong way.That sounded like the interrupt directly reads the "raw" counter (ie. the running value) and not the "latched" value the input-capture presents to you... that would be badAnyway, using the DMA to fetch the results from the input-capture registers would be the way to got to increase the upper frequency...73

author: AndrewBCN
author_rank: Frequent Contributor
timestamp: November 20, 2021, 01:21:46 pm
content: Quote from: mino-fm on November 20, 2021, 09:25:43 amNo. Check the datasheet. Max frequency for external clock must be < apb bus frequency / 3.5~4. Realistically that means 24MHz on the Black Pill with the apb bus frequency of 96MHz.

author: mino-fm
author_rank: Regular Contributor
timestamp: November 20, 2021, 04:05:21 pm
content: Take a look yourself.

author: bb1
author_rank: Regular Contributor
timestamp: November 28, 2021, 07:51:04 pm
content: There are multiple ways to measure high frequencies using Black Pill STM32F411 internal counters, so I see no need to post any code for that.I checked the highest frequencies which can be measured reliably.The input signal was connected to TIM2_ETR pin PA0. External clock source mode 2 was used.For async divider values of 1, 2, and 4 the highest frequencies were 47 MHz, 93 Mhz and 180 Mhz.For the divider value of 8 I also got the highest reliably measured frequency of 180 Mhz, but I cannot exclude that higher frequencies could be measured with better setup.

author: bb1
author_rank: Regular Contributor
timestamp: November 28, 2021, 10:01:38 pm
content: Failure to measure frequencies above 180 MHz may be due to insufficient amplitude of the input signal at such frequencies.Indeed, it is easy to measure hysteresis of the input pin of STM32F411. Trivial Arduino code can be used for that:#define LED_BUILTIN PC13int val = 0;void setup() {pinMode(LED_BUILTIN,OUTPUT);pinMode(PA0,INPUT);}void loop() {val=digitalRead(PA0);digitalWrite(LED_BUILTIN,val);}Scope Channel 1 is connected to the input signal on pin PA0, and scope Channel 2 is connected to the output pin PC13.The signals and 400 mV hysteresis can be seen on the attached scope screenshot.

author: bb1
author_rank: Regular Contributor
timestamp: December 01, 2021, 12:16:08 am
content: I improved the setup, and now with async divider=4 highest reliably measured frequency is185 MHz,while with divider=8 I was able reliably measure PA0 Timer 2 input frequency of260 MHz.

author: mino-fm
author_rank: Regular Contributor
timestamp: January 09, 2022, 11:47:47 am
content: Quote from: bb1 on December 01, 2021, 12:16:08 amVery interesting. Thank you for testing.So I tried ETR-input of TIM3 to realize an asynchronous divider 1:1024 for frequency measurement using STM32F429 disco-board. Upper limit was 415 MHz with unterminated flying connection (white = HF, black = GND).