arduino-pico/tools/platformio-build.py
2022-06-10 09:28:26 -07:00

270 lines
9.5 KiB
Python
Executable file

# Copyright 2021-present Maximilian Gerhardt <maximilian.gerhardt@rub.de>
# TinyUSB ignore snippet from https://github.com/episource/
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os, re, sys
from SCons.Script import DefaultEnvironment, Builder, AlwaysBuild
env = DefaultEnvironment()
platform = env.PioPlatform()
board = env.BoardConfig()
upload_protocol = env.subst("$UPLOAD_PROTOCOL") or "picotool"
#ram_size = board.get("upload.maximum_ram_size") # PlatformIO gives 264K here
# override to correct 256K for RAM section in linkerscript
ram_size = 256 * 1024 # not the 264K, which is 256K SRAM + 2*4K SCRATCH(X/Y).
FRAMEWORK_DIR = platform.get_package_dir("framework-arduinopico")
assert os.path.isdir(FRAMEWORK_DIR)
# read includes from this file to add them into CPPPATH later
includes_file = os.path.join(FRAMEWORK_DIR, "lib", "platform_inc.txt")
file_lines = []
includes = []
with open(includes_file, "r") as fp:
file_lines = fp.readlines()
for l in file_lines:
path = l.strip().replace("-iwithprefixbefore/", "").replace("/", os.sep)
# emulate -iprefix <framework path>.
path = os.path.join(FRAMEWORK_DIR, path)
# prevent non-existent paths from being added
# looking at you here, pico-extras/src/common/pico_audio and co.
if os.path.isdir(path):
includes.append(path)
# update progsize expression to also check for bootloader.
env.Replace(
SIZEPROGREGEXP=r"^(?:\.boot2|\.text|\.data|\.rodata|\.text.align|\.ARM.exidx)\s+(\d+).*"
)
env.Append(
ASFLAGS=env.get("CCFLAGS", [])[:],
CCFLAGS=[
"-Os", # Optimize for size by default
"-Werror=return-type",
"-march=armv6-m",
"-mcpu=cortex-m0plus",
"-mthumb",
"-ffunction-sections",
"-fdata-sections",
# use explicit include (-I) paths, otherwise it's
# not visible in the IDE's intellisense.
#"-iprefix" + os.path.join(FRAMEWORK_DIR),
#"@%s" % os.path.join(FRAMEWORK_DIR, "lib", "platform_inc.txt")
],
CFLAGS=[
"-std=gnu17"
],
CXXFLAGS=[
"-std=gnu++17",
"-fno-exceptions",
"-fno-rtti",
],
CPPDEFINES=[
("ARDUINO", 10810),
"ARDUINO_ARCH_RP2040",
("F_CPU", "$BOARD_F_CPU"),
("BOARD_NAME", '\\"%s\\"' % env.subst("$BOARD")),
],
CPPPATH=[
os.path.join(FRAMEWORK_DIR, "cores", "rp2040"),
os.path.join(FRAMEWORK_DIR, "cores", "rp2040", "api", "deprecated"),
os.path.join(FRAMEWORK_DIR, "cores", "rp2040",
"api", "deprecated-avr-comp")
],
LINKFLAGS=[
"-march=armv6-m",
"-mcpu=cortex-m0plus",
"-mthumb",
"@%s" % os.path.join(FRAMEWORK_DIR, "lib", "platform_wrap.txt"),
"-u_printf_float",
"-u_scanf_float",
# no cross-reference table, heavily spams the output
# "-Wl,--cref",
"-Wl,--check-sections",
"-Wl,--gc-sections",
"-Wl,--unresolved-symbols=report-all",
"-Wl,--warn-common"
],
LIBSOURCE_DIRS=[os.path.join(FRAMEWORK_DIR, "libraries")],
# do **NOT** Add lib to LIBPATH, otherwise
# erroneous libstdc++.a will be found that crashes!
#LIBPATH=[
# os.path.join(FRAMEWORK_DIR, "lib")
#],
# link lib/libpico.a by full path, ignore libstdc++
LIBS=[
File(os.path.join(FRAMEWORK_DIR, "lib", "libpico.a")),
"m", "c", "stdc++", "c"]
)
# expand with read includes
env.Append(CPPPATH=includes)
def configure_usb_flags(cpp_defines):
global ram_size
if "USE_TINYUSB" in cpp_defines:
env.Append(CPPPATH=[os.path.join(
FRAMEWORK_DIR, "libraries", "Adafruit_TinyUSB_Arduino", "src", "arduino")])
elif "PIO_FRAMEWORK_ARDUINO_NO_USB" in cpp_defines:
env.Append(
CPPPATH=[os.path.join(FRAMEWORK_DIR, "tools", "libpico")],
CPPDEFINES=[
"NO_USB",
"DISABLE_USB_SERIAL"
]
)
# do not further add more USB flags or update sizes. no USB used.
return
else:
# standard Pico SDK USB stack used.
env.Append(CPPPATH=[os.path.join(FRAMEWORK_DIR, "tools", "libpico")])
# in any case, add standard flags
# preferably use USB information from arduino.earlephilhower section,
# but fallback to sensible values derived from other parts otherwise.
usb_pid = board.get("build.arduino.earlephilhower.usb_pid",
board.get("build.hwids", [[0, 0]])[0][1])
usb_vid = board.get("build.arduino.earlephilhower.usb_vid",
board.get("build.hwids", [[0, 0]])[0][0])
usb_manufacturer = board.get(
"build.arduino.earlephilhower.usb_manufacturer", board.get("vendor", "Raspberry Pi"))
usb_product = board.get(
"build.arduino.earlephilhower.usb_product", board.get("name", "Pico"))
# Copy logic from makeboards.py.
# Depending on whether a certain upload / debug method is used, change
# the PID/VID.
# https://github.com/earlephilhower/arduino-pico/blob/master/tools/makeboards.py
vidtouse = usb_vid
pidtouse = usb_pid
if upload_protocol == "picoprobe":
pidtouse = '0x0004'
elif upload_protocol == "picodebug":
vidtouse = '0x1209'
pidtouse = '0x2488'
ram_size = 240 * 1024
env.Append(CPPDEFINES=[
("CFG_TUSB_MCU", "OPT_MCU_RP2040"),
("USB_VID", usb_vid),
("USB_PID", usb_pid),
("USB_MANUFACTURER", '\\"%s\\"' % usb_manufacturer),
("USB_PRODUCT", '\\"%s\\"' % usb_product),
("SERIALUSB_PID", usb_pid)
])
if "USBD_MAX_POWER_MA" not in env.Flatten(env.get("CPPDEFINES", [])):
env.Append(CPPDEFINES=[("USBD_MAX_POWER_MA", 500)])
print("Warning: Undefined USBD_MAX_OWER_MA, assuming 500mA")
# use vidtouse and pidtouse
# for USB PID/VID autodetection
hw_ids = board.get("build.hwids", [["0x2E8A", "0x00C0"]])
hw_ids[0][0] = vidtouse
hw_ids[0][1] = pidtouse
board.update("build.hwids", hw_ids)
board.update("upload.maximum_ram_size", ram_size)
#
# Process configuration flags
#
cpp_defines = env.Flatten(env.get("CPPDEFINES", []))
# Ignore TinyUSB automatically if not active without requiring ldf_mode = chain+
if not "USE_TINYUSB" in cpp_defines:
env_section = "env:" + env["PIOENV"]
ignored_libs = platform.config.get(
env_section, "lib_ignore", []
)
if not "Adafruit TinyUSB Library" in ignored_libs:
ignored_libs.append("Adafruit TinyUSB Library")
platform.config.set(
env_section, "lib_ignore", ignored_libs
)
# configure USB stuff
configure_usb_flags(cpp_defines)
# info about the filesystem is already parsed by the platform's main.py
# script. We can just use the info here
linkerscript_cmd = env.Command(
os.path.join("$BUILD_DIR", "memmap_default.ld"), # $TARGET
os.path.join(FRAMEWORK_DIR, "lib", "memmap_default.ld"), # $SOURCE
env.VerboseAction(" ".join([
'"$PYTHONEXE" "%s"' % os.path.join(
FRAMEWORK_DIR, "tools", "simplesub.py"),
"--input", "$SOURCE",
"--out", "$TARGET",
"--sub", "__FLASH_LENGTH__", "$PICO_FLASH_LENGTH",
"--sub", "__EEPROM_START__", "$PICO_EEPROM_START",
"--sub", "__FS_START__", "$FS_START",
"--sub", "__FS_END__", "$FS_END",
"--sub", "__RAM_LENGTH__", "%dk" % (ram_size // 1024),
]), "Generating linkerscript $BUILD_DIR/memmap_default.ld")
)
# if no custom linker script is provided, we use the command that we prepared to generate one.
if not board.get("build.ldscript", ""):
# execute fetch filesystem info stored in env to alawys have that info ready
env["fetch_fs_size"](env)
env.Depends("$BUILD_DIR/${PROGNAME}.elf", linkerscript_cmd)
env.Replace(LDSCRIPT_PATH=os.path.join("$BUILD_DIR", "memmap_default.ld"))
libs = []
variant = board.get("build.arduino.earlephilhower.variant", board.get("build.variant", ""))
if variant != "":
env.Append(CPPPATH=[
os.path.join(FRAMEWORK_DIR, "variants", variant)
])
libs.append(
env.BuildLibrary(
os.path.join("$BUILD_DIR", "FrameworkArduinoVariant"),
os.path.join(FRAMEWORK_DIR, "variants", variant)))
libs.append(
env.BuildLibrary(
os.path.join("$BUILD_DIR", "FrameworkArduino"),
os.path.join(FRAMEWORK_DIR, "cores", "rp2040")))
bootloader_src_file = board.get(
"build.arduino.earlephilhower.boot2_source", "boot2_generic_03h_2_padded_checksum.S")
# Add bootloader file (boot2.o)
# Only build the needed .S file, exclude all others via src_filter.
env.BuildSources(
os.path.join("$BUILD_DIR", "FrameworkArduinoBootloader"),
os.path.join(FRAMEWORK_DIR, "boot2"),
"-<*> +<%s>" % bootloader_src_file,
)
# Add include flags for all .S assembly file builds
env.Append(
ASFLAGS=[
"-I", os.path.join(FRAMEWORK_DIR, "pico-sdk", "src",
"rp2040", "hardware_regs", "include"),
"-I", os.path.join(FRAMEWORK_DIR, "pico-sdk", "src",
"common", "pico_binary_info", "include")
]
)
env.Prepend(LIBS=libs)