How to Debug your AVR Project with the Atmel-ICE
One of the tools that I valued most in my software development days was the debugger – the ability to step through code to find bugs quickly by tracing the execution path. Nowadays I don’t work on pure software projects any longer – I’ve ratcheted up the complexity by working on AVR projects combining hardware with the software. You’re dealing with this same complexity, so thankfully we have access to a debugger that can help us to step through our microcontroller-based projects. I’m sure that it’s no surprise that the debugger is a physical piece of hardware that connects to your microcontroller in order to track the code execution.
The tool that I currently use is an Atmel-ICE Basic debugger, a combination of great value and functionality. This tutorial is intended to give you an overview of how to debug your AVR projects with the Atmel ICE, focusing on the ATmega328P that I cover in my Nuts & Volts “Beyond the Arduino” series (and have built into my Toadstool mega328 board).
First Time Connections
The first time you connect your Atmel-ICE to your PC, the USB drivers will be installed. Make sure that you have installed Atmel Studio before connecting your ICE, or the drivers will not be available. When you select the Atmel ICE as the tool in the Atmel Studio “Device Programming” dialog, Atmel Studio will check whether firmware on the debugger is up to date – and if needed upgrade it for you. Read more about this here.
Step 1: Atmel-ICE Connections
1.1 Connect the Atmel-ICE to the Target Microcontroller
The ICE uses an interface called debugWIRE to talk to the ATmega328P, although is also able to use aWire, JTAG and SWD which allow you to debug AVR 32-bit and the range of Atmel ARM Cortex microcontrollers.
The Atmel-ICE Basic only comes with one ribbon cable, which is all we need for our purposes here. Connection is really straightforward: connect the one end of the cable to the “AVR” 10-pin connector on the ICE, and connect the 6-pin ISP connector to your board. If you’re using a board with a 6-pin header (such as the Toadstool), then this is a quick plug-in; if you’re connecting to a breadboard then connect the pins in the same order as you do when connecting your programmer.
1.2 Connect the Atmel-ICE to your PC
Connect the USB cable supplied between the ICE and the PC. I have heard that the micro-USB connector on the ICE is not very robust, so I’d suggest leaving that connected and performing any connections/disconnections at the USB-to-PC connection.
1.3 Connect Power to Your Project
Unlike some programmers that are able to provide power to your project, the Atmel-ICE is not able to. You’ll need to power your project separately – and if you’re anything like me you’ll forget to do this, and spend time wondering why you can’t debug your project!
Step 2: Start a Debug Session
IMPORTANT: It it critical that you always end your debug sessions properly – do not skip Step 4 in this process, or may need to use a special high-voltage programmer to recover your microcontroller.
2.1 Select the ICE as a Tool
From the Project menu, select Project Properties and then the Tools tab. Here you need to select the Atmel-ICE and then debugWIRE interface.
2.2 Select the Debug Configuration
It makes sense that your project be configured in Debug mode and not in Release mode. Choose this from the drop-down on the menu bar.
2.3 Start Debugging
This step can get a little complicated, so follow along carefully. When you program your microcontroller using a standard old programmer, you’re using an SPI interface. When you debug a project you need to switch to a debugWIRE interface – it can’t be in both modes at the same time. To switch to debugWIRE mode, you need to enable the DWEN fuse bit – for more on Fuses see this post. Thankfully Atmel Studio helps you to do this, but it can be quite clumsy. Here’s what you need to do:
- Click on the Debug menu, then Start Debugging and Break (or press Alt+F5). You should receive the below error message:
- Click on Yes. You’ll now be in debugWIRE mode but will see the below dialog:
- Follow the instructions by disconnecting and reconnecting the power on the target, and clicking on OK
You should now be in debug mode.
Step 3: Debugging a Project with the ICE
Now that you’re connected to your project using the Atmel-ICE, it’s time to start debugging the project. There are a couple of commands that you need to familiarise yourself with – we won’t go into all the possibilities here, but the following should be enough to get you started.
3.1 Stepping Through Code
The beauty of debugging is that you can execute your code one line at a time – called stepping. You are able to:
- Step Into (F11): This executes the current line of code, and if it is a function call it will drop down into that function so you can step through the function itself.
- Step Over (F10): This executes the current line of code, but will not drop down into a function if the instruction is a function call.
- Step Out (F12): This completes execution of the current function, and then halts again up at the calling routine.
The best way to get comfortable with these is to experiment.
3.2 Setting Breakpoints
If your “F11” finger is getting tired stepping to the section of code you actually want to debug, then breakpoints are here to save you! Program execution halts when it hits a breakpoint, allowing you to continue stepping from that point. Toggle a breakpoint on the highlighted line of code by pressing F9, or by clicking in the grey margin to the left. A red dot in the margin indicates that a breakpoint has been set. To run up to a breakpoint click on the Continue button on the toolbar or press F5
3.3 Monitoring Variables
Now we’re getting to the good stuff – while debugging you can track the values stored in your program variables. There are a few ways to do this:
- Hover over the variable, and a tooltip will appear with the value
- QuickWatch: Press Shift+F9 to look at the value of the highlighted variable in a pop-up dialog box
- Locals Window: This is available at the base of your screen, and shows current available local variables
- Watch Window: The watch window is more powerful, and allows you to keep a permanent eye on the value of a variable (or an expression) as you step through code. To add a variable to the watch window, simply drag it there, or type an expression on a new line.
For more detail on watching variables, I recommend you take a look at this section in the Atmel Studio online documentation. Also be aware of Atmel Studio’s compiler optimisations – variables can “optimised out” of your code, in which case they won’t be available to be examined.
3.4 Ending Your Debug Session
When you’re done with your debugging session, click on the Stop Debugging button on the toolbar or press Ctrl+Shift+F5. You can now make changes to your code, and are ready to initiate another session.
If you have completed all debugging of your project, you should return to SPI mode!
Step 4: Leaving Debugging Mode
Here is another clunky bit of behaviour by Atmel Studio. If you don’t leave debugging mode then your microcontroller will permanently be configured for the debugWIRE interface. This means that you can’t program it using a normal SPI programmer! To leave debugging mode, disable debugWIRE and re-enable the SPI interface you need to:
- Start a debugging session using “Start Debugging and Break”
- Click on the Debug menu, then Disable debugWIRE Mode and Close
I cannot stress the importance of this enough. If you disconnect your debugger, you will no longer be able to program your microcontroller using an SPI interface unless you use a special (and costly) high-voltage programmer.
Wrapping it Up
We’ve only touched on the debugger at a high level – if you would like a more detailed tutorial please drop me a mail or pop a comment below; otherwise experimentation can go a long way. Focus on the buttons on this toolbar:
I hope this helps you to squish more of those bugs!
I’ve just completed my brand new guide Arduino to AVR: Get Started in 3 Steps.
Get it now on Payhip for only $1.65.
Challenge yourself and learn how to gain the flexibility and additional control that the AVR microcontroller offers.