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:
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:
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:
Because PTA4 is configured by default for NMI interrupt, I have properly disabled NMI in the 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:
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:
- Use the Init_GPIO component to enable interrupts on PORTA with custom handler.
- Route the interrupts from the custom handler to the CPU component handler.
Happy Interrupting 🙂
How can I do for “Event Cbtr16”
LikeLike
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
LikeLike
Pingback: Disabling NMI (Non Maskable Interrupt) Pin | MCU on Eclipse