PlatformIO Community

Getting started with Debugging

Hi Guys,

Hope you can give me some guidance, as I am currently trying to setup debugging. But first things first …

I have a Arduino Due compatible board with JTAG connector and I want to debug my code.
That’s why I bought the Atmel-ICE external debugger. I connected it with my board and currently I am using the PlatformIO default settings for debug.
Somehow it’s working, but it feels bit clumsy.

I do have init sequence of external sensors (accelerometer, distance measuring, display via SPI) in the setup function.
In addition, I setup the watchdog timer during init.

I uploaded my program via Atmel-ice (debug symbols enabled).
My first problem is the watchdog timer. It will reset the mcu after 8s not invoking the reset function.
As loading memory, symbols etc takes quite long the mcu resets nearly immediately after setup has been finished. Is there any chance to recognize, that the debugger is attached or the debug build is loaded in order to deactivate watchdog timer entirely?
I tried using the debug_build_flags = -D DISABLE_WATCHDOG, but it seems not be allowed to pass defines.

I used to have init problems after the first start after flashing (even without all the debug stuff).
That’s why I would like to attach the debugger without uploading. From what I understand, the second target, that skips the pre-debug task is meant for that. Unfortunately, the display is always blank (white). Could the debugger disturb the display, as both are running on the same bus?

Is it necessary to reset the mcu, when the debugger is attaching?
Are there any options to improve the debug experience? Unfortunately, I cannot change the controller. Using STM32 would be probably easier for debugging, as debugger is built-in, right?

Thanks for your help,
caldi

Where did you find the information that this should be supported? I searched through the Arduino core for the Arduino Due board and I don’t get any hits at https://github.com/arduino/ArduinoCore-sam.

Also when I read through

and

the watchdog shouldn’t be on by default. Are you enabling it yourself?

Thanks for your reply.
Sorry, it seems that my initial post was not describing my environment precisely enough.

Yes, I am enabling the watchdog timer myself. It should be enabled in a release build. The problem is, that the timeout is exceeded when attaching the debugger (as this takes several seconds).
Not sure, if there is a better solution, but my idea was to disable the watchdog timer for a debug build. Therefore I tried to introduce another define variable, that prevents compiling the appropriate code snippet.

You’re right, it seems that setting a define variable with debug_build_flags is not supported.
Based on the similar name to the build_flags, I thought I could pass some defines for a debug build. But obviously this assumption was wrong.

Hope this clarifies my question :slight_smile:

Actually this exactly should work.

build_flags are always included, also in the debug build, and debug_build_flags are included in the debug build.

When I do a simple test project with

[env:uno]
platform = atmelavr
board = uno
debug_tool = simavr
framework = arduino
build_flags = -D START_WATCHDOG
debug_build_flags = -D NO_WATCHDOG

and code

#include <Arduino.h>

#ifdef START_WATCHDOG
#error "START_WATCHDOG is defined"
#else
#error "START_WATCHDOG is not defined"
#endif

#ifdef NO_WATCHDOG
#error "NO_WATCHDOG is defined"
#else
#error "NO_WATCHDOG is not defined"
#endif

void setup(){}
void loop(){}

for a normal build it correctly shows

src\main.cpp:4:2: error: #error "START_WATCHDOG is defined"
src\main.cpp:12:2: error: #error "NO_WATCHDOG is not defined"

and for a debug build that occurs when starting the default “PIO Debug (projectname)” configuration

src\main.cpp:4:2: error: #error "START_WATCHDOG is defined"
src\main.cpp:10:2: error: #error "NO_WATCHDOG is defined"

so debug_build_flags are used on top of build_flags.

(Yes the macro names make no sense here as you shouldn’t have a “start watchdog” and “no watchdog” option on at the same time, but it’s just to show that the macros work).

With what exact platformio.ini and code are you trying to disable the watchdog for a debug build?

Thanks for your detailed answer.
I do not see any structural difference between your example and my codebase.

The platformio.ini is quite complex as I do have many environments.
That’s why I only provide a simplified example:

[env:Due]
platform = atmelsam
board = due
framework = arduino
lib_deps = 
    11 ;I2Cdevlib-Core
    SCL3300
src_filter = +<*> -<.git/> -<svn/> -<example/> -<examples/> -<test/> -<tests/> 
             -<UI/ILI9325/> -<UI/UI.cpp>
monitor_speed = 9600
extra_scripts = reset.py
build_flags = 
    -D I2CDEV_IMPLEMENTATION=I2CDEV_ARDUINO_WIRE
    -D Is_Atmel=1
debug_build_flags = 
    -D DISABLE_WATCHDOG=1
debug_init_break = ; disable default breakpoint
debug_load_mode = modified

main.cpp:

  #ifndef DISABLE_WATCHDOG
    #if Is_Atmel
      watchdogEnable(WDTO);
    #else
      wdt_enable(WDTO);
    #endif
  #endif

I started this project on AVR based Arduino, that’s why I’ve to distinguish between Atmel (Arduino Due) and AVR (Arduino Mega2560).

This is the error I get:

.pio/build/Project/libFrameworkArduino.a(UARTClass.cpp.o): In function `HardwareSerial::HardwareSerial()':
UARTClass.cpp:(.text._ZN14HardwareSerialC2Ev[_ZN14HardwareSerialC5Ev]+0x20): undefined reference to `vtable for HardwareSerial'
collect2: error: ld returned 1 exit status
*** [.pio/build/Project/firmware.elf] Error 1

I do not understand what’s happening. It seems to be a linking error?!
The problem only occurs, when the define variable is set and only for debug_build_flags. Setting the same variable as build_flags it’s working fine.
Also removing the #ifndef results in an error as long as the debug_build_flags are set.

I am initializing 2 serial interfaces (Serial and Serial1). The first is obviously for the communication to the pc, and the second one is used to communicate with the distance sensor.
That said, both are working fine when not using debug_build_flags.

You’re right, I can reproduce the same behavior.

When you’re overriding the debug_build_flags, the default value gets completely overwritten through, so care must be taken to include them again.

If you write

debug_build_flags = 
    -Og 
    -ggdb3
    -D DISABLE_WATCHDOG=1

building works for me.

Without the -Og it’s probably doing no optimization ( -O0) and then it runs into a weird bug…

Thanks, adding the default values actually solves the problem for me, too.
I uploaded the firmware including the debug symbols and now I would like to attach the debugger.

When the debugger attaches, the device will be rested. Is the reset necessary?
After reset cycle, the debugger pause at a random breakpoint - at least it seems so be random.
As you saw in my platformio.ini I’ve removed the debug_init_break, but it still stops at the somewhere at the very beginning.
In addition, after the reset the display is always blank. The display is connected via 4wire SPI. From what I understand the JTAG is also using SPI, right?
Is it possible, that the debugger disturbs the display communication?

Is there any way to recognize if a device runs a debug build of the firmware?

If you want to debug the firmware starting from the beginning, yes, this is PlatformIO’s default behavior. But it can be manually overriden to not do a reset, in general see Attach debugger to running program without reset.

Hm, might have to do with the default debug_init_cmds where the target is (maybe) flashed, halted, breakpoints are added, and then restarted again, but without a debug_init_break it would behave differently.

Since I’ve not worked with the chip on the Arduino Due before I can’t tell that. Are the JTAG / SWD pins overlapping with the SPI pins? That would be weird because then you couldn’t debug the target and use the display. Usually those are different pins / pads.

Maybe it’s also an effect that PlatformIO resets the board and the display initialization routine is run that triggers a display clear / reset? In my view it would be very unlikely that, even if JTAG signals were given on the SPI bus, that those would be valid or triggering just the right SPI writes / commands to trigger a reset. But if one of the JTAG lines is also connected to a display reset line, it might caue it ofc.

Thanks for your comments.
Sorry, I was mixing things up: The JTAG does not have any connection to the SPI bus (nor to the display).
It’s not clear to me why the display resets. I’ll try to set a breakpoint before initialization and see if I can find some hints … :slight_smile:

I played around and did not find any regularity.
When I place a breakpoint at the first line of the setup method of my code, neither the display (SPI with DMA) nor the distance sensor (Serial1) will properly initialize.
I do not have much experience, but it could be related to some timings. That said, I don’t know why. The initialization of the distance sensor is the very first thing in the main function. Basically, that just enabling power for it and sending an init command via Serial1 - that’s it.

I found out, when placing the breakpoint at the very end of the main function, the distance sensor will initialize. Not sure why this makes a difference. The init sequence is also run, when stepping through it, but the distance sensor does not response.
Btw, this also happens, directly after flashing a firmware without debugging (via sam-ba). It seems, that the distance sensor is quite sensible …

The weird thing is, that the display does not work once the debugger is attached.
The backlight is turned on from my code, and the background is always blank/white. That said, it’s weird as I am not sure, if the background is white by default. I am drawing the background white - not sure if this triggers the white background or any reset.
When starting the Arduino without debugger, display is working fine. Maybe it’s a problem of the DMA?

All over all, the debugger is now working much better as the watchdog is now disabled when uploading the debug firmware.
Appreciate your help :slight_smile:

The problem I am having, and why I found this, is that it overrides the base debug_build_flags so I need to explicitly specify the no optimization and include debug info flags. Is it not possible to extend a built in variable in certain env sections eg

debug_build_flags:
    ${debug_build_flags}
    -D HELLOMAX

(Im new to this btw)

regards
r.