User Interrupt on NMI Pin with Kinetis and ExtInt Component

While my beef brisket (see “My First DIY Smoked Beef Brisket: Day 1“) is smoking on ;-), I have time to investigate a problem I was running on in my lecture on Friday: For the Joystick shield (see “JoyStick Shield with the FRDM Board“) on the FRDM-KL25Z board, I wanted to use an interrupt if I press the green button:

No Interrupts for Button C

No Interrupts for Button C

However, that did not work :-(.

First, I was thinking that the board might have a problem, as I had cases where such boards had bad soldering points. A verification with the logic analyzer showed that the hardware wiring is working:

Button C Pin Change

Button C Pin Change

But no interrupt for button C :-(. And it worked for all other pins which have interrupt ability. So what could be wrong?

First, I need to mention that this pin is on PTA4 on the Freescale FRDM-KL25Z board. PTA4 is used by default as NMI (Non Maskable Interrupt pin). I have configured it in Processor Expert with the ExtInt (External Interrupt) component:

ExtInt on PTA4

ExtInt on PTA4

Because PTA4 is configured by default for NMI interrupt, I have properly disabled NMI in the CPU component:

NMI Function Disabled in CPU component

NMI Function Disabled in CPU component

I have ExtInt components for several port A pin (PTA12, PTA4, PTA5 and PTA13), and they are all properly hooked into the Cpu_ivINT_PORTA interrupt service routine and interrupt vector:

PE_ISR(Cpu_ivINT_PORTA)
{
  ExtIntLdd2_Interrupt();              /* Call the service routine */
  ExtIntLdd3_Interrupt();              /* Call the service routine */
  ExtIntLdd4_Interrupt();              /* Call the service routine */
  ExtIntLdd5_Interrupt();              /* Call the service routine */
}

So I believe I might have uncovered a Processor Expert bug? Somehow my PTA4 ExtInt component gets in conflict with the NMI internal interrupt vector settings. As a result, my PTA4 user interrupt is not firing :-(.

I have found at least a way how to get it working. For this, I add the Init_GPIO component to my project and configure it to raise an interrupt for PTA4:

Init_GPIO Settings to enable interrupt on PTA4

Init_GPIO Settings to enable interrupt on PTA4

Now as there is my PORTA_OnInterrupt() used for the interrupt vector, I need to route it to the handler in Cpu.c:

void PORTA_OnInterrupt(void) {
  void Cpu_ivINT_PORTA(void); /* prototype of ISR in Cpu.c */

  Cpu_ivINT_PORTA(); /* call interrupt handler created by the ExtInt components */
}

Cpu_ivINT_PORTA() generated by Processor Expert in Cpu.c:

PE_ISR(Cpu_ivINT_PORTA)
{
  ExtIntLdd2_Interrupt();              /* Call the service routine */
  ExtIntLdd3_Interrupt();              /* Call the service routine */
  ExtIntLdd4_Interrupt();              /* Call the service routine */
  ExtIntLdd5_Interrupt();              /* Call the service routine */
}

This is calling the NMI interrupt like this

void ExtIntLdd3_Interrupt(void)
{
  /* {Default RTOS Adapter} ISR parameter is passed through the global variable */
  ExtIntLdd3_TDeviceDataPtr DeviceDataPrv = INT_PORTA__DEFAULT_RTOS_ISRPARAM;

  /* Check if the component is disabled */
  if (!DeviceDataPrv->UserEnabled) {
    return;
  }
  /* Call OnInterrupt event */
  ExtIntLdd3_OnInterrupt(DeviceDataPrv->UserData);
}

Note that this code does *not* acknowledge the ISR flag. It calls then the following handler:

void ExtIntLdd3_OnInterrupt(LDD_TUserData *UserDataPtr)
{
  (void)UserDataPtr;                   /* Parameter is not used, suppress unused argument warning */
  SW3_OnInterrupt();                   /* Invoke OnInterrupt event */
}

With this, I need to handle the acknowledge of the interrupt flag in my SW3_OnInterrupt():

void SW3_OnInterrupt(void)
{
#if PL_HAS_KBI
#if 1 /* Problem with Processor Expert and sharing PTA4/NMI interrupt: code below is missing in ExtIntLdd3_OnInterrupt() */
  /* Check the pin interrupt flag of the shared interrupt */
  if (PORT_PDD_GetPinInterruptFlag(PORTA_BASE_PTR, ExtIntLdd3_PIN_INDEX)) {
    /* Clear the interrupt flag */
    PORT_PDD_ClearPinInterruptFlag(PORTA_BASE_PTR, ExtIntLdd3_PIN_INDEX);
    /* call user event */
    KEY_OnInterrupt(KEY_BTN3);
  }
#else
  if (KEY3_Get()) {
    KEY_OnInterrupt(KEY_BTN3);
  }
#endif
#endif
}

With this, it works 🙂

Summary

It is possible to disable and predefined interrupts like NMI for the Kinetis. However, that might conflict with the default settings of the CPU (or is a bug in Processor Expert). In any case, I have found a solution to get it working:

  1. Use the Init_GPIO component to enable interrupts on PORTA with custom handler.
  2. Route the interrupts from the custom handler to the CPU component handler.

Happy Interrupting 🙂

Advertisements

2 thoughts on “User Interrupt on NMI Pin with Kinetis and ExtInt Component

    • Hello,
      not sure what you mean (or what you want)? The EventCntr16 component only counts the events (or better: the edges of a signal). If you want to count the edges manually, you can add a normal interrupt and then count the interrupts. Or better use an input capture and let the hardware count.
      Erich

      Like

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.