Skip to content

Commit 006d64e

Browse files
committed
Merge firmware before flashing via OpenOCD
Arduino core v2.0.4 contains updated bootloader images that have innacurate default headers. This results in bootloops if firmware is flashed via OpenOCD (e.g. debugging or uploading via debug tools). For this reason, before uploading or debugging we need to merge all binaries (firmware, bootloader, partitions, etc.) via esptoolpy so that the image headers will be adjusted according to --flash-size and --flash-mode arguments. Note that this behavior doesn't occur if uploading is done via esptoolpy, as esptoolpy overrides the binary image headers before flashing.
1 parent f2a5977 commit 006d64e

File tree

2 files changed

+63
-9
lines changed

2 files changed

+63
-9
lines changed

builder/main.py

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,18 @@ def __fetch_fs_size(target, source, env):
160160
return (target, source)
161161

162162

163+
def merge_binaries(source, target, env, for_signature):
164+
return " ".join([
165+
'"$PYTHONEXE"',
166+
join(platform.get_package_dir("tool-esptoolpy") or "", "esptool.py"),
167+
"--chip", mcu, "merge_bin",
168+
"-o", "$TARGET",
169+
"--flash_mode", "$BOARD_FLASH_MODE",
170+
"--flash_size", board.get("upload.flash_size", "detect"),
171+
"$ESP32_APP_OFFSET", "$SOURCES"
172+
] + ['"%s"' % itm for img in env.get("FLASH_EXTRA_IMAGES", []) for itm in img])
173+
174+
163175
env = DefaultEnvironment()
164176
platform = env.PioPlatform()
165177
board = env.BoardConfig()
@@ -169,6 +181,21 @@ def __fetch_fs_size(target, source, env):
169181
if mcu == "esp32c3":
170182
toolchain_arch = "riscv32-esp"
171183

184+
# Arduino core v2.0.4 contains updated bootloader images that have innacurate default
185+
# headers. This results in bootloops if firmware is flashed via OpenOCD (e.g. debugging
186+
# or uploading via debug tools). For this reason, before uploading or debugging we need
187+
# to merge binaries via esptoolpy so that the image headers will be adjusted according to
188+
# --flash-size and --flash-mode arguments.
189+
# Note: This behavior doesn't occur if uploading is done via esptoolpy, as esptoolpy
190+
# overrides the binary image headers before flashing.
191+
firmware_merge_required = bool(
192+
env.get("PIOFRAMEWORK", []) == ["arduino"]
193+
and (
194+
"debug" in env.GetBuildType()
195+
or env.subst("$UPLOAD_PROTOCOL") in board.get("debug.tools", {})
196+
)
197+
)
198+
172199
if "INTEGRATION_EXTRA_DATA" not in env:
173200
env["INTEGRATION_EXTRA_DATA"] = {}
174201

@@ -264,6 +291,10 @@ def __fetch_fs_size(target, source, env):
264291
source_factory=env.Dir,
265292
suffix=".bin",
266293
),
294+
MergeBin=Builder(
295+
generator=merge_binaries,
296+
suffix=".bin",
297+
),
267298
)
268299
)
269300

@@ -275,6 +306,7 @@ def __fetch_fs_size(target, source, env):
275306
#
276307

277308
target_elf = None
309+
target_firm_merged = None
278310
if "nobuild" in COMMAND_LINE_TARGETS:
279311
target_elf = join("$BUILD_DIR", "${PROGNAME}.elf")
280312
if set(["uploadfs", "uploadfsota"]) & set(COMMAND_LINE_TARGETS):
@@ -293,6 +325,14 @@ def __fetch_fs_size(target, source, env):
293325
else:
294326
target_firm = env.ElfToBin(
295327
join("$BUILD_DIR", "${PROGNAME}"), target_elf)
328+
if firmware_merge_required:
329+
# Note: Default offset address must be set to 0x0 because debugging
330+
# relies on OpenOCD that requires merged firmware
331+
env["INTEGRATION_EXTRA_DATA"].update(
332+
{"application_offset": "0x0", "merged_firmware": True}
333+
)
334+
target_firm_merged = env.MergeBin(join(
335+
"$BUILD_DIR", "${PROGNAME}_merged"), target_firm)
296336
env.Depends(target_firm, "checkprogsize")
297337

298338
env.AddPlatformTarget("buildfs", target_firm, target_firm, "Build Filesystem Image")
@@ -430,6 +470,10 @@ def __fetch_fs_size(target, source, env):
430470

431471

432472
elif upload_protocol in debug_tools:
473+
if firmware_merge_required:
474+
# Only merged firmware with proper headers will work when uploading is done via
475+
# debug probes. The firmware offset address must be adjusted to 0x0 accordingly.
476+
target_firm = target_firm_merged
433477
openocd_args = ["-d%d" % (2 if int(ARGUMENTS.get("PIOVERBOSE", 0)) else 1)]
434478
openocd_args.extend(
435479
debug_tools.get(upload_protocol).get("server").get("arguments", []))
@@ -442,11 +486,14 @@ def __fetch_fs_size(target, source, env):
442486
% (
443487
"$FS_START"
444488
if "uploadfs" in COMMAND_LINE_TARGETS
445-
else "$ESP32_APP_OFFSET"
489+
else board.get(
490+
"upload.offset_address",
491+
"0x0" if firmware_merge_required else "$ESP32_APP_OFFSET"
492+
)
446493
),
447494
]
448495
)
449-
if "uploadfs" not in COMMAND_LINE_TARGETS:
496+
if "uploadfs" not in COMMAND_LINE_TARGETS and not firmware_merge_required:
450497
for image in env.get("FLASH_EXTRA_IMAGES", []):
451498
openocd_args.extend(
452499
[

platform.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -261,16 +261,23 @@ def configure_debug_session(self, debug_config):
261261
if any(ignore_conds):
262262
return
263263

264-
load_cmds = [
265-
'monitor program_esp "{{{path}}}" {offset} verify'.format(
266-
path=to_unix_path(item["path"]), offset=item["offset"]
267-
)
268-
for item in flash_images
269-
]
264+
merged_firmware = build_extra_data.get("merged_firmware", False)
265+
load_cmds = []
266+
if not merged_firmware:
267+
load_cmds.extend([
268+
'monitor program_esp "{{{path}}}" {offset} verify'.format(
269+
path=to_unix_path(item["path"]), offset=item["offset"]
270+
)
271+
for item in flash_images
272+
])
273+
270274
load_cmds.append(
271275
'monitor program_esp "{%s.bin}" %s verify'
272276
% (
273-
to_unix_path(debug_config.build_data["prog_path"][:-4]),
277+
to_unix_path(
278+
debug_config.build_data["prog_path"][:-4]
279+
+ ("_merged" if merged_firmware else "")
280+
),
274281
build_extra_data.get("application_offset", "0x10000"),
275282
)
276283
)

0 commit comments

Comments
 (0)