How can I measure frequency (0 - 100KHz) of a signal using a K10 microcontroller?

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

How can I measure frequency (0 - 100KHz) of a signal using a K10 microcontroller?

5,795 Views
bobnayar
Contributor II

I am planning to use a MK10DX64VLH7 microcontroller on one of our new boards.

Can someone please advise me on how I can use its capabilities to measure the frequency of a digital signal that could range from 0 Hz to 100 KHz?

Thanks.

Bob N

9 Replies

1,963 Views
Edrianocarlos
Contributor IV

Hi.

there are some things you have to look at before deciding what methodologies you want to use.

does your frequency have jitter? if yes measuring it cycle by cycle would give you some error. and the best way would be measure a certain quantities of pulses in a known time.

in this case you could set  an input capture time and  measure how many pulses have you gotten in a given time.

if you have no jitter than you can measure a period of time. but you have to take in account that the precision will change. with low frequencies you will get better precision. with high frequencies worse precision. because there are less pulses to calculate the period and the counting error is always +- 1 pulse

0 Kudos

1,963 Views
bobnayar
Contributor II

Thanks, Adriano.

Let's say that the signal does have jitter and I want to measure it uisng an input capture time and measure the number of pulses.

How would I configure this on a MK10DX64VLH7 (K10) microcontroller?

Please advise.

Thanks.

BN

0 Kudos

1,963 Views
Edrianocarlos
Contributor IV

In my case each input interrupt i add 1 to a variable and wait for the next. than when the amount of time reach what i want. i make the calculation using the amont of time and the number of pulses.

0 Kudos

1,963 Views
bobnayar
Contributor II

Edriano,

I may have an issue with that, because I was going to use one input on the K10 to measure 16 different frequencies that could be switched through a selector switch (demux similar).

I was planning to allocate a certain period of time to measure one frequency and then switch to the next one and so on.

Your methodology is good, but may not work for my design :-(

BN

0 Kudos

1,963 Views
BlackNight
NXP Employee
NXP Employee

Here is how I did it:

This is where I measure it:

/* We are using input capture with timer channel to measure the frequency.

* To build an average, we measure CHA_TICK_NOF_SAMPLES falling edges,

* and then divide the time by CHA_TICK_NOF_SAMPLES

*/

static uint32_t CHA_freqCharger; /* charger frequency in kHz */

#define CHA_TICK_NOF_SAMPLES             16 /* number of edges to count */

static U_Freq_TU1_TValueType CHA_Ticks[2]; /* array with the time for the first edge and the last one */

static int CHA_TicksIdx = 0;               /* index into CHA_Ticks[] */

static volatile bool CHA_Ticks_Done = FALSE, CHA_Ticks_Overflow = FALSE;

void CHA_OnCounterRestart(void) {

  CHA_Ticks_Overflow = TRUE;

  U_Freq_TU1_Disable(U_Freq_TU1_DeviceData); /* disable timer */

}

void CHA_OnChannel0(void) {

  if (CHA_TicksIdx==0) {

    (void)U_Freq_TU1_GetCaptureValue(U_Freq_TU1_DeviceData, 0, &CHA_Ticks[0]);

  } else if (CHA_TicksIdx==CHA_TICK_NOF_SAMPLES) {

    (void)U_Freq_TU1_GetCaptureValue(U_Freq_TU1_DeviceData, 0, &CHA_Ticks[1]);

    U_Freq_TU1_Disable(U_Freq_TU1_DeviceData); /* disable timer */

    CHA_Ticks_Done = TRUE;

  }

  CHA_TicksIdx++;

}

void CHA_MeasureFrequency(void) {

  int32_t cntrUs;

  #define WAIT_TIME_US 100

 

  CHA_Ticks_Done = CHA_Ticks_Overflow = FALSE; /* init flags */

  CHA_TicksIdx = 0;

  cntrUs = 200; /* wait for max 200 us */

  (void)U_Freq_TU1_ResetCounter(U_Freq_TU1_DeviceData);

  U_Freq_TU1_Enable(U_Freq_TU1_DeviceData);

  while(!CHA_Ticks_Done && !CHA_Ticks_Overflow && cntrUs>=0) {

    /* wait for the number of edges or timer overflow */

    WAIT1_Waitus(WAIT_TIME_US); /* busy-wait, as in tickless idle mode we will not get interrupts */

    cntrUs -= WAIT_TIME_US;

  }

  if (!CHA_Ticks_Overflow) { /* overflow ISR already disabled the device */

    U_Freq_TU1_Disable(U_Freq_TU1_DeviceData); /* disable device */

  }

  if (CHA_Ticks_Done) {

    CHA_freqCharger = (U_Freq_TU1_CNT_INP_FREQ_U_0/1000)/((CHA_Ticks[1]-CHA_Ticks[0])/CHA_TICK_NOF_SAMPLES); /* in kHz */

  } else { /* Time out. Period of measured signal is too long */

    CHA_freqCharger = 0; /* no value measured */

  }

}

I'm counting the numer of falling edges, for a given period, and then calculate the frequency based on the number of samples/period.

The events get called from Events.c:

/*

** ===================================================================

**     Event       :  U_Freq_TU1_OnCounterRestart (module Events)

**

**     Component   :  U_Freq_TU1 [TimerUnit_LDD]

*/

/*!

**     @brief

**         Called if counter overflow/underflow or counter is

**         reinitialized by modulo or compare register matching.

**         OnCounterRestart event and Timer unit must be enabled. See

**         [SetEventMask] and [GetEventMask] methods. This event is

**         available only if a [Interrupt] is enabled.

**     @param

**         UserDataPtr     - Pointer to the user or

**                           RTOS specific data. The pointer passed as

**                           the parameter of Init method.

*/

/* ===================================================================*/

void U_Freq_TU1_OnCounterRestart(LDD_TUserData *UserDataPtr)

{

  CHA_OnCounterRestart();

}

/*

** ===================================================================

**     Event       :  U_Freq_TU1_OnChannel0 (module Events)

**

**     Component   :  U_Freq_TU1 [TimerUnit_LDD]

*/

/*!

**     @brief

**         Called if compare register match the counter registers or

**         capture register has a new content. OnChannel0 event and

**         Timer unit must be enabled. See [SetEventMask] and

**         [GetEventMask] methods. This event is available only if a

**         [Interrupt] is enabled.

**     @param

**         UserDataPtr     - Pointer to the user or

**                           RTOS specific data. The pointer passed as

**                           the parameter of Init method.

*/

/* ===================================================================*/

void U_Freq_TU1_OnChannel0(LDD_TUserData *UserDataPtr)

{

  CHA_OnChannel0();

}

}

I'm using the TimerUnit_LDD as input capture:

pastedImage_2.png

The input capture is configured like this:

pastedImage_3.png

I hope this helps.

Erich

1,963 Views
bobnayar
Contributor II

Erich,

Sorry about the late reply.

Can I please see the schematic of the board for which you wrote this code?

I want to see which pin you are using for input capture.

Thanks.

Bob N

0 Kudos

1,963 Views
BlackNight
NXP Employee
NXP Employee

Hi Bob,

see the last screenshot in my answer: it is pin PTC1.

Erich

0 Kudos

1,963 Views
BlackNight
NXP Employee
NXP Employee

Here is how I do something like this (on a K15):

- configure the input pin for input capture to count the signal (e.g. raising edge). Adjust the overflow interrupt to a suitable range for your application.

- use another timer for measurement, with possible high frequency to measure your high frequency signal properly, with a proper timeout based on your measurement duration

- in your measurement function, enable the input capture and measurement timer

- then two things could happen: either the input capture overflows (high frequency signal), or the measurement timer overflows (end of measurement duration)

- the number of input captures and your measurement duration allows you to calculate the frequency

Your timer and input capture values will depend how accurate you need to measure the signal, e.g. if you need to detect 0 Hz and 1 Hz (or 0 Hz and 5 Hz) will affect your measurement duration. You could as well have a dynamic measurement: you probe first for a fast signal, and if the timer overflows, you probe for a slower signal with adjusted timer settings.

I hope this helps,

Erich

0 Kudos

1,963 Views
bobnayar
Contributor II

Thanks, Erich.

Don't worry about the low frequencies for now.

Instead of 0 Hz to 100 KHz, let's say the range is 500 Hz to 100 KHz.

Am I supposed to use an FTM (FlexTimer Module) channel to capture this input?

When you said "configure the input pin for input capture" and "enable...measurement timer", is this what you meant?

Please advise.

Thanks.

Bob N

0 Kudos