Interrupt service routines

Two empty interrupt service routines are provided by the run-time library
(/usr/share/cpik/<version>/lib/rtl.slb).

A user specific interrupt service routine can be written at C level by using the (non-standard) __interrupt__ keyword:

__interrupt__ void hi_pri_ISR()
{
  /* interrupt service code */
}
Note that this routine will replace the default one, because user libraries are scanned before rtl.slb.

The keyword __interrupt__ insures that

The body of an ISR routine can be written in pure assembly language, using the __asm__ directive.

In this case, all previously mentionned registers can be freely altered, as long as FSR0 (the software stack pointer) is not altered when the ISR exits14.

When the interrupt code is written in C (or mix of C and asm code), registers used by the run-time library and user code must be saved and restored using the SAVE_REGS and RESTORE_REGS macros. Here is a typical example:

__interrupt__ void hi_pri_ISR()
{ 
   SAVE_REGS ;  /* MANDATORY */

   if (INTCON & (1 << TMR0IF))
   { // IT has occured on timer 0
      timer0_ISR() ; // any code can be used here
   }

   RESTORE_REGS ; /* MANDATORY */
}

The SAVE_REGS and RESTORE_REGS macro are defined in the <interrupt.h> header, that should be included. These macros save the registers that are used by integer arthmetic routines, but do not save the registers that are used for floating point calculation. For this reason, do not use floating point data in an interrupt routine. However, if you really need to handle FP data in an interrupt routine, it is easy to write your own macro to save the FP context. See section 9.2 for details about the registers usage.

It is possible to take a full control of context saving. In this case, just omit the __interrupt__ keyword and insert yourself the code you need with __asm__ instructions. Beware! in this case you must know what you are doing.

AG 2013-04-10