• No results found

4.1.2 Debugging INT/INTA Cycles

Lots of things can and will go wrong long before your ISR has a chance to exhibit buggy behavior. Remember that most processors service an interrupt with the following steps:

● The device hardware generates the interrupt pulse .

● The interrupt controller (if any) prioritizes multiple simultaneous requests and issues a single interrupt to the processor.

● The CPU responds with an interrupt acknowledge cycle. ● The controller drops an interrupt vector on the data bus.

A friend told me how his DOD project uses an antique language called CMS. The compiler is so buggy they have to look for bugs in the assembly listing after each and every compile— and then make a more or less random change and recompile, hoping to lure the tool into creating correct code. I laughed until I realized that ’ s exactly the situation we ’ re in when using a high quality C compiler in performance-bound applications.

101 Real Time

● The CPU reads the vector and computes the address of the user-stored vector in memory. It then fetches this value.

● The CPU pushes the current context, disables interrupts, and jumps to the ISR. Interrupts from internal peripherals (those on the CPU itself) will generally not generate an external interrupt acknowledge cycle. The vectoring is handled internally and invisibly to the wary programmer, tools in hand, trying to discover his system ’ s faults.

A generation of structured programming advocates has caused many of us to completely design the system and write all of the code before debugging. Though this is certainly a nice goal, it ’ s a mistake for the low level drivers in embedded systems. I believe in an early wrestling match with the system ’ s hardware. Connect an emulator, and exercise the I/O ports. They never behave quite how you expected. Bits might be inverted or transposed, or maybe there ’ s a dozen complex confi guration registers needing setup. Work with your system, understand its quirks, and develop notes about how to drive each I/O device. Use these notes to write your code.

Similarly, start prototyping your interrupt handlers with a hollow shell of an ISR. You ’ ve got to get a lot of thingsright just to get the ISR to start. Don ’ t worry about what the handler should do until you have it at least being called properly.

Set a breakpoint on the ISR. If your shell ISR never gets called, and the system doesn ’ t crash and burn, most likely the interrupt never makes it to the CPU. If you were clever enough to fi ll the vector table ’ s unused entries with pointers to a null routine, watch for a breakpoint on that function. You may have misprogrammed the table entry or the interrupt controller, which would then supply a wrong vector to the CPU.

If the program vectors to the wrong address, then use a logic analyzer or debugger ’ s trace (if it has trace; a lot of BDM/JTAG units don ’ t) to watch how the CPU services the interrupt. Trigger collection on the interrupt itself, or on any read from the vector table in RAM. You should see the interrupt controller drop a vector on the bus. Is it the right one? If not, perhaps the interrupt controller is misprogrammed.

Within a few instructions (if interrupts are on) look for the read from the vector table. Does it access the right table address? If not, and if the vector was correct, then you are either looking at the wrong system interrupt or there ’ s a timing problem in the interrupt acknowledge cycle. Break out the logic analyzer, and check this carefully.

102

w w w. n e w n e s p r e s s . c o m

Chapter 4

Hit the databooks and check the format of the table ’ s entries. On an 86-style processor, four bytes represent the ISR ’ s offset and segment address. If these are in the wrong order—and they often are—there ’ s no chance your ISR will execute.

Frustratingly often the vector is fi ne; the interrupt just does not occur. Depending on the processor and peripheral mix, only a handful of things could be wrong:

● Did you enable interrupts in the main routine? Without an EI instruction, no interrupt will ever occur. One way of detecting this is to sense the CPU ’ s INTR input pin. If it ’ s asserted all of the time, then generally the chip has all interrupts disabled.

● Does your I/O device generate an interrupt? It ’ s easy to check this with external peripherals.

● Have you programmed the device to allow interrupt generation? Most CPUs with internal peripherals allow you to selectively disable each device ’ s interrupt generation; quite often you can even disable parts of this (e.g., allow interrupts on “ received data ” but not on “ data transmitted ” ).

Modern peripherals are often incredibly complex. Motorola ’ s TPU, for example, has an entire book dedicated to its use. Set one bit in one register to the wrong value, and it won ’ t generate the interrupt you are looking for.

It ’ s not uncommon to see an interrupt work perfectly once and then never work again. The only general advice is to be sure your ISR re-enables interrupts before returning. Then look into the details of your processor and peripherals.

You may need to service the peripherals as well before another interrupt comes along. Depending on the part, you may have to read registers in the peripheral to clear the interrupt condition. UARTs and Timers usually require this. Some have peculiar requirements for clearing the interrupt condition, so be sure to dig deeply into the databook.