Interrupts

 interrupt Identifier([name])
   {statements}
 end interrupt
  • Name - is a constant string value that identifies the handler type.

For example,

Private Interrupt OnTimer(Pic.T1Interrupt)
   ' code statements here…
End Interrupt

A full list of available interrupt handler names can be found here.

Interrupts perform basic context saving. That is, volatile system registers such as WREG0, WREG1 etc are saved automatically. The basic context saving of an interrupt means it is unsuitable for supporting high level language constructs. For example, what appears to be a simple statement may involve using many different system and compiler registers underneath. If these are changed in your Interrupt Service Routine (ISR), your main program will almost certainly fail. You should also never call another subroutine or function from an interrupt unless additional steps have been taken with respect to context saving.

You can modify an interrupt to handle more complex context saving by using a save...restore block, which is discussed here.

Enabling and Disabling Interrupts

With Firewing, you only commit the assignment of your ISR to an individual interrupt vector when you issue an enable command. For example:

Enable(OnTimer)

The enable keyword explicitly assigns an ISR to a interrupt vector. Once enable is called, your program is committed to using this interrupt. To set the interrupt enable flags to false, call:

Disable(OnTimer)

Context Saving

 save (Item {, Item})
   {statements}
 restore
  • Item - A variable, subroutine or function to save. A constant 0 will context save the compilers system registers.

Extreme care needs to be taken when using interrupts and events with respect to context saving. This is because a certain number of system registers or frame variables may be allocated by the compiler when executing a routine or performing a mathematical calculation. The integrity of these variables must be preserved at all times when executing an interrupt or event.

For example, let's assume we have an interrupt which calls a simple function called GetValue(). The program looks like this:

' get value function...
Function GetValue(value As Byte) As UInteger
   Return value * value * value 
End Function

' some interrupt...
Interrupt MyInt(Pic.T1Interrupt)
   Dim value As UInteger
   Value = GetValue(10)   
End Interrupt

It looks harmless enough doesn't it? But it isn't. The GetValue() function uses a number of frame variables. One for the parameter, two to store the intermediate results of the calculation and four for the result, which is a UInteger (32 bit long word). When this function is called, RAM locations 0 to 6 will be altered. If the interrupt is triggered when your program is executing a routine which also uses one or more RAM locations between 0 and 6, then the outcome will be certain disaster. This is because when the interrupt finishes, it will return to the main program and these locations are now permanently damaged. Worst still, the calculation in GetValue() also uses a number of system registers to perform the long word multiplication. These will also be damaged. To correct the problem, use a save…restore statement block to protect the system and frame registers, like this:

' some interrupt...
Interrupt MyInt()
   Dim value As UInteger
   Save(GetValue) 
      Value = GetValue(10) 
   Restore     
End Interrupt