FreqCount Multi option - 2Mhz 4 channel frequency measurement

Status
Not open for further replies.

chase1873

New member
Hello, I need to measure four ~2Mhz channels. The FreqMeasureMulti tool is great, but barfs at inputs above 1.75Mhz on my teensy 4.1

The FreqCount function works for 2Mhz signal, but I am not sure how to measure multiple channels simultaneously.

AKA FreqCountMulti version of FreqMeasureMulti.

PaulStoffregen you out there?
 
Last edited:
I tested with a fix that is pending for FreqMeasureMulti (see below), and I got good results on 3 channels up to 500 kHz, or one channel up to 2 MHz, but definitely this library as is cannot handle 4 channels at 2 MHz. It's doing period measurement on every period, so I assume the interrupt rate is just too high. You'll need to pursue Pulse Counting rather than Period Measurement for now, but there is an enhancement possible to FreqMeasureMulti that I'll work on. These counters have an option to measure over multiple signal periods rather than 1 signal period. There is a one-byte register to specify 1-256 periods. This reduces the interrupt rate, which would work very well for your use case. Counting over multiple periods may require reducing the clock rate to prevent accumulating more than 2^32 clocks.

My original response below:

This may be caused by a bug in FreqMeasureMulti for T4. The problem is that the T4 code is not reading the correct capture registers. This shows up as inaccuracy at low frequencies, but probably would result in completely incorrect results at higher frequencies. The fix is simple if you want to try it. Just edit file FreqMeasureMultiIMXRT.cpp in your library, replacing reads of registers VAL0-5 with CVAL0-5, which are the actual capture registers. There is just one read instance for each. Here are the links to the Issue and Pull Request pages if you want to read more. Please let us know if it fixes your issue.

https://github.com/PaulStoffregen/FreqMeasureMulti/issues/12

https://github.com/PaulStoffregen/FreqMeasureMulti/pull/13
 
Last edited:
Per my post above, I experimented with enabling the edge count/compare capability for the FlexPWM timers in FreqMeasureMultiIMXRT.cpp, and I got it to work. I'm sure this feature can be folded into the library, but for now I just modified the configuration directly. In the code below from begin(), I added 3 lines for each of the 3 channels X,A,B. They set the edge compare value to 200 (which must be counting both edges because the result is frequency/100), and set two additional flags to enable the feature. The result is good measurement on 3 channels up to at least 10 MHz. The result is not always exact, but I think that's due to inaccuracy in the PWM output frequency for test. As you go higher in frequency you may need to reduce the counter's clock frequency to avoid overflow.

This is the output of the FreqMeasureMulti 3-channel example program with modifications for channel numbers and using 8-bit PWM resolution. The value of 100,000 represents 10,000,000 divided by 100. I get exact results for 12.5 MHz with 8-bit PWM and 25 MHz with 4-bit PWM.

FreqMeasureMulti Begin
1760.79, 1756.38, 1747.64
100000.00, 100000.00, 100000.00
100000.00, 100000.00, 100000.00
100000.00, 100000.00, 100000.00

I'll work on updating the library to support this configuration and include the divider in the frequency calculation, but this at least gives you a way to move forward.

Note that you must also make the fix to read capture registers CVAL0-5 per my post above. Without that fix, it doesn't work at all at high frequencies.

switch (_channel) {
case 0: // X channel
pflexpwm->SM[sub_module].CAPTCTRLX = capture_mode | FLEXPWM_SMCAPTCTRLA_ARMA;
pflexpwm->SM[sub_module].INTEN |= (inten & (FLEXPWM_SMINTEN_CX0IE | FLEXPWM_SMINTEN_CX1IE)) | FLEXPWM_SMINTEN_RIE;
// set capture compare to 200 edges and enable by setting two flags
pflexpwm->SM[sub_module].CAPTCOMPX = FLEXPWM_SMCAPTCOMPX_EDGCMPX(200);
pflexpwm->SM[sub_module].CAPTCTRLX |= FLEXPWM_SMCAPTCTRLX_INP_SELX;
pflexpwm->SM[sub_module].CAPTCTRLX |= FLEXPWM_SMCAPTCTRLX_EDGCNTX_EN;
break;

case 1: // A Channel
pflexpwm->SM[sub_module].CAPTCTRLA = capture_mode | FLEXPWM_SMCAPTCTRLA_ARMA;
pflexpwm->SM[sub_module].INTEN |= (inten & (FLEXPWM_SMINTEN_CA0IE | FLEXPWM_SMINTEN_CA1IE)) | FLEXPWM_SMINTEN_RIE;
// set capture compare to 200 edges and enable by setting two flags
pflexpwm->SM[sub_module].CAPTCOMPA = FLEXPWM_SMCAPTCOMPA_EDGCMPA(200);
pflexpwm->SM[sub_module].CAPTCTRLA |= FLEXPWM_SMCAPTCTRLA_INP_SELA;
pflexpwm->SM[sub_module].CAPTCTRLA |= FLEXPWM_SMCAPTCTRLA_EDGCNTA_EN;
break;
case 2: // B Channel;
pflexpwm->SM[sub_module].CAPTCTRLB = capture_mode | FLEXPWM_SMCAPTCTRLA_ARMA;
pflexpwm->SM[sub_module].INTEN |= (inten & (FLEXPWM_SMINTEN_CB0IE | FLEXPWM_SMINTEN_CB1IE)) | FLEXPWM_SMINTEN_RIE;
// set capture compare to 200 edges and enable by setting two flags
pflexpwm->SM[sub_module].CAPTCOMPB = FLEXPWM_SMCAPTCOMPB_EDGCMPB(200);
pflexpwm->SM[sub_module].CAPTCTRLB |= FLEXPWM_SMCAPTCTRLB_INP_SELB;
pflexpwm->SM[sub_module].CAPTCTRLB |= FLEXPWM_SMCAPTCTRLB_EDGCNTB_EN;
break;
}
 
Last edited:
@chase1873, back to your original question, how to do something like FreqCount on multiple channels. I don't see any libraries with that capability, but you could do it via the T4.x Quad Timer modules. Each of the 4 Quad Timer modules has 4 channels.

I found an example sketch by @manitou (link below) that configures one QTMR channel to count an external signal. It sets up the QTMR on pin 9, feeds it with PWM from pin 8, and reads the running count at precise 1-second intervals to get frequency in Hz. You could read more frequently if you need more frequent updates. His sketch includes a comment saying it works up to 75 MHz. I was able to get 50 MHz.

@manitou's sketch uses Q42 (QTMR 4 channel 2) on pin 9. You'll have to follow his example to configure other pins. The T4 pins that can be configured as Quad Timer channels are:

6=Q41, 9=Q42, 10=Q10, 11=Q12, 12=Q11, 13=Q20, 14=Q32, 15=Q33, 18=Q31, 19=Q30

So, you can use this counting method or the modified FreqMeasureMulti to do input capture. The input capture can provide high-resolution measurements very often. The counting method takes longer to get a good measurement, but has the advantage of (almost) no interrupt load.

https://github.com/manitou48/teensy4/blob/master/qtmr_count.ino
 
Thank you very much for the help thus far.

I have made edits to the "FreqMeasureMultiIMXRT" file as noted and can still only read up to about 1.7MHz (see attached)

I am unsure how to change the PWM resolution (I am a rookie) and unsure how to verify this.

I tried to change PWM resolution by editing the "Serial.begin(300)" in the serial output example file. I also tried using "analogReadResolution(2)"

Thank you for your time.
 

Attachments

  • FreqMeasureMultiIMXRT.cpp
    21.1 KB · Views: 50
I have made edits to the "FreqMeasureMultiIMXRT" file as noted and can still only read up to about 1.7MHz (see attached).

In the begin() function, you are referencing the "X" registers in the cases for the "A" and "B" timers. Check again versus what is in my earlier post, and I think that will be enough to allow you to measure higher frequencies. Are you working with one of the FreqMeasureMulti example sketches?
 
In the begin() function, you are referencing the "X" registers in the cases for the "A" and "B" timers. Check again versus what is in my earlier post, and I think that will be enough to allow you to measure higher frequencies. Are you working with one of the FreqMeasureMulti example sketches?

Thank you very much. The FreqMeasureMulti via example sketches works in the MHz frequency range now. The working file is attached.
 

Attachments

  • FreqMeasureMultiIMXRT.cpp
    21.1 KB · Views: 60
Status
Not open for further replies.
Back
Top