[SOLVED] J-Link won't reprogram a page with all 1's on STM32L4

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

  • [SOLVED] J-Link won't reprogram a page with all 1's on STM32L4

    Hi,

    I have an issue with JLinkExe/J-Flash on an STM32L433CC, which I suspect is due to some JLink flash access optimization.
    TL;DR
    if you programatically and explicitly write a flash page (2KB) with all-1's (from within your firmware code), J-Link won't be able to reprogram it unless you erase the whole flash first!

    Long story (after several hours of debugging):

    I am implementing a simple bootloader to allow for on-the-field firmware upgrade. I have two separate binaries: a small bootloader firmware (flashed at the reset address location, 0x08000000) and the actual application firmware (stored at 0x08020000).
    I use J-Link/GDB under Eclipse with the appropriate settings so that I can quickly program and debug both the bootloader and the application with a single mouse
    click, which I find very convenient.

    For the on-the-field upgrade, it goes like this: you flash the new application code starting at 0x08004000 and set a flag in the flash and then reboot.
    The bootloader then checks for the flag and if it is set, it erases the flash area containing the current firmware and overwrites it with the new one before jumping to it. Pretty simple.
    To test the bootloader code, I tried downloading an empty firmware (all-0xFF's) in the special area and setting the flag. The bootloader then just copies it over in the application-dedicated area, 0x08020000, (remember, it's all FF's!).

    After that, I can't reprogram the flash pages starting at 0x08020000 using J-Link/GDB anymore. The error message (or lack thereof) varies depending on the tool/OS I use.

    What's worse, GDB will just behave as if everything had been OK!
    See the output here (GDB/Linux):

    Brainfuck Source Code

    1. SEGGER J-Link GDB Server V6.22d Command Line Version
    2. JLinkARM.dll V6.22d (DLL compiled Dec 14 2017 18:34:21)
    3. Command
    4. line: -if swd -device STM32L433CC -endian little -speed 1000 -port 2331
    5. -swoport 2332 -telnetport 2333 -vd -ir -localhostonly 1 -singlerun
    6. -strict -timeout 0 -nogui
    7. -----GDB Server start settings-----
    8. GDBInit file: none
    9. GDB Server Listening port: 2331
    10. SWO raw output listening port: 2332
    11. Terminal I/O port: 2333
    12. Accept remote connection: localhost only
    13. Generate logfile: off
    14. Verify download: on
    15. Init regs on start: on
    16. Silent mode: off
    17. Single run mode: on
    18. Target connection timeout: 0 ms
    19. ------J-Link related settings------
    20. J-Link Host interface: USB
    21. J-Link script: none
    22. J-Link settings file: none
    23. ------Target related settings------
    24. Target device: STM32L433CC
    25. Target interface: SWD
    26. Target interface speed: 1000kHz
    27. Target endian: little
    28. Connecting to J-Link...
    29. J-Link is connected.
    30. Firmware: J-Trace Cortex-M Rev.3 compiled Nov 23 2017 16:43:50
    31. Hardware: V3.10
    32. S/N: <cut>
    33. Feature(s): RDI, FlashBP, FlashDL, JFlash, GDB
    34. Checking target voltage...
    35. Target voltage: 3.27 V
    36. Listening on TCP/IP port 2331Connecting to target...Connected to target
    37. Waiting for GDB connection...Connected to 127.0.0.1
    38. Reading all registers
    39. Read 4 bytes @ address 0x00000000 (Data = 0x2000C000)
    40. Read 2 bytes @ address 0x00000000 (Data = 0xC000)
    41. Received monitor command: speed 1000
    42. Target interface speed set to 1000 kHz
    43. Received monitor command: clrbp
    44. Received monitor command: reset
    45. Resetting target
    46. Received monitor command: halt
    47. Halting target CPU...
    48. ...Target halted (PC = 0x08001F24)
    49. Received monitor command: regs
    50. R0 = 00000000, R1 = 00000000, R2 = 00000000, R3 = 00000000
    51. R4 = 00000000, R5 = 00000000, R6 = 00000000, R7 = 00000000
    52. R8 = 00000000, R9 = 00000000, R10= 00000000, R11= 00000000
    53. R12= 00000000, R13= 2000C000, MSP= 2000C000, PSP= 00000000
    54. R14(LR) = FFFFFFFF, R15(PC) = 08001F24
    55. XPSR 01000000, APSR 00000000, EPSR 01000000, IPSR 00000000
    56. CFBP 00000000, CONTROL 00, FAULTMASK 00, BASEPRI 00, PRIMASK 00
    57. Reading all registers
    58. Read 4 bytes @ address 0x08001F24 (Data = 0xD034F8DF)
    59. Read 2 bytes @ address 0x08001F24 (Data = 0xF8DF)
    60. Received monitor command: speed auto
    61. Select auto target interface speed (2000 kHz)
    62. Received monitor command: flash breakpoints 1
    63. Flash breakpoints enabled
    64. Read 4 bytes @ address 0x08001F24 (Data = 0xD034F8DF)
    65. Read 2 bytes @ address 0x08001F24 (Data = 0xF8DF)
    66. Downloading 120 bytes @ address 0x08020000 - Verified OK
    67. ......cut.....
    68. Downloading 856 bytes @ address 0x08030808 - Verified OK
    69. Comparing flash [....................] Done.
    70. Erasing flash [....................] Done.
    71. Programming flash [....................] Done.
    72. Verifying flash [....................] Done.
    73. Writing register (PC = 0x0802BBBC)
    74. Read 4 bytes @ address 0x0802BBBC (Data = 0xFFFFFFFF)
    75. Read 2 bytes @ address 0x080212EA (Data = 0xFFFF)
    76. Read 2 bytes @ address 0x080212E8 (Data = 0xFFFF)
    77. Read 2 bytes @ address 0x0802B4D4 (Data = 0xFFFF)
    78. Read 2 bytes @ address 0x080212EA (Data = 0xFFFF)
    79. Read 2 bytes @ address 0x080212E8 (Data = 0xFFFF)
    80. Received monitor command: clrbp
    81. Received monitor command: reset
    82. Resetting target
    83. Received monitor command: halt
    84. Halting target CPU...
    85. ...Target halted (PC = 0x08001F24)
    86. Read 2 bytes @ address 0x0802B4D4 (Data = 0xFFFF)
    87. Received monitor command: regs
    88. R0 = 00000000, R1 = 00000000, R2 = 00000000, R3 = 00000000
    89. R4 = 00000000, R5 = 00000000, R6 = 00000000, R7 = 00000000
    90. R8 = 00000000, R9 = 00000000, R10= 00000000, R11= 00000000
    91. R12= 00000000, R13= 2000C000, MSP= 2000C000, PSP= 00000000
    92. R14(LR) = FFFFFFFF, R15(PC) = 08001F24
    93. XPSR 01000000, APSR 00000000, EPSR 01000000, IPSR 00000000
    94. CFBP 00000000, CONTROL 00, FAULTMASK 00, BASEPRI 00, PRIMASK 00
    95. Reading all registers
    96. Read 4 bytes @ address 0x08001F24 (Data = 0xD034F8DF)
    97. Read 2 bytes @ address 0x08001F24 (Data = 0xF8DF)
    98. Setting breakpoint @ address 0x080212E8, Size = 2, BPHandle = 0x0001
    99. Setting breakpoint @ address 0x0802B4D4, Size = 2, BPHandle = 0x0002
    100. Starting target CPU...
    Display All

    However, when reading back the area at 0x08020000 (where the application should have been), I read all FF's.
    If I do the same operation on the CLI tool JLinkExe/Linux, I at least get some hint that something went wrong:

    Source Code

    1. Comparing flash [100%] Done.
    2. Erasing flash [100%] Done.
    3. Programming flash [100%] Done.
    4. Verifying flash [100%] Done.
    5. J-Link: Flash download: Restarting flash programming due to program error (possibly skipped erasure of half-way erased sector).
    6. J-Link: Flash download: Skip optimizations disabled for second try.
    7. Error while programming flash: Programming failed.



    Almost in despair, I also tried using J-Flash (under Windows):

    Source Code

    1. Erasing selected sectors ...
    2. - 1 of 128 sectors selected, 1 range, 0x8020000 - 0x80207FF
    3. - Start of preparing flash programming
    4. - End of preparing flash programming
    5. - Start of determining dirty areas in flash cache
    6. - End of determining dirty areas
    7. - CPU speed could not be measured.
    8. - Start of erasing sectors
    9. - Start of blank checking
    10. - End of blank checking
    11. - End of erasing sectors
    12. - Start of restoring
    13. - End of restoring
    14. - Erase operation completed successfully - Completed after 0.156 sec
    15. Checking if selected data fits into selected flash sectors.
    16. Programming target (8 bytes, 1 range) ...
    17. - Start of preparing flash programming
    18. - End of preparing flash programming
    19. - Start of determining dirty areas in flash cache
    20. - End of determining dirty areas
    21. - CPU speed could not be measured.
    22. - Start of erasing sectors
    23. - Start of blank checking
    24. - End of blank checking
    25. - End of erasing sectors
    26. - Start of flash programming
    27. - Programming range 0x08020000 - 0x080207FF (001 Sector, 2 KB)
    28. - End of flash programming
    29. - Flash programming performed for 1 range (2048 bytes)
    30. - 0x8020000 - 0x80207FF (001 Sector, 2 KB)
    31. - Start of restoring
    32. - ERROR: Programming failed @ address 0x08020008 (program error)
    33. - ERROR: Failed to restore target. RAMCode never stops
    34. - End of restoring
    35. - ERROR: Failed to program target
    36. Disconnecting ...
    37. - Disconnected
    Display All


    After performing a mass erase actually everything goes back to normal.
    Also, programmatically erasing the incriminated pages seems to also fix the situation.

    So while I can't be 100% sure it's J-Link's fault, it looks like its optimization logic gets somehow deceived by this use case (albeit a pretty unique one, I admit).
    The root cause is perhaps to be found within the STM32L4 internal flash implementation with its out-of-band ECC making an empty/erased flash page look indistinguishable from a page programmed with all 1's, even though the former can be reprogrammed at will, while the latter must be erased first.

    For now I worked around the issue by adding an explicit check in the flash programming routine which refrains from explicitly writing a 64-bit double word if it's all 1's.

    Nevertheless, it's quite unnerving how:
    1) GDB incorrectly reports that programming was successful even though that was absolutely not the case!
    2) JLinkExe tries to disable its internal optimization, without much success though
    3) J-Flash reports "Erase operation completed successfully" (while apparently nothing was erased)
    4) I found no way to explicitly and unconditionally erase a single page!

    Could anyone please confirm whether my suspicion makes any sense at all or maybe I'm doing something wrong somewhere else?
    Is there any better way to deal with this?
    Any chance this could be fixed so that real errors are reported?

    Thank you!
  • Hello,

    Thank you for your inquiry.

    We were able to reproduce the issue with a STM32L4 board and J-Flash.
    For this particular device family it seems that the flash can only be programmed once after erase.
    Now programming all 0xFF also counts as programming once for the STM32L4.
    If you try to program again on top of that J-Link will read all 0xFF and due to optimization think it was already erased and try to program the same flash cells a second time without erasing beforehand which results in a "confused" state of the target device. Thus no operations afterwards work properly until a software or power on reset.
    As it is not feasible for us to remove optimizations for such a special case we can only offer workarounds in that matter:

    - Try to use other testdata than 0xFF to avoid the erase optimization, for this you can use e.g. J-Flash and there under Target->Test->Generate Test data... and generate data which creates code for an application that is a simple branch loop onto itself which is not harmful to Cortex-M devices.
    - Skip automatic flash compare, then an erase of the affected area will always be executed and thus you make sure that particular sector gets erased each time. For this you can use exec command "SetCompareMode" which sets the compare mode for the current session. Set this to "Skip" and you should no longer have any of the described issues.
    For more information consult the J-Link User Manual.

    I found no way to explicitly and unconditionally erase a single page!

    To do this specifically only J-Flash can be used as for all other cases the J-Link Software takes automatically care of only erasing affected sectors to increase the longevity of the users flash memory.

    Best regards,
    Nino
    Please read the forum rules before posting: Forum Rules

    Keep in mind, this is not a support forum. Its main purpose is user to user interaction.
    Our engineers will try to answer your questions between their projects if possible but this can be delayed by longer periods of time.
    Should you be entitled to support contact us per e-mail.
    The following contact form can be used for this: segger.com/about-us/contact-us/

  • Thank you for you reply, see my comments inline.

    SEGGER - Nino wrote:

    Hello,

    Thank you for your inquiry.

    We were able to reproduce the issue with a STM32L4 board and J-Flash.
    For this particular device family it seems that the flash can only be programmed once after erase.
    Now programming all 0xFF also counts as programming once for the STM32L4.
    If you try to program again on top of that J-Link will read all 0xFF and due to optimization think it was already erased and try to program the same flash cells a second time without erasing beforehand which results in a "confused" state of the target device. Thus no operations afterwards work properly until a software or power on reset.

    Actually a power on reset or even a power cycle, does not seem to help either.

    As it is not feasible for us to remove optimizations for such a special case we can only offer workarounds in that matter:

    - Try to use other testdata than 0xFF to avoid the erase optimization, for this you can use e.g. J-Flash and there under Target->Test->Generate Test data... and generate data which creates code for an application that is a simple branch loop onto itself which is not harmful to Cortex-M devices.
    - Skip automatic flash compare, then an erase of the affected area will always be executed and thus you make sure that particular sector gets erased each time. For this you can use exec command "SetCompareMode" which sets the compare mode for the current session. Set this to "Skip" and you should no longer have any of the described issues.
    For more information consult the J-Link User Manual.

    OK, I'll give it a try.


    I found no way to explicitly and unconditionally erase a single page!

    To do this specifically only J-Flash can be used as for all other cases the J-Link Software takes automatically care of only erasing affected sectors to increase the longevity of the users flash memory.



    Well, the above workaround should be enough.
    The last thing I don't understand though, is how J-Link GDB server does not report any error at all. I see a pretty reassuring line:

    Brainfuck Source Code

    1. Verifying flash [....................] Done.


    which is somehow misleading. This would suggest that programming was succesful as a later comparison would provide a match. Yet this is certainly not the case.
    Could you please elaborate? What does line refer to?

    Thank you!