Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion pyocd/flash/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def get_sector_count(count: int) -> str:

@dataclass
class ProgrammingInfo:
program_type: Any = None # Type of programming performed - FLASH_SECTOR_ERASE or FLASH_CHIP_ERASE
program_type: Any = None # Type of programming performed.
program_time: float = 0.0 # Time to program flash
erase_time: float = 0.0 # Time to erase flash contents
analyze_type: Any = None # Type of flash analysis performed - FLASH_ANALYSIS_CRC32 or FLASH_ANALYSIS_PARTIAL_PAGE_READ
Expand Down Expand Up @@ -194,6 +194,7 @@ class FlashBuilder(MemoryBuilder):
# Type of flash operation
FLASH_SECTOR_ERASE = 1
FLASH_CHIP_ERASE = 2
FLASH_MASS_ERASE = 3

# Type of flash analysis
FLASH_ANALYSIS_CRC32 = "CRC32"
Expand Down
5 changes: 3 additions & 2 deletions pyocd/flash/file_programmer.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@ def __init__(self,
@param progress A progress report handler as a callable that takes a percentage completed.
If not set or None, a default progress handler will be used unless the session option
'hide_programming_progress' is set to True, in which case progress will be disabled.
@param chip_erase Sets whether to use chip erase or sector erase. The value must be one of
"auto", "sector", or "chip". "auto" means the fastest erase method should be used.
@param chip_erase Sets whether to use auto, sector, chip, or mass erase. The value must be
one of "auto", "sector", "chip", or "mass". "auto" means the fastest erase method
should be used.
@param smart_flash If set to True, the programmer will attempt to not program pages whose
contents are not going to change by scanning target flash memory. A value of False will
force all pages to be erased and programmed.
Expand Down
55 changes: 41 additions & 14 deletions pyocd/flash/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,9 @@ def __init__(self,
@param progress A progress report handler as a callable that takes a percentage completed.
If not set or None, a default progress handler will be used unless the session option
'hide_programming_progress' is set to True, in which case progress will be disabled.
@param chip_erase Sets whether to use chip erase or sector erase. The value must be one of
"auto", "sector", or "chip". "auto" means the fastest erase method should be used.
@param chip_erase Sets whether to use auto, sector, chip, or mass erase. The value must be
one of "auto", "sector", "chip", or "mass". "auto" means the fastest erase method
should be used.
@param smart_flash If set to True, the flash loader will attempt to not program pages whose
contents are not going to change by scanning target flash memory. A value of False will
force all pages to be erased and programmed.
Expand Down Expand Up @@ -289,19 +290,37 @@ def commit(self):
"""
perfList = []
sorted_builders = sorted(self._builders.values(), key=lambda v: v.region.start)
use_mass_erase = self._chip_erase == "mass"
mass_erase_time = 0.0

LOG.info("Erasing...")
self._progress_offset = 0.0
for builder in sorted_builders:
self._current_progress_fraction = builder.buffered_data_size / self._total_data_size
if use_mass_erase:
erase_start = time()
LOG.info("Mass erasing device...")
if self._session.target.mass_erase() is False:
raise exceptions.TargetError("mass erase failed")
mass_erase_time = time() - erase_start
LOG.info("Mass erase complete")

# Some targets reset and/or change debug access state as a side effect of mass erase.
# Re-run target init before programming so AP/core/flash state is rediscovered and
# security auto-unlock hooks can run if needed.
LOG.debug("Reinitializing target after mass erase")
self._session.target.init()
if self._progress is not None:
self._progress(1.0)
else:
for builder in sorted_builders:
self._current_progress_fraction = builder.buffered_data_size / self._total_data_size

# Erase the data.
builder.erase(chip_erase=self._chip_erase,
progress_cb=self._progress_cb,
smart_flash=self._smart_flash,
fast_verify=self._trust_crc,
keep_unwritten=self._keep_unwritten)
self._progress_offset += self._current_progress_fraction
# Erase the data.
builder.erase(chip_erase=self._chip_erase,
progress_cb=self._progress_cb,
smart_flash=self._smart_flash,
fast_verify=self._trust_crc,
keep_unwritten=self._keep_unwritten)
self._progress_offset += self._current_progress_fraction

# Call FlashEraseDone after all erase operations are finished.
if self._delegate is not None and self._delegate.has_sequence_with_name('FlashEraseDone'):
Expand All @@ -314,9 +333,12 @@ def commit(self):

# Program the data.
perf = builder.program(progress_cb=self._progress_cb,
smart_flash=self._smart_flash,
smart_flash=(False if use_mass_erase else self._smart_flash),
fast_verify=self._trust_crc,
keep_unwritten=self._keep_unwritten)
keep_unwritten=(False if use_mass_erase else self._keep_unwritten))
if use_mass_erase and not perfList:
perf.erase_time = mass_erase_time
perf.program_type = FlashBuilder.FLASH_MASS_ERASE
perfList.append(perf)
self._progress_offset += self._current_progress_fraction

Expand Down Expand Up @@ -350,7 +372,12 @@ def _log_performance(self, perf_list):
else:
kbps = (program_byte_count/1024) / totalTime

if any(perf.program_type == FlashBuilder.FLASH_CHIP_ERASE for perf in perf_list):
if any(perf.program_type == FlashBuilder.FLASH_MASS_ERASE for perf in perf_list):
LOG.info("Mass erased, programmed %d bytes (%s), skipped %d bytes (%s) at %.02f kB/s",
actual_program_byte_count, get_page_count(actual_program_page_count),
skipped_byte_count, get_page_count(skipped_page_count),
kbps)
elif any(perf.program_type == FlashBuilder.FLASH_CHIP_ERASE for perf in perf_list):
LOG.info("Erased chip, programmed %d bytes (%s), skipped %d bytes (%s) at %.02f kB/s",
actual_program_byte_count, get_page_count(actual_program_page_count),
skipped_byte_count, get_page_count(skipped_page_count),
Expand Down
1 change: 1 addition & 0 deletions pyocd/subcommands/load_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class LoadSubcommand(SubcommandBase):
ERASE_OPTIONS = [
'auto',
'chip',
'mass',
'sector',
]

Expand Down