diff --git a/boards/nordic/thingy53/board.cmake b/boards/nordic/thingy53/board.cmake index 916d982b65c..f03b026d9fb 100644 --- a/boards/nordic/thingy53/board.cmake +++ b/boards/nordic/thingy53/board.cmake @@ -1,6 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 if(CONFIG_BOARD_THINGY53_NRF5340_CPUAPP OR CONFIG_BOARD_THINGY53_NRF5340_CPUAPP_NS) + board_runner_args(nrfutil "--ext-mem-config-file=${BOARD_DIR}/thingy53_qspi_nrfutil_config.json") board_runner_args(jlink "--device=nrf5340_xxaa_app" "--speed=4000") elseif(CONFIG_BOARD_THINGY53_NRF5340_CPUNET) board_runner_args(jlink "--device=nrf5340_xxaa_net" "--speed=4000") diff --git a/boards/nordic/thingy53/thingy53_qspi_nrfutil_config.json b/boards/nordic/thingy53/thingy53_qspi_nrfutil_config.json new file mode 100644 index 00000000000..8138801cd91 --- /dev/null +++ b/boards/nordic/thingy53/thingy53_qspi_nrfutil_config.json @@ -0,0 +1,22 @@ +{ + "firmware_config": { + "peripheral": "QSPI" + }, + "pins": { + "sck": 17, + "csn": 18, + "io0": 13, + "io1": 14, + "io2": 15, + "io3": 16 + }, + "flash_size": 67108864, + "sck_frequency": 8000000, + "address_mode": "MODE24BIT", + "readoc": "READ2IO", + "writeoc": "PP", + "pp_size": "PPSIZE256", + "sck_delay": 128, + "rx_delay": 2, + "page_size": 4096 +} diff --git a/doc/releases/migration-guide-4.1.rst b/doc/releases/migration-guide-4.1.rst index 868f7511aad..ab6355ed77d 100644 --- a/doc/releases/migration-guide-4.1.rst +++ b/doc/releases/migration-guide-4.1.rst @@ -46,6 +46,13 @@ Boards instead of pin reset when flashing with ``west flash``. If you want to keep using pin reset on the nRF52 family of ICs you can use ``west flash --pinreset``. +* Erasing the external memory when programming a new firmware image with ``west + flash`` on the nRF52 and nRF53 series now always correctly honors the + ``--erase`` flag (and its absence) both when using the ``nrfjprog`` and + ``nrfutil`` backends. Prior to this release, the ``nrjfprog`` backend would + always erase only the sectors of the external flash used by the new firmware, + and the ``nrfutil`` one would always erase the whole external flash. + Devicetree ********** diff --git a/scripts/west_commands/runners/nrf_common.py b/scripts/west_commands/runners/nrf_common.py index 60fc96bf392..a3af56c63fe 100644 --- a/scripts/west_commands/runners/nrf_common.py +++ b/scripts/west_commands/runners/nrf_common.py @@ -413,7 +413,7 @@ def program_hex(self): 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_ALL' + ext_mem_erase_opt = erase_arg self.op_program(self.hex_, erase_arg, ext_mem_erase_opt, defer=True, core=core) self.flush(force=False) diff --git a/scripts/west_commands/runners/nrfjprog.py b/scripts/west_commands/runners/nrfjprog.py index c7e003824a3..36461b7236d 100644 --- a/scripts/west_commands/runners/nrfjprog.py +++ b/scripts/west_commands/runners/nrfjprog.py @@ -91,8 +91,11 @@ def do_exec_op(self, op, force=False): raise RuntimeError(f'Invalid erase mode: {erase}') if opts.get('ext_mem_erase_mode'): - # In the future there might be multiple QSPI erase modes - cmd.append('--qspisectorerase') + if opts['ext_mem_erase_mode'] == 'ERASE_RANGES_TOUCHED_BY_FIRMWARE': + cmd.append('--qspisectorerase') + elif opts['ext_mem_erase_mode'] == 'ERASE_ALL': + cmd.append('--qspichiperase') + if opts.get('verify'): # In the future there might be multiple verify modes cmd.append('--verify') diff --git a/scripts/west_commands/runners/nrfutil.py b/scripts/west_commands/runners/nrfutil.py index a4f17282259..f937da74c07 100644 --- a/scripts/west_commands/runners/nrfutil.py +++ b/scripts/west_commands/runners/nrfutil.py @@ -18,12 +18,13 @@ class NrfUtilBinaryRunner(NrfBinaryRunner): def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False, reset=True, tool_opt=None, force=False, recover=False, - suit_starter=False): + suit_starter=False, ext_mem_config_file=None): super().__init__(cfg, family, softreset, pinreset, dev_id, erase, reset, tool_opt, force, recover) self.suit_starter = suit_starter + self.ext_mem_config_file = ext_mem_config_file self._ops = [] self._op_id = 1 @@ -43,7 +44,8 @@ def do_create(cls, cfg, args): reset=args.reset, tool_opt=args.tool_opt, force=args.force, recover=args.recover, - suit_starter=args.suit_manifest_starter) + suit_starter=args.suit_manifest_starter, + ext_mem_config_file=args.ext_mem_config_file) @classmethod def do_add_parser(cls, parser): @@ -51,6 +53,10 @@ def do_add_parser(cls, parser): parser.add_argument('--suit-manifest-starter', required=False, action='store_true', help='Use the SUIT manifest starter file') + parser.add_argument('--ext-mem-config-file', required=False, + dest='ext_mem_config_file', + help='path to an JSON file with external memory configuration') + def _exec(self, args): jout_all = [] @@ -139,8 +145,13 @@ def _exec_batch(self): self._ops = [] self._op_id = 1 self.logger.debug(f'Executing batch in: {json_file}') - self._exec(['x-execute-batch', '--batch-path', f'{json_file}', - '--serial-number', f'{self.dev_id}']) + precmd = [] + if self.ext_mem_config_file: + # This needs to be prepended, as it's a global option + precmd = ['--x-ext-mem-config-file', self.ext_mem_config_file] + + self._exec(precmd + ['x-execute-batch', '--batch-path', f'{json_file}', + '--serial-number', f'{self.dev_id}']) def do_exec_op(self, op, force=False): self.logger.debug(f'Executing op: {op}')