Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 87 additions & 6 deletions docs/EmbeddedSwift/IntegratingWithSDKs.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ For an introduction and motivation into Embedded Swift, please see "[A Vision fo

The following document sketches how to integrate Swift code into some popular embedded platforms' SDKs and build systems.

## Integrating with Raspberry Pi Pico (W) build system:
## Integrating with Raspberry Pi Pico / Pico W / Pico 2 build system:

Development for [Raspberry Pi Pico and Pico W](https://www.raspberrypi.com/products/raspberry-pi-pico/) normally uses the [Pico SDK](https://github.com/raspberrypi/pico-sdk) and the vendor provides several [sample projects in the pico-examples repository](https://github.com/raspberrypi/pico-examples). The SDK and sample project setup is described in:

Expand Down Expand Up @@ -58,20 +58,100 @@ Notice that we're using functions and variables defined in C in the Pico SDK. Fo

Finally, we need to define the application's build rules in CMake that will be using CMake logic from the Pico SDK. The following content of `CMakeLists.txt` shows how to *manually call swiftc, the Swift compiler* instead of using the recently added CMake native support for Swift, so that we can see the full Swift compilation command.

We'll make sure to dynamically set the Swift compiler's target architecture based on the pico board used. This is to support both RP2040 and RP2350 in ARM mode, and RP2350's RISC-V mode.

We'll also ensure to recursively gather all Pico SDK-related compiler definitions in order to append them to our `swiftc` command.

```cmake
cmake_minimum_required(VERSION 3.13)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)

project(swift-blinky)
pico_sdk_init()

if(APPLE)
execute_process(COMMAND xcrun -f swiftc OUTPUT_VARIABLE SWIFTC OUTPUT_STRIP_TRAILING_WHITESPACE)
else()
execute_process(COMMAND which swiftc OUTPUT_VARIABLE SWIFTC OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()

# Dinamically set the architecture based on the Pico board used.
set(SWIFT_TARGET "armv6m-none-none-eabi")

if(PICO_PLATFORM STREQUAL "rp2350-arm-s")
message(STATUS "PICO_PLATFORM is set to rp2350-arm-s, using armv7em")
set(SWIFT_TARGET "armv7em-none-none-eabi")
list(APPEND CLANG_ARCH_ABI_FLAGS "-Xcc" "-mfloat-abi=soft")
elseif(PICO_PLATFORM STREQUAL "rp2040")
message(STATUS "PICO_PLATFORM is set to RP2040, using armv6m")
list(APPEND CLANG_ARCH_ABI_FLAGS "-Xcc" "-mfloat-abi=soft")
elseif(PICO_PLATFORM STREQUAL "rp2350-riscv")
message(STATUS "PICO_PLATFORM is set to rp2350-riscv, using riscv32.")
set(SWIFT_TARGET "riscv32-none-none-eabi")
list(APPEND CLANG_ARCH_ABI_FLAGS "-Xcc" "-march=rv32imac_zicsr_zifencei_zba_zbb_zbs_zbkb" "-Xcc" "-mabi=ilp32")
endif()

add_executable(swift-blinky)

# You may need to add additional libraries here, if you're using the Pico W.
target_link_libraries(swift-blinky
pico_stdlib hardware_uart hardware_gpio
)

# Gather compile definitions from all dependencies

set_property(GLOBAL PROPERTY visited_targets "")
set_property(GLOBAL PROPERTY compilerdefs_list "")

function(gather_compile_definitions_recursive target)
# Get the current value of visited_targets
get_property(visited_targets GLOBAL PROPERTY visited_targets)

# make sure we don't visit the same target twice
# and that we don't visit the special generator expressions
if (${target} MATCHES "\\$<" OR ${target} MATCHES "::@" OR ${target} IN_LIST visited_targets)
return()
endif()

# Append the target to visited_targets
list(APPEND visited_targets ${target})
set_property(GLOBAL PROPERTY visited_targets "${visited_targets}")

# Get the current value of compilerdefs_list
get_property(compilerdefs_list GLOBAL PROPERTY compilerdefs_list)

get_target_property(target_definitions ${target} INTERFACE_COMPILE_DEFINITIONS)
if (target_definitions)
# Append the target definitions to compilerdefs_list
list(APPEND compilerdefs_list ${target_definitions})
set_property(GLOBAL PROPERTY compilerdefs_list "${compilerdefs_list}")
endif()

get_target_property(target_linked_libs ${target} INTERFACE_LINK_LIBRARIES)
if (target_linked_libs)
foreach(linked_target ${target_linked_libs})
# Recursively gather compile definitions from dependencies
gather_compile_definitions_recursive(${linked_target})
endforeach()
endif()
endfunction()

gather_compile_definitions_recursive(swift-blinky)
get_property(COMPILE_DEFINITIONS GLOBAL PROPERTY compilerdefs_list)

# Parse compiler definitions into a format that swiftc can understand
list(REMOVE_DUPLICATES COMPILE_DEFINITIONS)
list(PREPEND COMPILE_DEFINITIONS "")
string(REPLACE "$<TARGET_PROPERTY:PICO_TARGET_BINARY_TYPE>" "$<TARGET_PROPERTY:swift-blinky,PICO_TARGET_BINARY_TYPE>" COMPILE_DEFINITIONS "${COMPILE_DEFINITIONS}")
string(REPLACE ";" ";-Xcc;-D" COMPILE_DEFINITIONS "${COMPILE_DEFINITIONS}")

add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_swiftcode.o
COMMAND
${SWIFTC}
-target armv6m-none-none-eabi -Xcc -mfloat-abi=soft -Xcc -fshort-enums
-target ${SWIFT_TARGET} -Xcc -fshort-enums
${COMPILE_DEFINITIONS}
${CLANG_ARCH_ABI_FLAGS}
-Xfrontend -function-sections -enable-experimental-feature Embedded -wmo -parse-as-library
$$\( echo '$<TARGET_PROPERTY:swift-blinky,INCLUDE_DIRECTORIES>' | tr '\;' '\\n' | sed -e 's/\\\(.*\\\)/-Xcc -I\\1/g' \)
$$\( echo '${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES}' | tr ' ' '\\n' | sed -e 's/\\\(.*\\\)/-Xcc -I\\1/g' \)
Expand All @@ -84,8 +164,8 @@ add_custom_command(
)
add_custom_target(swift-blinky-swiftcode DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_swiftcode.o)


target_link_libraries(swift-blinky
pico_stdlib hardware_uart hardware_gpio
${CMAKE_CURRENT_BINARY_DIR}/_swiftcode.o
)
add_dependencies(swift-blinky swift-blinky-swiftcode)
Expand All @@ -95,10 +175,11 @@ pico_add_extra_outputs(swift-blinky)
With these three files, we can now configure and build a Swift firmware for the Pico:

```bash
$ export TOOLCHAINS=org.swift.59202401301a
$ export PICO_BOARD=pico
$ export TOOLCHAINS=org.swift.59202401301a # any toolchain that supports embedded
$ export PICO_BOARD=pico # or any other RP-based board (including pico2)
$ export PICO_PLATFORM=<platform> # optional; possible values: rp2040, rp2350-arm-s or rp2350-riscv
$ export PICO_SDK_PATH=<path_to_pico_sdk>
$ export PICO_TOOLCHAIN_PATH=<path_to_arm_toolchain>
$ export PICO_TOOLCHAIN_PATH=<path_to_toolchain> # ARM / RISC-V toolchain
$ ls -al
-rw-r--r-- 1 kuba staff 39B Feb 2 22:08 BridgingHeader.h
-rw-r--r-- 1 kuba staff 1.3K Feb 2 22:08 CMakeLists.txt
Expand Down