AVR/Arduino Hardware Debugger on the Cheap (part 3)

2/17/2018 - I've made additional improvements to the code to more reliably support targets running at 16 MHz, such as the ATMega328P.  Please get the latest code for my OnePinSerial Library and the  my DebugWireDebuggerProgrammer Arduino sketch at the bottom of this page.  I've also improved the command format for debug mode to that you no longer need to type leading zeros for hex and decimal values.  So, for example, typing "r1=5" is the same as typing "r01=05".

2/18/2018 - IMPORTANT - The OnePinSerial code is now included in the DebugWireDebuggerProgrammer Arduino sketch so you only need to download the file DebugWireDebuggerProgrammer.zip (at the bottom of this page.)  Also, fixed bug in disassembly of conditional relative branch instructions, such as "brne" that displayed incorrect destination address.

2/10/2019 - Fixed error in circuit schematic (1K resistor on LED connects to Vcc) and switched to TP2104N3-G P-Channel FET instead of ZVP3306A.

This is the 3rd installment in a series of articles on my explorations into learning how to use Atmel/Microchip's undocumented hardware debugging interface called debugWire™.  However, if you're new to this topic, please read my older two articles for additional details that I'm not going to cover again in this article:
In this article I'll how show you use one ATMega328P-based Arduino to connect to another, slightly modified ATMega328P-based Arduino and debug it.  However, before I get into that, I'll start by describing some of the problems I ran into while trying to get my debugger code to work with an ATMega328P-based Arduino running at 16 MHz and present new versions of my OnePinSerial Arduino Library and a new version of my DebugWireDebuggerProgrammer Arduino sketch (you can download both of these using links at the bottom of this page.)

Lessons Learned

The difficulty I experienced was in trying to get my OnePinSerial Library to communicate reliably at the higher baud rates needed to debug AVR chips running at 16, or even 8 MHz.  The debugWire interface runs at a speed fixed by the clock speed of the target chip divided by 128.  So, debugging an ATMega328P-based Arduino running at the standard clock speed of 16 MHz, requires OnePinSerial to work at 125,000 baud, which is above the upper limit of what the original library I used as the basis of OnePinSerial, the Arduino SoftwareSerial Library, could support.  However, after making a few tweaks and changes (see the source code for more details), I was able to get OnePinSerial to work rather reliably with a target ATMega328P-based Arduino running at 16 MHz.  Note: these same changes also make debugging an ATTiny85 running at 8 MHz more reliable as well.

Note: the method used to control the bit timing in OnePinSerial, the Arduino SoftwareSerial Library is dependent upon the code generated by the GCC compiler used in the Arduino IDE.  So, be aware that future changes to the GCC compiler might change the code being generated for the critical timing loops in both of these libraries and make serial communication using these libraries less reliable.

I also found that I'd missed implementing several instructions in my disassembler that are used in AVR chips with larger Flash memory sizes, such as "jmp" and "call" as well as instructions like "ldd rn,Y+q" and "std Y+q,rn".  Oddly, it was the unreliable communication I struggled with before fixing OnePinSerial that helped me discover the missing cases for these less used instructions, as I began seeing blank spots in the disassembly where opcodes matching these instructions got generated from garbled flash read operations.  Then, using a helpful table by Jeremy Brandon, I was able to track these down and add cases code to handle them.

New Programmer/Debugger Circuit

In "AVR/Arduino Hardware Debugger on the Cheap (revisited)" I showed a simple circuit I built to help me program and debug ATTiny85 chips.  This circuit directly used pin D8 on the controlling Arduino to switch the target ATTiny85's Vcc pin on and off, as needed.  This worked because the Arduino can source enough current to power up an ATTiny85 chip.  But, this approach is a bit of a hack and is not suitable for supplying power to another Arduino board.  So, I came up with the following, revised circuit to replace it:

Click for Larger View

This version uses a TP2104N3-G, P-Channel FET and a 2N3904 to implement a High Side switch for the target's Vcc pin that's controlled by pin D8.  Setting D8 HIGH causes the 2N3904 to switch on, which pulls down the TP2104N3-G's Gate, which switches it on and supplies Vcc to the target.  Taking D8 LOW switches the 2N3904 off, allowing the 51K resistor to pull the TP2104N3-G,'s Gate to +5 volts, which switches it off and cuts off Vcc to the Target.  Note: the Red LED on the PCB is used to indicate when Vcc is On.

Rather than try to breadboard this circuit, I designed a simple, "mini shield" PCB for it which I fabricated via OSH Park for a cost of $7 for 3 copies of the board.  You can order one here.  Here's an image of the top side of the PCB showing the placement of the different components:

Click for Larger View

Note: since publishing the PCB design I've switched to using a TP2104N3-G, P-Channel FET because it has slightly better specs and is slightly less expensive.  However,  the silkscreen on the PCB still shows this as part as a ZVP3306A.  Either part is fine for this application.

The two connectors on the right side of the board (one labelled "EMU" and the with a "1" inside it) accept cables that are used to connect to external target devices (more on this later.)  The big space in the middle is where you can attach a socket for an ATTiny85 to program or debug   It has extra space around it so you can, optionally, solder in an 8 pin DIP test/burn-in socket with a lower insertion/removal force, but a regular 8 pin DIP socket will work, too.  Here's a list of almost all the components you'll need to fully assemble the board.  You can elect to omit the last 2 items (in italics) on this list, as these are for an advanced option I'll describe in a future article.

 Part # Mouser # Digi-Key # Description#PriceExt
 TP2104N3-G 689-TP2104N3-G TP2104N3-G-ND P-Channel 60V MOSFET 1.60.60
 2N3904BU 512-2N3904BU 2N3904FS-ND General Purpose NPN BJT1.20.20
 270-10K-RC 270-10K-RC CF18JT10K0CT-ND 1/8 watt, 10K ohms thru hole resistor1.13.13
 270-1K-RC 270-1K-RC CF18JT1K00CT-ND 1/8 watt, 1K ohms thru hole resistor2.13.26
 270-51K-RC 270-51K-RC CF18JT51K0CT-ND 1/8 watt, 51K ohms thru hole resistor1.13.13
 0S102011MS2QN1 611-OS102011MS2QN1 CKN9565-ND C&K SPDT On-On Slide Switch1.39.39
 USR1E100MDD 647-USR1E100MDD USR1E100MDD-ND 25volts 10uF 25volts 10uF Electrolytic Cap1.22.22
 LTL-1CHE 859-LTL-1CHE 160-1704-ND T-1 (3 mm) Red LED1.12.12
 SX1100-A 806-SX1100-A S9000-ND 2.54 mm Shunt (jumper plug)1.10.10
 103321-2 571-103321-2 10129378-902001BLF-ND 1x2, 2.53 mm Male Header1.11.11
 61200621621 710-61200621621 732-5394-ND 6 Pin 2x3 Male Shrouded Header (ISP)1.82.82
 2178710-8 571-2178710-8 A120916CT-ND TE 8 Pin Connector (EMU)2.501.00
 2205105-3 571-2205105-3 A123409-ND Cable assembly with TE End Connectors11.361.36

Note: it's possible that some of these components may not be available when you try to order them, so you may need to substitute for equivalent
parts, or order the part from another source, such as Digi-Key.  If you substitute parts, pay attention to the lead spacing on the two transistors, the SPDT switch and the 10 uF capacitor, as the PCB layout is designed for the parts listed above.  The resistors are not critical, so you can use any brand of 1/8 watt resistors as long as they fit into the .2 inch spacing provided.

Attaching the Mini-Shield

To keep the cost of fabricating it as low as possible, the PCB is designed to plug into a standard Arduino using only a subset of the socketed connectors.  The lower left pin on the PCB fits into the socket marked "GND" (skipping the one marked "VIN".)  The lower right side pin plugs into the socket marked "8" for digital pin D8.  Be sure to get the PCB plugged into the proper pends before applying power to the Arduino board.  The rectangle drawn in the image below shows the proper placement of the PCB relative to the I/O pins on a typical, ATMega328P-based Arduino:

Click for Larger View

Using the Mini Shield to Program and Debug an ATTiny85

This new circuit should operate the same as the one shown in my previous article, AVR/Arduino Hardware Debugger on the Cheap (revisited), but you should update to the latest version of my OnePinSerial library and DebugWireDebuggerProgrammer Arduino sketch before using it.  Please use the links at the bottom of this page to download these files.  Note: you may need to remove the prior version of my OnePinSerial library before you can install the new version.  

The steps to program and debug an ATTiny85 are the same as described in my previous article but, for convenience, I'll repeat the step here.  However, 
remember that you cannot use Program mode as long as the DWEN fuse is enabled and you'll be unable to debug code when it is not enabled.  However, you can use a special feature in Debug mode to flip this fuse back and forth, as needed: 

If DWEN Fuse is enabled and you want to Upload new code, follow these steps:
  • Put switch in DEBUG position
  • Open the Serial Monitor (sketch will display menu of commands)
  • Type 'B' and press Send to engage the Debugger
  • Type "EXIT" and press Send to exit the Debugger (this puts the target in a mode where you can change fuse settings)
  • Type '-' (Minus symbol) and press Send to disable the DWEN Fuse
  • Type 'F" and press Send to verify DWEN fuse is disabled
  • Move switch to PROGRAM position (good idea to also press the RESET button on the Arduino)
  • Verify the Arduino IDE is configured properly to compile and upload to your target device
  • Compile and upload your code
If DWEN Fuse is not enabled and you want to Debug your code, follow these steps:
  • Put switch in DEBUG position
  • Open the Serial Monitor (sketch will display menu of commands)
  • Type '+' (Plus symbol) and press Send to enable the DWEN Fuse
  • Type 'B' and press Send to engage the Debugger
If DWEN Fuse is already enabled and you want to debug some more, follow these steps:
  • Put switch in DEBUG position
  • Open the Serial Monitor (sketch will display menu of commands)
  • Type 'B' and press Send to engage the Debugger

Using the Mini Shield to Debug another Arduino

The connector the PCB just to the right 8 pin DIP socket is wired to match the ISP (In-System Programming) connector (sometimes marked ICSP) found on most ATMega328P-based Arduino boards.  You'll need a cable like this to connect the Mini-Shield to the Arduino you want to debug.  The connectors on the cable are both keyed with notch.  The matching connector on the PCB is also keys, so it will only fit one way.  However, the ISP connector on most Arduino boards is only a set of 2x3 male header pins, so you'll need to look for a marking on the board near this header that shows either a dot, or a "1'" to indicate the location of pin one.  The cable should have a red stripe on one side that also indicates which side of the connector has the matching pin 1 connection, so align this stripe with the pin 1 marking on the Arduino board when you connect the cable.

Note: Some Arduino boards may not contain the a 2x3 male header where the ISP connector is marked, so you may need to solder one onto these boards.  Mouser part #649-68602-406HLF, or Sparkfun PRT-12807 should work for this, or a 2x3 section from a strip of 2 wide breakaway header.

Important: Do not apply power to the target Arduino, or leave the target Arduino's USB connection to your computer.  The Mini Shield and the DebugWireDebuggerProgrammer sketch need to be able to switch the power to the target (Vcc) on and off in order to perform some of the control functions.  Also, the ZVP3306A P-FET used to switch Vcc on and off can only source about 160 mA, so don't try to debug systems that might draw more than this amount of current.  If you need more power than this, you could try replacing the ZVP3306A with a TP0604N3-G, which can switch up to 400 mA, but this is close to the 500 mA you can safely draw from the controlling Arduino if it's powered though its USB connection.

Caution: The Arduino UNO board actually has two (2) ISP connectors.  One connects to the ATMega328P and the other connects to a ATMega16U2 that's used as the board's USB to serial converter.  You should use the one that connects to the ATMega328P, which is located near the bottom of the board, as shown below:

Modifying an Arduino UNO so it will work with debugWire

Unfortunately, the basic design of a typical Arduino board throws up one roadblock we need to solve before we can use the debugWire interface.  The Arduino uses the RESET pin on the ATMega328P in a tricky way in order to upload code.  To understand this, take a look at the following schematic, which shows the RESET circuit used on the Arduino UNO:

The combination of the 100nF capacitor and the 10K resistor connected to +5 volts forms what is called an RC Differentiator circuit.  When the Arduino IDE connects to the board to upload code, the DTR output pin on the ATMega23U2 (used as the USB interface for the UNO) transitions from HIGH to LOW.  This momentarily pulls the ATMega328P's RESET pin LOW, thus forcing the ATMega328P to restart and check for an upload from the IDE.  Unfortunately, if left installed, the 100nF capacitor will introduce a capacitive load on any signal we we want to send to the RESET pin, thus making it impossible to use the debugWire protocol to control the ATMega328P.

Fortunately, some newer Arduino boards, such as the UNO, include a simple way to disable the 100nF capacitor by routing the signal though a set of pads that are linked by a trace that you can cut, as shown in the diagram above.  These two pads and the link between them are labelled "RESET EN" on the Arduino UNO, as shown below:

You should be able to use a sharp, hobby knife to cut this thin trace, but be careful not to cut any other other traces, otherwise you might render the board unusable.  Be sure to use a continuity tester to verify the trace is cut.  Note: you'll need to restore this connection before you can upload code to the board.  One way is to use your soldering iron to create a solder bridge between the two pads.  Or, for a more permanent solution, you might be able to solder in a small, SPDT switch across the pads.  Or, perhaps solder a pair of wires to the pads and route them to another location on the board where you can use epoxy, or superglue to attach a switch, or a jumper.

Important: because the Arduino UNO has a 10K "pull up" resistor connected between RESET and +5 volts, you need to remove the PU jumper on the Mini Shield which will disconnect its 10K pull up resistor.  This resistor is only needed when programming and/or debugging an ATTiny85 plugged into the 8 pin DIP socket on the Mini Shield.  Note: to keep from losing the jumper, simply plug it into one of the pins of the two pin header.

Using Other Types/Makes of ATMega328P-based Arduino Boards

Some 3rd Party Arduino Compatible boards that are based on the design of the UNO, such as the Adafruit METRO 328 also contain pads with a trace you can cut whereas others, such as the Sparkfun RedBoard do not.  Others, such as the Arduino Mini, do not have an ISP connector or, like the Arduino NANO, have an ISP connector, but do not have an obvious trace that can be cut to disconnect the 100nF capacitor and, worse, have a 1K pull up resistor instead of a 10K pull up resistors.  And, finally, some such as the Arduino FIO, are designed to run at 3.3 volts rather than 5 volts.  While it's still possible to the debugWire interface on some of these boards, it requires some circuit surgery that's not as easy to undo when you need to upload code again.  For reference, here's a list of boards that are designed with a cuttable link, an ISP connector, use a 10K pull up resistor and run at 5 volts:
Caution: there are numerous copycat clones of the Arduino UNO that do not include pads with a cuttable trace.  While it's not impossible to modify these boards so use can use the debugWire interface with them, you'll have to figure out the circuit mods yourself.

You can also use the debugWire interface on 5 volt versions of the Arduino Mini, or Pro Mini.  But, you'll have to unplug the FTDI adapter from the board, first.  Unplugging the FTDI adapter leaves the 100 nF capacitor floating on one end, which should nearly eliminate any capacitive load.  However, as the Arduino Mini and Pro Mini do not have ISP connectors, you'll have to connect the 6 pins from the end of the ISP cable to different locations on the board using the connections on the edge of the board, like this:

Click for Larger View

No debugWire for Arduino Leonardo or other ATmega32U4-based Boards

Unfortunately, Arduino boards based on the ATmega32U4, such as the Arduino Leonardo, Arduino Micro, or Arduino Pro Micro, do not support the debugWire interface, so you can't use DebugWireDebuggerProgrammer with them.  The ATmega32U4 is designed to use another, JTAG-based interface to do debugging.

New Command Options

I've added a few new commands to DebugWireDebuggerProgrammer Arduino sketch as well as a menu that lists them.  So, when you open the Serial Monitor window when running the latest code, you should see this:

 F - Identify Device & Print Fuses
 + - Enable debugWire DWEN Fuse
 - - Disable debugWire DWEN Fuse
 8 - Enable CKDIV8 (divide clock by 8)
 1 - Disable CKDIV8
 B - Engage Debugger

If the DWEN fuse is enabled, you'll only be able to use the 'B' command to invoked the debugger.  But, you can use the same command sequence listed above in the "Using the Mini Shield to Program and Debug an ATTiny85" section to disable, or enable the DWEN fuse, as needed.  In addition, I've added an addition set of commands to enable, or disable another fuse called CKDIV8 that can slow the clock speed of the target Arduino device by dividing it by 8.  So, if you're having trouble using DebugWireDebuggerProgrammer with an Arduino running at 16 MHz, you can enable this fuse to make to make it run at 2 MHz, instead.  You can't change this fuse while debugWire is active, but you can use the same command sequence used to change the DWEN fuse to disable or enable the CKDIV8 fuse.

In debug mode, you can now type "HELP and press Send to print out a list of all the commands the debugger supports, like this:

Debugging Commands:
  HELP          Print this menu
  REGS          Print All Registers 0-31
  Rdd           Print Value of Reg dd (dd is a decimal value from 0 - 31)
  Rdd=xx        Set Reg dd to New Value xx (dd is a decimal value from 0 - 31)
  IOxx          Print Value of I/O space location xx
  IOxx=yy       Set I/O space location xx to new value yy
  IOxx.d=b      Change bit d (0-7) in I/O location xx to value b (1 or 0)
  SRAMxxxx      Read and Print 32 bytes from SRAM address xxxx
  SBxxxx        Print Byte Value of SRAM location xxxx
  SBxxxx=yy     Set SRAM location xxxx to new byte value yy
  SWxxxx        Print Word Value of SRAM location xxxx
  SWxxxx=yyyy   Set SRAM location xxxx to new word value yyyy
  EBxxxx        Print Byte Value of EEPROM location xxxx
  EBxxxx=yy     Set EEPROM location xxxx to new byte value yy
  EWxxxx        Print Word Value of EEPROM location xxxx
  EWxxxx=yyyy   Set EEPROM location xxxx to new word value yyyy
  CMD=xxxx      Send sequence of bytes xxxx... and show response
  FWxxxx        Print 32 Word Values (64 bytes) from Flash addr xxxx
  FBxxxx        Print 64 Byte Values from Flash addr xxxx and decode ASCII
  LISTxxxx      Disassemble 16 words (32 bytes) from Flash addr xxxx
  RUN           Start Execution at Current Value of PC (use BREAK to stop)
  RUNxxxx       Start Execution at xxxx (use BREAK to stop)
  RUNxxxx yyyy  Start Execution at xxxx with a Breakpoint set at yyyy
  RUN xxxx      Start Execution at Current Value of PC with breakpoint at xxxx
  BREAK         Send Async BREAK to Target (stops execution)
  STEP          Single Step One Instruction at Current PC
  RESET         Reset Target
  EXIT          Exit from debugWire mode back to In-System
  PC            Read and Print Program Counter
  PC=xxxx       Set Program Counter to xxxx
  SIG           Read and Print Device Signature

Wayne Holder,
Apr 2, 2018, 8:03 PM