FRDM K64F low frequency pulse measurement

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

FRDM K64F low frequency pulse measurement

Jump to solution
1,924 Views
es483
Contributor II

Dear NXP community users,

I'm trying to build a project on the FRDM K64F board, in which the Micrium uC/OS-III real-time operating systems is actually running. I think that this problem, in any case, should not be too much OS dependant (correct me if I'm wrong!). I'm a student in an academic environment.
In particular I'm trying to do a low frequency pulse measurement using the Dual Capture Mode available with the Flex Timer FTM0 (so, in hardware).
The problem is the following: with the attached code, I'm able to do measurements (thanks to the FTM0 counting up to 16 bits - 65535) going as down as 5 Hz. For lower frequencies (in particular I should be able to measure at least the interval 1->5 Hz) I though I could use the same code, adding only a few lines that count how many times, while FTM0 is counting, the TOF bit is set, and so how many times I'm getting an overflow, since the interupt handler is actually called (I think) every time some events happens, indipendetly if this is due to TOF set or to dual capture mode measurement end.
Having this information, I could compute the real pulse duration (i.e. its frequency) by adding a term equal to [number of times the counter is reset=number of times TOF is set]*65536.
However, adding this kind of workaround the measurements are completely wrong, even for frequencies higher than 5 Hz (that were previuosly correctly measured).
Why is this happening? Is the board, in general, not able to handle correctly all the incoming interrupt requestes?
Since the prescaler is already set to its maximum (dividing by 128 the 60 MHz bus clock), what should I do? I have no possibility at the moment of using an external clock.

Thank you very much in advance.

The relevant pieces of code are attached to this message in a C file.

0 Kudos
1 Solution
1,207 Views
es483
Contributor II

Hi,

Sorry for the very late reply, but I was able to test the code again only today!

Thank you very much for your support! In the end, I probably found out what was going wrong.

I checked the NUMTOF bits inside the FTM0_CONF register, and they were correctly set.

However, thanks to a collegue of mine, I discovered that in this way I was computing the overflows for all the period of the signal, while in dual edge I was measuring only half period to get the signal frequency.

So, modifying the central part of the FTM0 interrupt handler in this way, I was able to get (finally) correct results:

// Do not check the TOF bit at the beginning

FTM0_SC &= 0x7F; // Then, after the TOF bit has been read, we clear them to be ready for the next handler call

if(FTM0_STATUS & 0x8) { 
      FTM0_STATUS &= 0x0;

   if(FTM0_C2V > FTM0_C3V)
      ftm0_pulse=0xFFFF+FTM0_C3V-FTM0_C2V+(ftm0_overflow_count-1)*65536;
   else
      ftm0_pulse=FTM0_C3V-FTM0_C2V+(ftm0_overflow_count)*65536;

   OSSemPost(&ftm0sem, OS_OPT_POST_1 | OS_OPT_POST_NO_SCHED, &err);
   ftm0_overflow_count=0; // FTM0 overflow count is set again to 0 for the next measurement.
} else if(FTM0_STATUS & 0x4) { // Count overflow only if nothing has happened on CH03, but something has happened on CH2 (half period is considered)
   FTM0_overflow_count++;
}

This solutions seems to work correctly even for very low frequencies.

Thanks again!

View solution in original post

0 Kudos
7 Replies
1,208 Views
es483
Contributor II

Hi,

Sorry for the very late reply, but I was able to test the code again only today!

Thank you very much for your support! In the end, I probably found out what was going wrong.

I checked the NUMTOF bits inside the FTM0_CONF register, and they were correctly set.

However, thanks to a collegue of mine, I discovered that in this way I was computing the overflows for all the period of the signal, while in dual edge I was measuring only half period to get the signal frequency.

So, modifying the central part of the FTM0 interrupt handler in this way, I was able to get (finally) correct results:

// Do not check the TOF bit at the beginning

FTM0_SC &= 0x7F; // Then, after the TOF bit has been read, we clear them to be ready for the next handler call

if(FTM0_STATUS & 0x8) { 
      FTM0_STATUS &= 0x0;

   if(FTM0_C2V > FTM0_C3V)
      ftm0_pulse=0xFFFF+FTM0_C3V-FTM0_C2V+(ftm0_overflow_count-1)*65536;
   else
      ftm0_pulse=FTM0_C3V-FTM0_C2V+(ftm0_overflow_count)*65536;

   OSSemPost(&ftm0sem, OS_OPT_POST_1 | OS_OPT_POST_NO_SCHED, &err);
   ftm0_overflow_count=0; // FTM0 overflow count is set again to 0 for the next measurement.
} else if(FTM0_STATUS & 0x4) { // Count overflow only if nothing has happened on CH03, but something has happened on CH2 (half period is considered)
   FTM0_overflow_count++;
}

This solutions seems to work correctly even for very low frequencies.

Thanks again!

0 Kudos
1,207 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

Can you check the NUMTOF bits in FTMx_CONF register?  it defines the the ratio between the number of counter overflows to the number of times the TOF bit is set.

BTW, if you remove the code specific to RTOS, what is the result?

BR

Xiangjun Rong

0 Kudos
1,207 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

If you toggle a GPIO pin once the TOF bit is set, you can connect the GPIO to scope and check if the GPIO toggleing frequency matches with your expection.

BR

XiangJun rong

void FlexTimer_handler(void) {
    OS_ERR err;
    CPU_ERR cpu_err;

 

    CPU_CRITICAL_ENTER();
    OSIntEnter();
    if(FTM0_SC & 0x80)
    {
    FTM0_overflow_count++;  // Incrementing the number of times the counter has been reset,
                                                                     // by reading the TOF bit in FTM0_SC (7th bit inside the register)
                                                                     // and dividing by 128 in order to either add 0 (if TOF is not set)
                                                                     // or add 1 (if TOF is set)

  Toggle_GPIO;

    FTM0_SC &= 0x7F; // Then, after the TOF bit has been read, we clear them to be ready for the next handler call
    }
    if(FTM0_STATUS & 0x8) { // If channel 3 of FTM0 actually captured a falling edge event and the interrupt was originated for that reason,
                            // we do the measurement
        FTM0_STATUS &= 0x0; // First, we clear the previous flag, then...
        // ...FTM0_C3V holds the timer value when falling edge has occurred
        // ...FTM0_C2V holds the timer value when the rising edge has occurred
        if(FTM0_C2V > FTM0_C3V)
                ftm0_pulse=0xFFFF+FTM0_C3V-FTM0_C2V+(ftm0_overflow_count)*65536;
        else
                ftm0_pulse=FTM0_C3V-FTM0_C2V+(ftm0_overflow_count)*65536;
        
        // Posting the task waiting for the measurement (the semaphore code is not reported here but has been tested and seems to work correctly
        OSSemPost(&ftm0sem, OS_OPT_POST_1 | OS_OPT_POST_NO_SCHED, &err);
        ftm0_overflow_count=0; // FTM0 overflow count is set again to 0 for the next measurement.
    }

 

    CPU_CRITICAL_EXIT();
    OSIntExit();
}

0 Kudos
1,207 Views
es483
Contributor II

Hi,

Thank you very much for your reply!
I tried your code today with different frequencies (10 Hz/5 Hz/2 Hz/1 Hz), but unluckily it is still giving the wrong result, it seems due to an incorrect computation of the number of times the counter is set to zero (and so the TOF bit is consequently set).

Doing some debug and adding a few serial Printfs, it seems that the overflow counter for 1 Hz goes up to 7 (it is too much for a 1 Hz waveform?), but not always (sometimes it seems to stop at 6)...

The attached one is for example the output I get for a 2 Hz waveform: I should have obtained a quite stable "2.[something]" (or, I suppose, 1.9[something]) instead of an unstable value of 0.19/0.20...

Is there a way to know how many times the FlexTime overflowed instead of reading each time the TOF and incrementing a global variable?

Is there some numerical problem in the code that leads to problematic results such as the ones I'm obtaining?

The strange thing is that even for higher frequencies, where the overflow counter should remain equal to 0 (or at least 1, that is taken into account in the if-else part of the FTM0 handler), I get an incorrect (but seems to be more stable) result, even when calling the FTM timer to do a conversion each 2 s.

Thanks a lot in advance!

Output for 2 Hz:

2_Hz.png

Output for 10 Hz:

10_Hz.png

Output for 10 Hz without considering the FT0_overflow_count:

10_Hz_NO_TOF.png

Update: doing a few other test, it seems that the overflow counter is getting everytime a value which is too high (or the board is missing the CH03 event, so, never resetting the FTM0_overflow_count variable): for 10 Hz it should be (I think) 0 or 1, but I'm actually getting 15 or 16!

10Hz_problem.png

0 Kudos
1,207 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

If you do not display the double ftm0_frequency variable, just display the raw uint32_t ftm0_pulse variable, is it okay?

BR

Xiangjun rong

0 Kudos
1,207 Views
es483
Contributor II

Hi!
Sorry for the late reply, but I wasn't able to test it until today.

I tried printing the raw variable, but it is not correct, if I compute it considering also the timer overflow count...
 Do you have some idea on what's going wrong? It seems that the FTM0_overflow_count variable is actually never computed correctly!

Thanks in advance.

0 Kudos
1,207 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,
I have downloaded and checked your code, I have not found out any issue.
How about using the code:
BR
XiangJun Rong
void FlexTimer_handler(void) {
    OS_ERR err;
    CPU_ERR cpu_err;

    CPU_CRITICAL_ENTER();
    OSIntEnter();
    if(FTM0_SC & 0x80)
    {
    FTM0_overflow_count++;  // Incrementing the number of times the counter has been reset,
                                                                     // by reading the TOF bit in FTM0_SC (7th bit inside the register)
                                                                     // and dividing by 128 in order to either add 0 (if TOF is not set)
                                                                     // or add 1 (if TOF is set)

    FTM0_SC &= 0x7F; // Then, after the TOF bit has been read, we clear them to be ready for the next handler call
    }
    if(FTM0_STATUS & 0x8) { // If channel 3 of FTM0 actually captured a falling edge event and the interrupt was originated for that reason,
                            // we do the measurement
        FTM0_STATUS &= 0x0; // First, we clear the previous flag, then...
        // ...FTM0_C3V holds the timer value when falling edge has occurred
        // ...FTM0_C2V holds the timer value when the rising edge has occurred
        if(FTM0_C2V > FTM0_C3V)
                ftm0_pulse=0xFFFF+FTM0_C3V-FTM0_C2V+(ftm0_overflow_count)*65536;
        else
                ftm0_pulse=FTM0_C3V-FTM0_C2V+(ftm0_overflow_count)*65536;
        
        // Posting the task waiting for the measurement (the semaphore code is not reported here but has been tested and seems to work correctly
        OSSemPost(&ftm0sem, OS_OPT_POST_1 | OS_OPT_POST_NO_SCHED, &err);
        ftm0_overflow_count=0; // FTM0 overflow count is set again to 0 for the next measurement.
    }

    CPU_CRITICAL_EXIT();
    OSIntExit();
}

0 Kudos