Skip to content

Commit

Permalink
flash: allow FlashBuilder to work when program page size is larger th…
Browse files Browse the repository at this point in the history
…an sector erase size (#1608)

* Allow programming of devices where sector_size < program_size (e.g. STM32H7B0)
* fix sector iterator
  • Loading branch information
BrianPugh authored Aug 21, 2023
1 parent bb5aaf0 commit d64bfab
Showing 1 changed file with 37 additions and 14 deletions.
51 changes: 37 additions & 14 deletions pyocd/flash/builder.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# pyOCD debugger
# Copyright (c) 2015-2019 Arm Limited
# Copyright (c) 2021 Chris Reed
# Copyright (c) 2023 Brian Pugh
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -94,12 +95,22 @@ def _stub_progress(percent):

class _FlashSector:
"""@brief Info about an erase sector and all pages to be programmed within it."""
def __init__(self, sector_info):
def __init__(self, sector_info, n_subsectors: int = 1):
self.addr: int = sector_info.base_addr
self.size: int = sector_info.size
self._subsector_size: int = sector_info.size
self.max_page_count: int = 0
self.page_list: List[_FlashPage] = []
self.erase_weight: float = sector_info.erase_weight
self.n_subsectors = n_subsectors

@property
def size(self):
return self.n_subsectors * self._subsector_size

@property
def addrs(self):
for i in range(self.n_subsectors):
yield self.addr + (i * self._subsector_size)

def add_page(self, page):
# The first time a page is added, compute the page count for this sector. This
Expand All @@ -122,8 +133,8 @@ def mark_all_pages_not_same(self):
page.same = False

def __repr__(self):
return "<_FlashSector@%x addr=%x size=%x wgt=%g pages=%s>" % (
id(self), self.addr, self.size, self.erase_weight, self.page_list)
return "<_FlashSector@%x addr=%x size=%x wgt=%g pages=%s, subsectors=%d>" % (
id(self), self.addr, self.size, self.erase_weight, self.page_list, self.n_subsectors)

class _FlashPage:
"""@brief A page to be programmed and its data."""
Expand Down Expand Up @@ -187,8 +198,8 @@ def __init__(self, flash):
self.flash = flash
self.flash_start = flash.region.start
self.flash_operation_list = []
self.sector_list = []
self.page_list = []
self.sector_list: List[_FlashSector] = []
self.page_list: List[_FlashPage] = []
self.perf = ProgrammingInfo()
self.enable_double_buffering = True
self.log_performance = True
Expand Down Expand Up @@ -285,11 +296,23 @@ def _build_sectors_and_pages(self, keep_unwritten):
if page_info is None:
raise FlashFailure("attempt to program invalid flash address", address=flash_addr)

current_sector = _FlashSector(sector_info)
self.sector_list.append(current_sector)
def create_flash_sector(sector_info, page_info):
if page_info.size > sector_info.size:
assert page_info.size % sector_info.size == 0, \
f"Sector ({sector_info.size} bytes) do not fit evenly into page ({page_info.size} bytes)"
n_subsectors = page_info.size // sector_info.size
else:
n_subsectors = 1

return _FlashSector(sector_info, n_subsectors=n_subsectors)

current_page = _FlashPage(page_info)
current_sector.add_page(current_page)
current_sector = create_flash_sector(sector_info, page_info)

self.page_list.append(current_page)
self.sector_list.append(current_sector)

current_sector.add_page(current_page)

def fill_end_of_page_gap():
# Fill the gap at the end of the soon to be previous page if there is one
Expand All @@ -314,7 +337,7 @@ def fill_end_of_page_gap():
sector_info = self.flash.get_sector_info(flash_addr)
if sector_info is None:
raise FlashFailure("attempt to program invalid flash address", address=flash_addr)
current_sector = _FlashSector(sector_info)
current_sector = create_flash_sector(sector_info, page_info)
self.sector_list.append(current_sector)

# Check if operation is in a different page
Expand Down Expand Up @@ -807,11 +830,11 @@ def _sector_erase_program(self, progress_cb=_stub_progress):

for sector in self.sector_list:
if sector.are_any_pages_not_same():

if self.region.is_erasable:
# Erase the sector
self.flash.init(self.flash.Operation.ERASE)
self.flash.erase_sector(sector.addr)
for addr in sector.addrs:
self.flash.erase_sector(addr)
self.flash.uninit()

actual_sector_erase_weight += sector.erase_weight
Expand Down Expand Up @@ -909,14 +932,14 @@ def _sector_erase_program_double_buffer(self, progress_cb=_stub_progress):
# to read from flash while simultaneously programming it.
progress = self._scan_pages_for_same(progress_cb)


if self.region.is_erasable:
# Erase all sectors up front.
self.flash.init(self.flash.Operation.ERASE)
for sector in self.sector_list:
if sector.are_any_pages_not_same():
# Erase the sector
self.flash.erase_sector(sector.addr)
for addr in sector.addrs:
self.flash.erase_sector(addr)

# Update progress
progress += sector.erase_weight
Expand Down

0 comments on commit d64bfab

Please sign in to comment.