I am looking to setup an interrupt on a pin. I am pretty new to Freecale and was therefore wondering where I could get information on how to set the pin accordingly as well as how to handle the interrupt once it occurs.
Any help would be much appreciated.
Kas
Solved! Go to Solution.
Hi Kas
Below is a reference of how the IRQ is used in the uTasker project (the KEA-64 has this as port interrupt possibility but limited to a single pin - PTA5 - see further details at the end).
Here is the user interrupt callback (could do anything so it is just an example)
static void irq_handler(void)
{
fnInterruptMessage(OWN_TASK, IRQ_FIRED);
}
This is the user interface code to set up an IRQ interrupt (on KE and KEA parts)
INTERRUPT_SETUP interrupt_setup; // interrupt configuration parameters
interrupt_setup.int_type = PORT_INTERRUPT; // identifier to configure port interrupt
interrupt_setup.int_handler = irq_handler; // handling function
interrupt_setup.int_priority = PRIORITY_PORT_IRQ_INT; // interrupt priority level
interrupt_setup.int_port = KE_PORTI; // the port that the interrupt input is on
interrupt_setup.int_port_bits = KE_PORTI_BIT6; // the IRQ input connected
interrupt_setup.int_port_sense = (IRQ_FALLING_EDGE | PULLUP_ON); // interrupt is to be falling edge sensitive
fnConfigureInterrupt((void *)&interrupt_setup); // configure interrupt
fnConfigureInterrupt() does the following in the case of these settings:
static void (*IRQ_handler)(void) = 0; // handler for IRQ
unsigned char ucPortPin = SIM_PINSEL_IRQPS_PTI6;
POWER_UP(0, SIM_SCGC_IRQ); // enable clocks to the external interrupt module
SIM_PINSEL0 = ((SIM_PINSEL0 & ~(SIM_PINSEL_IRQPS_PTI6)) | ucPortPin); // select the IRQ pin to use
IRQ_SC = IRQ_SC_IRQPE; // enable IRQ pin function with pull-up
IRQ_handler = port_interrupt->int_handler; // enter the application handler
fnEnterInterrupt(irq_IRQ_ID, port_interrupt->int_priority, _IRQ_isr); // ensure that the handler is entered
IRQ_SC |= (IRQ_SC_IRQIE | IRQ_SC_IRQACK); // enable interrupt and reset pending interrupt
fnEnterInterrupt() enters the IRQ vector into the vector table (in SRAM in this case but can also be fixed in Flash).
To enable the interrupt source in the NVIC it does (in the case of the IRQ):
IRQ4_7_PRIORITY_REGISTER |= 0xc0000000;
IRQ0_32_SER = 0x00000080;
Of course the main Cortex interrupt must also be enabled.
When the IRQ triggers the IRQ handler is called, which resets the IRQ interrupt flag and calls the user's handler
static __interrupt void _IRQ_isr(void)
{
IRQ_SC |= (IRQ_SC_IRQACK); // reset the interrupt flag
if (IRQ_handler != 0) {
IRQ_handler(); // call the interrupt handler
}
}
The KEA-64 (as some smaller KE parts) has however only one IRQ input which can only be on PTA5. PTA5 defaults to RESET_b input and to use it the following differences are valid:
- the reset function must be disabled in SIM_SOPT0 [SIM_SOPT0 &= ~(SIM_SOPT_RSTPE);] - this is however a write-once field so it has to be used carefully. It is best to do it immediately after reset (where all such bits are defined together) so that it is guarantied to work.
- The SIM_PINSEL0 operations are redundant since the other sources don't exist
Regards
Mark
Yong
Are you sure that you haven't made a mistake with the part in question?
The K64 supports port interrupts but the KE (and KEA) don't. These have keyboaad or external IRQ support instead.
This means that there are no registers in the KE (or KEA) matching the ones in the K64 pin interrupt example.
The KEA doesn't need to enable clocks to the ports and the interrupt vectors also don't match, as is the interrupt flag clearing incompatible.
Regards
Mark
I did not noticed the difference between port interrupt on K64 and KE&KEA.
Thank you so much for your reminder, I will check it!
Hi Kas
I have had the opportunity to work with the KBI as in your device. The first thing to note is that there is a single interrupt for the 8 possible keyboard input interrupts of each of the two KBIs and there is no way to reliably know which one of them interrupted. This means that if any one triggers you know that one of them matched the interrupt requirement and you can read the port inputs (GPIOx_PDIR) to decide what to actually do.
The API looks like this (very similar to the IRQ) but referencing to the pins is performed by their port references and not their KBI references (this makes it more flexible).
It alows multiple pins to be configured for KBI use by referencing their port pins and so automatically allows configuring pins across multiple KBI controllers. The example shows 2 pins, whereby one belongs to KBI0 and KBI1, and both have the same user interrupt handler (although they would fire via differnet interrupt vectors),
INTERRUPT_SETUP interrupt_setup; // interrupt configuration parameters
interrupt_setup.int_type = PORT_INTERRUPT; // identifier to configure port interrupt
interrupt_setup.int_handler = test_kbi; // handling function
// Keyboard
//
interrupt_setup.int_type = KEYBOARD_INTERRUPT; // define keyboard interrupt rather than IRQ
interrupt_setup.int_priority = PRIORITY_KEYBOARD_INT; // interrupt priority level
interrupt_setup.int_port = KE_PORTD; // the port that the interrupt input is on (KE_PORTA, KE_PORTB, KE_PORTC and KE_PORTD are the same)
interrupt_setup.int_port_bits = (KE_PORTD_BIT5 | KE_PORTB_BIT3); // the IRQs input connected
interrupt_setup.int_port_sense = (IRQ_FALLING_EDGE | PULLUP_ON); // interrupt is to be falling edge sensitive
fnConfigureInterrupt((void *)&interrupt_setup); // configure interrupt
There is some assigning between pins and KBI inputs but basically it does (eg. of the input configured on KBI0_P7, which is PTB3):
POWER_UP(0, SIM_SCGC_KBI0); // ensure the module is powered
KBI_handlers[0] = port_interrupt->int_handler; // enter the user handler for the keyboard interrupt controller
fnEnterInterrupt(irq_KBI0_ID, port_interrupt->int_priority, _KBI0_isr);
PORT_PUEL |= port_interrupt->int_port_bits; // enabled pull-ups on the specified KBI inputs
KBI0_SC &= ~KBI_SC_KBIE; // mask main KBI interrupt
KBI0_SC &= ~KBI_SC_KBMOD; // detect only edges
KBI0_ES &= ~0x80; // select falling edge interrupt (this is the bit that was mapped between port and KBI pin)
KBI0_SC |= KBI_SC_KBACK; // clear any false interrupts
KBI0_PE |= 0x80; // enable the pin as KBI interrupt
KBI0_SC |= KBI_SC_KBIE; // enable main KBI interrupt
The interrupt (KBI0) does:
KBI0_SC |= KBI_SC_KBACK; // clear pending interrupt
if (KBI_handlers[0] != 0) {
KBI_handlers[0](); // call user handler
}
As you see it is indeed very similar to the IRQ.
Larger devices with more KBI interrupts have a different register set and 32 inputs per KBI controller. The set includes a register informing which of the inputs caused the interrupt and so allows more flexibility to assigning user call-backs to each individual pin interruts if required.
Regards
Mark
Hello Mark,
Thank you for your endless patience and help. I was reading your previous comment and was wondering, could a keyboard interrupt be used in the same way as a pin interrupt. I'll explain what I'm trying to do and then you could let me know if this may be a valid path to pursue. I am looking to sleep the KEA-64 until a temperature threshold is reached, at this point an interrupt from the sensor should fire and wake the KEA-64 to take action. While one interrupt should work two would be helpful as there is a second interrupt for a critical threshold that may be useful.
Thanks
Kas
Kas
There are more Keyboard interrupts (only one IRQ) and these can wake from sleep modes so this will certainly be more suitable as soon as you need >1 such interrupt.
Unfortunately I can't working KBI code at the moment since I have used it only on the KE04 and KE06, which is a little different to the KE02 (closest to the KEA-64); it is however very similar to the IRQ but with additioanl status flags to indicate which one (or more) if the inputs causes the interrupt.
Regards
Mark
Hello Mark,
I have been looking around but I can not seem to find what the difference is between a KBI and a IRQ. They appear to behave very similarly if not the same, any clarification here would be much appreciated.
Kas
Kas
Yes, they are very similar. However when the IRQ triggers you know that the single IRQ pin state has changed to cause the interrupt. In the case of the KBI your know that one of the possible ones triggered the interrupt and then you need to work out which one it was by reading the staus register and resetting it.
Since further changes can take place when doing the handling it can be a little tricky to ensure than no changes are ever missed.
If you just need to wake up then it makes it a lot simpler because you can enable multiple KBI inputs/interrupts and you will be woken when any one of them fires.
Regards
Mark
Hi Kas
Below is a reference of how the IRQ is used in the uTasker project (the KEA-64 has this as port interrupt possibility but limited to a single pin - PTA5 - see further details at the end).
Here is the user interrupt callback (could do anything so it is just an example)
static void irq_handler(void)
{
fnInterruptMessage(OWN_TASK, IRQ_FIRED);
}
This is the user interface code to set up an IRQ interrupt (on KE and KEA parts)
INTERRUPT_SETUP interrupt_setup; // interrupt configuration parameters
interrupt_setup.int_type = PORT_INTERRUPT; // identifier to configure port interrupt
interrupt_setup.int_handler = irq_handler; // handling function
interrupt_setup.int_priority = PRIORITY_PORT_IRQ_INT; // interrupt priority level
interrupt_setup.int_port = KE_PORTI; // the port that the interrupt input is on
interrupt_setup.int_port_bits = KE_PORTI_BIT6; // the IRQ input connected
interrupt_setup.int_port_sense = (IRQ_FALLING_EDGE | PULLUP_ON); // interrupt is to be falling edge sensitive
fnConfigureInterrupt((void *)&interrupt_setup); // configure interrupt
fnConfigureInterrupt() does the following in the case of these settings:
static void (*IRQ_handler)(void) = 0; // handler for IRQ
unsigned char ucPortPin = SIM_PINSEL_IRQPS_PTI6;
POWER_UP(0, SIM_SCGC_IRQ); // enable clocks to the external interrupt module
SIM_PINSEL0 = ((SIM_PINSEL0 & ~(SIM_PINSEL_IRQPS_PTI6)) | ucPortPin); // select the IRQ pin to use
IRQ_SC = IRQ_SC_IRQPE; // enable IRQ pin function with pull-up
IRQ_handler = port_interrupt->int_handler; // enter the application handler
fnEnterInterrupt(irq_IRQ_ID, port_interrupt->int_priority, _IRQ_isr); // ensure that the handler is entered
IRQ_SC |= (IRQ_SC_IRQIE | IRQ_SC_IRQACK); // enable interrupt and reset pending interrupt
fnEnterInterrupt() enters the IRQ vector into the vector table (in SRAM in this case but can also be fixed in Flash).
To enable the interrupt source in the NVIC it does (in the case of the IRQ):
IRQ4_7_PRIORITY_REGISTER |= 0xc0000000;
IRQ0_32_SER = 0x00000080;
Of course the main Cortex interrupt must also be enabled.
When the IRQ triggers the IRQ handler is called, which resets the IRQ interrupt flag and calls the user's handler
static __interrupt void _IRQ_isr(void)
{
IRQ_SC |= (IRQ_SC_IRQACK); // reset the interrupt flag
if (IRQ_handler != 0) {
IRQ_handler(); // call the interrupt handler
}
}
The KEA-64 (as some smaller KE parts) has however only one IRQ input which can only be on PTA5. PTA5 defaults to RESET_b input and to use it the following differences are valid:
- the reset function must be disabled in SIM_SOPT0 [SIM_SOPT0 &= ~(SIM_SOPT_RSTPE);] - this is however a write-once field so it has to be used carefully. It is best to do it immediately after reset (where all such bits are defined together) so that it is guarantied to work.
- The SIM_PINSEL0 operations are redundant since the other sources don't exist
Regards
Mark
Hi Kas,
Isn't the following KEA64 Reference Manual enough?
http://cache.freescale.com/files/microcontrollers/doc/ref_manual/KEA64RM.pdf?WT_TYPE=Reference Manuals&WT_VENDOR=FREESCALE&WT_FILE_FORMAT=pdf&WT_ASSET=Documentation&fileExt=.pdf
Best regards,
Yasuhiko Koumoto.