2424
2525# Extends: https://github.com/platformio/platform-espressif32/blob/develop/builder/main.py
2626
27- from os .path import abspath , isdir , isfile , join
27+ from os .path import abspath , basename , isdir , isfile , join
2828
2929from SCons .Script import DefaultEnvironment , SConscript
3030
3131env = DefaultEnvironment ()
3232platform = env .PioPlatform ()
3333board_config = env .BoardConfig ()
3434build_mcu = board_config .get ("build.mcu" , "" ).lower ()
35+ partitions_name = board_config .get (
36+ "build.partitions" , board_config .get ("build.arduino.partitions" , "" )
37+ )
3538
3639FRAMEWORK_DIR = platform .get_package_dir ("framework-arduinoespressif32" )
3740assert isdir (FRAMEWORK_DIR )
4144# Helpers
4245#
4346
47+
4448def get_partition_table_csv (variants_dir ):
4549 fwpartitions_dir = join (FRAMEWORK_DIR , "tools" , "partitions" )
50+ variant_partitions_dir = join (variants_dir , board_config .get ("build.variant" , "" ))
4651
47- custom_partition = board_config .get (
48- "build.partitions" , board_config .get ("build.arduino.partitions" , "" )
49- )
52+ if partitions_name :
53+ # A custom partitions file is selected
54+ if isfile (join (variant_partitions_dir , partitions_name )):
55+ return join (variant_partitions_dir , partitions_name )
5056
51- if custom_partition :
52- partitions_csv = board_config .get ("build.partitions" , board_config .get (
53- "build.arduino.partitions" , "default.csv" ))
5457 return abspath (
55- join (fwpartitions_dir , partitions_csv )
56- if isfile (join (fwpartitions_dir , partitions_csv ))
57- else partitions_csv
58+ join (fwpartitions_dir , partitions_name )
59+ if isfile (join (fwpartitions_dir , partitions_name ))
60+ else partitions_name
5861 )
5962
60- variant_partitions = join (
61- variants_dir , board_config .get ("build.variant" , "" ), "partitions.csv"
62- )
63+ variant_partitions = join (variant_partitions_dir , "partitions.csv" )
6364 return (
6465 variant_partitions
6566 if isfile (variant_partitions )
@@ -68,9 +69,16 @@ def get_partition_table_csv(variants_dir):
6869
6970
7071def get_bootloader_image (variants_dir ):
72+ bootloader_image_file = "bootloader.bin"
73+ if partitions_name .endswith ("tinyuf2.csv" ):
74+ bootloader_image_file = "bootloader-tinyuf2.bin"
75+
7176 variant_bootloader = join (
72- variants_dir , board_config .get ("build.variant" , "" ), "bootloader.bin"
77+ variants_dir ,
78+ board_config .get ("build.variant" , "" ),
79+ board_config .get ("build.arduino.custom_bootloader" , bootloader_image_file ),
7380 )
81+
7482 return (
7583 variant_bootloader
7684 if isfile (variant_bootloader )
@@ -85,6 +93,76 @@ def get_bootloader_image(variants_dir):
8593 )
8694
8795
96+ def get_patched_bootloader_image (original_bootloader_image , bootloader_offset ):
97+ patched_bootloader_image = join (env .subst ("$BUILD_DIR" ), "patched_bootloader.bin" )
98+ bootloader_cmd = env .Command (
99+ patched_bootloader_image ,
100+ original_bootloader_image ,
101+ env .VerboseAction (
102+ " " .join (
103+ [
104+ '"$PYTHONEXE"' ,
105+ join (
106+ platform .get_package_dir ("tool-esptoolpy" ) or "" , "esptool.py"
107+ ),
108+ "--chip" ,
109+ build_mcu ,
110+ "merge_bin" ,
111+ "-o" ,
112+ "$TARGET" ,
113+ "--flash_mode" ,
114+ "${__get_board_flash_mode(__env__)}" ,
115+ "--flash_size" ,
116+ board_config .get ("upload.flash_size" , "4MB" ),
117+ "--target-offset" ,
118+ bootloader_offset ,
119+ bootloader_offset ,
120+ "$SOURCE" ,
121+ ]
122+ ),
123+ "Updating bootloader headers" ,
124+ ),
125+ )
126+ env .Depends ("$BUILD_DIR/$PROGNAME$PROGSUFFIX" , bootloader_cmd )
127+
128+ return patched_bootloader_image
129+
130+
131+ def add_tinyuf2_extra_image ():
132+ tinuf2_image = board_config .get (
133+ "upload.arduino.tinyuf2_image" ,
134+ join (variants_dir , board_config .get ("build.variant" , "" ), "tinyuf2.bin" ),
135+ )
136+
137+ # Add the UF2 image only if it exists and it's not already added
138+ if not isfile (tinuf2_image ):
139+ print ("Warning! The `%s` UF2 bootloader image doesn't exist" % tinuf2_image )
140+ return
141+
142+ if any (
143+ "tinyuf2.bin" == basename (extra_image [1 ])
144+ for extra_image in env .get ("FLASH_EXTRA_IMAGES" , [])
145+ ):
146+ print ("Warning! An extra UF2 bootloader image is already added!" )
147+ return
148+
149+ env .Append (
150+ FLASH_EXTRA_IMAGES = [
151+ (
152+ board_config .get (
153+ "upload.arduino.uf2_bootloader_offset" ,
154+ (
155+ "0x2d0000"
156+ if env .subst ("$BOARD" ).startswith ("adafruit" )
157+ else "0x410000"
158+ ),
159+ ),
160+ tinuf2_image ,
161+ ),
162+ ]
163+ )
164+
165+
88166#
89167# Run target-specific script to populate the environment with proper build flags
90168#
@@ -99,32 +177,6 @@ def get_bootloader_image(variants_dir):
99177 )
100178)
101179
102- #
103- # Process framework extra images
104- #
105-
106- env .Append (
107- LIBSOURCE_DIRS = [
108- join (FRAMEWORK_DIR , "libraries" )
109- ],
110-
111- FLASH_EXTRA_IMAGES = [
112- (
113- "0x1000" if build_mcu in ("esp32" , "esp32s2" ) else "0x0000" ,
114- get_bootloader_image (board_config .get (
115- "build.variants_dir" , join (FRAMEWORK_DIR , "variants" )))
116- ),
117- ("0x8000" , join (env .subst ("$BUILD_DIR" ), "partitions.bin" )),
118- ("0xe000" , join (FRAMEWORK_DIR , "tools" , "partitions" , "boot_app0.bin" ))
119- ]
120- + [
121- (offset , join (FRAMEWORK_DIR , img ))
122- for offset , img in board_config .get (
123- "upload.arduino.flash_extra_images" , []
124- )
125- ],
126- )
127-
128180#
129181# Target: Build Core Library
130182#
@@ -137,23 +189,68 @@ def get_bootloader_image(variants_dir):
137189 variants_dir = join ("$PROJECT_DIR" , board_config .get ("build.variants_dir" ))
138190
139191if "build.variant" in board_config :
140- env .Append (
141- CPPPATH = [
142- join (variants_dir , board_config .get ("build.variant" ))
143- ]
144- )
192+ env .Append (CPPPATH = [join (variants_dir , board_config .get ("build.variant" ))])
145193 env .BuildSources (
146194 join ("$BUILD_DIR" , "FrameworkArduinoVariant" ),
147- join (variants_dir , board_config .get ("build.variant" ))
195+ join (variants_dir , board_config .get ("build.variant" )),
148196 )
149197
150- libs .append (env .BuildLibrary (
151- join ("$BUILD_DIR" , "FrameworkArduino" ),
152- join (FRAMEWORK_DIR , "cores" , board_config .get ("build.core" ))
153- ))
198+ libs .append (
199+ env .BuildLibrary (
200+ join ("$BUILD_DIR" , "FrameworkArduino" ),
201+ join (FRAMEWORK_DIR , "cores" , board_config .get ("build.core" )),
202+ )
203+ )
154204
155205env .Prepend (LIBS = libs )
156206
207+ #
208+ # Process framework extra images
209+ #
210+
211+ # Starting with v2.0.4 the Arduino core contains updated bootloader images that have
212+ # innacurate default headers. This results in bootloops if firmware is flashed via
213+ # OpenOCD (e.g. debugging or uploading via debug tools). For this reason, before
214+ # uploading or debugging we need to adjust the bootloader binary according to
215+ # the values of the --flash-size and --flash-mode arguments.
216+ # Note: This behavior doesn't occur if uploading is done via esptoolpy, as esptoolpy
217+ # overrides the binary image headers before flashing.
218+
219+ bootloader_patch_required = bool (
220+ env .get ("PIOFRAMEWORK" , []) == ["arduino" ]
221+ and (
222+ "debug" in env .GetBuildType ()
223+ or env .subst ("$UPLOAD_PROTOCOL" ) in board_config .get ("debug.tools" , {})
224+ or env .IsIntegrationDump ()
225+ )
226+ )
227+
228+ bootloader_image_path = get_bootloader_image (variants_dir )
229+ bootloader_offset = "0x1000" if build_mcu in ("esp32" , "esp32s2" ) else "0x0000"
230+ if bootloader_patch_required :
231+ bootloader_image_path = get_patched_bootloader_image (
232+ bootloader_image_path , bootloader_offset
233+ )
234+
235+ env .Append (
236+ LIBSOURCE_DIRS = [join (FRAMEWORK_DIR , "libraries" )],
237+ FLASH_EXTRA_IMAGES = [
238+ (bootloader_offset , bootloader_image_path ),
239+ ("0x8000" , join (env .subst ("$BUILD_DIR" ), "partitions.bin" )),
240+ ("0xe000" , join (FRAMEWORK_DIR , "tools" , "partitions" , "boot_app0.bin" )),
241+ ]
242+ + [
243+ (offset , join (FRAMEWORK_DIR , img ))
244+ for offset , img in board_config .get ("upload.arduino.flash_extra_images" , [])
245+ ],
246+ )
247+
248+ # Add an extra UF2 image if the 'TinyUF2' partition is selected
249+ if partitions_name .endswith ("tinyuf2.csv" ) or board_config .get (
250+ "upload.arduino.tinyuf2_image" , ""
251+ ):
252+ add_tinyuf2_extra_image ()
253+
157254#
158255# Generate partition table
159256#
0 commit comments