Software Interrupts in BASIC


Although the most efficient method of using an interrupt is in assembler, hardware interrupts and BASIC are poor bedfellows. By far the easiest way to write an interrupt handler is to write it in BASIC, in combination with the ON INTERRUPT statement. This is not the same as the compiler's original ON_INTERRUPT statement, which initiates a HARDWARE interrupt. ON INTERRUPT (two separate words.. ON INTERRUPT) informs the compiler to activate its internal interrupt handling and to jump to the BASIC interrupt handler as soon as it's capable, after receiving an interrupt. However, there's no such thing as a free lunch, and there are some penalties to pay for the ease of use that this method brings.

Important Note

The compiler will highlight the hardware interrupt directive (ON_INTERRUPT) as BOLD RED. While the software interrupt directive (ON INTERRUPT) will highlight BOLD BLACK. This makes for easy debugging should the underscore be forgotten.

When ON INTERRUPT is used, the compiler simply flags that the interrupt has happened and immediately goes back to what it was doing before it was rudely interrupted. Unlike a hardware interrupt, the code does not immediately jump to the interrupt handler. And since the compiler's commands are non re-entrant, there could be a considerable delay before the interrupt is actually handled.

For example, if the program has just started to execute a DelayMS 2000 command when an interrupt occurs, the compiler will flag the interrupt and continue with the delay. It could be as much as 2 seconds later before the interrupt handler is executed. Any time critical routines dependant on the interrupt occurring regularly will be ruined. For example, multiplexing seven segment display.

To minimise the above problem, use only statements that don't take long to execute. For example, instead of DelayMS 2000, use DelayMS 1 in a for...next, or repeat...until loop. This will allow the compiler to complete each command more quickly and handle any awaiting interrupts: -

 FOR VAR1 = 0 TO 199 : DELAYMS 1 : NEXT ' Delay for 200ms

If interrupt processing needs to occur more regularly, then there is no choice but to use a hardware interrupt, with all it's quirks.

Exactly what happens when ON INTERRUPT is used is this: A short interrupt handler is placed at location 4 in the PICmicro. This interrupt handler is simply a Return. What this does is send the program back to what it was doing before the interrupt occurred. It does not require any processor context saving. What it doesn't do is re-enable Global Interrupts as happens when using a RETFIE
instruction.

A Call to a short subroutine is placed before each command in the BASIC program once an ON INTERRUPT statement is encountered. This short subroutine checks the state of the Global Interrupt Enable bit (GIE). If it's off, an interrupt is awaiting so it vectors to the users interrupt handler. Which is essentially a BASIC subroutine.

If it is still set, the program continues with the next BASIC statement, after which, the GIE bit is checked again, and so forth.

Return from Interrupt

When the RESUME statement is encountered at the end of the BASIC interrupt handler, it sets the GIE bit to re-enable interrupts and returns to where the program was before the interrupt occurred. DISABLE stops the compiler from inserting the Call to the interrupt checker before each command. This allows sections of code to execute without the possibility of being interrupted. ENABLE allows the insertion to continue.

A DISABLE should be placed before the interrupt handler so that it will not be restarted every time the GIE bit is checked. If it is desired to turn off interrupts for some reason after ON INTERRUPT is encountered, you must not turn off the GIE bit. Turning off this bit informs the compiler an interrupt has happened and it will execute the interrupt handler forever.

Instead use: -

 INTCON = $80

This disables all the individual interrupts but leaves the Global Interrupt Enable bit set.

A final note about interrupts in BASIC is if the program uses the command structure: -

Fin:  GOTO Fin

You must remember the interrupt flag is checked before each instruction. It immediately jumps to label Fin with no interrupt check. Other commands must be placed in the loop for the interrupt check to happen: -

Fin: DELAYMS 1
GOTO Fin


Enabling an