Go to Triangle Digital Support Home Page TDS9092 TECHNICAL MANUAL
Programming
Interrupts
Live website search
Enter key words
 

INTERRUPTS

 

ASSIGN

( a - )

Following Forth word is executed on interrupt whose jump table address is a

CMI

( - a )

Jump table address of timer 2 counter match interrupt

DIS

( - )

Disable interrupts. Sets microprocessor interrupt mask bit

EIS

( - )

Enable interrupts. Clears microprocessor interrupt mask bit

ICI

( - a )

Jump table address of timer 1 input compare interrupt

IRQ1

( - a )

Jump table address of first maskable interrupt

IRQ2

( - a )

Jump table address of second maskable interrupt

LATER

( n - )

Used in Forth word entered on timer 1 output compare interrupt. Will reoccur after 0.8138�s

NMI

( - a )

Jump table address of non-maskable interrupt

OCI

( - a )

Jump table address of timer 1 output compare interrupt

RETURN;

( - )

Ends definition of high level Forth interrupt

SIO

( - a )

Jump table address of serial port interrupt

SWI

( - a )

Jump table address of software interrupt

TOI

( - a )

Jump table address of timer 1 overflow interrupt

TRAP

( - a )

Jump table address of crashed machine interrupt

 

See INTERRUPT JUMP TABLE for interrupt addresses,
INTERRUPT MULTITASKING for repetitive interrupts and
6301 STRUCTURED FORTH ASSEMBLER for assembler.

AVOID INTERRUPTS WHEN POSSIBLE

Inexperienced real-time programmers often think that interrupts are essential, for example that an interrupt should always occur every time a particular event happens. This might be necessary but interrupts are more difficult to debug and mutual interference of different interrupts due to inadequate safeguards may only show up problems in your program years after the design. The advice to someone who is still learning real-time design must be to avoid all interrupts on whatever microprocessor. In some safety-critical applications, for example in certain railway uses, interrupts in programs are banned. Each job is different, however, and there are occasions where you must use interrupts.

Having said that, the TDS9092 has 10 possible interrupts and they can all be used in one program if you wish! A program written in assembler or high level Forth can be tied to each. TDS9092 is particularly suitable for applications where interrupts are necessary and the next section may help you decide.

EXAMPLE PROBLEM

This example demonstrates how an application apparently needing interrupts could probably be done better without them.

A particular application needs a keyboard and LCD display. The system counts items on a production line conveyor belt and shows the number on the LCD. One solution is to have a main program for the LCD and keyboard and to interrupt the TDS9092 when an item arrives. The essence of the main program is:

 

: DISPLAY #ITEMS @ ( get number of items

    ' LCDEMIT CFA 'EMIT ! ( revector EMIT to LCD

   0AT 6 U.R ( show qty on LCD

    ' <EMIT> CFA 'EMIT ! ; ( back to serial port

: WORK ( word executed at power-up

   INITIALISE

   BEGIN

   BEGIN DISPLAY NEWKEY -DUP UNTIL

   PROCESSKEY

   AGAIN ;

 

Here we will not concern ourselves with the detail of PROCESSKEY or INITIALISE . Perhaps a certain key will cause the number of items counted in the variable #ITEMS to be sent down the serial link to another computer for example.

The interrupt program is:

 

: TALLY   1 #ITEMS +!   RETURN;

 

This increments a variable #ITEMS when an external interrupt arrives and then we return from interrupt back to the main program WORK shown above.

It remains to establish WORK as the main, or foreground, task and TALLY as the background task. The former is done using the word SET as shown in the section STAND-ALONE SYSTEMS and the latter, of concern to us here, is done with ASSIGN . Include the following, most conveniently done at the end of the program listing:

 

IRQ1 ASSIGN TALLY ( associates TALLY with the

                  ( interrupt IRQ1 at this address

SET WORK ( alters cold start parameters to

         ( cause power-on entry into WORK

 

Note that they must be in this order; SET is always the last line of a system that will be put in PROM.

Having seen the outline of how to approach this counting problem using interrupts, note that it might have been possible to do it without them:

 

: TALLY ?ITEM IF 1 #ITEMS +! THEN ;

: WORK

   INITIALISE

   BEGIN

   BEGIN DISPLAY TALLY NEWKEY -DUP UNTIL

   PROCESSKEY

   AGAIN ;

 

This works because the program spends most of its time in the middle BEGIN .  UNTIL loop. As long as PROCESSKEY does not take longer than the time between items arriving on the conveyor the second, non-interrupt, solution would be the better one. The inner BEGIN . AGAIN can be called a 'flash around loop' because you design it to be as quick as possible, diverting to do other functions, or part of a function, for only short times.

Interrupts can be written either in assembly language or, as above, in high level Forth. These are considered in turn.

EXTERNAL INTERRUPTS

Note that IRQ1 and IRQ2 are level operated; an interrupt will occur if the input is low. This means that your negative going input pulse must be narrow, in fact shorter than the execution time of the interrupt, otherwise you'll get more interrupts when the first one finishes. On the other hand NMI is edge operated (negative edge) and has no such restriction.

INTERRUPTS USING ASSEMBLY LANGUAGE

The Forth system ROM contains vectors to internal RAM at which you can put your own jump table. There are three bytes each to hold machine-code jump instructions and the full INTERRUPT JUMP TABLE is available.

This table is at the start of the user's RAM/PROM area and so once set will be blown into the application PROM along with the program. It is instructive to look at this area in a TDS9092 after power-up. HEX 0800 20 DUMP gives:

 

0800 3B 3B 3B 3B 3B 3B 7E E8 4E 3B 3B 3B 7E E8 A3 3B

0810 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 80  0

 

The jump table is mainly preset to 3B, which is the Return From Interrupt RTI instruction. Two interrupt jumps are pre-configured and these are marked in the Interrupt Jump Table. We can see them in the above memory dump.

Each jump has three bytes. The first is 7E and the next two give the absolute address that will be jumped to when the interrupt occurs. When setting the jump table you must make sure that this address will start a string of machine code and that eventually an RTI instruction will cause a return from interrupt.

One preset interrupt is the TRAP which gives the message CRASHED MACHINE if the microprocessor loses control, and the other is TOI timer 1 overflow interrupt which is set to keep time and date. You are free to set up the jump table as needed, including re-assignment of these two.

Next is an example of an assembler interrupt routine. Apart from being an example, it is a useful one to know. In the 63B01Y0 microprocessor there is a free-running counter which overflows every 53.33ms. This routine maintains a variable which is incremented on each counter overflow. Together the two give a 32-bit timer with a resolution of about 814ns and a full range of about 58 minutes. It can be extended further if needed.

This also shows the use of the 6301 Forth assembler. Note that the address to jump to is the Parameter Field Address of the assembly language interrupt routine. This is readily found with ' as seen below. If in difficulty with an interrupt written in assembler see if it is possible to start with the example below and then change it to meet your needs.

 

( _ASTIMER.TDS)  DECIMAL

88 USER %TIMER ( a 16-bit extension of timer 1

CODE +TIME ( Interrupting word which increments

           ( %TIMER

   $08 A LDA,  $09 LDX, ( clear timer 1 overflow

                        ( flag

   %TIMER LDX,  INX,  %TIMER STX, ( increment

                                  ( variable

   RTI, ?CSP SMUDGE     ( return from interrupt

: INITIALISE  DIS       ( disable interrupts

   $8 C@ $4 OR $8 C!    ( enable overflow interrupts

   0 %TIMER !  0 $09 !  ( clear timer

   EIS ;                ( general interrupt enable

: TEST ( to demonstrate the extended timer

   INITIALISE CR

   BEGIN $09 @ %TIMER @ (   - double word time

      20 D.R  100MS     ( print 10 times per second

      ?TERMINAL         ( stop on ctrl+C

   UNTIL ;

$7E TOI C!  ' +TIME TOI 1+ ! ( interrupt table entry

 

Note that apart from the general interrupt enable EIS , the particular interrupt must also have its enable bit set. In the above example this is bit 2 of address 8.

INTERRUPTS WRITTEN IN HIGH LEVEL FORTH

To clearly show the difference between interrupts in assembly language and Forth the same example above is now coded in Forth:

 

( _HITIMER.TDS)  DECIMAL

88 USER %TIMER ( a 16-bit extension of timer 1

: +TIME ( interrupting word which increments %TIMER

   $08 C@  $09 @ 2DROP ( clear timer 1 overflow flag

   1 %TIMER +!         ( increment variable

   RETURN;             ( return from interrupt

: INITIALISE  DIS      ( disable interrupts

   $8 C@ $4 OR $8 C!   ( enable overflow interrupt

   0 %TIMER !  0 $09 ! ( clear timer

   EIS ;               ( general interrupt enable

TOI ASSIGN +TIME       ( set up task switch

: TEST ( to demonstrate the extended timer

   INITIALISE CR

   BEGIN $09 @ %TIMER @ (   - double word time

      20 D.R  100 MS    ( print 10 times per second

      ?TERMINAL         ( stop on ctrl+C

   UNTIL ;

 

This is easy as we saw in the example at the beginning of this section because the words ASSIGN and RETURN; do all the work for you.

To create an interrupt in high level Forth:

 

q       Write the interrupt routine as a normal Forth word and debug it.

q       Now change the semicolon to RETURN; so that it has this form:
: NAME . high level Forth words . RETURN;

q       Use ASSIGN to set up the interrupt.

q       Create an initialising word which enables the interrupt, both a particular and general interrupt enable.

 

The word ASSIGN works by compiling a headerless word which saves Forth 'registers' on the stack. A new return stack base is then allocated in the free space above the old one. The Code Field Address (cfa) of the interrupting Forth word is put in the Interpreter Pointer of the Forth inner interpreter and we jump back to Forth. A completely 'new' Forth system has now been created for the duration of the interrupt. ASSIGN also sets the entry in the interrupt jump table.

The return from interrupt performed by RETURN; is simpler, we just pull all the old data back off the stack and replace it in the Forth 'registers' before executing a return from interrupt instruction (RTI) which puts us back in the original Forth system exactly where we left it.

Go to Triangle Digital Support Home Page Go to top   Next page