The Microchip ICD 2 may be used unconventionally as an external trigger without the use of breakpoints. This allows for extension of the hardware breakpoint limit or adds an extra external trigger to halt the microcontroller asynchronously. In this article, I will demonstrate limitless breakpoints using the Microchip PIC18F4550 microcontroller which normally supports up to three breakpoints and three external triggers.
Little is needed to extend the capabilities of the ICD 2, two diodes and a transistor. That's it. Here's a schematic of how to wire the PIC18F4550:
Please note that in the above schematic, I have the transistor connected to PORTB, pin RB0. If you put everything together, it should look something like this:
Launch Microchip's MPLAB IDE and start a C or assembly project. If you chose an assembly project, define the following macro in an assembly:
break macro bsf PORTB, RB0 bcf PORTB, RB0 nop nop endm
If you chose a C project, define this macro instead:
#define Break(); \ PORTBbits.RB0 = 1; \ PORTBbits.RB0 = 0; \ Nop(); \ Nop();
Before you use these macros, you'll need to configure PORTB for digital output. This is a four step process. The first three steps I'll illustrate in the following assembly snippet:
; ****************** Breakpoint setup. ****************** ; Turn off RB0. bcf PORTB, RB0 ; PORTB digital IO on all channels. movlw 0x0F movwf ADCON1 ; RB0 to output. bcf TRISB, TRISB0
Or in C:
/****************** Breakpoint setup. ******************/ /* Turn off RB0. */ PORTBbits.RB0 = 0; /* PORTB digital IO on all channels. */ ADCON1 = 0x0F; /* RB0 to output. */ TRISBbits.TRISB0 = 0;
It's the last step that's a little confusing. You need to change the PORTB configuration bits so that RB0 is configured for digital IO, not analog input. There's two ways to do this, compiler directives or IDE menu settings. In the example code bundled with this document, I do it using compiler directives. Here I'll show how to do it using the IDE.
In MPLAB, if you click the Configure drop down menu and select Configuration Bits, you should see the following window:
Two main points here: First, if you're going to use the IDE to change the configuration bits, you'll want to make sure the 'Configuration Bits set in code' checkbox is unchecked. Second, make sure 'PortB A/D enable' is set to 'PORTB<4:0> configured as digital I/O on reset.' The default values for all the other configuration bits here should be fine. When you close the window, your changes are automatically saved.
Time to try it out, in your assembly file write the following:
nop nop break nop ; Pop out of breakpoint here. nop nop
Or in C:
Nop(); Nop(); Break(); Nop(); /* Pop out of breakpoint here. */ Nop(); Nop();
If you compile and run this code using the debugger, you should find yourself paused at the nop following the break or Break(); macro. You may now have as many breakpoints as you wish by using these macros.
The above method of pausing MCU execution may also be used by any external device. Instead of wiring a transistor to RB0, the signal is supplied by the external device. This may be very useful in the debugging of larger systems where the state of the microcontroller is unknown during a specific event.
How This Works
There's two conditions under which the microcontroller should halt execution during debugging: a user presses the pause button during program execution or a breakpoint is encountered. In the first case, there must be a communication from the computer, to the MCU. In the latter, vice versa. As I am unfamiliar with the ICD 2 communication protocol, I found through experimentation that if a short pulse was applied to both the PGD and PGC lines, that a breakpoint or pause could be emulated. The length doesn't seem too terribly important, as I've had success using pulses from about 250 ns to the hundreds of milliseconds. This is very much a hack, use at your own risk.
A means of providing infinite breakpoints and an additional trigger has been described. The major benefit this additional external trigger provides is a means of halting microcontroller execution without a single comparison in an interrupt handler, this may prove exceptionally useful when debugging complex systems.
Notes on the Example Code
The example code bundled with this document differs from that presented in two ways: configuration bits are set using preprocessor directives; the program loops infinitely until a high signal is read on RB1 (not shown in the schematic). Download example code here.
PIC18F2455/2550/4455/4550 Data Sheet http://ww1.microchip.com/downloads/en/DeviceDoc/39632b.pdf
hlpPIC18ConfigSet MPLAB IDE -> Help -> Topics ->Language Tools -> PIC18 Config Settings