west: runners: nrf: Generalize the erase command

Instead of providing an `--erase-pages` command, generalize it to a new
`--erase-mode` one that can be set to `none`, `ranges`, or `all`. This
gives the user full control over the erase mode that will be passed on
to nrfutil.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
This commit is contained in:
Carles Cufi 2025-04-11 19:32:20 +02:00 committed by Benjamin Cabé
commit 58e0e31c7e
4 changed files with 32 additions and 19 deletions

View file

@ -41,8 +41,8 @@ Boards
* All boards based on a Nordic IC of the nRF54L series now default to not
erasing any part of the internal storage when flashing. If you'd like to
revert to the previous default of erasing the pages that will be written to by
the firmware to be flashed you can use the new ``--erase-pages`` command-line
switch when invoking ``west flash``.
the firmware to be flashed you can set the new ``--erase-mode`` command-line
switch when invoking ``west flash`` to ``ranges``.
Note that RRAM on nRF54L devices is not physically paged, and paging is
only artificially provided, with a page size of 4096 bytes, for an easier
transition of nRF52 software to nRF54L devices.

View file

@ -79,7 +79,7 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
'''Runner front-end base class for nrf tools.'''
def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False,
erase_pages=False, reset=True, tool_opt=None, force=False,
erase_mode=None, reset=True, tool_opt=None, force=False,
recover=False):
super().__init__(cfg)
self.hex_ = cfg.hex_file
@ -89,7 +89,7 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
self.pinreset = pinreset
self.dev_id = dev_id
self.erase = bool(erase)
self.erase_pages = bool(erase_pages)
self.erase_mode = erase_mode
self.reset = bool(reset)
self.force = force
self.recover = bool(recover)
@ -139,9 +139,10 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
help='''erase all user available non-volatile
memory and disable read back protection before
flashing (erases flash for both cores on nRF53)''')
parser.add_argument('--erase-pages', required=False,
action='store_true', dest='erase_pages',
help='erase pages to be used by the firmware')
parser.add_argument('--erase-mode', required=False,
choices=['none', 'ranges', 'all'], dest='erase_mode',
help='Select the type of erase operation for the '
'internal non-volatile memory')
parser.set_defaults(reset=True)
@ -341,6 +342,18 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
return None
def _get_erase_mode(self, mode):
if not mode:
return None
elif mode == "none":
return "ERASE_NONE"
elif mode == "ranges":
return "ERASE_RANGES_TOUCHED_BY_FIRMWARE"
elif mode == "all":
return "ERASE_ALL"
else:
raise RuntimeError(f"Invalid erase mode: {mode}")
def program_hex(self):
# Get the command use to actually program self.hex_.
self.logger.info(f'Flashing file: {self.hex_}')
@ -421,8 +434,8 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
else:
if self.erase:
erase_arg = 'ERASE_ALL'
elif self.family == 'nrf54l' and not self.erase_pages:
erase_arg = 'ERASE_NONE'
elif self.family == 'nrf54l':
erase_arg = self._get_erase_mode(self.erase_mode) or 'ERASE_NONE'
else:
erase_arg = 'ERASE_RANGES_TOUCHED_BY_FIRMWARE'
@ -531,14 +544,14 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
raise RuntimeError('Options --softreset and --pinreset are mutually '
'exclusive.')
if self.erase and self.erase_pages:
raise RuntimeError('Options --erase and --erase-pages are mutually '
if self.erase and self.erase_mode:
raise RuntimeError('Options --erase and --erase-mode are mutually '
'exclusive.')
self.ensure_family()
if self.family != 'nrf54l' and self.erase_pages:
raise RuntimeError('Option --erase-pages can only be used with the '
if self.family != 'nrf54l' and self.erase_mode:
raise RuntimeError('Option --erase-mode can only be used with the '
'nRF54L family.')
self.ensure_output('hex')

View file

@ -18,11 +18,11 @@ class NrfJprogBinaryRunner(NrfBinaryRunner):
'''Runner front-end for nrfjprog.'''
def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False,
erase_pages=False, reset=True, tool_opt=None, force=False,
erase_mode=None, reset=True, tool_opt=None, force=False,
recover=False, qspi_ini=None):
super().__init__(cfg, family, softreset, pinreset, dev_id, erase,
erase_pages, reset, tool_opt, force, recover)
erase_mode, reset, tool_opt, force, recover)
self.qspi_ini = qspi_ini
@ -46,7 +46,7 @@ class NrfJprogBinaryRunner(NrfBinaryRunner):
def do_create(cls, cfg, args):
return NrfJprogBinaryRunner(cfg, args.nrf_family, args.softreset,
args.pinreset, args.dev_id, erase=args.erase,
erase_pages=args.erase_pages, reset=args.reset,
erase_mode=args.erase_mode, reset=args.reset,
tool_opt=args.tool_opt, force=args.force,
recover=args.recover, qspi_ini=args.qspi_ini)
@classmethod

View file

@ -17,11 +17,11 @@ class NrfUtilBinaryRunner(NrfBinaryRunner):
'''Runner front-end for nrfutil.'''
def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False,
erase_pages=False, reset=True, tool_opt=None, force=False,
erase_mode=None, reset=True, tool_opt=None, force=False,
recover=False, suit_starter=False, ext_mem_config_file=None):
super().__init__(cfg, family, softreset, pinreset, dev_id, erase,
erase_pages, reset, tool_opt, force, recover)
erase_mode, reset, tool_opt, force, recover)
self.suit_starter = suit_starter
self.ext_mem_config_file = ext_mem_config_file
@ -50,7 +50,7 @@ class NrfUtilBinaryRunner(NrfBinaryRunner):
def do_create(cls, cfg, args):
return NrfUtilBinaryRunner(cfg, args.nrf_family, args.softreset,
args.pinreset, args.dev_id, erase=args.erase,
erase_pages=args.erase_pages, reset=args.reset,
erase_mode=args.erase_mode, reset=args.reset,
tool_opt=args.tool_opt, force=args.force,
recover=args.recover,
suit_starter=args.suit_manifest_starter,