How do I detect both rising and falling edge interrupt with input capture?

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

How do I detect both rising and falling edge interrupt with input capture?

Jump to solution
5,659 Views
exgreyfox
Contributor II

I am trying to measure the pulse width of an input signal at TPM1_CH0 but I am having no luck. I am configuring TPM1_C0SC register to interrupt on both rising and falling edges as such:

/* Input Capture mode rising and falling edge interrupt */

  TPM1_C0SC |= TPM_CnSC_ELSA_MASK;

  TPM1_C0SC |= TPM_CnSC_ELSB_MASK;

  TPM1_C0SC &= ~(TPM_CnSC_MSA_MASK);

  TPM1_C0SC &= ~(TPM_CnSC_MSB_MASK);

  TPM1_C0SC |= TPM_CnSC_CHIE_MASK;

And then inside main.c I execute the following code:

enable_irq (INT_TPM1-16);     /* Enable Timer1 interrupt in NVIC */

TPM1_SC |= TPM_SC_CMOD(0);    /* Enable the TPM1_CH0 Timer */

TPM1_CNT = 0;                 /* Reset TPM1 */

DelayMs_NoIRQ(19);            /* delay 19ms */             

TPM1_SC |= TPM_SC_CMOD        /* Disable the TPM1_CH0 Timer */

disable_irq (INT_TPM1-16);    /* Disable Timer1 interrupt in NVIC */

val = falling_val - rising_val; /* calculate pulse width of input signal */

And inside the ISR i attempt to detect the logic level of the input signal to and decide whether it is falling or rising edge:

void FTM1_IRQHandler(void)

{

  if(TPM1_C0SC & TPM_CnSC_CHF_MASK)

  { 

       TPM1_C0SC |= TPM_CnSC_CHF_MASK;

       if(GPIOA_PDIR & GPIO_PTA12_LOC)

       {

            rising_val = TPM1_C0V;

       }

       if(!(GPIOA_PDIR & GPIO_PTA12_LOC))

       {

            falling_val = TPM1_C0V;

       }

  }

  return;

}

But I am not having any luck as "val" returns wrong value. I am using KL25Z freedom board.

0 Kudos
1 Solution
2,856 Views
exgreyfox
Contributor II

I figured it out. The issue was with my initialization of TPM1 as capture input and ISR:

void TPM1_CH0_Timer_Capture_Init(void)

{

  SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK;  /* Enable clock to PORTA */

  PORTA_PCR12 &= ~(PORT_PCR_PS_MASK);

  PORTA_PCR12 |= PORT_PCR_PE_MASK;

  PORTA_PCR12 = PORT_PCR_MUX(3);  /* Set Port A for TPM1CH0 input */

  SIM_SCGC6 |= SIM_SCGC6_TPM1_MASK;  /* Enable clock to TPM1 */

  SIM_SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK;  /* Set for MCGPLLCLK with fixed divide by two */

  SIM_SOPT2 &= ~(SIM_SOPT2_TPMSRC_MASK);  /* Clear TPMSRC bit filed to 2'b00 */

  SIM_SOPT2 |= SIM_SOPT2_TPMSRC(1);  /* Set for MCGPLLCLK/2 */

  

  TPM1_SC = 0;  /* Blow away the control registers to ensure that the counter is not running */

  TPM1_CONF = 0;  /* Blow away the control registers to ensure that the counter is not running */

  TPM1_C0SC = 0;  /* Blow away the control registers to ensure that the counter is not running */

  TPM1_SC = TPM_SC_PS(TPM1_CLK_PRESCALE);  /* Setup prescaler to DIV by 64 */

  TPM1_MOD = 0xFFFF;  /* Set max modulo */

  /* Input Capture mode rising and falling edge interrupt */

  TPM1_C0SC |= TPM_CnSC_CHIE_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK;  /* Set all these bits */

  TPM1_C0SC &= ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK);    /* Clear these bits */

}

void FTM1_IRQHandler(void)

{

  if(TPM1_C0SC & TPM_CnSC_CHF_MASK) {   /* Check to see if channel capture interrupt flag is set */

       TPM1_C0SC |= TPM_CnSC_CHF_MASK;   /* If set then clear interrupt flag */

       if(GPIOA_PDIR & GPIO_PTA12_LOC) { /* Check logic level of PTA12 */

            TPM1_CNT = 0; /* If rising edge has hapened, reset the count to 0 */

       }

  if(!(GPIOA_PDIR & GPIO_PTA12_LOC)) { /*check level of PTA12 */

       BLUE_LED_ON;

       val = TPM1_C0V; /* if LOW store the current count */

       }

     }

  return;

}

View solution in original post

0 Kudos
6 Replies
2,857 Views
exgreyfox
Contributor II

I figured it out. The issue was with my initialization of TPM1 as capture input and ISR:

void TPM1_CH0_Timer_Capture_Init(void)

{

  SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK;  /* Enable clock to PORTA */

  PORTA_PCR12 &= ~(PORT_PCR_PS_MASK);

  PORTA_PCR12 |= PORT_PCR_PE_MASK;

  PORTA_PCR12 = PORT_PCR_MUX(3);  /* Set Port A for TPM1CH0 input */

  SIM_SCGC6 |= SIM_SCGC6_TPM1_MASK;  /* Enable clock to TPM1 */

  SIM_SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK;  /* Set for MCGPLLCLK with fixed divide by two */

  SIM_SOPT2 &= ~(SIM_SOPT2_TPMSRC_MASK);  /* Clear TPMSRC bit filed to 2'b00 */

  SIM_SOPT2 |= SIM_SOPT2_TPMSRC(1);  /* Set for MCGPLLCLK/2 */

  

  TPM1_SC = 0;  /* Blow away the control registers to ensure that the counter is not running */

  TPM1_CONF = 0;  /* Blow away the control registers to ensure that the counter is not running */

  TPM1_C0SC = 0;  /* Blow away the control registers to ensure that the counter is not running */

  TPM1_SC = TPM_SC_PS(TPM1_CLK_PRESCALE);  /* Setup prescaler to DIV by 64 */

  TPM1_MOD = 0xFFFF;  /* Set max modulo */

  /* Input Capture mode rising and falling edge interrupt */

  TPM1_C0SC |= TPM_CnSC_CHIE_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK;  /* Set all these bits */

  TPM1_C0SC &= ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK);    /* Clear these bits */

}

void FTM1_IRQHandler(void)

{

  if(TPM1_C0SC & TPM_CnSC_CHF_MASK) {   /* Check to see if channel capture interrupt flag is set */

       TPM1_C0SC |= TPM_CnSC_CHF_MASK;   /* If set then clear interrupt flag */

       if(GPIOA_PDIR & GPIO_PTA12_LOC) { /* Check logic level of PTA12 */

            TPM1_CNT = 0; /* If rising edge has hapened, reset the count to 0 */

       }

  if(!(GPIOA_PDIR & GPIO_PTA12_LOC)) { /*check level of PTA12 */

       BLUE_LED_ON;

       val = TPM1_C0V; /* if LOW store the current count */

       }

     }

  return;

}

0 Kudos
2,856 Views
ysoh-
Contributor I

Hi exgreyfox,

Could you further explain on your fix? I just encountered the same issue as yours. Thanks.

0 Kudos
2,856 Views
mjbcswitzerland
Specialist V

Hi

See also chapter 7 (from page 9) of http://www.utasker.com/docs/uTasker/uTaskerHWTimers.PDF
This shows a method for measuring PWM signals (on any Kinetis with a DMA channel) with very high accuracy and no interrupt overhead (50kHz PWM signals can be measured with < 0.01% accuracy with a processor with 60MHz bus clock).


It is not limited to pins that are connected to the TPM (or FlexTimer) and so has greater flexibility.

Regards

Mark

0 Kudos
2,856 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi exgreyfox,

      Another way to detect both rising and falling edge, just like the KL25 tpm sample code, use to channel.

17.jpg

  You can find this sample code from this link:

http://cache.freescale.com/files/32bit/software/KL25_SC.exe

path is : kl25_sc_rev10\klxx-sc-baremetal\build\iar\LQRUG_tpm_ex1

Wish it helps you!

If you still have question, please contact me!


Have a great day,
Jingjing

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
2,856 Views
exgreyfox
Contributor II

Thanks, but I don't see any source code in that directory.

0 Kudos
2,856 Views
kerryzhou
NXP TechSupport
NXP TechSupport

That directory is the project path, if you want to find the source code, please goto this directory:

kl25_sc_rev10\klxx-sc-baremetal\src\projects\LQRUG_tpm_ex1

If your TPM1 capture pin is enough, you can use two capture pin instead of just one caputure pin associate the GPIO state read.

Two capture pin, on is for rising edge capture, another is for falling edge capture is more accurate than on capture pin with GPIO state read.

0 Kudos