Having trouble setting NVIC interrupt priority on KL05

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

Having trouble setting NVIC interrupt priority on KL05

2,747 Views
jeffmajeff
Contributor I

I am using a KL05Z32 and I cannot seem to set NVIC priority for two interrupts.  I am trying the same method for the PIT and the I2C interrupt.  When I run the code with a debugger and I directly inspect the NVIC priority, I do not see a change after using the 'set_irq_priority()' function or directly writing to the NVIC_IPR5 register.  Here is a code sample for setting the PIT priority:

void PIT_Init(void)
{
 // Enable PIT clock
 SIM_SCGC6 |= SIM_SCGC6_PIT_MASK; // enable PIT module
 
 /* Enable PIT Interrupt in NVIC*/ 
 enable_irq(INT_PIT - 16);
 
 /* Set PIT priority relatively low so as not to interfere with communication interrupts */
 set_irq_priority(INT_PIT - 16, 1);
 //NVIC_IPR5 = 0x01;
 
 PIT_MCR = 0x00; // MDIS = 0 enables timer
 PIT_TCTRL1 = 0x00; // disable PIT0
 // Configure PIT to produce an interrupt every 1ms
 PIT_LDVAL1 = 23999; // 24000 - 1 cycles at 24MHz
 PIT_TCTRL1 = PIT_TCTRL_TIE_MASK; // enable PIT0 and interrupt
 PIT_TFLG1 = 0x01; // clear flag
 PIT_TCTRL1 |= PIT_TCTRL_TEN_MASK;
}
Labels (1)
Tags (2)
0 Kudos
6 Replies

1,716 Views
mjbcswitzerland
Specialist V

Jeff

You may be using code from a Cortex-m4 based part rather than a Cortex-M0+ part.

Cortex-m4 (eg. K60 ) has 16 priority levels but the Cortex-M0+ (eg. KL05) has 4.

When you set it manually you are writing the value incorrectly to the register because it is left aligned and not right aligned.

This code will do it correctly:

unsigned char ucPriority  = 1; // (or whatever) 0..3 for KL05

NVIC_IPR5 = = (ucPriority << __NVIC_PRIORITY_SHIFT); // define the interrupt's priority (16 levels for K and 4 levels for KE/KL)

where
#define __NVIC_PRIORITY_SHIFT   6
is to be used for Cortex-M0+ based parts

and

#define __NVIC_PRIORITY_SHIFT   4
for Cortex-M4 parts.

In the uTasker project the PIT and I2C interrupts (priority and handlers) are set up with:

fnEnterInterrupt(irq_PIT_ID, PRIORITY_PIT, _PIT_Interrupt);

fnEnterInterrupt(irq_I2C0_ID, PRIORITY_I2C0, _I2C_Interrupt_0);

Which requires no porting and is fool-proof. If anything is wrong or out of range its simulator will report it as a fatal error.

Regards

Mark

 

Slash your project time with uTasker and KL05 simulation at
http://www.utasker.com/kinetis.html
http://www.utasker.com/kinetis/FRDM-KL05Z.html

Also free and open source....

0 Kudos

1,716 Views
jeffmajeff
Contributor I

I see what you mean.

Would it be something like this:

NVIC_IPR5 = (ucPriority << (__NVIC_PRIORITY_SHIFT + 16))

since (INT_PIT - 16) % 4 = 2 we have have to set the priority for IRQ2 on NVIC_IPR5, or am I interpreting that wrong?  Otherwise you wouldn't be able to set the priority independently for each of the interrupts that share NVIC_IPR5.

0 Kudos

1,716 Views
mjbcswitzerland
Specialist V

Hi Jeff

I see, your code base is doing long word accesses which is making it over-complicated.

This is the simplest way - just write each priority as a byte and then there is no complication.

volatile unsigned char *ptrPriority = IRQ0_3_PRIORITY_REGISTER_ADD; // set a pointer to the first priority register location

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)

Otherwise the PIT one for KL05 does happen to be a 16 bit shift (but you need to calculate the shift for each ID and it will change depending on which processor you are on - non-portable and costs time, money and new testing/debugging in case you were to need to re-use code on a different part.

KL05 PIT interrupt ID is 0x16 (22), so it needs to be set in the IRQ20_23_PRIORITY_REGISTER priority register (this is the 6th register in this area and therefore your framework presumably calls it NVIC_IPR5.

The actual bit involved to set a priority of 1 is 0x00400000, so your formula is correct.

You do still have an error though because
NVIC_IPR5 = (ucPriority << (__NVIC_PRIORITY_SHIFT + 16));

writes the other three neighbor vector priorities to 0 (if they were previously set), so the correct code when doing this particular interrupt's long word access would be:

NVIC_IPR5 = (NVIC_IPR5 & 0xff00ffff) | (ucPriority << (__NVIC_PRIORITY_SHIFT + 16)));

Therefore I prefer the simple byte access method (above) because it only requires the ID of the interrupt to be known and no calculating on the back of a napkin is needed each time one is used (with the associated risk of errors).

By the way, the user's manual gives the description for each priority register, showing the locations (and shifts) involved.

pastedImage_2.png

Finally, you may find code doing this (eg. Cortex CMSIS code)

int iPriorities = 1;
unsigned long ullPriority;
IRQ0_3_PRIORITY_REGISTER = 0xff0000; // set lowest priority (hoping 256 are available)
ulPriority = IRQ0_3_PRIORITY_REGISTER; // read back the register to see how many bits stuck
while ((ulPriority & 0x80000000) != 0) { // if the priority bit is implemented
    iPriorities *= 2;

    ulPriority  <<= 1;
}

//iPriorities now is equal to the priority levels that this processor type supports...

Regards

Mark

0 Kudos

1,716 Views
ribeiroruan2
Contributor I

Hello, Mark

Where do I find IPR registers addresses in the MKL28Z manual? I can't find it anywhere...

0 Kudos

1,716 Views
mjbcswitzerland
Specialist V

Hi

The NVIC is part of the Cortex core and so is not documented in the Kinetis user's manuals - you can get all core documentation from ARM: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0432c/Cihbecee.html

If you are just starting out with Kinetis try the uTasker open source version on Git Hub since it allows you to simulate operation and will cut your learning curve and development times dramatically.

Furthermore it is the only solution that allows you to develop on one Kinetis part but permits the code to run on almost any other Kinetis part (including i.MX RTs if the project finds it needs more speed) without a redesign being necessary.

Regards

Mark
[uTasker project developer for Kinetis and i.MX RT]

1,716 Views
ribeiroruan2
Contributor I

Thank you very much!

0 Kudos