PlatformIO Community

PIO/Debug crashes after pressing reset. Possible to change reset behavior?

Is PIO compatible with rom images that do not start at the mcu default address?

I have a no-framework PIO project. I’ve brought all the files in on my own from STM32CubeIDE. I can get into debugging and step over code.

Relavent .ini:

description = Application
src_dir = .\code
include_dir = .\code\sys\core\Inc
lib_dir = .\lib

platform = ststm32
board = h743vi_splitbank
extra_scripts =
board_build.ldscript = ./code/sys/STM32H743VIHX_FLASH.ld
build_flags = 
build_src_filter = 
build_type = debug
debug_tool = jlink
upload_protocol = jlink

The mcu rom starts at 0x80000000. The linkerscript is adjusted to start the rom at 0x80200000, making a sector reserved for bootloader (not programmed yet).

  ITCMRAM (xrw)  : ORIGIN = 0x00000000, LENGTH = 64K
  DTCMRAM (xrw)  : ORIGIN = 0x20000000, LENGTH = 128K
  FLASH (rx)     : ORIGIN = 0x08020000, LENGTH = 768K
  RAM_D1 (xrw)   : ORIGIN = 0x24000000, LENGTH = 512K
  RAM_D2 (xrw)   : ORIGIN = 0x30000000, LENGTH = 288K
  RAM_D3 (xrw)   : ORIGIN = 0x38000000, LENGTH = 64K

The vector table is adjusted at the start of main()

int main(void)
    SCB->VTOR = 0x08020000;

The first load of PIO Debug works.

There is a hang and a crash on subsequent reloads using the Reset or CTRLSHIFTF5 shortcut.

I had a similar issue with STM32CubeIDE that always tried to reset to 0x80000000 and would work about 50% of the time. At least STM32CubeIDE would show me processor was in hardfault.

I suspect hitting reset() puts the mcu to 0x80000000 where it hard faults and hangs. PIO shows me nothing.

I am not certain why the initial load settings are different from reset settings. Is there a way to fix this behavior?

EDIT: It is a custom board, same as the WeArt STM32H743, only difference is I cut the rom down to a number I can actually use to show a correct percentage used on building.

EDIT2: I see in builder/ for Jlink:

elif upload_protocol.startswith("jlink"):

    def _jlink_cmd_script(env, source):
        build_dir = env.subst("$BUILD_DIR")
        if not isdir(build_dir):
        script_path = join(build_dir, "upload.jlink")
        commands = [
            "loadbin %s, %s" % (source, board.get(
                "upload.offset_address", "0x08000000")),

Seems like code to start at the correct address. Is it possible that the reset() does not have similar thinking and just resets to default/0x80000000?

EDIT3: I’ve called it reset, but the actual command seems to be restart.

EDIT4: I’m not great at Python or JS, but it seems to me that VSCode specifically sends the reset event to PIO Core and then it either turns into a straight JLink command or GDB (more likely?). So maybe I can find a partial solution in GDB (or OpenOCD?), but then I still need to know how this command works and if it’s possible to customize the data sent.