Link here

Chapter 11 - Interrupts and Register Initializations


How the 68HC11 Handles Interrupts

The 68HC11 processor has 21 interrupts including input capture and output compare timers, a pulse accumulator, synchronous and asynchronous serial I/O, maskable and non-maskable external interrupt signals, computer-operating-properly and clock monitor failures, software and real-time interrupts, and the master reset interrupt. The Motorola 68HC11 manuals and the QED Hardware Manual describe the interrupt system in detail; a few basic aspects of the system are discussed here.

Recognition and servicing of maskable interrupts are controlled by a global interrupt enable bit (the I bit in the condition code register) and a set of local interrupt mask bits. If a local interrupt mask bit is not enabled, then the interrupt is "masked" and will not be recognized. If the relevant local mask bit is enabled and the interrupt event occurs, the interrupt is recognized and its interrupt flag bit is set to indicate that the interrupt is pending. It is only serviced, however, if the global interrupt bit is enabled.

When an interrupt is both recognized and serviced, the processor automatically globally disables all maskable interrupts by setting the I bit in the condition code register until the service routine is over. Other maskable interrupts can become pending during this time, but will not be serviced until interrupts are again globally enabled when the service routine ends. (The programmer can also explicitly re-enable global interrupts inside an interrupt service routine to allow nesting of interrupts; however, this can cause hard-to-diagnose problems in multitasking application programs). Non-maskable interrupts (reset, clock monitor failure, COP failure, illegal opcode, and XIRQ) are serviced regardless of the state of the I bit.

When an interrupt is serviced, the processor globally disables interrupts, pushes the contents of the 68HC11's programming registers onto the return stack, and then fetches the address of the service routine from a memory location (called an "interrupt vector") near the top of memory that is associated with that interrupt. In QED-Forth the interrupt vectors (which are in non-modifiable ROM) point to modifiable locations in the EEPROM so that the interrupt service routines can be specified by the user. The service routine must, at a minimum, perform two duties:

  1. Reset the interrupt flag bit (not the mask bit) so that the interrupt is no longer pending. The flag bit, oddly enough, is reset by writing a 1 to it.
  2. Execute an RTI (return from interrupt) instruction which pops the saved registers from the return stack and re-enables the global interrupt mask bit.

In addition there are several minor constraints on the interrupt service routine:

  1. Local variables should not be used in interrupt service routines or in any code called by the interrupt service routine. See LOCALS{ in the glossary.
  2. If floating point operations are used in an interrupt service routine then FP.PUSH and FP.POP must be used. See glossary entries for FP.PUSH and FP.POP.

QED-Forth simplifies interrupt handling, and transparently executes the RTI instruction for you.


How QED-Forth Simplifies Interrupts

With QED-Forth it is easy to define an interrupt service routine and ATTACH it to a specified interrupt. You define your service routine in either assembly code or in high level FORTH. Your routine ends with a normal RTS (return from subroutine) in assembly code or with a normal ; in FORTH (as opposed to an RTI instruction). Thus the service routine can be debugged just like any other FORTH word.

A set of kernel words has been defined as identifiers for each interrupt except the hardware reset which is not revectorable. The revectorable interrupts are:

Kernel word identifier Interrupt description
SCI.ID Serial communications interface
SPI.ID Serial peripheral interface
PULSE.EDGE.ID Pulse accumulator edge detection
PULSE.OVERFLOW.ID Pulse accumulator overflow
TIMER.OVERFLOW.ID Timer overflow
IC4/OC5.ID Timer input capture 4/output compare 5
OC4.ID Timer output compare 4
OC3.ID Timer output compare 3
OC2.ID Timer output compare 2 (used by timeslicer)
OC1.ID Timer output compare 1
IC3.ID Timer input capture 3
IC2.ID Timer input capture 2
IC1.ID Timer input capture 1
RTI.ID Real-time interrupt
IRQ.ID IRQ external pin
XIRQ.ID IRQ external pin (pseudo-nonmaskable)
SWI.ID Software interrupt (nonmaskable)
ILLEGAL.OPCODE.ID Illegal opcode trap (nonmaskable)
COP.ID COP failure (causes reset; nonmaskable)
CLOCK.MONITOR.ID Clock failure (causes reset; nonmaskable)

The kernel word ATTACH makes it easy to specify an action which is invoked by a given interrupt. ATTACH expects the 32-bit extended code field address (xcfa) of your service routine under an interrupt identifier on the stack, and it sets up the interrupt vector so that subsequent interrupts will execute the specified service routine. The code installed by ATTACH includes the RTI instruction that terminates the interrupt service sequence.

For example, if you define a word called TIMER.SERVICE to respond to the timer output compare #4 interrupt, you simply execute


to vector the output compare 4 interrupt so that it will call the TIMER.SERVICE routine. The QED Hardware Manual describes some examples of interrupt service routines.

Note that the OC2 interrupt is used as the multitasker's timeslice clock. Before using this interrupt for another purpose, make sure that you don't need the services provided by the timeslicer (see the glossary entry for START.TIMESLICER).


Implementation Details

The interrupt vectors near the top of memory are in ROM locations that cannot be modified by the programmer. The contents of these locations point to a series of locations in the EEPROM (at AE20-AEBFH) which can be modified and, if desired, write-protected using the BPROT register. ATTACH writes some code at the EEPROM locations corresponding to the specified interrupt. This code loads the code field address of the user's service word into registers and jumps to a routine that saves the current page, changes the page to that of the user's service word, and calls the service word as a subroutine. When the user-defined service word returns, the code installed by ATTACH restores the original page and executes RTI (return from interrupt) to complete the interrupt service process. This calling scheme ensures that the interrupt service will be properly called no matter which page the processor is operating in when the interrupt occurs. And because the interrupt calling routine which is installed by ATTACH ends with an RTI, your service routine can end with a standard RTS or ; which makes debugging much easier.


Interrupt Latency

The time required between the processor's initiation of interrupt servicing and the execution of the first byte of the specified service routine is called the interrupt latency. Most of the 68HC11's interrupts have an inherent latency of 12 machine cycles during which the registers are saved on the return stack and the interrupt vector is fetched. This corresponds to 6 microseconds (abbreviated as usec) if the board is clocked at 8 MHz, and of course this time is halved if the board is clocked at 16 MHz. QED-Forth's interrupt latency is longer because the interrupts are re-vectored via the EEPROM to allow the programmer to modify the vectors, and because the page must be changed. The latency of service routines installed with ATTACH is 34 machine cycles, or 17 usec with an 8 MHz crystal. That is, the first opcode of the user's service routine is executed 17 usec after interrupt service begins. After the service routine's concluding RTS executes, an additional 20 cycles (10 usec) lapses before the originally interrupted program resumes execution. 12 of these cycles are accounted for by the RTI instruction, and the other 8 cycles are required to restore the original page.


Performing Floating Point Operations and Numeric/String Conversions Inside Interrupt Service Routines

The words FP&STRING.PUSH and FP&STRING.POP or FP.PUSH and FP.POP must be used in interrupt routines that call floating point or number/string conversion operations. Consult the QED-Forth Glossary for implementation details.


QED-Forth Routines that Disable Interrupts

Certain QED-Forth routines temporarily disable interrupts by setting the I bit in the condition code register. These routines are summarized here to assist you in planning the time-critical aspects of your application.

The kernel provides a set of uninterruptable memory operators that disable interrupts for a few microseconds during the memory access. These are very useful in applications where several tasks or interrupt routines must access a shared memory location. The glossary entries for these words detail the length of time that interrupts are disabled.

|2!| |F!||X!|

The multitasker mediates access to shared resources and ensures smooth transfer of information among tasks. The routines that manage resource variables and mailboxes must disable interrupts for short periods of time to ensure proper access to shared resources and messages. Consequently, the following routines temporarily disable interrupts:


Consult their glossary entries for details.

The following routines temporarily disable interrupts to ensure that a new task is not corrupted while it is being built:


These routines disable interrupts to ensure that the elapsed time clock is not updated while it is being read:


The multitasker is charged with smoothly transferring control among tasks via timeslicing or cooperative task switching. The timeslicer is an interrupt service routine associated with output compare#2. It disables interrupts for the duration of a task switch which requires 58 microseconds plus 6.5 microseconds for each ASLEEP task encountered (these times are halved if the processor is clocked at 16 MHz). The cooperative task switch routine


disables interrupts for 31 microseconds plus 6.5 microseconds for each ASLEEP task encountered, and again these times are halved if the processor is clocked at 16 MHz.

The PAUSE routine (which temporarily disables interrupts) is called by the following built-in device drivers:


These routines as well as the following device driver routines GET and RELEASE resource variables, and so disable interrupts for short periods of time:

  • ?KEY
  • ?KEY1
  • ?KEY2
  • >DAC
  • A/D12.SAMPLE|
  • A/D8.SAMPLE|

The battery-backed real-time clock option shares the RAM socket on the QED Board. While the "watch" is being read or set by the routines


the RAM cannot be accessed, so interrupts cannot be properly serviced. Therefore these routines disable interrupts for approximately 1 msec (or 0.5 msec with a 16 MHz crystal) while the watch is being accessed.

All of the routines that write to the EEPROM disable interrupts for 20 msec per programmed byte. This results from the 68HC11's design which prohibits any EEPROM locations from being read while other EEPROM locations are being modified. Since all interrupts are vectored through EEPROM, interrupts cannot be serviced while an EEPROM storage operation is in progress. The following fundamental EEPROM storage routines

  • (EEC!)
  • (EE!)
  • (EEX!)
  • (EEF!)
  • (EE2!)

disable interrupts for 20 msec per programmed byte. These routines are smart enough to avoid programming a byte that already has the correct contents. The following routines may modify EEPROM locations:


The following routines disable interrupts and do not re-enable them:


DISABLE.INTERRUPTS and its assembly language counterpart SEI explicitly set the I bit in the condition code register. The routines ENABLE.INTERRUPTS and CLI clear the I bit to globally enable interrupts. The restart routines COLD and WARM disable interrupts so that the initialization process is not interrupted.


Special Reset-Type Interrupts

The RESET interrupt is the most important interrupt in the 68HC11. It is invoked when the processor is powered up or when the reset line is pulled low (which occurs when the reset button is pushed). When a reset occurs, the processor initializes its hardware registers to their specified reset conditions and calls QED-Forth's restart routine. RESET is the only interrupt that cannot be revectored by the programmer.

As explained in Chapter 3, a reset is a hardware initialization sequence, and a restart is a software-controlled initialization sequence. QED-Forth's restart routine initializes the system using either a COLD or WARM restart sequence, and commences execution of the operation program. The program decides whether to perform a COLD or WARM restart based on the contents of a variable in the user area. If this user variable is properly initialized, a warm restart is performed; if not, a cold startup occurs. A WARM restart initializes the minimum number of hardware registers and user variables necessary to run QED-Forth. It clears the stacks and ensures that there is one awake task running. A COLD restart is more thorough: it completely re-initializes the user area to default values.

In addition to the RESET interrupt, two other interrupts also cause hardware resets that initialize the processor's registers: the computer operating properly (COP) failure and clock monitor failure. These interrupts then execute a specified service routine. QED-Forth initializes the vectors of these interrupts so that they execute the same program that the standard reset does. These interrupts are vectored via the EEPROM so that the user can change the interrupt service routine if necessary.

The illegal opcode trap interrupt does not force a hardware reset. But it is very important that this interrupt's vector is initialized at all times to perform a proper restart. Otherwise, a crash which invokes this interrupt could cause another crash, causing an infinite loop of calls to the un-initialized interrupt that can only be exited by resetting the processor. The default service routine for this interrupt is the standard startup routine like the other three interrupts just described. This default service routine can be changed by the programmer.


Initialization of the Vital Interrupts

QED-Forth treats the RESET, computer operating properly (COP) failure, clock monitor failure, and illegal opcode trap interrupts as "vital interrupts" whose vectors should always be properly initialized. The RESET interrupt vector is in ROM and can never be changed. The other three vital interrupts are revectored via the EEPROM. QED-Forth's cold restart routine checks to make sure that these vital interrupts are properly initialized to their default values. If they are already initialized, it does nothing; if not, the cold restart routine writes to their EEPROM vectors to initialize them. The warm restart routine does not do this.

If you wish to maintain customized service routines for these interrupts, install the service routines (using ATTACH, for example) and then execute


This installs a pattern in a special EEPROM location which informs the cold startup routine not to initialize the illegal opcode trap, COP and clock monitor failure interrupts. Be careful with custom service routines for COP and clock monitor failure interrupts. Because these interrupts are associated with hardware resets, the four protected registers INIT, OPTION, BPROT, and TMSK2 must be initialized in the first 64 cycles of operation. Make sure that your service routine can accomplish the initializations within the allotted time.

To revert to the default initialization of the vital interrupts, simply execute


Forcing Cold Restarts

Some applications are more reliable if any reset condition (power-up, reset button, or COP or clock monitor failure) causes a cold restart which completely initializes the user area and system parameters. This is especially important in embedded systems applications where the main program has been configured to automatically execute after each restart. Such main programs typically perform a set of initializations that configure the system to perform the application program. The combination of a cold (as opposed to a warm) restart and the main program's initializations establishes a well-known starting state for the system.

To force a cold restart every time a reset occurs, execute


which installs a pattern in a specified location in the EEPROM. The startup routine checks this location and, if the proper pattern is present, always performs a cold startup. Because the pattern is in EEPROM, it need not be re-installed after each restart. To revert to the standard warm/cold startup behavior, execute


which removes the pattern from the location in the EEPROM.


Initializing the Protected Registers

There are four "protected" 68HC11 registers that contain bits that can be modified only during the first 64 machine cycles after a startup. These are the INIT, OPTION, BPROT, and TMSK2 registers. The QED-Forth restart routine initializes these registers to default values. You have the option of installing customized initialization values for OPTION, BPROT, TMSK2, and BAUD; initializing the BAUD register allows you to specify a serial communications baud rate that is set every time the processor restarts.

The INIT register specifies the memory locations of the hardware registers and on-chip RAM. The protected portion of the OPTION register controls the edge sensitivity of the external IRQ signal, STOP mode exit delay, and COP timer rate selection. BPROT can write-protect sections of the EEPROM and the CONFIG register. Two protected bits (bits 0 and 1) of TMSK2 control the frequency of the free-running counter. BAUD controls the baud rate of the serial communications interface.

The default initializations of these special registers are as follows:

INIT is set to B8H to place the on-chip RAM at B000H-B3FFH and the hardware registers at 8000H-805FH. INIT must have this value for QED-Forth to operate properly.

OPTION is initialized to 33H which configures the A/D converter to use the E-clock to power its charge pump, keeps the 8-bit A/D converter off at startup, makes the IRQ input edge sensitive, sets a 4 msec delay after exiting the STOP mode, disables the clock monitor circuit, and sets the COP timer rate to 1.049 sec. The A/D power-up bit, the clock/charge-pump select bit, and the clock monitor enable bit can be set at any time. The other bits can only be modified within the first 64 machine cycles after a reset.

The 2 protected bits in TMSK2, called PR0 and PR1, control the frequency of the main timer. The other bits in the register are interrupt mask bits that are not protected (they can be modified at any time); they are initialized to 0 so that 4 interrupts associated with the timer subsystem are not enabled after a reset. PR0 and PR1 are set such that the main timer has a period of 2 microseconds (usec), and the timer "rolls over" to 0 after just over 131 msec. If the QED Board is clocked at 8 MHz the register is initialized to 01H which drives the main timer at 1/4 the E-clock frequency, and if the QED Board is clocked at 8 MHz the register is initialized to 02H which drives the main timer at 1/8 the E-clock frequency. (For experts and the curious: A flag in the kernel ROM at location FFC0H tells QED-Forth the crystal frequency.)

BPROT is initialized to 10H which enables writes to all EEPROM cells and disables writes to the CONFIG register.

BAUD is initialized such that the baud rate is 9600 bits per second. If the onboard crystal frequency is 8 MHz, the BAUD register is initialized to 30H, and if the onboard crystal frequency is 16 MHz, the BAUD register is initialized to 31H. The BAUD register may be modified at any time.

The default register initialization values are summarized in Figure 11.1.

Register Name Register Address Default Value @ 8 MHz Default Value @ 16 MHz
OPTION 8039H 33H 33H
TMSK2 8024H 01H 02H
BPROT 8035H 10H 10H
BAUD 802BH 30H 31H

Figure 11.1. Default values of the registers initialized by INSTALL.REGISTER.INITS. These are the values that take effect after DEFAULT.REGISTER.INITS has been executed.

The kernel word INSTALL.REGISTER.INITS specifies initialization values for OPTION, BPROT, BAUD, and the lowest 2 bits of TMSK2. The specified values take effect upon the next reset, and the registers are appropriately initialized each time the processor resets. INSTALL.REGISTER.INITS expects the value of OPTION under the value of TMSK2 under the value of BPROT under the value of BAUD on the stack. After ANDing the specified value of TMSK2 with 03H so that only the lowest 2 (protected) bits are retained, INSTALL.REGISTER.INITS writes a pattern followed by the specified bytes in a special area of the EEPROM. The restart routine checks this pattern after every reset and, if it is present, initializes the registers during the first 64 cycles to the specified values.

For example, suppose that your board is clocked by an 8 MHz crystal, and you want to speed up the main free-running timer to run at 2 MHz (its default value is 500 kHz). This requires setting the value of TMSK2 to 00H (see the description of TMSK2 in the Motorola 68HC11 manuals). To install this value of TMSK2 while maintaining the default values for the INIT, OPTION, and BAUD registers, execute:

33        \ default value for OPTION
00        \ new value for TMSK2
10        \ default value for BPROT
30         \ default value for BAUD at 8MHz, yields 9600 baud

The specified values will take effect upon the next reset.

To return to the default initializations for the five registers, execute


which erases the pattern that INSTALL.REGISTER.INITS put in the EEPROM. After executing DEFAULT.REGISTER.INITS the registers will be initialized to the default values shown in Figure 11.1 each time the processor executes its restart sequence.


Changing the Baud Rate of the Primary Serial Port

INSTALL.REGISTER.INITS can be used to change the baud rate of the primary serial communications channel from its default value of 9600 baud (bits per second). The primary serial channel is implemented using the 68HC11's on-chip serial hardware. The next chapter discusses how to change the baud rate of the secondary serial port which is implemented by QED-Forth's software UART.

Setting the baud rate of the primary serial channel is accomplished by modifying the contents of the BAUD register at address 802BH in the 68HC11. The following table relates the register contents to some commonly used baud rates.

Desired Baud Rate (decimal) BAUD contents (hex) 8 MHz crystal BAUD contents (hex) 16 MHz crystal
19200 N/A 30H
9600 30H31H
4800 31H 32H
2400 32H 33H
1200 33H 34H
600 34H 35H
300 35H 36H

Figure 11.2. Baud rates and corresponding contents of the BAUD register.

For example, to immediately change the baud rate of the primary serial port to 1200 baud, execute

HEX 33 802B 0 C!

to set the contents of the BAUD register.

The kernel word INSTALL.REGISTER.INITS may be used to initialize the BAUD register to a specified value every time the processor restarts. For example, assume that we want standard initialization values to be used for the OPTION, TMSK2, and BPROT registers, but we want to establish a baud rate of 1200 baud. Using the information from Figure 11.1 and assuming an 8 MHz crystal frequency, we specify the default values for the OPTION, TMSK2, and BPROT registers, and from Figure 11.2, we use a BAUD value of 33H to set the baud rate. Thus executing

33        \ default value for OPTION
01        \ default value for TMSK2 at 8 MHz (use 02 at 16 MHz)
10        \ default value for BPROT
33         \ new value for 1200 BAUD

sets the baud rate to 1200 upon each subsequent reset or restart. Likewise, executing

33        \ default value for OPTION
01        \ default value for TMSK2 at 8 MHz (use 02 at 16 MHz)
10        \ default value for BPROT
35         \ new value for 300 BAUD

sets the baud rate to 300 upon each subsequent reset or restart. To revert to 9600 baud, execute DEFAULT.REGISTER.INITS or use the switch-selectable special cleanup mode described at the end of this chapter.


Changing the CONFIG Register

The CONFIG register is a special hardware register implemented as an EEPROM cell. It controls the position of the 512-byte EEPROM, determines whether the EEPROM is enabled, and enables or disables the computer operating properly (COP) feature. The CONFIG register is writable as long as bit 4 of the BPROT register is cleared. QED-Forth's default value for BPROT has this bit set so that the CONFIG register is unwritable. This prevents inadvertent modifications which could crash the system. If you wish to modify CONFIG (for example, to turn on the COP feature), first use INSTALL.REGISTER.INITS to set a value for BPROT with bit 4 cleared. If you have an 8 MHz crystal, you could execute

33        \ default value for OPTION
01        \ default value for TMSK2 at 8 MHz (use 02 at 16 MHz)
00        \ new value for BPROT enabling writes to CONFIG
30         \ default value for BAUD at 8 MHz (use 31H at 16 MHz)

Now issue a reset so that the new value of BPROT takes effect, and CONFIG becomes writable. Then use (EEC!) to set the desired value of the CONFIG register, whose address is 803FH. For example, to enable the COP while keeping the EEPROM enabled at AE00-AEFFH, execute

HEX AB 803F (EEC!)

Before executing a reset, the CONFIG register should be write-protected again by specifying a value for BPROT with bit 4 clear. This can be accomplished by another INSTALL.REGISTER.INITS command or by executing DEFAULT.REGISTER.INITS. If the COP has been enabled, make sure that an autostart routine has been installed that can service the COP before its intermittent time-out. Only then should a reset be issued so that the new value of CONFIG takes effect. The chapter titled "External Interrupts, Resets, Operating Modes, and the COP" in the QED Hardware Manual defines a step-by-step sequence to assist you in configuring the COP.


The Special Cleanup Mode

If a buggy program has been installed as an autostart routine, an infinite series of crashes may result: the program crashes, which causes a restart, which calls the autostart program, which crashes, etc... Another sticky situation arises if an improper value is written to the non-volatile CONFIG register which controls the location of the EEPROM and the enabling of the COP interrupt. Or, if INSTALL.REGISTER.INITS has been used to set a value for the BPROT register that write-protects the EEPROM, it will not be possible to use DEFAULT.REGISTER.INITS to undo the initialization, because the initializations themselves are stored in the EEPROM.

The special cleanup mode allows you to recover from any of these situations. Simply set DIP switch #5 "on" and reset the board by toggling DIP switch #6. This puts the processor in the "special test mode". QED-Forth's special "cleanup routine" is automatically called in this mode. It removes any installed autostart patterns, initializes the CONFIG register, sets all of the options specified by EEPROM locations to their default values, and performs a COLD restart to enter the QED-Forth monitor. Note that the cleanup mode cannot remove a PRIORITY.AUTOSTART vector if page 4 is write-protected or PROM. If a buggy PRIORITY.AUTOSTART routine is installed in PROM, remove the PROM to fix the problem. If a buggy PRIORITY.AUTOSTART routine is installed in write-protected RAM, turn DIP switch#1 OFF before entering the special cleanup mode so that the autostart pattern can be erased.

After using the cleanup mode, set DIP switch #5 to its standard "off" position and reset the processor to re-establish the normal operating mode and continue programming.

This page is about: Programming Interrupts and Register Initializations – Programming on microcontroller systems requires access to many hardware resources on processor chip, including interrupts and registers that control chips special functions. QED Forth has utilities that make these resources easy to use. Interrupts How …