[SOLVED] Segger Embedded Studio STM32F411 startup files doing something that prevents code execution

This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

  • [SOLVED] Segger Embedded Studio STM32F411 startup files doing something that prevents code execution

    Hello-
    Our project is on the STM32F411 Discovery board produced and sold by ST. We have a project that is meant to run as a stand-alone image but also can be uploaded via USB to the STM32F411 that is also running our bootloader. To enable this behavior the memory map XML is edited to start the flash space at 0x08008000 instead of the normal 0x08000000. The __VTOR_CONFIG property is also defined for all configurations. This setup worked fine for quite a while but recently stopped running correctly. Currently, our code only correctly executes when building the DEBUG configuration and launching it via the debugger. If we run RELEASE or power cycle the Discovery board after a successful debug session, the code fails to execute (usually, even with debug code loaded, it will run on a power cycle with no debugger attached). Our project involves a lot of external circuits attached to the Discovery board, however, we see this same problem exhibited on a Discovery board with no external circuits. We can still verify if our code is running or not by looking for a COM port to be spawned by connecting the user-USB port on the Discovery board. So even running the code without all of our stuff attached, we will see the COM port appear in Windows only if a debug session is launched (side note: the on-board ST Link is replaced with the Segger J-Link firmware).


    To help troubleshoot this issue we implemented the following test code which lights up LD3 connected to PD13:


    Source Code

    1. movw r3, #14384
    2. movt r3, #16386
    3. ldr r2, [r3, #0]
    4. orr.w r2, r2, #8
    5. str r2, [r3, #0]
    6. movw r3, #3072
    7. movt r3, #16386
    8. ldr r2, [r3, #0]
    9. movs r4, #1
    10. bfi r2, r4, #26, #2
    11. str r2, [r3, #0]
    12. movw r3, #3076
    13. movt r3, #16386
    14. ldr r2, [r3, #0]
    15. bic.w r2, r2, #8192
    16. str r2, [r3, #0]
    17. movw r3, #3092
    18. movt r3, #16386
    19. ldr r2, [r3, #0]
    20. orr.w r2, r2, #8192
    21. str r2, [r3, #0]
    Display All

    We found the problem area by moving this test sequence farther and farther up the execution chain. The following code is in SEGGER_THUMB_startup.s


    Source Code

    1. START_FUNC _start
    2. //
    3. // Call linker init functions which in turn performs the following:
    4. // * Perform segment init
    5. // * Perform heap init (if used)
    6. // * Call constructors of global Objects (if any exist)
    7. //
    8. ldr R4, =__SEGGER_init_table__ // Set table pointer to start of initialization table
    9. L(RunInit):
    10. ldr R0, [R4] // Get next initialization function from table
    11. adds R4, R4, #4 // Increment table pointer to point to function arguments
    12. blx R0 // Call initialization function
    13. b L(RunInit)
    14. //
    15. MARK_FUNC __SEGGER_init_done
    16. MARK_FUNC __startup_complete
    17. //
    18. // Time to call main(), the application entry point.
    19. //
    20. #ifndef FULL_LIBRARY
    21. //
    22. // In a real embedded application ("Free-standing environment"),
    23. // main() does not get any arguments,
    24. // which means it is not necessary to init R0 and R1.
    25. //
    26. bl APP_ENTRY_POINT // Call to application entry point (usually main())
    27. END_FUNC _start
    Display All
    If we place our test code at the start of this function, the light turns on, however, if we place it at the end, the light stays off. So something in one of these init functions that are being looped over is blocking the code from running unless it's under a debug session (and the code doesn't have to be stepped line by line, if allowed to run immediately on session start it's fine). Stepping through this code constantly ends up in the __SEGGER_init_zero function and nowhere else (after stepping through this loop a dozen times) but somehow code execution eventually breaks out since if we place a breakpoint on APP_ENTRY_POINT it does get there. Or perhaps this is the core issue, that under RELEASE code the normal process to exit __SEGGER_init_zero never happens? Either way it is unclear how to proceed unless we try editing project settings to stop this function being called to begin with, but it would be nice to avoid that.
  • Attached are the map files and the file compare results of the compiled code for debug and release mode. Aside from formatting the differences appear to be related to address locations, so this information didn't help us any.
    Files
    • diff.txt

      (20.88 kB, downloaded 72 times, last: )
    • orca_2_release.txt

      (213.67 kB, downloaded 92 times, last: )
    • orca_2_debug.txt

      (213.67 kB, downloaded 82 times, last: )
  • So the issue was that code didn't run right due to the relocation of the application from 0x800_0000 to 0x800_8000. The real processor reset vector at 0x800_0000 is now unpopulated so under normal operating conditions the code fails to execute. If I edit the project to Debug->Debugger->Start From Entry Point Symbol to "No" then the execution from the IDE fails properly under debug mode, but in Release mode the code will still launch and execute correctly if I do "Build and Run" (until power cycled, forcing the processor to execute address 0x800_0000). The fix for this is to add a post-build step that edits the HEX file output to add in the branch to 0x800_8000 to 0x800_8000. The other fix would be to never run this without the matching bootloader loaded into 0x800_0000 but we wanted the bootloader and application projects to be as independent as possible.