4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Embedded SwiftでRaspberry Pi Picoを動かす、Dockerでビルドして

Last updated at Posted at 2024-08-05

Embedded SwiftをDockerでビルドして、Raspberry Pi Picoを動かす

Appleからswift-embedded-examplesという、Raspberry Pi PicoやESP32-C6、STM32などをSwiftで動かすサンプルが公開されています
これをベースにSwiftでRaspberry Pi Pico Wを動かすのを試してみました
また、Raspberry Pi Picoは書き込みの際、USBメモリとして振る舞うので、専用の書き込みソフトが不要です
そこで、Dockerを利用してビルドし、開発環境を色々いい感じにするのも試してみました

SwiftをDockerでRaspberry Pi Pico向けにビルドする

Dockerfile

Swiftの開発チームが公開しているイメージをベースにします

Dockerfile
FROM swiftlang/swift:nightly-main-jammy

RUN apt-get update && apt-get install -y \
    gcc \
    cmake \
    gcc-arm-none-eabi \
    libnewlib-arm-none-eabi \
    build-essential \
    git \
    ninja-build \
    python3 \
    && apt-get clean

RUN git clone --depth 1 -b 1.5.1 https://github.com/raspberrypi/pico-sdk.git \
    && cd pico-sdk \
    && git submodule update --init

RUN git clone -b master https://github.com/raspberrypi/pico-examples.git

ENV PICO_SDK_PATH=/pico-sdk
ENV PICO_TOOLCHAIN_PATH=/usr/bin/arm-none-eabi-gcc

WORKDIR /workspace

ENTRYPOINT ["/bin/bash"]

必要なツール類をインストールして適当に設定してます
Raspberry Pi Picoのスタートガイドを参考にしました
Swiftをビルドするために追加でNinjaとPython3が必要だったので追加しました

Dockerイメージをビルドする

docker buildします
Apple Siliconではビルドできなかったので、明示的にアーキテクチャとしてamd64を指定する必要がありました

$ docker build --platform linux/amd64 -t swift-build-env-amd64 .

Swiftをビルド

swift-embedded-examplesのpico-w-blink-sdkをビルドしてみます
print関数でUSB UARTを使用したいので、stdio_init_all()を追加します

Main.swift
@main
struct Main {
    static func main() {
        stdio_init_all() // 追加

        let led = UInt32(CYW43_WL_GPIO_LED_PIN)
        if cyw43_arch_init() != 0 {
            print("Wi-Fi init failed")
            return
        }
        let dot = {
            cyw43_arch_gpio_put(led, true)
            sleep_ms(250)
            cyw43_arch_gpio_put(led, false)
            sleep_ms(250)
        }
        let dash = {
            cyw43_arch_gpio_put(led, true)
            sleep_ms(500)
            cyw43_arch_gpio_put(led, false)
            sleep_ms(250)
        }
        while true {
            dot()
            dot()
            dot()

            dash()
            dash()
            dash()

            dot()
            dot()
            dot()
        }
    }
}

作成したイメージを使って、プログラムをビルドします

$ docker run -it --rm -v $(pwd):/workspace swift-build-env-amd64 /workspace/build.sh

swift-embedded-examplesのpico-w-blink-sdkのREADMEを参考にしています

build.sh
#!/bin/bash

export PICO_BOARD=pico_w
export PICO_SDK_PATH='/pico-sdk'
export PICO_TOOLCHAIN_PATH='/usr/bin/arm-none-eabi-gcc'

cmake -B build -G Ninja .
cmake --build build

CMakeはswift-embedded-examplesを参考に作成しました

ビルドに成功すると、buildディレクトリにuf2ファイルが作成されています

Raspberry Pi Pico Wに書き込み

Raspberry Pi Pico WにあるBOOTSEL(たぶんBoot Select)ボタンを押下しなが、PCと接続します
RPI RP2というUSBデバイスが認識されるので、作成したuf2ファイルをコピペします

copy2pi.png

動作確認

BOOTSELボタンを押下せずに、再度PCに接続するなどして電源を入れて、Raspberry Pi Pico W上にあるLEDがチカチカしてたら成功です

Xcode上でコーティングする

せっかくSwiftなので、Xcode上でコーディングするのも試してみました

XcodeGenでxcprojectを作成する

Swift 5系ではBridging Headerが指定できないため、XcodeGenを利用してxcprojectを作成するようにしました

CMakeを見ながら必要そうな箇所を適当に設定しました
Xcode上ではpico-sdkの実態まではビルドしないため、リンカのエラーは握り潰し、あくまでXcode上ではSwiftから正しくpico-sdkのC言語のインタフェースを呼び出しているかだけチェックしています

project.yml
name: swift-raspberry-pi-pico-examples
settings:
  OTHER_LDFLAGS:
    - "-Wl,-undefined,dynamic_lookup"
targets:
  pico-sdk:
    type: framework
    platform: macOS
    sources:
      - path: pico-sdk
        type: folder
      - path: built-headers
        type: folder
  ex00-pico-w-blink:
    type: framework
    platform: macOS
    sources:
      - path: ex00-pico-w-blink
        excludes:
          - "build/**"
    settings:
      SWIFT_OBJC_BRIDGING_HEADER: ex00-pico-w-blink/BridgingHeader.h
      GCC_PREPROCESSOR_DEFINITIONS:
        - "$(inherited)"
        - "XCODE_WORKAROUND=1"
        - "PICO_DEFAULT_UART_INSTANCE=1"
      HEADER_SEARCH_PATHS:
        - "$(inherited)"
        - "$(PROJECT_DIR)/pico-sdk/src/common/pico_stdlib/include"
        - "$(PROJECT_DIR)/pico-sdk/src/rp2_common/hardware_gpio/include"
        - ...中略...
        - "$(PROJECT_DIR)/pico-sdk/lib/lwip/src/include"
        - "$(PROJECT_DIR)/include"

全文はこちら

ビルドを通すためにpico-sdkにパッチをあてる

arm向けのgccがDocker内にしか無い関係でそのままではビルドが通らなかったので、適当にパッチをあてました
Xcodeでビルドされる場合はパッチをあてた方を参照するように、GCC_PREPROCESSOR_DEFINITIONSにフラグを渡します
この辺はもう少しうまくやりたいです

312a313,314
> #elif XCODE_WORKAROUND
> #define __force_inline inline __attribute__((always_inline))
337a340,343
> #ifdef XCODE_WORKAROUND
> #define pico_default_asm(...) __asm ("")
> #define pico_default_asm_volatile(...) __asm volatile ("")
> #else
339a346
> #endif

まとめ

Appleから公開されたswift-embedded-examplesを参考に、SwiftをDockerでビルドしてRaspberry Pi Pico Wを動かしてみました
すんなりとDockerでビルドできて感動しました
Swiftの使える箇所が増えると、夢が広がっていきます

4
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?