Is it possible to use the code debugger for Arduino UNO without separate hardware?

Hi, so I’ve already read through avr-stub documentation and that set-up doesn’t seem to work for me. Maybe its because my code doesn’t use Arduino libraries as a backend? I’m writing C (not C++) code with a main.c file as an entry point and using avrdude to compile it to .elf images. The only hardware I’m using is the Arduino UNO board itself connected over USB to my PC. Is it not possible to utilize this software debugger to step through my code as is?

Below is the platformIO debug log:

Processing uno (platform: atmelavr; board: uno; framework: arduino)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Removing unused dependencies...
Error: Traceback (most recent call last):
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\__main__.py", line 102, in main
    cli()  # pylint: disable=no-value-for-parameter
  File "C:\Users\John\.platformio\penv\lib\site-packages\click\core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
  File "C:\Users\John\.platformio\penv\lib\site-packages\click\core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\commands\__init__.py", line 44, in invoke
    return super().invoke(ctx)
  File "C:\Users\John\.platformio\penv\lib\site-packages\click\core.py", line 1657, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "C:\Users\John\.platformio\penv\lib\site-packages\click\core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "C:\Users\John\.platformio\penv\lib\site-packages\click\core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "C:\Users\John\.platformio\penv\lib\site-packages\click\decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\commands\run\command.py", line 142, in cli
    process_env(
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\commands\run\command.py", line 197, in process_env
    result = {"env": name, "duration": time(), "succeeded": ep.process()}
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\commands\run\processor.py", line 83, in process
    install_project_env_dependencies(
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\package\commands\install.py", line 132, in install_project_env_dependencies
    _install_project_env_libraries(project_env, options),
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\package\commands\install.py", line 204, in _install_project_env_libraries
    _uninstall_project_unused_libdeps(project_env, options)
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\package\commands\install.py", line 264, in _uninstall_project_unused_libdeps
    lm.uninstall(spec)
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\package\manager\_uninstall.py", line 29, in uninstall
    return self._uninstall(spec, skip_dependencies)
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\package\manager\_uninstall.py", line 34, in _uninstall
    pkg = self.get_package(spec)
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\package\manager\base.py", line 262, in get_package
    spec = self.ensure_spec(spec)
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\package\manager\base.py", line 132, in ensure_spec
    return spec if isinstance(spec, PackageSpec) else PackageSpec(spec)
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\package\meta.py", line 143, in __init__
    self._parse(self.raw)
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\package\meta.py", line 250, in _parse
    raw = parser(raw)
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\package\meta.py", line 275, in _parse_requirements
    self.requirements = tokens[1].strip()
  File "C:\Users\John\.platformio\penv\lib\site-packages\platformio\package\meta.py", line 190, in requirements
    else semantic_version.SimpleSpec(str(value))
  File "C:\Users\John\.platformio\penv\lib\site-packages\semantic_version\base.py", line 618, in __init__
    self.clause = self._parse_to_clause(expression)
  File "C:\Users\John\.platformio\penv\lib\site-packages\semantic_version\base.py", line 1014, in _parse_to_clause
    return cls.Parser.parse(expression)
  File "C:\Users\John\.platformio\penv\lib\site-packages\semantic_version\base.py", line 1034, in parse
    raise ValueError("Invalid simple block %r" % block)
ValueError: Invalid simple block '^~1.4'

============================================================

An unexpected error occurred. Further steps:

* Verify that you have the latest version of PlatformIO using
  `pip install -U platformio` command

* Try to find answer in FAQ Troubleshooting section
  https://docs.platformio.org/page/faq.html

* Report this problem to the developers
  https://github.com/platformio/platformio-core/issues

============================================================

The terminal process "C:\Users\John\.platformio\penv\Scripts\platformio.exe 'run'" terminated with exit code: 1.

my .ini file:

[env:uno]

platform = atmelavr

board = uno

; change microcontroller

board_build.mcu = atmega328p

; change MCU frequency

board_build.f_cpu = 16000000L

# sets baud rate of terminal (MiniTerm)

monitor_speed = 9600

debug_tool = avr-stub

debug_port = COM4

; GDB stub implementation

lib_deps =

    jdolinay/avr-debugger @ ~1.4

This isn’t even a compile error, you or a library you use declared something wrong in the platformio.ini (or library.json dependencies) regarding a neeed version. ^~1.4 is not a valid semantic version. ^1 would be, or ~1.4 would be.

The platformio.ini looks good with

Can you delete the .pio folder of the project along with C:\Users\<user>\.platformio\.cache and retry building?

Hi,

Your suggestions fixed the build errors I saw however the base issue still exists with the debug mode not running:
image

Reading symbols from e:\Users\class\Desktop\atmega328p docs\Visual Studio Code Project\atmega328p_lib\.pio\build\uno\firmware.elf...
done.
PlatformIO Unified Debugger -> https://bit.ly/pio-debug
PlatformIO: debug_tool = avr-stub
PlatformIO: Initializing remote target...
Ignoring packet error, continuing...
warning: unrecognized item "timeout" in "qSupported" response
2
Ignoring packet error, continuing...
.pioinit:13: Error in sourced command file:
Bogus trace status reply from target: timeout

What’s the minimal main.c which you are using? Should be akin to the given example in the docs, something like

#include "Arduino.h"
#include "avr8-stub.h"

int main()
{
  // initialize GDB stub
  debug_init();

  breakpoint();
  // LED blinky code..
}

Yes, I have those lines of code as mentioned in the docs.

In my main(), I also have my infinite loop

int main(void)
{
  // initialize GDB stub
  debug_init();
  // initialize peripherals...
  breakpoint();
  // do other stuff...
  while(1)
         ;
}

Do you reinitialize the UART after calling debug_init()?

Have you verified that without calling into the debug stuff, that the timing is correct? E.g., a one second LED blinking using

#include <avr/io.h>
#include <util/delay.h>

void blink(void)
{
    DDRB   |= (1 << PB2);           // LED on pin PB2
    
    while(1)
    {
        _delay_ms(1000);
        PORTB &= ~(1 << PB2);       // LED off
        _delay_ms(1000);
        PORTB |=  (1 << PB2);       // LED on
    }
}

works properly?

Okay, so like you mentioned, I had to disable my UART. I was previously using it for debugging via logging over console.

I think in my original usage, I was missing the call to breakpoint(). I though that this could be used like a traditional debugger where you can set-up breakpoints via red dot placement (much more obscure) but this makes more sense.

Thank you for your help with debugging!

1 Like

Indeed, that’s one of the limitatations. UART will be taken up by the GDB logic. You can still log through GDb by using