Skip to content

FLM valEmpty ignored for sparse HEX holes #2025

Closed

Description

@ybisland

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

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_empty

not only generated subregions.

Activity

  1. ybisland commented on Oct 14, 2026

    @ybisland
    Author

    This issue has been fixed by @swimmingbrain #2032.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions