FRDM KE02 board constant capture interrupt

cancel
Showing results for 
Search instead for 
Did you mean: 

FRDM KE02 board constant capture interrupt

Jump to solution
706 Views
davetelling
Contributor I

I am trying to learn the Kinetis ARM system, and so far, it has been the most frustrating experience I have ever had with a microcontroller!

I cannot even get what should be a simple capture program to work.

I'm using the IAR 7.3 toolset, and my "main" project code is below:

/* simple capture program */

#include "common.h"

#include "ics.h"

#include "ftm.h"

#include "uart.h"

#include "sysinit.h"

static uint16_t counterVal;

void FTM2_Task(void);

int main(void)

{

  // Set FTM2 capture interrupt for rising edge, also enables IRQ

  FTM_InputCaptureInit(FTM2,FTM_CHANNEL_CHANNEL0,FTM_INPUTCAPTURE_RISINGEDGE);

  // Select system clock, with 16 divisor

  FTM_ClockSet(FTM2, FTM_CLOCK_SYSTEMCLOCK, FTM_CLOCK_PS_DIV16);

  // Set interrupt function reference

  FTM_SetCallback(FTM2, FTM2_Task);

  // Enable the channel mask for FTM2CH0

  FTM_EnableChannelInt(FTM2, (FTM_CHANNEL_CHANNEL0));   

  // GPIOA PTA0 and PTB3 are outputs

  GPIOA->PDDR = 0xffff0801;

  /* set PTB3 high to start */

  GPIOA->PDOR = 0x00000800;

  // Now just loop

  while (1)

  {

    ;

  }

}

void FTM2_Task(void)

  // Get capture value in variable

  counterVal = FTM2->CONTROLS[0].CnV;

  // Toggle PTB3

  GPIOA->PTOR = 0x0800; // toggle PTB3

}

Note that I SHOULD be going to FTM2_task at each rising edge of my input signal - I'm using the TTL output of a function generator, in the 600 Hz range. At each capture event, PTB3 should toggle.

If I put a breakpoint in the interrupt function, the system does what it should (kind of) i.e. PTB3 toggles each pass through. However - if I eliminate the breakpoint, and just run the program, the PTB3 output toggles at an interval of about 2.8 usec, no matter what the clock divider is set. It is as if the interrupt is constantly being called, and I cannot figure out why.

Any clues would be appreciated.

0 Kudos
1 Solution
232 Views
Jorge_Gonzalez
NXP Employee
NXP Employee

Hello Dave:

I hope not to confuse you more, but there are two things:

1- The "cause" of the interrupt, let's call it trigger:

Each peripheral in Kinetis devices has different triggers: low/high levels, rising/falling edges, a counter reaching a specific count, completing an ADC conversion, etc. These are only the events that cause a determined interrupt flag to become set.

2- The interrupt flags:

These flags are the actual interrupt driving mechanism, as you call it. Adrian was referring to these flags to be level sensitive. As long as you do not reset the flag in the interrupt function to its default state, then the interrupt will be entered again, even if the event or trigger that caused it is no longer present.

I hope this clarifies!

Jorge_Gonzalez

View solution in original post

0 Kudos
11 Replies
232 Views
davetelling
Contributor I

OK, I finally got the functionality for which I was trying. Here is the code:

/* simple capture program */

#include "common.h"

#include "ics.h"

#include "ftm.h"

#include "sysinit.h"

static uint16_t counterVal;

void FTM2_Task(void);

void FTM0_Task(void);

int main(void)

{

  sysinit();

    /* FTM2 output compare mode, channel 1 clears when match */

    FTM_OutputCompareInit(FTM2, FTM_CHANNEL_CHANNEL1, FTM_OUTPUT_CLEAR);

    /* set C1V value, 800 usec with divide by 16 clock */

    FTM_SetChannelValue(FTM2, FTM_CHANNEL_CHANNEL1, 1000);   

    /* Set up FTM2 CH0 as rising edge capture input */

    FTM_InputCaptureInit(FTM2,FTM_CHANNEL_CHANNEL0,FTM_INPUTCAPTURE_RISINGEDGE);

    /* set clock source and start the counter */

    FTM_ClockSet(FTM2, FTM_CLOCK_SYSTEMCLOCK, FTM_CLOCK_PS_DIV16);

    /* set MOD value */

    FTM_SetModValue(FTM2,0);

    /* set callback function for ISR */

    FTM_SetCallback(FTM2, FTM2_Task);

    /* clear any pending channel 0 interrupt flags */

    FTM_ClrChannelFlag(FTM2, FTM_CHANNEL_CHANNEL0);

    /* Emnable CH0 interrupt */

    FTM_EnableChannelInt(FTM2, FTM_CHANNEL_CHANNEL0);

    /* Clear any pending CH1 inteerupt */

    FTM_ClrChannelFlag(FTM2, FTM_CHANNEL_CHANNEL1);

    /* Allow FTM2 interrupts now */

    NVIC_EnableIRQ(FTM2_IRQn);

  while (1)

  {

    /* dummy read */

    counterVal = FTM2->CNT;

  }

}

void FTM2_Task(void)

  static uint8_t channel;

  channel = FTM_GetChannelFlag(FTM2, 0);

  if (channel == 128)

  {

    /* Reset FTM2 counter */

    FTM2->CNT = 0;

    /* Force CH1 output high */

    FTM_SWOutputControlSet(FTM2,FTM_CHANNEL_CHANNEL1,FTM_SWOCTRL_HIGH);

    /* clear any pending CH1 interrupt flag */

    FTM_ClrChannelFlag(FTM2, FTM_CHANNEL_CHANNEL1);

    /* Enabvle the CH1 interrupt */

    FTM_EnableChannelInt(FTM2, FTM_CHANNEL_CHANNEL1);

    /* Claer CH0 capture interrupt flag */

    FTM_ClrChannelFlag(FTM2, FTM_CHANNEL_CHANNEL0);

   

  }

  else // interrupt is CH1 compare

  {

    /* Force CH1 output low. WHY DO I NEED TO DO THIS??? */

    FTM_SWOutputControlSet(FTM2,FTM_CHANNEL_CHANNEL1,FTM_SWOCTRL_LOW);

    /* Clear both interrupt flags */

    FTM_ClrChannelFlag(FTM2, FTM_CHANNEL_CHANNEL1);

    FTM_ClrChannelFlag(FTM2, FTM_CHANNEL_CHANNEL0);

    /* Disable further CH1 interrupts */

    FTM_DisableChannelInt(FTM2, FTM_CHANNEL_CHANNEL1);   

  } 

}

The big question now is, "Why do I need to use the force the CH1 output low at the compare interrupt, if the channel is already configured to clear the output bit at compare? I SHOULD just need to force it (CH1 output on PTC1) high at the capture interrupt, then the compare interrupt should bring it low, but that is not happening. I have to explicitly force the output low. What am I missing?:

0 Kudos
232 Views
davetelling
Contributor I

OK, it seems that using the software "force" instructions, the output state doesn't stay in the state you told it to once you disable the software force, so you can't use the timer to change the state. So, how can you set the FTM so that, for example, when a capture occurs on channel 0, you can then set the channel 1 output high, and use the channel 1 output compare to set the bit low? If you have to keep the software force output enabled, how can the compare operation clear that output, or is that even possible? Is there another way to set an output channel bit when a capture happens, so that the compare timer can reset it?

0 Kudos
232 Views
davetelling
Contributor I

UPDATE: I did get the firmware to do what I wanted - you have to set the correct bit in the "INIT" register for the FTM, then you write a "1" to the INIT field of the MODE register. This initializes the channel output. The problem is that it initializes ALL of the FTMx channel outputs (if you are using more than one) so you have to be careful to keep track of the state of the other channels. Perhaps using the software force option is less messy overall.

0 Kudos
232 Views
adriancano
NXP Employee
NXP Employee

Hi,

I notice something in your code that I want to emphasize.

In the line:

  // GPIOA PTA0 and PTB3 are outputs

  GPIOA->PDDR = 0xffff0801;

You are configuring the pins showed in the picture below as outputs:

KE02.jpg

According to the reference manual the  Channel 0 of the FTM2 you are configured by default is the PTC0, which is already configured as output. You can select between PTC0 or PTH0 to be the FTM2_CH0 input in the SIM_PINSEL[FTM2PS0]. I think that is probably causing that strange behavior.

ftm2pinsel.jpg

To configure just PTA0 and PTB3 as outputs you can write:

  GPIOA->PDDR |= (1<<0)|(1<<11);


Hope this information can help you.

Best Regards,
Adrian Sanchez Cano
Technical Support Engineer
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
232 Views
davetelling
Contributor I

Adrian,

The PTC0 should be an input by default, if I understand the reference manual, and I don't change that, I leave it at 0. PTB3 is being used as an output for my test program, and it does, in fact, generate an output.

What I finally found that worked is that I have to clear the flag bit in the CnSC register when the capture interrupt occurs, otherwise, it apparently continually tells the system that CH0 is constantly interrupting.

0 Kudos
232 Views
adriancano
NXP Employee
NXP Employee

Hi,

Yes, that is true since all the interrupts in Kinetis devices are level-sensitive interrupts.

A level-sensitive interrupt is held asserted until the peripheral deasserts the interrupt signal. Tipically this happens because the ISR (Interrupt Service Routine) accesses the peripheral, causing it to clear the interrupt request. If the signal is not deasserted before the processor returns from the ISR, the interrupt becomes pending again, and the processor must execute its ISR again. This means that the peripheral can hold the interrupt signal asserted until it no longer requires servicing.


Hope this information can help you.

Best Regards,
Adrian Sanchez Cano
Technical Support Engineer
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

232 Views
davetelling
Contributor I

Adrian,

I suppose I was fooled by the way the manual refers to interrupt bit configuration as "rising" or "falling", implying an edge-triggered configuration. It might be better if the documentation said "high" or "low" level as the interrupt driving mechanism? I have spent hours trying to figure out why I was getting continuous interrupts.

0 Kudos
233 Views
Jorge_Gonzalez
NXP Employee
NXP Employee

Hello Dave:

I hope not to confuse you more, but there are two things:

1- The "cause" of the interrupt, let's call it trigger:

Each peripheral in Kinetis devices has different triggers: low/high levels, rising/falling edges, a counter reaching a specific count, completing an ADC conversion, etc. These are only the events that cause a determined interrupt flag to become set.

2- The interrupt flags:

These flags are the actual interrupt driving mechanism, as you call it. Adrian was referring to these flags to be level sensitive. As long as you do not reset the flag in the interrupt function to its default state, then the interrupt will be entered again, even if the event or trigger that caused it is no longer present.

I hope this clarifies!

Jorge_Gonzalez

View solution in original post

0 Kudos
232 Views
davetelling
Contributor I

Jorge,

I understand now what is going on. Because the system uses a single interrupt vector for a variety of interrupts, the ISR does not automatically clear the interrupt flag as I'm used to seeing with my Atmel AVR devices, so I have to poll the interrupt flags and reset those relevant to the particular interrupt I'm using. I realize that this can be deduced from the documentation, but I, unfortunately, made an incorrect assumption about the flag bits.
At this point, I have more of my desired functionality. What would really help is if there was additional documentation that explained the various function and macros that the IAR toolset uses. Having to dig through multiple files, sometimes not even knowing which header or .c file that has the necessary information is very time-consuming and frustrating. Even when you find the function, there is very little that explains things in a manner that makes sense to a new user.

0 Kudos
232 Views
robotjosh
Contributor IV

You might save time by using kinetis design studio with processor expert to get your peripherals operational.  Then you can run the debugger and see each thing working as you try to implement the same things in IAR.  I also used AVRs for over 10 years and love their simple hardware modules.  It is different for kinetis the hardware modules are much more complex, I have spent days trying to get certain things to work.  Sometimes it takes a lot of trial and error so don't feel bad if it takes an entire day to see something like eDMA work correctly.  The biggest time saving thing I can recommend to someone coming from simple 8bit stuff like AVR is to use processor expert to observe working configurations.

232 Views
davetelling
Contributor I

Josh,

Thanks for the tip. I downloaded the KDS & will see how it works. It is encouraging to know that I'm not the only one scratching my head, trying to figure out this device!

0 Kudos