Skip to content

Commit cdd0867

Browse files
committed
Update bootloader image headers before debugging or uploading via debug tools
This approach is less intrusive than merging the entire application into one binary implemented in #006d64e8b268e479703a0aac7eed8bef1ebea587 In this implementation we safely copy the required bootloader binary to the build directory, adjust the headers via esptoolpy and the "merge_bin" command according to --flash-size and --flash-mode arguments. Resolves platformio#872
1 parent bb2d073 commit cdd0867

File tree

2 files changed

+49
-61
lines changed

2 files changed

+49
-61
lines changed

builder/main.py

Lines changed: 42 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -160,18 +160,6 @@ 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", "4MB"),
171-
"$ESP32_APP_OFFSET", "$SOURCES"
172-
] + ['"%s"' % itm for img in env.get("FLASH_EXTRA_IMAGES", []) for itm in img])
173-
174-
175163
env = DefaultEnvironment()
176164
platform = env.PioPlatform()
177165
board = env.BoardConfig()
@@ -181,21 +169,6 @@ def merge_binaries(source, target, env, for_signature):
181169
if mcu == "esp32c3":
182170
toolchain_arch = "riscv32-esp"
183171

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-
199172
if "INTEGRATION_EXTRA_DATA" not in env:
200173
env["INTEGRATION_EXTRA_DATA"] = {}
201174

@@ -291,10 +264,6 @@ def merge_binaries(source, target, env, for_signature):
291264
source_factory=env.Dir,
292265
suffix=".bin",
293266
),
294-
MergeBin=Builder(
295-
generator=merge_binaries,
296-
suffix=".bin",
297-
),
298267
)
299268
)
300269

@@ -306,7 +275,6 @@ def merge_binaries(source, target, env, for_signature):
306275
#
307276

308277
target_elf = None
309-
target_firm_merged = None
310278
if "nobuild" in COMMAND_LINE_TARGETS:
311279
target_elf = join("$BUILD_DIR", "${PROGNAME}.elf")
312280
if set(["uploadfs", "uploadfsota"]) & set(COMMAND_LINE_TARGETS):
@@ -325,14 +293,6 @@ def merge_binaries(source, target, env, for_signature):
325293
else:
326294
target_firm = env.ElfToBin(
327295
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)
336296
env.Depends(target_firm, "checkprogsize")
337297

338298
env.AddPlatformTarget("buildfs", target_firm, target_firm, "Build Filesystem Image")
@@ -362,6 +322,46 @@ def merge_binaries(source, target, env, for_signature):
362322
"Calculate program size",
363323
)
364324

325+
# Arduino core v2.0.4 contains updated bootloader images that have innacurate default
326+
# headers. This results in bootloops if firmware is flashed via OpenOCD (e.g. debugging
327+
# or uploading via debug tools). For this reason, before uploading or debugging we need
328+
# to adjust the bootloader binary according to --flash-size and --flash-mode arguments.
329+
# Note: This behavior doesn't occur if uploading is done via esptoolpy, as esptoolpy
330+
# overrides the binary image headers before flashing.
331+
bootloader_patch_required = bool(
332+
env.get("PIOFRAMEWORK", []) == ["arduino"]
333+
and (
334+
"debug" in env.GetBuildType()
335+
or env.subst("$UPLOAD_PROTOCOL") in board.get("debug.tools", {})
336+
)
337+
)
338+
339+
if bootloader_patch_required:
340+
result = []
341+
for offset, image in env.get("FLASH_EXTRA_IMAGES", []):
342+
# 0x1000 for ESP32/S2, 0x0 for others
343+
default_bootloader_offsets = ("0x0", "0x0000", "0x1000")
344+
if offset in default_bootloader_offsets:
345+
original_bootloader_path = env.subst(image)
346+
image = join(env.subst("$BUILD_DIR"), "patched_bootloader.bin")
347+
env.AddPreAction(
348+
target_elf,
349+
env.VerboseAction(" ".join([
350+
'"$PYTHONEXE"',
351+
join(platform.get_package_dir("tool-esptoolpy") or "", "esptool.py"),
352+
"--chip", mcu, "merge_bin",
353+
"-o", '"%s"' % image,
354+
"--flash_mode", _get_board_flash_mode(env),
355+
"--flash_size", board.get("upload.flash_size", "4MB"),
356+
"--target-offset", offset,
357+
offset, '"%s"' % original_bootloader_path
358+
]), "Updating bootloader headers")
359+
)
360+
361+
result.append((offset, image))
362+
363+
env.Replace(FLASH_EXTRA_IMAGES=result)
364+
365365
#
366366
# Target: Upload firmware or FS image
367367
#
@@ -470,10 +470,6 @@ def merge_binaries(source, target, env, for_signature):
470470

471471

472472
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
477473
openocd_args = ["-d%d" % (2 if int(ARGUMENTS.get("PIOVERBOSE", 0)) else 1)]
478474
openocd_args.extend(
479475
debug_tools.get(upload_protocol).get("server").get("arguments", []))
@@ -487,13 +483,12 @@ def merge_binaries(source, target, env, for_signature):
487483
"$FS_START"
488484
if "uploadfs" in COMMAND_LINE_TARGETS
489485
else board.get(
490-
"upload.offset_address",
491-
"0x0" if firmware_merge_required else "$ESP32_APP_OFFSET"
486+
"upload.offset_address", "$ESP32_APP_OFFSET"
492487
)
493488
),
494489
]
495490
)
496-
if "uploadfs" not in COMMAND_LINE_TARGETS and not firmware_merge_required:
491+
if "uploadfs" not in COMMAND_LINE_TARGETS:
497492
for image in env.get("FLASH_EXTRA_IMAGES", []):
498493
openocd_args.extend(
499494
[

platform.py

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

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-
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+
]
274270
load_cmds.append(
275271
'monitor program_esp "{%s.bin}" %s verify'
276272
% (
277-
to_unix_path(
278-
debug_config.build_data["prog_path"][:-4]
279-
+ ("_merged" if merged_firmware else "")
280-
),
273+
to_unix_path(debug_config.build_data["prog_path"][:-4]),
281274
build_extra_data.get("application_offset", "0x10000"),
282275
)
283276
)

0 commit comments

Comments
 (0)