diff --git a/docs/images/the_arduinoide_experience.png b/docs/images/the_arduinoide_experience.png new file mode 100644 index 000000000..1f2282a26 Binary files /dev/null and b/docs/images/the_arduinoide_experience.png differ diff --git a/docs/images/the_platformio_experience.png b/docs/images/the_platformio_experience.png new file mode 100644 index 000000000..263cb8617 Binary files /dev/null and b/docs/images/the_platformio_experience.png differ diff --git a/docs/index.rst b/docs/index.rst index 8cd7ad81d..8d87c1e38 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -20,6 +20,8 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p Installation IDE Menus + Platform.IO Integration + Pin (Re)Assignment Analog I/O diff --git a/docs/platformio.rst b/docs/platformio.rst new file mode 100644 index 000000000..d63a7c37a --- /dev/null +++ b/docs/platformio.rst @@ -0,0 +1,219 @@ +Using this core with PlatformIO +=============================== + +What is PlatformIO? +------------------- + +`PlatformIO `__ is a free, open-source build-tool written in Python, which also integrates into VSCode code as an extension. + +PlatformIO significantly simplifies writing embedded software by offering a unified build system, yet being able to create project files for many different IDEs, including VSCode, Eclipse, CLion, etc. +Through this, PlatformIO can offer extensive features such as IntelliSense (autocomplete), debugging, unit testing etc., which not available in the standard Arduino IDE. + +The Arduino IDE experience: + +.. image:: images/the_arduinoide_experience.png + +The PlatformIO experience: + +.. image:: images/the_platformio_experience.png + +Refer to the general documentation at https://docs.platformio.org/. + +Especially useful is the `Getting started with VSCode + PlatformIO `__ page. + +Hereafter it is assumed that you have a basic understanding of PlatformIO in regards to project creation, project file structure and building and uploading PlatformIO projects, through reading the above pages. + +Current state of development +---------------------------- + +At the time of writing, PlatformIO integration for this core is a work-in-progress and not yet merged into mainline PlatformIO. This is subject to change soon. + +If you want to use the PlatformIO integration right now, make sure you first create a standard Raspberry Pi Pico + Arduino project within PlatformIO. +This will give you a project with the ``platformio.ini`` + +.. code:: ini + + [env:pico] + platform = raspberrypi + board = pico + framework = arduino + +Here, you need to change the `platform` to take advantage of the features described hereunder. +You *also* need to inject two PlatformIO packages, one for the compiler toolchain and one for the Arduino core package. + +.. code:: ini + + [env:pico] + platform = https://github.com/maxgerhardt/platform-raspberrypi.git + board = pico + framework = arduino + ; note that download link for toolchain is specific for OS. see https://github.com/earlephilhower/pico-quick-toolchain/releases. + platform_packages = + maxgerhardt/framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git + maxgerhardt/toolchain-pico@https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.1-a/x86_64-w64-mingw32.arm-none-eabi-7855b0c.210706.zip + +When the support for this core has been merged into mainline PlatformIO, this notice will be removed and a standard `platformio.ini` as shown above will work as a base. + +Selecting the new core +---------------------- + +Prerequisite for using this core is to tell PlatformIO to switch to it. +There will be board definition files where the Earle-Philhower core will +be the default since it's a board that only exists in this core (and not +the other https://github.com/arduino/ArduinoCore-mbed). To switch boards +for which this is not the default core (e.g. the standard +``board = pico``), the directive + +.. code:: ini + + board_build.core = earlephilhower + +must be added to the ``platformio.ini``. This controls the `core +switching +logic `__. + +Flash size +---------- + +Controlled via specifying the size allocated for the filesystem. +Available sketch size is calculated accordingly by using (as in +``makeboards.py``) that number and the (constant) EEPROM size (4096 +bytes) and the total flash size as known to PlatformIO via the board +definition file. The expression on the right can involve "b","k","m" +(bytes/kilobytes/megabytes) and floating point numbers. This makes it +actually more flexible than in the Arduino IDE where there is a finite +list of choices. Calculations happen in `the +platform `__. + +.. code:: ini + + ; in reference to a board = pico config (2MB flash) + ; Flash Size: 2MB (Sketch: 1MB, FS:1MB) + board_build.filesystem_size = 1m + ; Flash Size: 2MB (No FS) + board_build.filesystem_size = 0m + ; Flash Size: 2MB (Sketch: 0.5MB, FS:1.5MB) + board_build.filesystem_size = 1.5m + +CPU Speed +--------- + +As for all other PlatformIO platforms, the ``f_cpu`` macro value (which +is passed to the core) can be changed as +`documented `__ + +.. code:: ini + + ; 133MHz + board_build.f_cpu = 133000000L + +Debug Port +---------- + +Via +`build_flags `__ +as done for many other cores +(`example `__). + +.. code:: ini + + ; Debug Port: Serial + build_flags = -DDEBUG_RP2040_PORT=Serial + ; Debug Port: Serial 1 + build_flags = -DDEBUG_RP2040_PORT=Serial1 + ; Debug Port: Serial 2 + build_flags = -DDEBUG_RP2040_PORT=Serial2 + +Debug Level +----------- + +Done again by directly adding the needed `build +flags `__. +When wanting to define multiple build flags, they must be accumulated in +either a sing line or a newline-separated expression. + +.. code:: ini + + ; Debug level: Core + build_flags = -DDEBUG_RP2040_CORE + ; Debug level: SPI + build_flags = -DDEBUG_RP2040_SPI + ; Debug level: Wire + build_flags = -DDEBUG_RP2040_WIRE + ; Debug level: All + build_flags = -DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE + ; Debug level: NDEBUG + build_flags = -DNDEBUG + + ; example: Debug port on serial 2 and all debug output + build_flags = -DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_PORT=Serial2 + ; equivalent to above + build_flags = + -DDEBUG_RP2040_WIRE + -DDEBUG_RP2040_SPI + -DDEBUG_RP2040_CORE + -DDEBUG_RP2040_PORT=Serial2 + +USB Stack +--------- + +Not specifying any special build flags regarding this gives one the +default Pico SDK USB stack. To change it, add + +.. code:: ini + + ; Adafruit TinyUSB + build_flags = -DUSE_TINYUSB + ; No USB stack + build_flags = -DPIO_FRAMEWORK_ARDUINO_NO_USB + +Note that the special "No USB" setting is also supported, through the +shortcut-define ``PIO_FRAMEWORK_ARDUINO_NO_USB``. + + +Selecting a different core version +---------------------------------- + +If you wish to use a different version of the core, e.g., the latest git +``master`` version, you can use a +`platform_packages `__ +directive to do so. Simply specify that the framework package +(``framework-arduinopico``) comes from a different source. + +.. code:: ini + + platform_packages = + framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#master + +Whereas the ``#master`` can also be replaced by a ``#branchname`` or a +``#commithash``. If left out, it will pull the default branch, which is ``master``. + +The ``file://`` pseudo-protocol can also be used instead of ``https://`` to point to a +local copy of the core (with e.g. some modifications) on disk. + +Note that this can only be done for versions that have the PlatformIO +builder script it in, so versions before 1.9.2 are not supported. + +Examples +-------- + +The following example ``platformio.ini`` can be used for a Raspberry Pi Pico +and 0.5MByte filesystem. + +.. code:: ini + + [env:pico] + platform = https://github.com/maxgerhardt/platform-raspberrypi.git + board = pico + framework = arduino + build_board.core = earlephilhower + board_build.filesystem_size = 0.5m + ; note that download link for toolchain is specific for OS. see https://github.com/earlephilhower/pico-quick-toolchain/releases. + platform_packages = + maxgerhardt/framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git + maxgerhardt/toolchain-pico@https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.1-a/x86_64-w64-mingw32.arm-none-eabi-7855b0c.210706.zip + + +The initial project structure should be generated just creating a new +project for the Pico and the Arduino framework, after which the +auto-generated ``platformio.ini`` can be adapted per above. diff --git a/package.json b/package.json index 9c152619f..b58b89cbf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,17 @@ { - "name": "framework-arduinopico", - "description": "Arduino Wiring-based Framework (RPi Pico RP2040)", - "url": "https://github.com/earlephilhower/arduino-pico", - "version": "0.9.2" + "name": "framework-arduinopico", + "version": "1.10903.0", + "description": "Arduino Wiring-based Framework (RPi Pico RP2040)", + "keywords": [ + "framework", + "arduino", + "Cortex-M", + "Raspberry Pi", + "RP2040" + ], + "homepage": "https://arduino-pico.readthedocs.io/en/latest/", + "repository": { + "type": "git", + "url": "https://github.com/earlephilhower/arduino-pico" + } } diff --git a/tools/platformio-build.py b/tools/platformio-build.py new file mode 100644 index 000000000..9c49305a5 --- /dev/null +++ b/tools/platformio-build.py @@ -0,0 +1,228 @@ +# Copyright 2021-present Maximilian Gerhardt +# +# 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") + +FRAMEWORK_DIR = platform.get_package_dir("framework-arduinopico") +assert os.path.isdir(FRAMEWORK_DIR) + +# 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=[ + "-Werror=return-type", + "-march=armv6-m", + "-mcpu=cortex-m0plus", + "-mthumb", + "-ffunction-sections", + "-fdata-sections", + "-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")], + + LIBPATH=[ + os.path.join(FRAMEWORK_DIR, "lib") + ], + + # link lib/libpico.a + LIBS=["pico", "m", "c", "stdc++", "c"] +) + + +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) + ]) + + # 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", [])) + +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", None)) + +if variant is not None: + 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)