Debugging

From AVR-Eclipse

Jump to: navigation, search

There are multiple ways to debug your AVR application. They fall in two main categories

  • Using a software simulator
  • Using a JTAG connector for on chip debugging

Both methods can be again be divided in two groups

  • Using the Eclipse debugger
  • Using external tools

All methods have their advantages and drawbacks. However they are all based upon gdb, the GNU Project debugger. This means that debugging is client/server based, with the client being the user interface and the server either a simulator or a JTAG interface.

Some external applications for debugging (e.g. AVR Studio, Proteus, VMLab) integrate both the client and the server, so the user will only see the client side, with the server hidden inside the applications.


Contents

Debugging Servers

On the open source side, there are two main gdb servers for AVR development


AVaRICE

AVaRICE acts as gdb server for JTAG connections, so it is an interface between gdb and JTAG hardware. To use in for in-system debugging you also need some hardware to connect your target hardware (with the JTAG port) to your development system.

Currently AVaRICE supports three kinds of JTAG interfaces:

AVR JTAGICE mkII This is the best supported interface, but no cheap clones are available.
  • USB / RS232 Interface
  • Supports JTAG and dW
  • Supports all current AVR processors as well as AVR32 processors
AVR Dragon The Dragon is a low-cost scaled down version of the MkII.
  • USB Interface
  • Supports JTAG, dW, ISP, HV and PP programming modes
  • Does not support all AVR processors (officially max 32k Flash)
AVR JTAG (MkI) The first AVR JTAG interface. Now dated and not much supported by AVaRICE.
  • RS232 Interface (some clones have USB)
  • Supports JTAG only.
  • Does not support all current AVR processors.
  • Many Cheap and do-it-yourself clones available, some with USB interfaces and some with ISP programming mode.

Here are some examples of MkI clones to build yourself. Feel free to add more links

dW = debugWire: a proprietary interface similar to JTAG, but using only one wire (the reset line). Used on some low pin count AVR processors.

Simulavr / Simulavrxx

Simulavr is a open source software simulator to simulate AVR processors. While development has ceased (last release Feb. 2005), it can still be used as it will simulate at least some current AVR processors. However the simulation is incomplete, missing many I/O functionalities and should not be relied upon. Consider simulavr as a toy to get started with debugging, but it should not be used as a real debugging tool.

Simulavrxx is a rewrite of simulavr in C++, which also has been dormant for the last two years, however there has been some CVS activity in early 2008, so it might come under active development again. Although distinct projects, they both share the same homepage and project page.


Debugging with Eclipse

While the AVR Eclipse Plugin currently does not support debugging itself, Eclipse with CDT has all the required tools to debug AVR applications, although it does require some configurations and - as always with Eclipse - there is more that one way to do it.

Debugging AVR applications with Eclipse requires two steps, starting the gdb server and then connecting to the server.

Setup

The following step by step instructions were performed on my development system, consisting of

  • Windows XP
  • Eclipse 3.4.1 with CDT 5.0.1
  • winAVR 20081124rc3 (includes avarice 2.8 and avr-gdb 6.8)
  • AVR Butterfly connected via JTAG cable to an AVR Dragon

I have used two sample applications for the tests.

  • avrtest is a simple test program with an empty endless loop in main(), compiled for the ATmega16 to test simulavr.
  • ButterflyLCDTest is a simple application for the AVR Butterfly, compiled for the ATmega169 to test avarice.

Both were build with an unmodified Debug build configuration. This means they both use the default settings of "Standard debugging info (-g2)" for the debugging level and "stabs" as the debug info format.

Debugging debug settings.png


Optimization has been set to "No Optimizations (-O0)". All other optimization levels will cause output where the actual machine code instructions do not resemble the control flow of the C source code, making C level debugging impractical. Of course you can still debug a optimized program, but be prepared to only step through the disassembly as the C source code will be mostly useless.


As your setup will probably differ from mine so there might be some differences in your experience. However the instructions should be detailed enough to cover those differences.

Starting the gdbserver

The easiest way to start th gdbserver is as an 'External Tool' within Eclipse. Click on the little triangle next to the external tools icon and select External Tools Configurations

Debugginig select external tools config.png

On the External Tools Configuration dialog right click on program and select new. You can then enter the configuration data for the gdbserver as detailed below.

If you do not pass the flash image to the gdbserver on the commandline, you probably want to go to the build tab and deselect the Build before launch option.


AVaRICE

The setup for avarice should look something like this:

Debugging avarice setup.png
Name 
A distinctive name for this configuration
Location 
Use Browse File System... to enter the location of your avarice executable.
Working Directory 
The directory where avarice will write anything to. Except for the occasional core dump this is unused.
Arguments 
The avarice command line arguments. In this example I have used
  • --dragon for the JTAG interface (alternatives are -1 and -2 for a MkI resp. MkII AVR JTAG interface)
  • --ignore-intr prevents avarice from stopping on each interrupt
  • --jtag usb tells avarice I am using the USB port
  • :4242 is the port number.
Take a look at the avarice man page for some other options.


Note that I did not specify --erase --program --file xxx in the arguments to upload a flash image to the target. Instead I use avrdude to upload the project to the target hardware. Two reasons: The upload with avarice is buggy with the AVR Dragon and also because I do not want a dependency on any project for this external tools configuration.

Click on the Run button to save the configuration and start avarice.

Avarice will quit whenever the a debugging session with the Eclipse Debugger is stopped. It has to be restarted for a new session. The Debug view on the debug perspective will show if avarice is still running.

SimulAVR

The setup for simulavr should look something like this:

Debugging simulavr setup.png

Name 
A distinctive name for this configuration
Location 
Use Browse File System... to enter the location of your simulavr executable.
Working Directory 
The directory where simulavr will write anything to. Unused and could be empty.
Arguments 
The simulavr command line arguments. In this example I use
  • --gdbserver to start simulavr in gdbserver mode
  • --port 4242 to make simulavr listen on port 4242 (the same as I use with avarice, so I can use one Debug Configuration for both)
  • --device atmega16 to tell simulavr that it should simulate an ATmega16. Use "simulavr -L" on a command shell to get the (short) list of supported devices.
Take a look at the simulavr man page for some other options.


Note that I did not specify a filename in the arguments to upload a flash image to the simulator. Two reasons: simulavr accepts only raw binary images (see Tips and Tricks on how to create them) and also because I do not want a dependency on any project for this external tools configuration. But in this case you have to use the [[[#GDB Hardware debugging | GDB Hardware debugging]]] configuration to upload the flash image at the start of the debugging session.

Click on the Run button to save the configuration and start simulavr.

Simulavr will continue to run, even when a Debug session is terminated. So it can be used for multiple debug sessions. To stop simulavr go to the Debug view in the debug perspective, right click on the simulavr entry and select Terminate.

Eclipse Debug Configurations

Once the gdbserver is started we can then start the Eclipse debugger. But first we need to configure the debugger. There are two types of debug configurations usable for AVR debugging: C/C++ Local Application and GDB Hardware Debugging. The core debug engine is the same for both. The differences are just in the user interface and in the initial GDB commands to start the remote debugging session. Both configurations are known to work with both avarice and simulavr, so you can test for yourself which configuration works better for you. Below we will describe the setup for both configurations.

But first open the Debug Configuration dialog: select the project to debug and then click on the little triangle icon next to the debug icon and select Debug Configurations...

The dialog should look something like this:

Debugging debug config dialog.png


If the GDB Hardware Debugging configuration type is not shown you do not have this optional featue installed. Start Software Updates... from the Help Menu and add the CDT update site (for Eclipse 3.4 it is http://download.eclipse.org/tools/cdt/releases/ganymede). Then browse this update site and install the Eclipse C/C++ GDB Hardware Debugging optional feature.


Now double click on either configuration type to create a new configuration. If you had a project selected before openeing the dialog the configuration will have a name like "projectname Debug". You might want to adjust the configuration name while you are still testing which configuration is best for you. Use something descriptive like the project name and the type of configuration like "projectname as Local" or "projectname as Hardware debugging with upload".

The first Tab (Main) is the same for both configurations:

Debugging main.png

Project 
If your project is not already shown use the Browse button to select the project to debug.
C/C++ Application 
Click on the Search Project button and select the .elf file from the project. If you are working with multiple build configurations check the Qualifier field to select the right one. If the Program Selection dialog is empty you need to build the project first.

Now continue with the configuration specific settings.


C/C++ Local Application

For the C/C++ Local Application all relevant settings are on the Debugger tab:

Debugging local debugger tab.png

Debugger 
Set this to gdbserver Debugger
GDB debugger 
change this to "avr-gdb". The preselected "gdb" does not work, as it would try to debug the target as an i386.
GDB command file 
delete the preselected ".gdbinit". However, if you still need to upload the flash image to your target (e.g. with simulavr), you need to write a small gdb script and enter its filename here. See below for this.
GDB command set
choose "Standard" or "Standard (Windows)". Don't use "Cygwin" because avr-gdb is not a cygwin application. The differences in the different command sets are minimal and are mainly about the handling of shared libraries, which are irrelevant for avr programming.
Protocol 
leave this at "mi". This is the same as "mi2". "mi1" is an older gdbserver protocol that has no advantages as avr-gdb understands the mi2 protocol.
Verbose console mode 
If you are having problems you can select this option to see the communication between Eclipse and avr-gdb. See #Troubleshooting for more information.


Then click on the Connection tab to configure the communication parameters between avr-gdb and the gdbserver:

Debugging local connection tab.png

Type 
Select "TCP"
Host name or IP address 
enter "localhost" if not preselected.
Port number 
enter the same port number you have entered in the configurations for avarice/simulavr.


Now the configuration is finished. Click on the Debug button and if all is well the debugging session should start and your application should stop at the beginning of your main() function.

If this does not work then take a look at the Troubleshooting section below.


Additional info: For completeness here is a gdb init script to upload a flash image to simulavr. Save this somewhere (e.g. in the project folder as 'gdbinit') and enter the complete pathname to this file in the GDB command file field on the Debugger configuration page. While this gdb init script does work (for me) you are probably better off by using the GDB Hardware Debugging configuration described in the next section.

# make sure simuavr has code to run (it would complain Unknown opcode)
# change the filename as required, but with the name of the build configuration (here: Debug)
file Debug/avrtest.elf

#also don't forget to change the port number if you are using a different one.
target remote localhost:4242
load

GDB Hardware Debugging

For the GDB Hardware Debugging configuration we need to change the settings on two tabs.

Lets start with the Debugger tab. Most options have been set to reasonable defaults by Eclipse. The only options that need to be changed have been marked in the screenshot.

Debugging hardware debugger tab.png


GDB Command
change this to "avr-gdb". The preselected "gdb" does not work, as it would try to debug the target as an i386.
GDB command set
choose "Standard" or "Standard (Windows)". Don't use "Cygwin" because avr-gdb is not a cygwin application. The differences in the different command sets are minimal and are mainly about the handling of shared libraries, which are irrelevant for avr programming.
Verbose console mode 
If you are having problems you can select this option to see the communication between Eclipse and avr-gdb. See #Troubleshooting for more information.
Port number 
enter the same port number you have entered in the configurations for avarice/simulavr.


Next continue on the Startup tab

Debugging hardware startup tab1.png

Reset and Delay (seconds)
Halt 
If you have selected the Generic JTAG Device on the previous page these two settings are ignored and can be either on or off.

Debugging hardware startup tab2.png

Load image
Upload a flash image at the start of the debugging session. The image file can be either an .elf or an.hex, but make sure that you select the right one for the project. Note: This does not work for me and my AVR Dragon, probably due to a bug in avarice. Instead I upload the image with avrdude before starting a debug session.
Load symbols 
There seem to be no advantages to uploading symbols so leave this off.

Debugging hardware startup tab3.png

Set program counter at (hex) 
if not set the gdbserver starts at 0x0000, which is the location of the reset vector. So you probably do not need to set anything here.
Set breakpoint at
Set this to "main" or the name of some other function where you want to stop the initial execution and start debugging.
Resume 
Select this option. If not selected avarice will not execute your application and you need to enter "continue" on the avr-gdb console view to get started.


Now the configuration is finished. Click on the Debug button to save everything and if all is well the debugging session should start and your application should stop at the beginning of your main() function.

If this does not work then take a look at the Troubleshooting section below.


Working with the Debugger

If the debugging session has started all right, then your Eclipse Debug perspective could look something like this:

Debugging debug session all.png


Note that this is a real session debugging an AVR Butterfly with an AVR Dragon through the JTAG interface. The screenshot has been condensed to show many of the Eclipse/CDT Debug features.

BTW, the memory segment shown in the screenshot starts at 0x800020. This is the start of the I/O registers range for AVR microprocessors. So you can see the content of all I/O registers from the Debugger. To find a specific register you have to get its address (e.g. from the AVR Device Explorer view) and add 0x800020 to it. An additional AVR I/O Register view is planned for the next AVR Eclipse Release (2.4).


Caveats

Restart

The Restart toolbar button (restart icon) does not work with avr-gdb. Pressing it will cause the debugging session to end with an error message (Background: Eclipse sends an "-exec-run" to avr-gdb, which causes avrdude to kill the gdbserver and to show a "Don't know how to run." error message.


Here is a workaround to perform a soft reset:

  1. set a breakpoint at main() or any other place you want to stop the execution
  2. in the registers view set the PC register to 0 (PC = Program Counter)
  3. 'Resume' the program

The workaround will cause the processor to resume execution at address 0x0000, the place of the reset vector for all AVR processors. This will re-run the reset program code. Please note that this will not reset the I/O and Control registers. They will remain at their previous state.


Breakpoints and Watchpoints with AVaRICE

AVR processors in JTAG mode have only 3 available hardware breakpoints, two of which can changed to memory watchpoints. In DebugWire mode no hardware break- or watchpoints are supported by the AVR's.


AVaRICE has the ability to use soft breakpoints. These are special instructions written to the flash memory at the required breakpoint address. Once this soft breakpoint is hit, the original content of the flash page is written back. So each soft breakpoint causes at least two flash memory write cycles. While AVR flash memory usually lasts much longer than the guaranteed 1.000 cycles (for older AVR's) you should keep this in mind when working with many breakpoints.

Soft watchpoints in the SRAM are also supported by AVaRICE. But they slow down debugging significantly because AVaRICE then has to single-step every instruction to check the watched memory afterwards. Note that watching a 16-bit value, e.g. a pointer, uses two watchpoints, one for each byte. So if the application flow allows for it, it's probably a good idea to watch only one byte of the 16-bit value for changes (using only one hardware watchpoint)


Harvard Architecture

The Atmel AVR processors have a Harvard architecture (separate code and data address spaces). To distinguish data address 0 (in SRAM) from code address 0 (in Flash memory), the debugger adds 0x800000 to all data addresses. Bear this in mind when examining pointers to flash memory (e.g. pointers to strings).

To make matters even more complicated AVR addresses the code space as 16bit words and the data space as 8 bit Bytes. But avr-gdb only uses byte addresses, so all addresses in code space shown by the debugger must be divided by two to get the real address used by the AVR processor.

Example: a memorydump at address 0x0000 (the reset vector) shows <0c 94 6d 00>. In AVR syntax <0c 94> is opcode for <tjmp> and <6d 00> contains an encoded address to jump to. If you disassemble the section with avr-gdb it outputs <tjmp 0xda> = jump to byte address 0x00da. And if you execute this jump instruction in the debugger it will continue at avr-gdb byte address 0x00da (binary 11011010). Divided by two gives 0x006d (binary 01101101), the word address as the processor sees it.

Fortunately this thing is mostly transparent for you, as avr-gdb is very consistent with its addresses. But this can be an issue if you are comparing the disassembly to a memory dump.


Also note that the first part of the data address space is used to memory-map the CPU registers and the I/O and control registers. The actual SRAM memory starts behind the I/O registers. The size of the I/O register block depends on the AVR MCU type.

Troubleshooting

If the previous instructions did not work for you and you can't get Eclipse to debug your application then here are a few tips for troubleshooting.


First switch on the verbose console mode on the Debugger page of your debug configuration. While you are at it you might as well switch on debugging output for the gdbserver. Add the following option to the respective command line arguments

  • avarice:
'-d' or '--debug'
  • simulavr:
'-G' or '--gdb-debug'

Then start debugging. Here is a complete avr-gdb output for a good debugging session, including the start and a few actions.

Analyzing the avr-gdb debug output

Please note, and this is important:

Because

  • all three involved parts (Eclipse, avr-gdb and the gdbserver) run asynchronously, and
  • avr-gdb will happily continue to run even when the gdbserver has stopped

it is important to scroll the avr-gdb output up a bit to find the real cause for the failure. The end of the log is usually not the cause of the problem.


If you are not familiar with the gdb commands you will need to look at the GDB manual, especially the GDB/MI Interface section of the manual.


Now here are some avr-gdb output snippets for typical failures:


"Could not connect..."
7 target remote localhost:4242
target remote localhost:4242
&"target remote localhost:4242\n"
&"localhost:4242: Es konnte keine Verbindung hergestellt werden, da der Zielcomputer die Verbindung verweigerte.\n"
localhost:4242: Es konnte keine Verbindung hergestellt werden, da der Zielcomputer die Verbindung verweigerte.
7^error,msg="localhost:4242: Es konnte keine Verbindung hergestellt werden, da der Zielcomputer die Verbindung verweigerte."

Sorry for the error message in german, but I am running a german WinXP system and the error message is supplied by the operating system. Translated the error message means "Could not connect because target system refused connection"

This message is shown when avr-gdb cannot connect to the gdbserver. Check that the gdbserver (avarice or simulavr) is running and that the port numbers are the same. Note that even with this failure Eclipse and avr-gdb will continue with the debugging session. The session will fail later with a "the program is not being run" message.


"Don't know how to run"
61-exec-run
61^running
(gdb) 
&"Don't know how to run.  Try \"help target\".\n"
61^error,msg="Don't know how to run.  Try \"help target\"."

Told you not to press the restart button ;-)


"The program is not being run"
13 continue
continue
The program is not being run.
&"continue\n"
&"The program is not being run.\n"
13^error,msg="The program is not being run."

This usually means that the gdbserver is not running (anymore). Either because avr-gdb never connected to the gdbserver or because the gdbserver has shutdown on its own.

In any case, take a look at the avr-gdb debugging output between the

&"target remote localhost:4242\n"

and

&"The program is not being run.\n"

lines to look for other reasons that might have caused the gdbserver to fail. But it is probably more useful to look at the output from the gdbserver to find the reason for the gdbserver failure

You will find this error messages in almost any log where debugging problems exist. This error message is the one to cause Eclipse to abort the debugging session and stop avr-gdb. Again, due to the asynchronous communication between the two programs avr-gdb will continue to log more debugging output before it is shut down by Eclipse.

"info sharedlibrary"
46-data-list-changed-registers
46^done,changed-registers=["26","28","29","30","32","33","34"]
(gdb) 
47 info sharedlibrary
&"info sharedlibrary\n"
48-gdb-exit

This happens if your avr-gdb is 6.4 (released 2005-12-01, [1]), which is still shipped on Debian and Ubuntu. See Gentoo bug 126288. Complain to your distro and build gdb from source.

To test for this bug use GDB's command line and type "info sharedlibrary". This produces:

(gdb) info sharedlibrary
../../src/gdb/solib.c:707: internal-error: TARGET_PTR_BIT returned unknown size 16
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n)

Probably GDB's mi interface does not display this warning. It such case it is not Eclipse CDT's fault in not reporting it to the user.

Harmless error messages

Because the Eclipse/CDT debugger is geared toward the normal gdb application it will send some commands that avr-gdb can not handle. Most of them are ignored by avr-gdb or acknowledged with a harmless error message. Here are a few examples:

6-gdb-set new-console on
&"No symbol \"new\" in current context.\n"
6^error,msg="No symbol \"new\" in current context."
38 info proc
&"Undefined info command: \"proc\".  Try \"help info\".\n"
38^error,msg="Undefined info command: \"proc\".  Try \"help info\"."
40 info threads
&"warning: RMT ERROR : failed to get remote thread list.\n"

Analyzing the avarice debug output

Debug view

To understand the avarice debug output you need to reference some protocols

and for the communication between avarice and the JTAG interface:

  • AVR060 documents the Atmel JTAGICE MkI protocol
  • AVR067 documents the Atmel JTAGICE MkII protocol

With these references you can start analyzing the avarice output. To see the output of avarice in the console view you need to click on the avarice executable in the Debug view. To go back to the avr-gdb output click on the avr-gdb line.


"JTAG ICE communication failed"

Here is an example of an (real life) failure of avarice to communicate with the JTAG device. The JTAG device in this case was a AVRJTAG Mk I clone that seems to have a problem satisfying the valid command sent from avarice.

...
->GDB: 
GDB: <g>

GDB: (Registers)Read 32 bytes from 0x800000
jtagRead 
command[R, 1]: 52 20 1F 00 00 00 20 20 
response:
[...]
JTAG ICE communication failed
91 00 41 
Timed Out (partial response)

Messages like this indicate either a bug in avarice or in the firmware of the JTAG interface. In this example there was also the normal avarice startup message intermixed with the verbose output (replaced by '[...]'). This shows that you have to be careful reading the output.

If you have a problem like this it is probably best to address the problem to the avarice maintainers (Hi Jörg ;-)).

Debugging with external Debuggers

If debugging with Eclipse does not work out for you, you can take a look at the Debugging with external Tools article for some other debugging solutions.

Personal tools