I have an issue with the supplied 'How to handle interrupts in kinetis k60.txt', and it is the same issue I have with the arm_cm4 files I find in Freescale example code. The register name NVICICPR0 is short for 'NVIC Interrupt Clear Pending Register 0', and NVICISER0 is 'NVIC Interrupt Set Enable Register 0' (as described in 'DUI0553A_cortex_m4_dgug.pdf'). 'Set' and 'Clear' registers, like those also available on Port I/O in Kinetis (such as Port A 'set' GPIOA_PSOR), accept '1' bits to perform the named function, and zero bits where NOT to perform any action. So first and foremost it is unnecessary to 'or equals' (|=) those kinds of registers, and simply writing the '1' bit(s) does exactly what you want and sets or clears the appropriate bit(s) in said register. However, for something like NVICICPR0 (and NVICICER0 as is in the matching disable_irq function) this 'or equals' Read-Modify-Write sequence has a VERY UNDESIRED side effect, in that the NVICICPR0 'read' will return '1' bits for ALL pending interrupts at the time, and thus the write-back will clear ANY pending interrupt, not only on the 'desired' new-interrupt, throwing them all away! Similarly, the original 'disable_irq' code using a RMW of NVICICER0 will clear ALL interrupts enabled in that register, as the 'read' operation returns ALL currently enabled interrupts.
Corrected code, with some optimization:
void enable_irq (int irq)
{
int div;
register long int Ibit;
/* Make sure that the IRQ is an allowable number. Right now up to 91 is
* used.
*/
if (irq > 91)
printf("\nERR! Invalid IRQ value passed to enable irq function!\n");
/* Determine which of the NVICISERs corresponds to the irq */
div = irq & (3*32);
Ibit = 1 << (irq & (32-1));
switch (div)
{
case (0*32):
NVICICPR0 = Ibit;
NVICISER0 = Ibit;
break;
case (1*32):
NVICICPR1 = Ibit;
NVICISER1 = Ibit;
break;
case (2*32):
NVICICPR2 = Ibit;
NVICISER2 = Ibit;
break;
}
}
void disable_irq (int irq)
{
int div;
register long int Ibit;
/* Make sure that the IRQ is an allowable number. Right now up to 91 is
* used.
*/
if (irq > 91)
printf("\nERR! Invalid IRQ value passed to disable irq function!\n");
/* Determine which of the NVICICERs corresponds to the irq */
div = irq & (3*32);
Ibit = 1 << (irq & (32-1));
switch (div)
{
case (0*32):
NVICICER0 = Ibit;
break;
case (1*32):
NVICICER1 = Ibit;
break;
case (2*32):
NVICICER2 = Ibit;
break;
}
}