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):
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:
Almost in despair, I also tried using J-Flash (under Windows):
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!
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
- SEGGER J-Link GDB Server V6.22d Command Line Version
- JLinkARM.dll V6.22d (DLL compiled Dec 14 2017 18:34:21)
- Command
- line: -if swd -device STM32L433CC -endian little -speed 1000 -port 2331
- -swoport 2332 -telnetport 2333 -vd -ir -localhostonly 1 -singlerun
- -strict -timeout 0 -nogui
- -----GDB Server start settings-----
- GDBInit file: none
- GDB Server Listening port: 2331
- SWO raw output listening port: 2332
- Terminal I/O port: 2333
- Accept remote connection: localhost only
- Generate logfile: off
- Verify download: on
- Init regs on start: on
- Silent mode: off
- Single run mode: on
- Target connection timeout: 0 ms
- ------J-Link related settings------
- J-Link Host interface: USB
- J-Link script: none
- J-Link settings file: none
- ------Target related settings------
- Target device: STM32L433CC
- Target interface: SWD
- Target interface speed: 1000kHz
- Target endian: little
- Connecting to J-Link...
- J-Link is connected.
- Firmware: J-Trace Cortex-M Rev.3 compiled Nov 23 2017 16:43:50
- Hardware: V3.10
- S/N: <cut>
- Feature(s): RDI, FlashBP, FlashDL, JFlash, GDB
- Checking target voltage...
- Target voltage: 3.27 V
- Listening on TCP/IP port 2331Connecting to target...Connected to target
- Waiting for GDB connection...Connected to 127.0.0.1
- Reading all registers
- Read 4 bytes @ address 0x00000000 (Data = 0x2000C000)
- Read 2 bytes @ address 0x00000000 (Data = 0xC000)
- Received monitor command: speed 1000
- Target interface speed set to 1000 kHz
- Received monitor command: clrbp
- Received monitor command: reset
- Resetting target
- Received monitor command: halt
- Halting target CPU...
- ...Target halted (PC = 0x08001F24)
- Received monitor command: regs
- R0 = 00000000, R1 = 00000000, R2 = 00000000, R3 = 00000000
- R4 = 00000000, R5 = 00000000, R6 = 00000000, R7 = 00000000
- R8 = 00000000, R9 = 00000000, R10= 00000000, R11= 00000000
- R12= 00000000, R13= 2000C000, MSP= 2000C000, PSP= 00000000
- R14(LR) = FFFFFFFF, R15(PC) = 08001F24
- XPSR 01000000, APSR 00000000, EPSR 01000000, IPSR 00000000
- CFBP 00000000, CONTROL 00, FAULTMASK 00, BASEPRI 00, PRIMASK 00
- Reading all registers
- Read 4 bytes @ address 0x08001F24 (Data = 0xD034F8DF)
- Read 2 bytes @ address 0x08001F24 (Data = 0xF8DF)
- Received monitor command: speed auto
- Select auto target interface speed (2000 kHz)
- Received monitor command: flash breakpoints 1
- Flash breakpoints enabled
- Read 4 bytes @ address 0x08001F24 (Data = 0xD034F8DF)
- Read 2 bytes @ address 0x08001F24 (Data = 0xF8DF)
- Downloading 120 bytes @ address 0x08020000 - Verified OK
- ......cut.....
- Downloading 856 bytes @ address 0x08030808 - Verified OK
- Comparing flash [....................] Done.
- Erasing flash [....................] Done.
- Programming flash [....................] Done.
- Verifying flash [....................] Done.
- Writing register (PC = 0x0802BBBC)
- Read 4 bytes @ address 0x0802BBBC (Data = 0xFFFFFFFF)
- Read 2 bytes @ address 0x080212EA (Data = 0xFFFF)
- Read 2 bytes @ address 0x080212E8 (Data = 0xFFFF)
- Read 2 bytes @ address 0x0802B4D4 (Data = 0xFFFF)
- Read 2 bytes @ address 0x080212EA (Data = 0xFFFF)
- Read 2 bytes @ address 0x080212E8 (Data = 0xFFFF)
- Received monitor command: clrbp
- Received monitor command: reset
- Resetting target
- Received monitor command: halt
- Halting target CPU...
- ...Target halted (PC = 0x08001F24)
- Read 2 bytes @ address 0x0802B4D4 (Data = 0xFFFF)
- Received monitor command: regs
- R0 = 00000000, R1 = 00000000, R2 = 00000000, R3 = 00000000
- R4 = 00000000, R5 = 00000000, R6 = 00000000, R7 = 00000000
- R8 = 00000000, R9 = 00000000, R10= 00000000, R11= 00000000
- R12= 00000000, R13= 2000C000, MSP= 2000C000, PSP= 00000000
- R14(LR) = FFFFFFFF, R15(PC) = 08001F24
- XPSR 01000000, APSR 00000000, EPSR 01000000, IPSR 00000000
- CFBP 00000000, CONTROL 00, FAULTMASK 00, BASEPRI 00, PRIMASK 00
- Reading all registers
- Read 4 bytes @ address 0x08001F24 (Data = 0xD034F8DF)
- Read 2 bytes @ address 0x08001F24 (Data = 0xF8DF)
- Setting breakpoint @ address 0x080212E8, Size = 2, BPHandle = 0x0001
- Setting breakpoint @ address 0x0802B4D4, Size = 2, BPHandle = 0x0002
- Starting target CPU...
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
- Comparing flash [100%] Done.
- Erasing flash [100%] Done.
- Programming flash [100%] Done.
- Verifying flash [100%] Done.
- J-Link: Flash download: Restarting flash programming due to program error (possibly skipped erasure of half-way erased sector).
- J-Link: Flash download: Skip optimizations disabled for second try.
- Error while programming flash: Programming failed.
Almost in despair, I also tried using J-Flash (under Windows):
Source Code
- Erasing selected sectors ...
- - 1 of 128 sectors selected, 1 range, 0x8020000 - 0x80207FF
- - Start of preparing flash programming
- - End of preparing flash programming
- - Start of determining dirty areas in flash cache
- - End of determining dirty areas
- - CPU speed could not be measured.
- - Start of erasing sectors
- - Start of blank checking
- - End of blank checking
- - End of erasing sectors
- - Start of restoring
- - End of restoring
- - Erase operation completed successfully - Completed after 0.156 sec
- Checking if selected data fits into selected flash sectors.
- Programming target (8 bytes, 1 range) ...
- - Start of preparing flash programming
- - End of preparing flash programming
- - Start of determining dirty areas in flash cache
- - End of determining dirty areas
- - CPU speed could not be measured.
- - Start of erasing sectors
- - Start of blank checking
- - End of blank checking
- - End of erasing sectors
- - Start of flash programming
- - Programming range 0x08020000 - 0x080207FF (001 Sector, 2 KB)
- - End of flash programming
- - Flash programming performed for 1 range (2048 bytes)
- - 0x8020000 - 0x80207FF (001 Sector, 2 KB)
- - Start of restoring
- - ERROR: Programming failed @ address 0x08020008 (program error)
- - ERROR: Failed to restore target. RAMCode never stops
- - End of restoring
- - ERROR: Failed to program target
- Disconnecting ...
- - Disconnected
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!