Debugging STM32H7R/S Applications in External Memory

This tutorial shows how to create an application project for the STM32H7R/S device, that will reside in an external memory, and will be launched by a bootloader. Before you begin, follow this tutorial to create a basic bootloader project.

  1. In the solution containing the bootloader project, right-click on the solution node and select “Add->New Project”:
  2. Select the same project type and device as you did when creating bootloader, but this time pick the Appli project instead of Boot in the Sample Selection page:
  3. In order to program the external memory, we will need to use the STM32CubeProgrammer tool that requires the ELF files to have the .elf extension. This can be accomplished by adding the following line at the end of CMakeLists.txt:
    set_target_properties(<Executable Name> PROPERTIES SUFFIX ".elf")

  4. Build the project and verify that it got placed into XSPI2, and the FLASH memory is empty. If you still see the stats from the bootloader project, right-click on the STM32H7S_App project (with triangular CMake icon) and select “Set as startup project”:
  5. Now we can test programming the FLASH memory with STM32CubeProgrammer. Go to its binary directory, and run the following command line:
    STM32_Programmer_CLI.exe -c port=SWD reset=HWrst -el ExternalLoader\MX25UW25645G_NUCLEO-H7S3L8.stldr -w <full path to STM32H7S_App.elf>

  6. Once the programming succeeds, you can configure VisualGDB to run STM32CubeProgrammer automatically before each debug session. Add the following command as a pre-debug step:
    Command <full path to STM32_Programmer_CLI.exe>
    Arguments STM32_Programmer_CLI.exe -c port=SWD reset=HWrst -el ExternalLoader\MX25UW25645G_NUCLEO-H7S3L8.stldr -w $(TargetPath)
    Working directory <directory of STM32_Programmer_CLI.exe>

  7. If we try to just debugging the application, GDB will try to directly program it into the FLASH memory and will fail. It will also assume that the FLASH memory is actually RAM that can be directly modified to set breakpoints, which is not the case. To work around it, change the following settings via VisualGDB Project Properties -> Debug Settings:
    Program FLASH memory Never
    Reset device Before programming + After programming

    Also add “mon gdb_breakpoint_override hard” to the startup GDB commands (requires using the ST fork of OpenOCD and not the discontinued H7R/S OpenOCD branch):

  8. Set a breakpoint in the application’s main() function and press F5. VisualGDB will launch the application and the breakpoint will trigger:
  9. If you continue the application and connect the other port of the board to USB, it will get recognized as a virtual serial port:
  10. Now we will show how to merge both the bootloader and the application into the same CMake project. Apply the following changes to CMakeLists.txt files:
    1. Add ALIAS BOOTLOADER_BSP to the find_bsp() statement in the bootloader’s CMakeLists.txt file.
    2. Add BSP_ALIAS BOOTLOADER_BSP  to the bsp_include_directories(), bsp_compile_definitions() and add_bsp_based_executable( ) statements. In this particular example, many include directories imported from the STM32 SDK are not needed as long as the project references the correct frameworks, so we have removed them in our example.
    3. Copy the find_bsp() statement and everything below it from the application’s CMakeLists.txt file.

    This way you will end up with one CMakeLists.txt file defining two separate BSPs, each of them having one application. You can use this git commit as a reference for the changes necessary to merge both projects.

  11. Open VisualGDB Project Properties for the bootloader project and add a custom debug step similar to the one added before. Use $(TargetDir)/(application name) instead of $(TargetPath), as $(TargetPath) will now resolve to the bootloader binary:
  12. As the main application from VisualGDB’s view is now the bootloader, you can keep the FLASH programming turned on and don’t need to reset the device after programming. However, you still need to force the hardware breakpoints via gdb_breakpoint_override:
  13. Finally, go to the Embedded Debug Tweaking page, expand the Related Executables list: and add the application there, checking the Symbols and Live Watch checkboxes, but not the FLASH checkbox. This will ensure that you can step set breakpoints in both the bootloader and the main application, but GDB will rely on the STM32CubeProgrammer (via a custom pre-debug step) to program the application into the external FLASH memory:
  14. Having bootloader and application symbols loaded at the same time can cause confusion if both of them have variables with the same name (e.g. TickCount). If this happens, you can limit the debug symbols to application only by selecting it as the startup target (console icon in Solution Explorer), disabling the FLASH memory programming and enabling reset-after-program as shown here:This will reuse the existing bootloader, program the application and reset the device so that the bootloader takes control and launches the app.