Basics of Design CC Blog Research & Design Hub

Evaluation of Debugger on Arduino IDE V2.0.4

Written by Aubrey Kagan

Noticing a lack of available materials on the Arduino Debugger, I took it upon myself recently to draft something of an introductory “user manual” for this software. Hence, this article!

  • How can I use the Arduino IDE v2 debugger?
  • What are some benefits of the Arduino debugger?
  • What are some drawbacks of the Arduino debugger?
  • Arduino IDE V2 Debugger

I recently joined a maker space in order to have access to their equipment for a hobby project I’m working on. The project has taken a turn and it looks like I’m going to need either a servo motor or some robotics, so it was opportune when one of the maker organizers put on a series of three presentations on the Arduino Integrated Development Environment (IDE) v1 and the Arduino UNO. As part of the discussions, the presenter showed two or three YouTube videos that demonstrated simple aspects of interfacing the Uno board with external devices, like a pushbutton switch. There were so many blatant errors that I was forced to put my hand up and correct them.

Me and my big mouth! I won’t say that I was volunteered to run an Arduino group, but it wouldn’t be far from the truth. The idea was that there would be a presentation every month, followed by a discussion, workshop, and anything else that might arise.

I’ve been in the electronics business since 1976, before there were even assemblers, to say nothing of compilers or any form of debugging. I clearly remember the old times, and believe me, when it comes to microcomputer programming and testing, those were not the “good ol’ days.” It struck me that the Arduino Uno/IDE v1 was not that far removed from those times, compiler notwithstanding. Any debugging was based on implied observations. You can only activate I/O pins to indicate execution of portions of code or log some text to the internal IDE monitor. I had no intention of reliving my initiation into electronics.

I discovered that there was a recent upgrade to Arduino IDE v2, which included a debugger that worked with a different microcontroller (MCU) within the Arduino family, including the Arduino Zero board. The debugger required some additional hardware for interfacing, but one option, the Atmel Embedded Debugger (EDBG), is included on the Arduino Zero board. It adds to the cost of the board, but there are knockoffs without the EDBG, so that you can develop on the Zero and then download to the cheaper board when development is over. I decided that debugging in the newer environment would be the topic of my first presentation.

I started research on the Arduino Debugger but could only find the basic description of its operation [1] and one forum thread about a breakpoint problem. I experimented with this debugger, and it has an impressive array of features that resemble those in other debuggers. Unfortunately, some of those features were problematic, either because the programming is incomplete, or there is a flaw in the programming. I thought I would write a “user manual” for the attendees of my presentation. While I was preparing it, it occurred to me that there might be a wider audience, and perhaps my criticism might lead to improvements, hence this article.

The words “debugger,” “debug,” and “bug” have contextual meanings and are used with such gay abandon that I thought I ought to define their usage in this article. A “debugger” is a combination of hardware and software that allows the user to stop and start the operation of the target MCU both at random and specific points during the execution of the software. The debugger also enables the inspection and modification of variables. This combination allows the user to analyze the program flow and correct errors that are embedded in the software. “Debugging” is the process of using the debugger, and a “bug” is an error in the user code.

SETUP

To start, install the SAMD21 Core for MKR boards. You can find a link to Arduino’s instructions for this task on Circuit Cellar’s Article Materials and Resources web page [2]. Next, connect the Arduino Zero to a USB port and listen for the audio tone indicating recognition. Again, head to the Article Materials page for an Arduino link that identifies the location of the programming USB port [3].

Start the Arduino IDE with an existing program or a blank sketch that resembles Figure 1. Each time you start the debugger, verify by checking under the Tools menu that the board selected is the “Arduino Zero (Programming Port).” If not, drill down to select that board. The selection is confirmed in the box identified as “D” in Figure 1.

FIGURE 1
Arduino IDE with a sketch uploaded and relevant controls highlighted
FIGURE 1
Arduino IDE with a sketch uploaded and relevant controls highlighted

Ensure that the correct COM port is selected by clicking on the Tools menu and looking at the Port line. Under the Sketch menu, ensure that “Optimize for Debugging” is checked.

CODE

The program I have written is a trivial sketch to try and help understand the features of the debugger. It simply increases a global variable iUtility from the value of 0 to 65,535 (16-bit unsigned integer), after which it rolls over to 0. This carries on ad infinitum. The program will flash the onboard LED once every second, but the LED is only off for 125ms while it is on for 875ms. The three least significant bits of iUtility increment from 0 to 7 continuously, and the program looks for when all three bits are 0, which happens for 125ms during the 1-second cycle. If the three bits are 0, the LED is turned off. In any other case, the LED is turned on. For every path through the loop, the process waits 125ms, which admittedly is rather poor programming practice since the program could be doing something else instead of just hanging around waiting for time to pass. This is just for a simple program.

Rather than simply incrementing iUtility, I chose to create a function (iAddOne) that increases the value of the parameter passed to it and returns the increased value. Again, this is to help understand the features of the debugger. The code from Figure 1 is shown magnified in Figure 2. The code is included in the ShowDebug.ino Arduino sketch on
Circuit Cellar’s Article Materials and Resources web page.

FIGURE 2
The code for the simple program used to showcase the Arduino Debugger
FIGURE 2
The code for the simple program used to showcase the Arduino Debugger
START DEBUGGING

One of the issues I have with the Arduino IDE v2 Debugger is that it allows you to modify the code even when the debugger is running, so there can be a mismatch between the code on the screen and the code that is being executed, as well as some weird issues like breakpoints in locations different from where they were set. All this is to say that it’s good practice to compile the program before starting a debug session. Compilation is invoked by clicking on the check mark on the top left of the screen (button A in Figure 1).

You can start debugging by clicking on the Start Debugging icon (button C in Figure 1), to the right of the compile icon. Although the lower icon (E in Figure 1) also claims to start the debugging, it has a different function and, pending further investigation, should be avoided. Buttons E, F, and G in the bounded section of Figure 1 are all puzzling and will be discussed later in the “Threads” section of this article.

Button H in Figure 1 turns on the Debug Console beneath the program if it has not already been opened. Closing the debug window is a function on the Debug Console itself.

Running ahead a little, if the program is stopped during execution of the code included in a library, the associated code will appear in a tab, like the “delay.c” and “main.cpp” tabs in Figure 1 (labeled S and T in the figure). The tabs normally become noticeable after the first time the user program has been run. Once open, that tab must be manually closed or will always appear every time Arduino is invoked for a given sketch. It’s easy to close by clicking on the “x” on the right side of the tab.

A consequence of inadvertently invoking the lower “Start Debugging” (item E in Figure 1) is that you may end up with a duplicate source file, an artifact that is impossible to get rid of as shown in Figure 3. There is a further disadvantage in that the lower “Start Debugging” (item E in Figure 1), is near the run/stop icon (item K in Figure 1) and is easily confused with the continue icon, with irritating consequences like the artifact just mentioned.

FIGURE 3
Duplicate source file, and impossible to get rid of
FIGURE 3
Duplicate source file, and impossible to get rid of

Unlike all the other debuggers that I have ever used, the Arduino Debugger begins execution of the user program immediately. I could think of some reasons why I think this should not be, but in truth, it’s probably that old habits die hard.

BREAKPOINTS

A breakpoint stops the execution of the user program before the line chosen as the breakpoint. A breakpoint is set by clicking to the left of the line number; a brown dot indicates its establishment. You can see one such breakpoint on line 7 of Figure 2. One of the methods to clear a particular breakpoint is to click over the existing breakpoint dot. We will get to other methods shortly.

There is a flaw in this version of the debugger. It must be paused before placing the first breakpoint. If not, the visibility of the breakpoint dot is irrelevant, and the breakpoint will stop the code at the breakpoint’s original placement until the IDE is exited and restarted. Since the code starts immediately, you need to establish a habit whereby you clear all the breakpoints before invoking the debugger, and then the first thing you do on starting to debug is to pause the code by clicking on button K in Figure 1. Thereafter you can place breakpoints without concern as to whether the processor is running or not. Note that any breakpoints that exist at startup, irrespective of if it was the reason for the debugger break, will cause the same problem.

An alternative approach is to set and leave a breakpoint in the setup code as in line 7 of Figure 2. All other breakpoints must be cleared before invoking the Arduino Debugger. In this way, every time the processor is reset, execution will stop at line 7, allowing you to prepare for the running of the program and thereby solving two of my concerns in one shot. That breakpoint can even be set before the debugger is invoked. Unfortunately, this approach does sacrifice one of the four allowable breakpoints, which we will discuss shortly.

Since this is important, I will repeat it. Any breakpoint that exists at startup (even multiple breakpoints) will cause the same problem. Make it a practice to clear all breakpoints before closing or starting the Arduino Debugger, apart from my suggestion of the breakpoint in the setup code. Breakpoints are preserved on exiting the IDE and restored on restarting the sketch.

Start the execution of the user program, if it’s not already running, by clicking on the continue/pause button—button K in Figure 1. If the program is already executing, button K is a pause symbol (two vertical parallel lines), as pictured in Figure 1. If the user program is paused, the icon on the continue/pause button changes to the one seen as button B in Figure 4. Clicking on the continue/pause button will start execution from the place where it was paused. Verify that the onboard LED flashes.

FIGURE 4
Setting a breakpoint and halting operation
FIGURE 4
Setting a breakpoint and halting operation

Staying with Figure 4, if the ShowDebug.ino tab is not selected, click on it now. Let’s establish a breakpoint by clicking in the breakpoint column to the left of line 22. The program screeches to a halt, indicated by the five-sided figure surrounding the breakpoint dot symbol shown at line 22 indicated as A in Figure 4. The five-sided figure represents a pointer to the next line that will be executed.

Click the Run/Pause button (B in Figure 4) to continue operation. Note that execution stops at the breakpoint again. Because it’s a loop, this will go on and on.

Hover the mouse over any occurrence of the iUtility variable (E in Figure 4) when the user program execution is paused. The value that pops up is that variable’s current value. It can be shown in decimal or hex notation, and it can be toggled by right-clicking on the Global entry of the VARIABLES section (actually any of the sections) on the left of the screen (C of Figure 4) and selecting either “Enable Hex Mode” or “Disable Hex Mode.” Unfortunately, this is a global setting, so you cannot have some variables in decimal and others in hex at the same time. I will further discuss variable values later in this piece.

Clear the breakpoint by clicking the brown dot to the left of line 22, and continue execution of the code. Notice that the processor now continues without breaking.

Pausing execution by clicking on the Run/Pause button will stop execution at some random spot. If the program is not performing as expected, you can examine the location of the code to see if the program has “locked up.” You can set a breakpoint and continue, or simply continue with the execution.

Now, set a breakpoint at line 26 and start execution. The program only executes this line every eighth time through the program loop. The program should halt at the breakpoint. Next, set a breakpoint at line 23, leaving the breakpoint at line 26 untouched. Resume running the program every time the program encounters a breakpoint. Start counting the number of times it hits the breakpoint at line 23 before it hits the breakpoint at line 26. It should break seven times at line 23 before it executes line 26 on the eighth time. This indicates that your program is executing correctly.

I’m not sure how many breakpoints can be set, but it appears to be at least four. Although the IDE appears to allow more than four, exceeding four generates an “Exception has occurred” message when the program resumes execution, and the phantom breakpoint problem reappears. You must close the IDE and start again to get back to normal operation.

I’ve noticed that sometimes the program seems to break one instruction past the breakpoint. At this point, I have no idea if this is a finger problem of my own making (like inadvertently touching the return button and modifying the source code) or a flaw in the software, and I cannot duplicate the problem consistently. My only solution is to exit the IDE and start from scratch.

Notice on the lower left-hand side of the IDE is a “BREAKPOINTS” window (D in Figure 4), and that each breakpoint appears in this window. On the left side of each entry is a checkmark in a blue square (A in Figure 5). Notice the line number on the right-hand side of each entry indicating which breakpoint it is identified with.

FIGURE 5
Breakpoints listing
FIGURE 5
Breakpoints listing

Clicking on the checkmark disables the breakpoint. The breakpoint is left in location and can be re-enabled by clicking on the blue box again. The color of the breakpoint dot changes from brown to gray to indicate a disabled breakpoint (this may depend on the IDE theme). This feature can be useful in enabling and disabling a breakpoint in a “distant” part of the code, without searching the code and finding it again. It appears that as long as there are only four enabled breakpoints when the user program resumes you can have more breakpoints listed, but I have no idea of the maximum number.

When the mouse hovers over the top righthand corner of the BREAKPOINTS window, three icons appear, marked B, C, and D in Figure 5. B allows you to add a “Function Breakpoint,” although I am not sure how a Function Breakpoint differs from a regular breakpoint, nor how you go about adding a breakpoint using this method. Item C will enable/disable all breakpoints simultaneously. You should remain aware if it has been activated (all breakpoints disabled) because it is an overriding and latched function. Setting a new breakpoint with this option enabled will establish a disabled breakpoint. The setting is preserved through IDE shutdown. D will clear all breakpoints.

Right-clicking on any breakpoint entry either in the breakpoint window or on the dot in the breakpoint column provides the ability to clear/disable the individual breakpoint. It’s also possible to edit the breakpoint by right-clicking on any breakpoint entry either in the breakpoint window or on the dot in the breakpoint column. On selecting Edit, a line pops up over the code with a dropdown menu as seen in Figure 6. Clicking on one of the three options will generate a description of the selection in the line to the right of the drop-down box. Note that the <Esc> key will allow you to exit without changing anything.

FIGURE 6
Editing breakpoints options
FIGURE 6
Editing breakpoints options

Expression option: The Expression setting enables the breakpoint every time the entered expression is true. Let’s say we want the program to pause every time the variable iUtility is 0. Delete all breakpoints. Set a breakpoint at line 22. Right-click on the breakpoint dot and select Edit Breakpoint. Select the Expression option from the drop-down menu and in the line to the right, enter (iUtility & 0x0f)==0 followed by <Enter>. Notice the use of C notation. The IDE is not smart enough to autocomplete the variable and cannot detect an error in the expression. The solid breakpoint dot changes to a circle with a small line in the middle.

Allow execution of the user program to continue until the breakpoint is activated. Note that at each pause, the four least significant bits of the variable value are 0.

Hit Count option: The Hit Count setting allows a breakpoint when the line has been executed N times. Delete all breakpoints. Set a breakpoint at line 30 and one at line 34. Right-click on the breakpoint dot of line 34 and select Edit Breakpoint. Select the Hit Count option from the drop-down menu and in the line to the right, enter the number 3 followed by <Enter>. The solid breakpoint dot changes to a circle with a small line in the middle.

Allow execution of the user program to continue. Count the number of times the breakpoint at line 30 is encountered before the breakpoint at line 34 is encountered. It should be three times. There appears to be a persistence and/or value problem with this breakpoint setting after the first time it is encountered, and I cannot find any consistency, but it does work for the first time.

Log Message option: The description that appears on the right of this option is “Message to log when breakpoint is hit. Expressions within {} are interpolated. ‘Enter’ to accept, ‘esc’ to cancel.” If you enter a message within quotes—for instance, “breakpoint reached”—this message will appear on the Debug Console if it is visible (button H in Figure 1) every time the breakpoint is encountered, but the micro will not stop.

I am unsure what “expressions within {} are interpolated” means. When I tried to enter some test expressions to see the effect, it produced a diamond shape in the breakpoint margin and the whole system froze, requiring exit of the debugger state. Given all the other debugging capabilities, I am not sure what benefit this feature offers and I would love to see some examples.

STEPPING

Aside from running from breakpoint to breakpoint, the debugger also allows you to single step through the program, one instruction at a time. There are a series of buttons in the DEBUG window at the top left of the IDE (Figure 1). As we have seen the Run/Pause function is controlled by button K Figure 1.

Clear all the breakpoints and resume the execution of the user program. Place a breakpoint at line 30. Once the program has halted at line 30, observe the value of the variable iUtility by hovering over an instance in the listing. Click the step-over button (button L in Figure 1). Note the five-sided program pointer is now pointing at line 33. Check the value of iUtility now, in the same way as before, and see that it has increased by one.

Click the Step-Over button again and note that the 5-sided pointer is now at line 35, which is the end of the loop. Resume the execution by clicking the Run/Pause button. The program should halt once again at line 30. This time, click on the Step-Into button (button M in Figure 1). Note that this takes you into the iAddOne function. If you hover over the local variables (iI and iNumber) you can see their values.

You could step over the next instructions using either Step-Over or Step-Into, but if you are satisfied with the operation of the function, you could click on the Step-Out button (N in Figure 1), which will return you to the calling step of the program.

— ADVERTISMENT—

Advertise Here

If you chose to step through the end of the main program loop, the debugger seems to get lost. But this is nothing too problematic, and can be cured by simply clicking on the Run button.

THREADS

The Arduino debugger appears to offer support for “threads,” although there is no explanation as to what these threads are or how to define them. As far as I’ve been able to establish, to date the Arduino IDE does not support a thread structure, but there are some user-provided libraries that will approximate the approach. There are also some modern processors that have multiple cores. Perhaps that is what is meant. In either event, until we can figure out precisely what is going on, I would recommend avoiding these options entirely.

The drop-down menu (F in Figure 1) to the right of the Start Debugging button (E in Figure 1) allows you to add a configuration, but selecting it introduces a new boilerplate source file and provides no simple answers. It seems to me that you would add a configuration while coding, not while debugging. The button with a gear icon (G in Figure 1) appears to duplicate this function. Perhaps this is an undocumented/incomplete feature of IDE2 that will allow the creation of threads. We can but hope.

If you click (don’t do it!) on the Start Debugging button, it invokes a second instance of the existing program shown in the THREADS window of the IDE, and perhaps creates a second tab of the program as described above in the Start Debugging section. I cannot find any way of deleting the second instance or even identifying which instance is which. It may make sense if there were already pre-defined threads listed in the drop-down menu. Clicking the Reset Device button (J in Figure 1) restarts the processor with a result very similar to clicking the “Start Debugging” button (E in Figure 1)—not what I would expect.

OTHER BUTTONS

The Restart button (P in Figure 1) seems to reset the micro and begins execution again. This one I understand. The Stop button (Q in Figure 1) stops the debugging process, allowing you to edit the source file and start the debug process again.

The right-pointing arrowhead (button H in Figure 1) moves the cursor to the Debug Console. Since this version of Arduino and SAMD21 processor allows for a separate USB port, I assume that the communication with that channel would be managed in this way.

VARIABLES

We have seen that it’s possible to view the contents of a variable by hovering over its name. But wait, there’s more! It’s also possible to view the contents in the VARIABLES window (C in Figure 4). There are four categories of variables, as can be seen. More advanced programming can investigate and even change the values of the microcomputer’s registers. However, the variables that are part of the program will appear as Local, Global, or Static, depending on the declaration in the code.

You can expand each category to view individual variables by clicking on the right-pointing arrowhead next to the category. Figure 7 shows the Global variables. If you scroll down the list, you’ll come to our iUtility variable along with its current value. You can see how many global variables the compiler generates. I think I would have preferred it if they were separated from the user variables.

FIGURE 7
Changing the value of a variable
FIGURE 7
Changing the value of a variable

If you right-click on the variable name in the VARIABLES window, it is possible to set the value to whatever you like. Beware: there are no checks to prevent you from changing the value to something illegal like a number greater than 65,535 for a 16-bit number.

You can view and change the value of the variables for the other categories of variables as well. When the program is stopped within a function, the local variables will be accessible.

Of course, you can change the radix from hex to decimal and vice versa at any time. When entering a variable value, the debugger will accept decimal or hex (with the “0x” prefix) without consideration of the display radix.

WATCH

You can group the variables you want to monitor in one place, the WATCH window. To add a variable, place the cursor over the right-hand side of the WATCH bar and three buttons appear as seen in Figure 8. To add a watch, click on button X; to collapse all, use button Y (I don’t know what this means, and I don’t know what it does); and to get rid of all the watches, use button Z.

You can add more than just a variable name—you can also add an expression. For instance, you could enter iUtility & 0x07 and just the three least significant bits would be represented. Beware that there is no autocomplete of the variable name and no check to see that the variable entered (which, remember, is case- and spelling-sensitive) exists. Figure 9 shows three such expressions.

FIGURE 8
Creation of Watch Settings
FIGURE 8
Creation of Watch Settings
FIGURE 9
Different watch settings
FIGURE 9
Different watch settings
SUNDRY

There are three more windows on the left-hand side of the IDE: the CALL STACK, CORTEX PERIPHERALS, and CORTEX REGISTERS. These are for advanced programming well beyond the scope of this report (and my capabilities).

Most of the registers in the CORTEX REGISTERS are the same as those in the VARIABLES | Registers section, except that in this section they are only visible with the decimal radix—mostly. There are one or two levels that are in hex. I don’t know why.

Right-clicking on any of the window separation cross bars with the window title, such as CALL STACK, will allow you to hide or make visible any window you choose.

CONCLUSION

Arduino IDE v2 is an ambitious project, and has made admirable progress toward a complete debugging environment. It will take a real project to determine if the idiosyncrasies of the Arduino Debugger are merely annoyances or major stumbling blocks. In either event, I believe the software could do with more development and improvement. I hope that my article will help the beginners amongst you to understand and use the Arduino Debugger and introduce you to the wonders of 21st-century debugging. 

REFERENCES
[1] Debugging with the Arduino IDE 2.0: https://docs.arduino.cc/software/ide-v2/tutorials/ide-v2-debugger
[2] Installing the SAMD21 core for MKR boards: https://docs.arduino.cc/software/ide-v1/tutorials/getting-started/cores/arduino-samd
[3] Arduino Zero: https://store-usa.arduino.cc/products/arduino-zero
[4] List author’s MCU blogs, with links: http://bit.ly/2m26MJB
[5] List of author’s writings on Using Microsoft Excel in Electronics, with links: http://bit.ly/2mv8W0z

RESOURCES
Arduino | www.arduino.cc

Code and Supporting Files

PUBLISHED IN CIRCUIT CELLAR MAGAZINE • AUGUST 2023 #397 – Get a PDF of the issue

— ADVERTISMENT—

Advertise Here

Keep up-to-date with our FREE Weekly Newsletter!

Don't miss out on upcoming issues of Circuit Cellar.


Note: We’ve made the Dec 2022 issue of Circuit Cellar available as a free sample issue. In it, you’ll find a rich variety of the kinds of articles and information that exemplify a typical issue of the current magazine.

Would you like to write for Circuit Cellar? We are always accepting articles/posts from the technical community. Get in touch with us and let's discuss your ideas.

Sponsor this Article
Engineering Manager at | + posts

Aubrey Kagan has worked in electronics for more years than he cares to remember. He is currently Engineering Manager at Emphatec, an industrial electronics design house in Markham, Ontario. He has written many articles for Circuit Cellar over the past 25 years as well as a book Excel by Example based on three of those articles. Aubrey was one of the “notable contributors” interviewed in Circuit Cellar’s 25th Anniversary issue. He has also published several design ideas as well as numerous blogs covering many aspects of electronic design. You can find a list and links to more of his publications on the Circuit Cellar article materials webpage. He can be contacted at akagan@emphatec.com.

Supporting Companies

Upcoming Events


Copyright © KCK Media Corp.
All Rights Reserved

Copyright © 2024 KCK Media Corp.

Evaluation of Debugger on Arduino IDE V2.0.4

by Aubrey Kagan time to read: 19 min