Repository navigation
FLM valEmpty ignored for sparse HEX holes #2025
Description
Summary
pyOCD appears to ignore the CMSIS-Pack FLM FlashDevice.valEmpty value when programming sparse Intel HEX files if the FLM describes one uniform sector range covering the whole flash memory region.
For the SinOne SC32F1xxxx target, the APROM erased value is 0x00, and the FLM reports FlashDevice.valEmpty = 0x00. However, pyOCD keeps the parent FlashRegion.erased_byte_value as the default 0xFF. As a result, when loading a sparse Intel HEX file, holes inside programmed pages are filled/programmed as 0xFF instead of 0x00.
pyocd erase --chip itself works correctly and leaves flash erased bytes as 0x00. The issue only appears during sparse image programming.
Environment
- pyOCD version:
0.44.1 - Also inspected:
0.45.1, the related logic appears unchanged - Probe: SEGGER J-Link
- Target: SinOne
SC32F12TC7 - Pack:
SinOne.SC32xxxxx_DFP.2.0.0.pack - Flash region:
- APROM /
IROM1 - Start:
0x08000000 - Size:
0x20000 - Sector/page size:
0x200 - FLM:
Flash/SC32F1XXX_128K_APROM.FLM
- APROM /
Expected Behavior
When loading a sparse Intel HEX file, pyOCD should fill holes according to the target flash erased value from the FLM:
FlashDevice.valEmpty = 0x00
Therefore, sparse HEX holes should be treated as 0x00.
Actual Behavior
pyOCD fills sparse HEX holes as 0xFF.
After flashing with:
pyocd load --target sc32f12tc7 --project . --erase chip --format hex build/debug/xxx.hex
and reading back the full APROM, explicit HEX bytes match, but hole bytes programmed as 0xFF instead of 0x00.
Why I Think This Happens
The FLM parser correctly reads FlashDevice.valEmpty.
In pyocd/target/pack/flash_algo.py, FlashDevice.value_empty is parsed from the FLM.
However, in pyocd/target/pack/flm_region_builder.py, when the FLM has a single sector range covering the parent memory region, pyOCD does not create subregions. In that path it sets attributes like page_size and sector_size, but does not propagate pack_algo.flash_info.value_empty to the parent flash region's erased_byte_value.
So the parent region keeps the default value from pyocd/core/memory_map.py:
FlashRegion.erased_byte_value = 0xFF
Later, pyocd/flash/builder.py uses self.flash.region.erased_byte_value when building page buffers for programming sparse images. Because the region value is still 0xFF, sparse HEX holes are filled as 0xFF.
Local Workaround
I added a project-local pyocd_user.py hook to fill holes with 0x00.
def _patch_erased_byte_value(memory_map):
for region in memory_map:
if region.name == "IROM1" and region.start == 0x08000000:
region.attributes["erased_byte_value"] = 0x00
submap = getattr(region, "submap", None)
if submap is not None:
for subregion in submap:
if subregion.start >= 0x08000000 and subregion.end <= 0x0801FFFF:
subregion.attributes["erased_byte_value"] = 0x00
def did_connect(board):
target = board.target
_patch_erased_byte_value(target.memory_map)
for core in target.cores.values():
_patch_erased_byte_value(core.memory_map)Suggested Fix
When building CMSIS-Pack flash regions from FLM data, pyOCD should propagate FlashDevice.valEmpty to the resulting FlashRegion.erased_byte_value, including the case where no subregion is created because the FLM sector range covers the full parent memory region.
In other words, the parent flash region should get:
erased_byte_value = pack_algo.flash_info.value_emptynot only generated subregions.
Activity
ybisland commentedon Oct 14, 2026
This issue has been fixed by @swimmingbrain #2032.