runners: nrf: Default to ERASE_NONE for the nRF54L series

The Nordic nRF54L series ICs use RRAM instead of flash. This implies
that erasing the internal storage before writing the new firmware is not
required anymore (unlike NOR flash, which does).
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.
In order to speed up the flashing operation and avoiding doing wasteful
write operations on the RRAM, default to ERASE_NONE for ICs in these
series.
A new ``--erase-pages`` command-line switch has been added to allow
users to keep erasing the pages that will be written to the firmware.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
This commit is contained in:
Carles Cufi 2025-03-27 16:10:04 +01:00 committed by Benjamin Cabé
commit f42cef9c81
4 changed files with 42 additions and 14 deletions

View file

@ -38,6 +38,15 @@ Boards
nRF Util can be found
`here <https://docs.nordicsemi.com/bundle/nrfutil/page/README.html>`_.
* 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``.
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.
* The config option :kconfig:option:`CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME` has been deprecated
in favor of :kconfig:option:`CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME`.

View file

@ -79,7 +79,8 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
'''Runner front-end base class for nrf tools.'''
def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False,
reset=True, tool_opt=None, force=False, recover=False):
erase_pages=False, reset=True, tool_opt=None, force=False,
recover=False):
super().__init__(cfg)
self.hex_ = cfg.hex_file
# The old --nrf-family options takes upper-case family names
@ -88,6 +89,7 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
self.pinreset = pinreset
self.dev_id = dev_id
self.erase = bool(erase)
self.erase_pages = bool(erase_pages)
self.reset = bool(reset)
self.force = force
self.recover = bool(recover)
@ -137,6 +139,9 @@ 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.set_defaults(reset=True)
@ -413,9 +418,13 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
else:
if self.erase:
erase_arg = 'ERASE_ALL'
elif self.family == 'nrf54l' and not self.erase_pages:
erase_arg = 'ERASE_NONE'
else:
erase_arg = 'ERASE_RANGES_TOUCHED_BY_FIRMWARE'
self.logger.debug(f'Erase type: {erase_arg}')
xip_ranges = {
'nrf52': (0x12000000, 0x19FFFFFF),
'nrf53': (0x10000000, 0x1FFFFFFF),
@ -424,7 +433,9 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
if self.family in xip_ranges:
xip_start, xip_end = xip_ranges[self.family]
if self.hex_refers_region(xip_start, xip_end):
ext_mem_erase_opt = erase_arg
# Default to pages for the external memory
ext_mem_erase_opt = erase_arg if erase_arg == 'ERASE_ALL' else \
'ERASE_RANGES_TOUCHED_BY_FIRMWARE'
self.op_program(self.hex_, erase_arg, ext_mem_erase_opt, defer=True, core=core)
self.flush(force=False)
@ -517,6 +528,16 @@ 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 '
'exclusive.')
self.ensure_family()
if self.family != 'nrf54l' and self.erase_pages:
raise RuntimeError('Option --erase-pages can only be used with the '
'nRF54L family.')
self.ensure_output('hex')
if IntelHex is None:
raise RuntimeError('Python dependency intelhex was missing; '
@ -527,7 +548,6 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
self.hex_contents.loadfile(self.hex_, format='hex')
self.ensure_snr()
self.ensure_family()
self.ops = deque()

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,
reset=True, tool_opt=None, force=False, recover=False,
qspi_ini=None):
erase_pages=False, reset=True, tool_opt=None, force=False,
recover=False, qspi_ini=None):
super().__init__(cfg, family, softreset, pinreset, dev_id, erase, reset,
tool_opt, force, recover)
super().__init__(cfg, family, softreset, pinreset, dev_id, erase,
erase_pages, 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,
reset=args.reset,
erase_pages=args.erase_pages, 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,
reset=True, tool_opt=None, force=False, recover=False,
suit_starter=False, ext_mem_config_file=None):
erase_pages=False, 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, reset,
tool_opt, force, recover)
super().__init__(cfg, family, softreset, pinreset, dev_id, erase,
erase_pages, 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,
reset=args.reset,
erase_pages=args.erase_pages, reset=args.reset,
tool_opt=args.tool_opt, force=args.force,
recover=args.recover,
suit_starter=args.suit_manifest_starter,
@ -66,7 +66,6 @@ class NrfUtilBinaryRunner(NrfBinaryRunner):
dest='ext_mem_config_file',
help='path to an JSON file with external memory configuration')
def _exec(self, args):
jout_all = []