FRDM-KL46Z setting up NVIC

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

FRDM-KL46Z setting up NVIC

Jump to solution
2,071 Views
neilporven
Senior Contributor I

Hi everyone,

How do you setup the NVIC on the KL46Z?

Labels (2)
1 Solution
1,475 Views
mjbcswitzerland
Specialist V

Hi

The NVIC configuration for the KL46 is essentially identical to that used by any other Cortex m0/m3/m4/m7 processor. The only thing that needs to be known (for individual processors) is the actual mapping of the interrupt ID to the source (eg. first DMA channel is 0 for all Kinetis parts with it, but the PORTA interrupt on the KL46 is 30 but 59 on a K21, etc. etc.)
The Cortex m4 Kinetis parts have 16 levels of priority and the Cortex m0+ ones only 4 so there is one difference in the code used to configure interrupts (see __NVIC_PRIORITY_SHIFT)


#define __NVIC_PRIORITY_SHIFT  6 // for KE,KEA, KL parts (priorities 0..3)
#define __NVIC_PRIORITY_SHIFT  4 // or other Kinetis parts (priorities 0..15)


To entere an interrupt handler (with its priority) a call can be used such as:
fnEnterInterrupt(irq_PIT_ID, _PRIORITY3, _PIT_Interrupt);
where irq_PIT_ID is 22 for the KL46 and _PIT_Interrupt() is the handling routine. Generic code will map the irq_PIT_ID to the chip so that there is no porting required between chips.

The following is a generic configuration for the NVIC (peripherals also need their own interrupt configured before it enters to the NVIC layer of course):

extern void fnEnterInterrupt(int iInterruptID, unsigned char ucPriority, void (*InterruptFunc)(void))
{
    volatile unsigned long *ptrIntSet = IRQ0_31_SER_ADD;
    volatile unsigned char *ptrPriority = IRQ0_3_PRIORITY_REGISTER_ADD;
#if !defined INTERRUPT_VECTORS_IN_FLASH
    VECTOR_TABLE *ptrVect = (VECTOR_TABLE *)VECTOR_TABLE_OFFSET_REG;
    void (**processor_ints)(void);
#endif

#if !defined INTERRUPT_VECTORS_IN_FLASH
    processor_ints = (void (**)(void))&ptrVect->processor_interrupts;    // first processor interrupt location in the vector table
    processor_ints += iInterruptID;                                      // move the pointer to the location used by this interrupt number
    *processor_ints = InterruptFunc;                                     // enter the interrupt handler into the vector tale
#endif
    ptrPriority += iInterruptID;                                         // move to the priority location used by this interrupt
    *ptrPriority = (ucPriority << __NVIC_PRIORITY_SHIFT);                // define the interrupt's priority (16 levels for K and 4 levels for KE/KL)
    ptrIntSet += (iInterruptID/32);                                      // move to the interrupt enable register in which this interrupt is controlled
    *ptrIntSet = (0x01 << (iInterruptID%32));                            // enable the interrupt
}

Notice that INTERRUPT_VECTORS_IN_FLASH removes entering the actual handler address in case these are fixed in Flash, although it is more flexible (and faster) to have then in SRAM.

Regards

Mark

Kinetis for professionals: http://www.utasker.com/kinetis.html

View solution in original post

0 Kudos
5 Replies
1,475 Views
neilporven
Senior Contributor I

Thank you everyone for helping me on this.  I'm actually working with the last interrupt #31

for portC_D.  I have to do a bit more reading and get back to this, once I'm more knowledgeable 

regarding the NVIC.

1,475 Views
mjbcswitzerland
Specialist V

Neil

I have attached the port interrupt code from the uTasker project since it handles interrupt and DMA on all ports of any processor type (KEA,KE,KL, K, KV etc.). In fact there is only the single call to the previously discussed routine that is needed for the NVIC - the rest is for setting up the port's characteristics and interrupt as well as handling individual interrupts on the ports.

fnEnterInterrupt(irq_PORTC_D_ID, port_interrupt->int_priority, _portC_D_isr); // ensure that the handler for this port is entered

If you need to understand the user interface it is the same as used for low leakage wake up interrupts/wakeup as shown at http://www.utasker.com/kinetis/LLWU.html

The peculiarity with the PORTC_D interrupt source is that it ties together the interrupt sources of two ports (otherwise there tends to be a single interrupt vector per port) so the handler (see _portC_D_isr()) needs to check and handle both sources, if both can trigger in the particular design.

_portC_D_isr() in the attached code shows how individual user handers are attached to each port input (with individual interrupt or DMA characteristics) so that the application layer can effectively work with unique interrupts on each possible input rather than needing to understand the workings and restrictions of the peripherals involved.

Regards

Mark

Kinetis for professionals: http://www.utasker.com/kinetis.html

0 Kudos
1,476 Views
mjbcswitzerland
Specialist V

Hi

The NVIC configuration for the KL46 is essentially identical to that used by any other Cortex m0/m3/m4/m7 processor. The only thing that needs to be known (for individual processors) is the actual mapping of the interrupt ID to the source (eg. first DMA channel is 0 for all Kinetis parts with it, but the PORTA interrupt on the KL46 is 30 but 59 on a K21, etc. etc.)
The Cortex m4 Kinetis parts have 16 levels of priority and the Cortex m0+ ones only 4 so there is one difference in the code used to configure interrupts (see __NVIC_PRIORITY_SHIFT)


#define __NVIC_PRIORITY_SHIFT  6 // for KE,KEA, KL parts (priorities 0..3)
#define __NVIC_PRIORITY_SHIFT  4 // or other Kinetis parts (priorities 0..15)


To entere an interrupt handler (with its priority) a call can be used such as:
fnEnterInterrupt(irq_PIT_ID, _PRIORITY3, _PIT_Interrupt);
where irq_PIT_ID is 22 for the KL46 and _PIT_Interrupt() is the handling routine. Generic code will map the irq_PIT_ID to the chip so that there is no porting required between chips.

The following is a generic configuration for the NVIC (peripherals also need their own interrupt configured before it enters to the NVIC layer of course):

extern void fnEnterInterrupt(int iInterruptID, unsigned char ucPriority, void (*InterruptFunc)(void))
{
    volatile unsigned long *ptrIntSet = IRQ0_31_SER_ADD;
    volatile unsigned char *ptrPriority = IRQ0_3_PRIORITY_REGISTER_ADD;
#if !defined INTERRUPT_VECTORS_IN_FLASH
    VECTOR_TABLE *ptrVect = (VECTOR_TABLE *)VECTOR_TABLE_OFFSET_REG;
    void (**processor_ints)(void);
#endif

#if !defined INTERRUPT_VECTORS_IN_FLASH
    processor_ints = (void (**)(void))&ptrVect->processor_interrupts;    // first processor interrupt location in the vector table
    processor_ints += iInterruptID;                                      // move the pointer to the location used by this interrupt number
    *processor_ints = InterruptFunc;                                     // enter the interrupt handler into the vector tale
#endif
    ptrPriority += iInterruptID;                                         // move to the priority location used by this interrupt
    *ptrPriority = (ucPriority << __NVIC_PRIORITY_SHIFT);                // define the interrupt's priority (16 levels for K and 4 levels for KE/KL)
    ptrIntSet += (iInterruptID/32);                                      // move to the interrupt enable register in which this interrupt is controlled
    *ptrIntSet = (0x01 << (iInterruptID%32));                            // enable the interrupt
}

Notice that INTERRUPT_VECTORS_IN_FLASH removes entering the actual handler address in case these are fixed in Flash, although it is more flexible (and faster) to have then in SRAM.

Regards

Mark

Kinetis for professionals: http://www.utasker.com/kinetis.html

0 Kudos
1,475 Views
rastislav_pavlanin
NXP Employee
NXP Employee

Hello,

I also recommend to use CMSIS API:

Interrupts and Exceptions (NVIC) 

Our SDK is fully supported.

regards

R.

0 Kudos
1,475 Views
ivadorazinova
NXP Employee
NXP Employee
0 Kudos