Raspberry Pi PicoとEmbedded Swiftを試してみる

はじめに

WWDC2024での出会い

WWDC2024のセッションをたまたま視聴したところ、非常に興味深い内容がありました。

WWDC2024 - Swift Embedded Programming

「Swiftでこんなことまでできるのか!」と驚き、そのまま試してみることにしました。Swiftを使った組み込み開発はこれまであまり聞いたことがなかったので、この機会にぜひ遊んでみようと思い立ちました。

購入の決断

まずは実際に試すために、必要なハードウェアをAmazonで検索。思ったより安く手に入ることがわかり、即購入しました。 今回はPico Wの方を購入しています。Pico とPico Wは少し機能が違います。

Pico WはWi-Fi機能を備えています。 面白さの観点からも、今回はPico Wを試してみたいと思います。

開発環境の構築

初期設定

Swiftを使った組み込み開発の初期設定は、公式ドキュメントに従うのが一番です。

Swift Embedded Examples - GitHub

ドキュメントによれば、開発中の実験的なアプローチであるため、Development SnapshotsのToolchainを使用するように指示されています。Swift 6.0のリリース前の段階なので、まだ正式なリリースではありませんが、問題ありません。実験の一環として楽しみます。

無事にインストールが完了しました。

サンプルプログラムの実行

Raspberry Pi Pico向けのサンプルプログラムも公式で提供されています。

swift-embedded-examples/pico-blink-sdk - GitHub

SDKの準備

サンプルプログラムを読むと、Raspberry Pi Pico SDKが必要であることがわかりました。

Pico SDK - GitHub

公式のSDKはLinuxベースで開発されているため、macOSで使用する場合は以下のツールをインストールする必要があります。

cmake
arm-none-eabi-gcc
git
python3
ninja

これらのツールは、Homebrewで簡単にインストールできます。

$ brew install cmake
$ brew install armmbed/formulae/arm-none-eabi-gcc
$ brew install git
$ brew install python
$ brew install ninja

また、環境変数の設定も必要です。

vi ~/.zshrc
export TOOLCHAINS=arm-none-eabi-gcc
export PICO_BOARD=pico-w
export PICO_SDK_PATH=(あなたのSDKまでのPATH)/pico-sdk
export PICO_TOOLCHAIN_PATH=$(brew --prefix)/opt/arm-none-eabi-gcc/bin

トラブルシューティング

Swift Toolchainの設定

ここで一度詰まりました。swiftcのバージョンがおかしいと感じ、確認してみたところ、設定が間違っていることがわかりました。

% swiftc --version
swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
Target: arm64-apple-macosx14.0

自分の目的はSwift 6.0のToolchainを使うことだったため、以下のようにToolchainのパスを修正しました。

export PATH="/Library/Developer/Toolchains/swift-6.0-DEVELOPMENT-SNAPSHOT-2024-08-22-a.xctoolchain/usr/bin:$PATH"

ビルドの実行

設定が完了したので、サンプルプログラムをビルドします。まずはCMakeを実行。

cmake -B build -G Ninja .

次に、ビルドを実行します。

cmake --build build

すると

[9/10] Building CXX object CMakeFiles/pioasm.dir/pio_assembler.cpp.o
[10/10] Linking CXX executable pioasm
[88/88] Linking CXX executable swift-blinky.elf

エラーメッセージが出ることなく、無事にビルドが完了しました。

最後の仕上げ

最終的なzshrcの設定は以下のようになりました。

export PATH="/Library/Developer/Toolchains/swift-6.0-DEVELOPMENT-SNAPSHOT-2024-08-22-a.xctoolchain/usr/bin:$PATH"
export TOOLCHAINS="/Library/Developer/Toolchains/swift-6.0-DEVELOPMENT-SNAPSHOT-2024-08-22-a.xctoolchain/usr/bin"
export PICO_BOARD=pico_w
export PICO_SDK_PATH="(あなたのpico-SDKまでのPATH)/pico-sdk"
export PICO_TOOLCHAIN_PATH=/opt/homebrew/opt/arm-none-eabi-gcc/lib/

※私の私物Macと古いWindowsマシンで開発をしていましたが、Macの方はToolchainsの設定をいじるので設定をいじった後は元に戻したりして実験終了しておかないと趣味アプリとかで「急にビルドエラーが発生するようになった!」というトラブルになるので要注意です。

サンプルコードの確認

ビルドが完了したので、サンプルコードを確認してみます。このプログラムは、LEDを点滅させるシンプルなものです。

github.com

@main
struct Main {
    static func main() {
        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()
        }
    }
}

上記プログラムを実行した際の実際の動作の様子

このプログラムは、モールス信号のようにLEDを点滅させます。短い点滅をdot、長い点滅をdashと定義し、それぞれを3回ずつ繰り返しています。使用しているGPIOはCYW43_WL_GPIO_LED_PINで、他のGPIOピンも使用できるようです。今後はこの部分を調査し、さらに応用していきたいと思います。

終わりに

ここまでおよそ1ヶ月半ほどかかりましたが、仕事の合間を縫って進めたので、実際に取り組んだ時間はもう少し短いと思います。 Swiftでの組み込み開発はまだ始まったばかりですが、これからさらに面白い展開が期待できそうです。次は、さらに高度な機能に挑戦してみたいと思います。

アンドパッドでは様々なチャレンジをし、技術を高めたい好奇心旺盛なiOSエンジニアを募集しています!

hrmos.co

engineer.andpad.co.jp